summaryrefslogtreecommitdiffstats
path: root/libnetdata/adaptive_resortable_list/adaptive_resortable_list.h
blob: 294c52e81bc76e402a354e57b8fcf46cef348e60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// SPDX-License-Identifier: GPL-3.0-or-later

#include "../libnetdata.h"

#ifndef NETDATA_ADAPTIVE_RESORTABLE_LIST_H
#define NETDATA_ADAPTIVE_RESORTABLE_LIST_H 1

#define ARL_ENTRY_FLAG_FOUND    0x01    // the entry has been found in the source data
#define ARL_ENTRY_FLAG_EXPECTED 0x02    // the entry is expected by the program
#define ARL_ENTRY_FLAG_DYNAMIC  0x04    // the entry was dynamically allocated, from source data

typedef struct arl_entry {
    char *name;             // the keywords
    uint32_t hash;          // the hash of the keyword

    void *dst;              // the dst to pass to the processor

    uint8_t flags;          // ARL_ENTRY_FLAG_*

    // the processor to do the job
    void (*processor)(const char *name, uint32_t hash, const char *value, void *dst);

    // double linked list for fast re-linkings
    struct arl_entry *prev, *next;
} ARL_ENTRY;

typedef struct arl_base {
    char *name;

    size_t iteration;   // incremented on each iteration (arl_begin())
    size_t found;       // the number of expected keywords found in this iteration
    size_t expected;    // the number of expected keywords
    size_t wanted;      // the number of wanted keywords
                        // i.e. the number of keywords found and expected

    size_t relinkings;  // the number of relinkings we have made so far

    size_t allocated;   // the number of keywords allocated
    size_t fred;        // the number of keywords cleaned up

    size_t rechecks;    // the number of iterations between re-checks of the
                        // wanted number of keywords
                        // this is only needed in cases where the source
                        // is having less lines over time.

    size_t added;       // it is non-zero if new keywords have been added
                        // this is only needed to detect new lines have
                        // been added to the file, over time.

#ifdef NETDATA_INTERNAL_CHECKS
    size_t fast;        // the number of times we have taken the fast path
    size_t slow;        // the number of times we have taken the slow path
#endif

    // the processor to do the job
    void (*processor)(const char *name, uint32_t hash, const char *value, void *dst);

    // the linked list of the keywords
    ARL_ENTRY *head;

    // since we keep the list of keywords sorted (as found in the source data)
    // this is next keyword that we expect to find in the source data.
    ARL_ENTRY *next_keyword;
} ARL_BASE;

// create a new ARL
ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks);

// free an ARL
void arl_free(ARL_BASE *arl_base);

// register an expected keyword to the ARL
// together with its destination ( i.e. the output of the processor() )
ARL_ENTRY *arl_expect_custom(ARL_BASE *base, const char *keyword, void (*processor)(const char *name, uint32_t hash, const char *value, void *dst), void *dst);
#define arl_expect(base, keyword, dst) arl_expect_custom(base, keyword, NULL, dst)

// an internal call to complete the check() call
int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *value);

// begin an ARL iteration
void arl_begin(ARL_BASE *base);

void arl_callback_str2ull(const char *name, uint32_t hash, const char *value, void *dst);
void arl_callback_str2kernel_uint_t(const char *name, uint32_t hash, const char *value, void *dst);
void arl_callback_ssize_t(const char *name, uint32_t hash, const char *value, void *dst);

// check a keyword against the ARL
// this is to be called for each keyword read from source data
// s = the keyword, as collected
// src = the src data to be passed to the processor
// it is defined in the header file in order to be inlined
static inline int arl_check(ARL_BASE *base, const char *keyword, const char *value) {
    ARL_ENTRY *e = base->next_keyword;

#ifdef NETDATA_INTERNAL_CHECKS
    if(unlikely((base->fast + base->slow) % (base->expected + base->allocated) == 0 && (base->fast + base->slow) > (base->expected + base->allocated) * base->iteration))
        info("ARL '%s': Did you forget to call arl_begin()?", base->name);
#endif

    // it should be the first entry (pointed by base->next_keyword)
    if(likely(!strcmp(keyword, e->name))) {
        // it is

#ifdef NETDATA_INTERNAL_CHECKS
        base->fast++;
#endif

        e->flags |= ARL_ENTRY_FLAG_FOUND;

        // execute the processor
        if(unlikely(e->dst)) {
            e->processor(e->name, e->hash, value, e->dst);
            base->found++;
        }

        // be prepared for the next iteration
        base->next_keyword = e->next;
        if(unlikely(!base->next_keyword))
            base->next_keyword = base->head;

        // stop if we collected all the values for this iteration
        if(unlikely(base->found == base->wanted)) {
            // fprintf(stderr, "FOUND ALL WANTED 2: found = %zu, wanted = %zu, expected %zu\n", base->found, base->wanted, base->expected);
            return 1;
        }

        return 0;
    }

#ifdef NETDATA_INTERNAL_CHECKS
    base->slow++;
#endif

    // we read from source, a not-expected keyword
    return arl_find_or_create_and_relink(base, keyword, value);
}

#endif //NETDATA_ADAPTIVE_RESORTABLE_LIST_H