]> arthur.barton.de Git - netdata.git/blob - src/registry_person.c
Merge pull request #1998 from ktsaou/master
[netdata.git] / src / registry_person.c
1 #include "registry_internals.h"
2
3 // ----------------------------------------------------------------------------
4 // PERSON_URL INDEX
5
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 inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, const char *url) {
16     debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, url);
17
18     char buf[sizeof(REGISTRY_URL) + strlen(url)];
19
20     REGISTRY_URL *u = (REGISTRY_URL *)&buf;
21     strcpy(u->url, url);
22     u->hash = simple_hash(u->url);
23
24     REGISTRY_PERSON_URL tpu = { .url = u };
25
26     REGISTRY_PERSON_URL *pu = (REGISTRY_PERSON_URL *)avl_search(&p->person_urls, (void *)&tpu);
27     return pu;
28 }
29
30 inline REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
31     debug(D_REGISTRY, "Registry: registry_person_url_index_add('%s', '%s')", p->guid, pu->url->url);
32     REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_insert(&(p->person_urls), (avl *)(pu));
33     if(tpu != pu)
34         error("Registry: registry_person_url_index_add('%s', '%s') already exists as '%s'", p->guid, pu->url->url, tpu->url->url);
35
36     return tpu;
37 }
38
39 inline REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
40     debug(D_REGISTRY, "Registry: registry_person_url_index_del('%s', '%s')", p->guid, pu->url->url);
41     REGISTRY_PERSON_URL *tpu = (REGISTRY_PERSON_URL *)avl_remove(&(p->person_urls), (avl *)(pu));
42     if(!tpu)
43         error("Registry: registry_person_url_index_del('%s', '%s') deleted nothing", p->guid, pu->url->url);
44     else if(tpu != pu)
45         error("Registry: registry_person_url_index_del('%s', '%s') deleted wrong URL '%s'", p->guid, pu->url->url, tpu->url->url);
46
47     return tpu;
48 }
49
50 // ----------------------------------------------------------------------------
51 // PERSON_URL
52
53 REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, REGISTRY_URL *u, char *name, size_t namelen, time_t when) {
54     debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
55
56     // protection from too big names
57     if(namelen > registry.max_name_length)
58         namelen = registry.max_name_length;
59
60     REGISTRY_PERSON_URL *pu = mallocz(sizeof(REGISTRY_PERSON_URL) + namelen);
61
62     // a simple strcpy() should do the job
63     // but I prefer to be safe, since the caller specified urllen
64     strncpyz(pu->machine_name, name, namelen);
65
66     pu->machine = m;
67     pu->first_t = pu->last_t = (uint32_t)when;
68     pu->usages = 1;
69     pu->url = u;
70     pu->flags = REGISTRY_URL_FLAGS_DEFAULT;
71     m->links++;
72
73     registry.persons_urls_memory += sizeof(REGISTRY_PERSON_URL) + namelen;
74
75     debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, u->url);
76     REGISTRY_PERSON_URL *tpu = registry_person_url_index_add(p, pu);
77     if(tpu != pu) {
78         error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", u->url, name, p->guid);
79         free(pu);
80         pu = tpu;
81     }
82     else
83         registry_url_link(u);
84
85     return pu;
86 }
87
88 void registry_person_url_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
89     debug(D_REGISTRY, "registry_person_url_free('%s', '%s')", p->guid, pu->url->url);
90
91     REGISTRY_PERSON_URL *tpu = registry_person_url_index_del(p, pu);
92     if(tpu) {
93         registry_url_unlink(tpu->url);
94         tpu->machine->links--;
95         registry.persons_urls_memory -= sizeof(REGISTRY_PERSON_URL) + strlen(tpu->machine_name);
96         freez(tpu);
97     }
98 }
99
100 // this function is needed to change the name of a PERSON_URL
101 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) {
102     debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url, sizeof(REGISTRY_PERSON_URL) + namelen);
103
104     // keep a backup
105     REGISTRY_PERSON_URL pu2 = {
106             .first_t = pu->first_t,
107             .last_t = pu->last_t,
108             .usages = pu->usages,
109             .flags = pu->flags,
110             .machine = pu->machine,
111             .machine_name = ""
112     };
113
114     // remove the existing one from the index
115     registry_person_url_free(p, pu);
116     pu = &pu2;
117
118     // allocate a new one
119     REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, u, name, namelen, when);
120     tpu->first_t = pu->first_t;
121     tpu->last_t = pu->last_t;
122     tpu->usages = pu->usages;
123     tpu->flags = pu->flags;
124
125     return tpu;
126 }
127
128
129 // ----------------------------------------------------------------------------
130 // PERSON
131
132 REGISTRY_PERSON *registry_person_find(const char *person_guid) {
133     debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid);
134     return dictionary_get(registry.persons, person_guid);
135 }
136
137 REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) {
138     debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON));
139
140     REGISTRY_PERSON *p = mallocz(sizeof(REGISTRY_PERSON));
141     if(!person_guid) {
142         for(;;) {
143             uuid_t uuid;
144             uuid_generate(uuid);
145             uuid_unparse_lower(uuid, p->guid);
146
147             debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid);
148             if (!dictionary_get(registry.persons, p->guid)) {
149                 debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid);
150                 break;
151             }
152             else
153                 info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid);
154         }
155     }
156     else
157         strncpyz(p->guid, person_guid, GUID_LEN);
158
159     debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): creating dictionary of urls", p->guid);
160     avl_init(&p->person_urls, person_url_compare);
161
162     p->first_t = p->last_t = (uint32_t)when;
163     p->usages = 0;
164
165     registry.persons_memory += sizeof(REGISTRY_PERSON);
166
167     registry.persons_count++;
168     dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON));
169
170     return p;
171 }
172
173
174 // 1. validate person GUID
175 // 2. if it is valid, find it
176 // 3. if it is not valid, create a new one
177 // 4. return it
178 REGISTRY_PERSON *registry_person_get(const char *person_guid, time_t when) {
179     debug(D_REGISTRY, "Registry: registry_person_get('%s'): creating dictionary of urls", person_guid);
180
181     REGISTRY_PERSON *p = NULL;
182
183     if(person_guid && *person_guid) {
184         char buf[GUID_LEN + 1];
185         // validate it is a GUID
186         if(unlikely(regenerate_guid(person_guid, buf) == -1))
187             info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid);
188         else {
189             person_guid = buf;
190             p = registry_person_find(person_guid);
191         }
192     }
193
194     if(!p) p = registry_person_allocate(NULL, when);
195
196     return p;
197 }
198
199 void registry_person_del(REGISTRY_PERSON *p) {
200     debug(D_REGISTRY, "Registry: registry_person_del('%s'): creating dictionary of urls", p->guid);
201
202     while(p->person_urls.root)
203         registry_person_unlink_from_url(p, (REGISTRY_PERSON_URL *)p->person_urls.root);
204
205     debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
206     dictionary_del(registry.persons, p->guid);
207
208     debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
209     freez(p);
210 }
211
212 // ----------------------------------------------------------------------------
213 // LINKING OF OBJECTS
214
215 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) {
216     debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, u->url);
217
218     REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, u->url);
219     if(!pu) {
220         debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, u->url);
221         pu = registry_person_url_allocate(p, m, u, name, namelen, when);
222         registry.persons_urls_count++;
223     }
224     else {
225         debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, u->url);
226         pu->usages++;
227         if(likely(pu->last_t < (uint32_t)when)) pu->last_t = (uint32_t)when;
228
229         if(pu->machine != m) {
230             REGISTRY_MACHINE_URL *mu = dictionary_get(pu->machine->machine_urls, u->url);
231             if(mu) {
232                 debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.",
233                      p->guid, m->guid, u->url, pu->machine->guid);
234                 mu->flags |= REGISTRY_URL_FLAGS_EXPIRED;
235             }
236             else {
237                 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.",
238                      p->guid, m->guid, u->url, pu->machine->guid);
239             }
240
241             pu->machine->links--;
242             pu->machine = m;
243         }
244
245         if(strcmp(pu->machine_name, name)) {
246             // the name of the PERSON_URL has changed !
247             pu = registry_person_url_reallocate(p, m, u, name, namelen, when, pu);
248         }
249     }
250
251     p->usages++;
252     if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when;
253
254     if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) {
255         debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, u->url);
256         pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED;
257     }
258
259     return pu;
260 }
261
262 void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) {
263     registry_person_url_free(p, pu);
264 }