lower registry memory requirements by eliminating DICTIONARY structures for PERSON_URLs
Costa Tsaousis (ktsaou) committed
Jan 1, 2017 at 05:51 UTC
3d239c5bf9abf9a263409fc8a2dc0c190efcdf70
11 files changed
+119
-58
src/avl.c
+24
-10
@@ -283,18 +283,30 @@ avl *avl_remove(avl_tree *tree, avl *item) {
283
// ---------------------------
284
// traversing
285
286
-void avl_walker(avl *node, void (*callback)(void *entry, void *data), void *data) {
287
- if(node->avl_link[0])
288
- avl_walker(node->avl_link[0], callback, data);
286
+int avl_walker(avl *node, int (*callback)(void *entry, void *data), void *data) {
287
+ int total = 0, ret = 0;
288
290
- callback(node, data);
289
+ if(node->avl_link[0]) {
290
+ ret = avl_walker(node->avl_link[0], callback, data);
291
+ if(ret < 0) return ret;
292
+ total += ret;
293
+ }
294
+
295
+ ret = callback(node, data);
296
+ if(ret < 0) return ret;
297
+ total += ret;
298
292
- if(node->avl_link[1])
293
- avl_walker(node->avl_link[1], callback, data);
299
+ if(node->avl_link[1]) {
300
+ ret = avl_walker(node->avl_link[1], callback, data);
301
+ if (ret < 0) return ret;
302
+ total += ret;
303
+ }
304
+
305
+ return total;
306
}
307
296
-void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data) {
297
- avl_walker(t->root, callback, data);
308
+int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data) {
309
+ return avl_walker(t->root, callback, data);
310
}
311
312
// ---------------------------
@@ -372,10 +384,12 @@ avl *avl_insert_lock(avl_tree_lock *t, avl *a) {
384
return ret;
385
}
386
375
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data) {
387
+int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data) {
388
+ int ret;
389
avl_read_lock(t);
377
- avl_traverse(&t->avl_tree, callback, data);
390
+ ret = avl_traverse(&t->avl_tree, callback, data);
391
avl_unlock(t);
392
+ return ret;
393
}
394
395
void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
src/avl.h
+2
-2
@@ -80,7 +80,7 @@ void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b));
80
void avl_init(avl_tree *t, int (*compar)(void *a, void *b));
81
82
83
-void avl_traverse_lock(avl_tree_lock *t, void (*callback)(void *entry, void *data), void *data);
84
-void avl_traverse(avl_tree *t, void (*callback)(void *entry, void *data), void *data);
83
+int avl_traverse_lock(avl_tree_lock *t, int (*callback)(void *entry, void *data), void *data);
84
+int avl_traverse(avl_tree *t, int (*callback)(void *entry, void *data), void *data);
85
86
#endif /* avl.h */
src/health.c
+3
-1
@@ -663,7 +663,7 @@ struct variable2json_helper {
663
size_t counter;
664
};
665
666
-static void single_variable2json(void *entry, void *data) {
666
+static int single_variable2json(void *entry, void *data) {
667
struct variable2json_helper *helper = (struct variable2json_helper *)data;
668
RRDVAR *rv = (RRDVAR *)entry;
669
calculated_number value = rrdvar2number(rv);
@@ -674,6 +674,8 @@ static void single_variable2json(void *entry, void *data) {
674
buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
675
676
helper->counter++;
677
+
678
+ return 0;
679
}
680
681
void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
src/registry.c
+8
-8
@@ -75,7 +75,7 @@ struct registry_json_walk_person_urls_callback {
75
};
76
77
// callback for rendering PERSON_URLs
78
-static inline int registry_json_person_url_callback(void *entry, void *data) {
78
+static int registry_json_person_url_callback(void *entry, void *data) {
79
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
80
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
81
struct web_client *w = c->w;
@@ -86,11 +86,11 @@ static inline int registry_json_person_url_callback(void *entry, void *data) {
86
buffer_sprintf(w->response.data, "\n\t\t[ \"%s\", \"%s\", %u000, %u, \"%s\" ]",
87
pu->machine->guid, pu->url->url, pu->last_t, pu->usages, pu->machine_name);
88
89
- return 1;
89
+ return 0;
90
}
91
92
// callback for rendering MACHINE_URLs
93
-static inline int registry_json_machine_url_callback(void *entry, void *data) {
93
+static int registry_json_machine_url_callback(void *entry, void *data) {
94
REGISTRY_MACHINE_URL *mu = (REGISTRY_MACHINE_URL *)entry;
95
struct registry_json_walk_person_urls_callback *c = (struct registry_json_walk_person_urls_callback *)data;
96
struct web_client *w = c->w;
@@ -113,7 +113,7 @@ struct registry_person_url_callback_verify_machine_exists_data {
113
int count;
114
};
115
116
-int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
116
+static inline int registry_person_url_callback_verify_machine_exists(void *entry, void *data) {
117
struct registry_person_url_callback_verify_machine_exists_data *d = (struct registry_person_url_callback_verify_machine_exists_data *)data;
118
REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)entry;
119
REGISTRY_MACHINE *m = d->m;
@@ -181,7 +181,7 @@ int registry_request_access_json(struct web_client *w, char *person_guid, char *
181
182
buffer_sprintf(w->response.data, ",\n\t\"person_guid\": \"%s\",\n\t\"urls\": [", p->guid);
183
struct registry_json_walk_person_urls_callback c = { p, NULL, w, 0 };
184
- dictionary_get_all(p->person_urls, registry_json_person_url_callback, &c);
184
+ avl_traverse(&p->person_urls, registry_json_person_url_callback, &c);
185
buffer_strcat(w->response.data, "\n\t]\n");
186
187
registry_json_footer(w);
@@ -284,7 +284,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
284
struct registry_person_url_callback_verify_machine_exists_data data = { m, 0 };
285
286
// verify the old person has access to this machine
287
- dictionary_get_all(op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
287
+ avl_traverse(&op->person_urls, registry_person_url_callback_verify_machine_exists, &data);
288
if(!data.count) {
289
registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
290
registry_json_footer(w);
@@ -294,7 +294,7 @@ int registry_request_switch_json(struct web_client *w, char *person_guid, char *
294
295
// verify the new person has access to this machine
296
data.count = 0;
297
- dictionary_get_all(np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
297
+ avl_traverse(&np->person_urls, registry_person_url_callback_verify_machine_exists, &data);
298
if(!data.count) {
299
registry_json_header(w, "switch", REGISTRY_STATUS_FAILED);
300
registry_json_footer(w);
@@ -372,7 +372,7 @@ void registry_statistics(void) {
372
rrddim_set(stm, "persons", registry.persons_memory + registry.persons_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
373
rrddim_set(stm, "machines", registry.machines_memory + registry.machines_count * sizeof(NAME_VALUE) + sizeof(DICTIONARY));
374
rrddim_set(stm, "urls", registry.urls_memory);
375
- rrddim_set(stm, "persons_urls", registry.persons_urls_memory + registry.persons_count * sizeof(DICTIONARY) + registry.persons_urls_count * sizeof(NAME_VALUE));
375
+ rrddim_set(stm, "persons_urls", registry.persons_urls_memory);
376
rrddim_set(stm, "machines_urls", registry.machines_urls_memory + registry.machines_count * sizeof(DICTIONARY) + registry.machines_urls_count * sizeof(NAME_VALUE));
377
rrdset_done(stm);
378
}
src/registry.h
+2
@@ -54,9 +54,11 @@
54
// should only happen when netdata starts
55
extern int registry_init(void);
56
57
+/*
58
// free all data held by the registry
59
// should only happen when netdata exits
60
extern void registry_free(void);
61
+*/
62
63
// HTTP requests handled by the registry
64
extern int registry_request_access_json(struct web_client *w, char *person_guid, char *machine_guid, char *url, char *name, time_t when);
src/registry_db.c
+2
-1
@@ -86,7 +86,8 @@ static inline int registry_person_save(void *entry, void *file) {
86
);
87
88
if(ret >= 0) {
89
- int ret2 = dictionary_get_all(p->person_urls, registry_person_save_url, fp);
89
+ //int ret2 = dictionary_get_all(p->person_urls, registry_person_save_url, fp);
90
+ int ret2 = avl_traverse(&p->person_urls, registry_person_save_url, fp);
91
if (ret2 < 0) return ret2;
92
ret += ret2;
93
}
src/registry_init.c
+2
-1
@@ -80,7 +80,7 @@ int registry_init(void) {
80
81
return 0;
82
}
83
-
83
+/*
84
void registry_free(void) {
85
if(!registry.enabled) return;
86
@@ -158,3 +158,4 @@ void registry_free(void) {
158
debug(D_REGISTRY, "Registry: destroying machines dictionary");
159
dictionary_destroy(registry.machines);
160
}
161
+*/
src/registry_internals.c
+4
-5
@@ -115,7 +115,7 @@ REGISTRY_PERSON_URL *registry_verify_request(char *person_guid, char *machine_gu
115
}
116
if(pp) *pp = p;
117
118
- REGISTRY_PERSON_URL *pu = dictionary_get(p->person_urls, url);
118
+ REGISTRY_PERSON_URL *pu = registry_person_url_find(p, url);
119
if(!pu) {
120
info("Registry Request Verification: URL not found for person, person: '%s', machine '%s', url '%s'", person_guid, machine_guid, url);
121
return NULL;
@@ -170,7 +170,7 @@ REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid,
170
return NULL;
171
}
172
173
- REGISTRY_PERSON_URL *dpu = dictionary_get(p->person_urls, delete_url);
173
+ REGISTRY_PERSON_URL *dpu = registry_person_url_find(p, delete_url);
174
if(!dpu) {
175
info("Registry Delete Request: URL not found for person: '%s', machine '%s', url '%s', delete url '%s'", p->guid, m->guid, pu->url->url, delete_url);
176
return NULL;
@@ -178,7 +178,7 @@ REGISTRY_PERSON *registry_request_delete(char *person_guid, char *machine_guid,
178
179
registry_log('D', p, m, pu->url, dpu->url->url);
180
181
- dictionary_del(p->person_urls, dpu->url->url);
181
+ registry_person_url_del(p, dpu);
182
183
registry_url_unlink(dpu->url);
184
@@ -240,8 +240,7 @@ REGISTRY_MACHINE *registry_request_machine(char *person_guid, char *machine_guid
240
struct machine_request_callback_data rdata = { m, NULL };
241
242
// request a walk through on the dictionary
243
- // no need for locking here, the underlying dictionary has its own
244
- dictionary_get_all(p->person_urls, machine_request_callback, &rdata);
243
+ avl_traverse(&p->person_urls, machine_request_callback, &rdata);
244
245
if(rdata.result)
246
return m;
src/registry_machine.c
+1
-1
@@ -93,7 +93,7 @@ REGISTRY_MACHINE_URL *registry_machine_link_to_url(REGISTRY_MACHINE *m, REGISTRY
93
if(likely(m->last_t < (uint32_t)when)) m->last_t = (uint32_t)when;
94
95
if(mu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
96
- info("registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url);
96
+ debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): accessing an expired URL.", m->guid, u->url);
97
mu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
98
}
99
src/registry_person.c
+62
-28
@@ -1,21 +1,42 @@
1
#include "registry_internals.h"
2
3
// ----------------------------------------------------------------------------
4
-// PERSON
4
+// PERSON_URL
5
6
-REGISTRY_PERSON *registry_person_find(const char *person_guid) {
7
- debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
8
- return dictionary_get(registry.persons, person_guid);
6
+int person_url_compare(void *a, void *b) {
7
+ register uint32_t hash1 = ((REGISTRY_PERSON_URL *)a)->url->hash;
8
+ register uint32_t hash2 = ((REGISTRY_PERSON_URL *)b)->url->hash;
9
+
10
+ if(hash1 < hash2) return -1;
11
+ else if(hash1 > hash2) return 1;
12
+ else return strcmp(((REGISTRY_PERSON_URL *)a)->url->url, ((REGISTRY_PERSON_URL *)b)->url->url);
13
+}
14
+
15
+#define registry_person_url_index_add(person, rc) (REGISTRY_PERSON_URL *)avl_insert(&((person)->person_urls), (avl *)(rc))
16
+#define registry_person_url_index_del(person, rc) (REGISTRY_PERSON_URL *)avl_remove(&((person)->person_urls), (avl *)(rc))
17
+
18
+REGISTRY_PERSON_URL *registry_person_url_find(REGISTRY_PERSON *p, const char *url) {
19
+ debug(D_REGISTRY, "Registry: registry_person_url_find('%s', '%s')", p->guid, url);
20
+
21
+ char buf[sizeof(REGISTRY_URL) + strlen(url)];
22
+
23
+ REGISTRY_URL *u = (REGISTRY_URL *)&buf;
24
+ strcpy(u->url, url);
25
+ u->hash = simple_hash(u->url);
26
+
27
+ REGISTRY_PERSON_URL tpu = { .url = u };
28
+
29
+ REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu);
30
+ return pu;
31
}
32
33
REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
34
+ debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
35
+
36
// protection from too big names
37
if(namelen > registry.max_name_length)
38
namelen = registry.max_name_length;
39
16
- debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
17
- sizeof(REGISTRY_PERSON_URL) + namelen);
18
-
40
REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen);
41
42
// a simple strcpy() should do the job
@@ -32,43 +53,54 @@ REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_M
53
registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen;
54
55
debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
35
- dictionary_set(p->person_urls, u->url, pu, sizeof(REGISTRY_PERSON_URL));
56
+ registry_person_url_index_add(p, pu);
57
+
58
registry_url_link(u);
59
60
return pu;
61
}
62
63
+// this function is needed to change the name of a PERSON_URL
64
REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when, REGISTRY_PERSON_URL *pu) {
42
- // this function is needed to change the name of a PERSON_URL
65
+ debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
66
44
- debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
45
- sizeof(REGISTRY_PERSON_URL) + namelen);
67
+ // remove the existing one from the index
68
+ registry_person_url_index_del(p, pu);
69
+ registry_url_unlink(pu->url);
70
+ pu->machine->links--;
71
+ registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(pu->machine_name);
72
73
+ // allocate a new one
74
REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
75
tpu->first_t = pu->first_t;
76
tpu->last_t = pu->last_t;
77
tpu->usages = pu->usages;
51
-
52
- // ok, these are a hack - since the registry_person_url_allocate() is
53
- // adding these, we have to subtract them
54
- tpu->machine->links--;
55
- registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(pu->machine_name);
56
- registry_url_unlink(u);
78
+ tpu->flags = pu->flags;
79
80
freez(pu);
59
-
81
return tpu;
82
}
83
63
-REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
64
- REGISTRY_PERSON *p = NULL;
84
66
- debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
85
+void registry_person_url_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
86
+ debug(D_REGISTRY, "Registry: registry_person_url_del('%s', '%s')", p->guid, pu->url->url);
87
+ registry_person_url_index_del(p, pu);
88
+}
89
68
- p = mallocz(sizeof(REGISTRY_PERSON));
90
+// ----------------------------------------------------------------------------
91
+// PERSON
92
93
+REGISTRY_PERSON *registry_person_find(const char *person_guid) {
94
+ debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
95
+ return dictionary_get(registry.persons, person_guid);
96
+}
97
+
98
+REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
99
+ debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
100
+
101
+ REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON));
102
if(!person_guid) {
71
- for (; ;) {
103
+ for(;;) {
104
uuid_t uuid;
105
uuid_generate(uuid);
106
uuid_unparse_lower(uuid, p->guid);
@@ -86,7 +118,7 @@ REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when)
118
strncpyz(p->guid, person_guid, GUID_LEN);
119
120
debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
89
- p->person_urls = dictionary_create(DICTIONARY_FLAGS);
121
+ avl_init(&p->person_urls, person_url_compare);
122
123
p->first_t = p->last_t = (uint32_t)when;
124
p->usages = 0;
@@ -105,6 +137,8 @@ REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when)
137
// 3. if it is not valid, create a new one
138
// 4. return it
139
REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
140
+ debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid);
141
+
142
REGISTRY_PERSON *p = NULL;
143
144
if(person_guid && *person_guid) {
@@ -129,7 +163,7 @@ REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
163
REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
164
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
165
132
- REGISTRY_PERSON_URL *pu = dictionary_get(p->person_urls, u->url);
166
+ REGISTRY_PERSON_URL *pu = registry_person_url_find(p, u->url);
167
if(!pu) {
168
debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
169
pu = registry_person_url_allocate(p, m, u, name, namelen, when);
@@ -143,12 +177,12 @@ REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MA
177
if(pu->machine != m) {
178
REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url);
179
if(mu) {
146
- info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
180
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
181
p->guid, m->guid, u->url, pu->machine->guid);
182
mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
183
}
184
else {
151
- info("registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
185
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - but the URL is not linked to the old machine.",
186
p->guid, m->guid, u->url, pu->machine->guid);
187
}
188
@@ -166,7 +200,7 @@ REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MA
200
if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when;
201
202
if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
169
- info("registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
203
+ debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
204
pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
205
}
206
src/registry_person.h
+9
-1
@@ -8,6 +8,8 @@
8
9
// for each PERSON-URL pair we keep this
10
struct registry_person_url {
11
+ avl avl; // binary tree node
12
+
13
REGISTRY_URL *url; // de-duplicated URL
14
REGISTRY_MACHINE *machine; // link the MACHINE of this URL
15
@@ -26,11 +28,14 @@ typedef struct registry_person_url REGISTRY_PERSON_URL;
28
struct registry_person {
29
char guid[GUID_LEN + 1]; // the person GUID
30
29
- DICTIONARY *person_urls; // dictionary of PERSON_URL *
31
+ avl_tree person_urls; // dictionary of PERSON_URLs
32
33
uint32_t first_t; // the first time we saw this
34
uint32_t last_t; // the last time we saw this
35
uint32_t usages; // how many times this has been accessed
36
+
37
+ //uint32_t flags;
38
+ //char *email;
39
};
40
typedef struct registry_person REGISTRY_PERSON;
41
@@ -41,4 +46,7 @@ extern REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t
46
extern REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when);
47
extern REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when);
48
49
+extern REGISTRY_PERSON_URL *registry_person_url_find(REGISTRY_PERSON *p, const char *url);
50
+extern void registry_person_url_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu);
51
+
52
#endif //NETDATA_REGISTRY_PERSON_H