]> arthur.barton.de Git - netdata.git/blob - src/adaptive_resortable_list.h
adaptive resortable list implementation; used it in cgroups and vmstat
[netdata.git] / src / adaptive_resortable_list.h
1 #ifndef NETDATA_ADAPTIVE_RESORTABLE_LIST_H
2 #define NETDATA_ADAPTIVE_RESORTABLE_LIST_H
3
4 /*
5  * ADAPTIVE RE-SORTABLE LIST
6  * This structure allows netdata to read a file of NAME VALUE lines
7  * in the fastest possible way.
8  *
9  * It maintains a linked list of all NAME (keywords), sorted in the
10  * same order as found in the source data file.
11  * The linked list is kept sorted at all times - the source file
12  * may change at any time, the list will adapt.
13  *
14  * The caller:
15  *
16  * 1. calls arl_create() to create a list
17  *
18  * 2. calls arl_expect() to register the expected keyword
19  *
20  * Then:
21  *
22  * 3. calls arl_begin() to initiate a data collection iteration.
23  *    This is to be called just ONCE every time the source is re-scanned.
24  *
25  * 4. calls arl_check() for each line read from the file.
26  *
27  * Finally:
28  *
29  * 5. calls arl_free() to destroy this and free all memory.
30  *
31  * The program will call the processor() function, given to
32  * arl_create(), for each expected keyword found.
33  * The default processor() expects dst to be an unsigned long long *.
34  *
35  * LIMITATIONS
36  * DO NOT USE THIS IF THE A NAME/KEYWORD MAY APPEAR MORE THAN
37  * ONCE IN THE SOURCE DATA SET.
38  */
39
40 #include "common.h"
41
42 #define ARL_ENTRY_FLAG_FOUND    0x01    // the entry has been found in the source data
43 #define ARL_ENTRY_FLAG_EXPECTED 0x02    // the entry is expected by the program
44 #define ARL_ENTRY_FLAG_DYNAMIC  0x04    // the entry was dynamically allocated, from source data
45
46 typedef struct arl_entry {
47     char *name;             // the keywords
48     uint32_t hash;          // the hash of the keyword
49
50     void *dst;              // the dst to pass to the processor
51
52     uint8_t flags;          // ARL_ENTRY_FLAG_*
53
54     // double linked list for fast re-linkings
55     struct arl_entry *prev, *next;
56 } ARL_ENTRY;
57
58 typedef struct arl_base {
59     size_t iteration;   // incremented on each iteration (arl_begin())
60     size_t found;       // the number of expected keywords found in this iteration
61     size_t expected;    // the number of expected keywords
62     size_t wanted;      // the number of wanted keywords
63                         // i.e. the number of keywords found and expected
64
65     size_t relinkings;  // the number of relinkings we have made so far
66     size_t allocated;   // the number of keywords allocated
67
68     size_t rechecks;    // the number of iterations between re-checks of the
69                         // wanted number of keywords
70                         // this is only needed in cases where the source
71                         // is having less lines over time.
72
73     size_t added;       // it is non-zero if new keywords have been added
74                         // this is only needed to detect new lines have
75                         // been added to the file, over time.
76
77     // the processor to do the job
78     void (*processor)(const char *name, uint32_t hash, const char *value, void *dst);
79
80     // the linked list of the keywords
81     ARL_ENTRY *head;
82
83     // since we keep the list of keywords sorted (as found in the source data)
84     // this is next keyword that we expect to find in the source data.
85     ARL_ENTRY *next_keyword;
86 } ARL_BASE;
87
88 // create a new ARL
89 extern ARL_BASE *arl_create(void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks);
90
91 // free an ARL
92 extern void arl_free(ARL_BASE *arl_base);
93
94 // register an expected keyword to the ARL
95 // together with its destination ( i.e. the output of the processor() )
96 extern ARL_ENTRY *arl_expect(ARL_BASE *base, const char *keyword, void *dst);
97
98 // an internal call to complete the check() call
99 extern int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, uint32_t hash, const char *value);
100
101 // begin an ARL iteration
102 extern void arl_begin(ARL_BASE *base);
103
104 // check a keyword against the ARL
105 // this is to be called for each keyword read from source data
106 // s = the keyword, as collected
107 // src = the src data to be passed to the processor
108 // it is defined in the header file in order to be inlined
109 static inline int arl_check(ARL_BASE *base, const char *keyword, const char *value) {
110     ARL_ENTRY *e = base->next_keyword;
111     uint32_t hash = simple_hash(keyword);
112
113     // it should be the first entry (pointed by base->next_keyword)
114     if(likely(hash == e->hash && !strcmp(keyword, e->name))) {
115         // it is
116
117         e->flags |= ARL_ENTRY_FLAG_FOUND;
118
119         // execute the processor
120         if(unlikely(e->dst)) {
121             base->processor(e->name, e->hash, value, e->dst);
122             base->found++;
123         }
124
125         // be prepared for the next iteration
126         base->next_keyword = e->next;
127         if(unlikely(!base->next_keyword))
128             base->next_keyword = base->head;
129
130         // stop if we collected all the values for this iteration
131         if(unlikely(base->found == base->wanted))
132             return 1;
133
134         return 0;
135     }
136
137     // we read from source, a not-expected keyword
138     return arl_find_or_create_and_relink(base, keyword, hash, value);
139 }
140
141 #endif //NETDATA_ADAPTIVE_RESORTABLE_LIST_H