}
// create a new ARL
-ARL_BASE *arl_create(void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks) {
+ARL_BASE *arl_create(const char *name, void (*processor)(const char *, uint32_t, const char *, void *), size_t rechecks) {
ARL_BASE *base = callocz(1, sizeof(ARL_BASE));
+ base->name = strdupz(name);
+
if(!processor)
base->processor = arl_callback_str2ull;
else
freez(e);
}
+ freez(arl_base->name);
+
#ifdef NETDATA_INTERNAL_CHECKS
memset(arl_base, 0, sizeof(ARL_BASE));
#endif
}
void arl_begin(ARL_BASE *base) {
- ARL_ENTRY *e;
- /*
- info("iteration %zu, expected %zu, wanted %zu, allocated %zu, fred %zu, relinkings %zu, found %zu, added %zu, fast %zu, slow %zu"
- , base->iteration
- , base->expected
- , base->wanted
- , base->allocated
- , base->fred
- , base->relinkings
- , base->found
- , base->added
- , base->fast
- , base->slow
- );
- for(e = base->head; e ; e = e->next) fprintf(stderr, "%s ", e->name);
- fprintf(stderr, "\n");
- */
+#ifdef NETDATA_INTERNAL_CHECKS
+ if(likely(base->iteration > 10)) {
+ // do these checks after the ARL has been sorted
+
+ if(unlikely(base->relinkings > (base->expected + base->allocated)))
+ info("ARL '%s' has %zu relinkings with %zu expected and %zu allocated entries. Is the source changing so fast?"
+ , base->name, base->relinkings, base->expected, base->allocated);
+
+ if(unlikely(base->slow > base->fast))
+ info("ARL '%s' has %zu fast searches and %zu slow searches. Is the source really changing so fast?"
+ , base->name, base->fast, base->slow);
+
+ if(unlikely(base->iteration % 60 == 0)) {
+ info("ARL '%s' statistics: iteration %zu, expected %zu, wanted %zu, allocated %zu, fred %zu, relinkings %zu, found %zu, added %zu, fast %zu, slow %zu"
+ , base->name
+ , base->iteration
+ , base->expected
+ , base->wanted
+ , base->allocated
+ , base->fred
+ , base->relinkings
+ , base->found
+ , base->added
+ , base->fast
+ , base->slow
+ );
+ // for(e = base->head; e; e = e->next) fprintf(stderr, "%s ", e->name);
+ // fprintf(stderr, "\n");
+ }
+ }
+#endif
if(unlikely(base->added || base->iteration % base->rechecks) == 1) {
base->added = 0;
base->wanted = 0;
- for(e = base->head; e ; e = e->next) {
+ ARL_ENTRY *e = base->head;
+ while(e) {
if(e->flags & ARL_ENTRY_FLAG_FOUND) {
// remove the found flag
// count it in wanted
if(e->flags & ARL_ENTRY_FLAG_EXPECTED)
base->wanted++;
+
}
- else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC) {
+ else if(e->flags & ARL_ENTRY_FLAG_DYNAMIC && !(base->head == e && !e->next)) { // not last entry
// we can remove this entry
// it is not found, and it was created because
// it was found in the source file
+
+ // remember the next one
+ ARL_ENTRY *t = e->next;
+
+ // remove it from the list
if(e->next) e->next->prev = e->prev;
if(e->prev) e->prev->next = e->next;
if(base->head == e) base->head = e->next;
+
+ // free it
freez(e->name);
freez(e);
+ // count it
base->fred++;
+
+ // continue
+ e = t;
+ continue;
}
+
+ e = e->next;
}
}
+ if(unlikely(!base->head)) {
+ // hm... no nodes at all in the list #1700
+ // add a fake one to prevent a crash
+ // this is better than checking for the existence of nodes all the time
+ arl_expect(base, "a-really-not-existing-source-keyword", NULL);
+ }
+
base->iteration++;
base->next_keyword = base->head;
base->found = 0;
+
}
// register an expected keyword to the ARL
break;
#ifdef NETDATA_INTERNAL_CHECKS
- if(unlikely(e == base->next_keyword))
+ if(unlikely(base->next_keyword && e == base->next_keyword))
fatal("Internal Error: e == base->last");
#endif
if(e) {
// found it in the keywords
+
base->relinkings++;
// run the processor for it
base->added++;
}
+#ifdef NETDATA_INTERNAL_CHECKS
+ if(unlikely(base->iteration % 60 == 0 && e->flags & ARL_ENTRY_FLAG_FOUND))
+ info("ARL '%s': entry '%s' is already found. Did you forget to call arl_begin()?", base->name, s);
+#endif
+
e->flags |= ARL_ENTRY_FLAG_FOUND;
// link it here