| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "database/rrd.h" |
| 4 | #include "registry_internals.h" |
| 5 | |
| 6 | // ---------------------------------------------------------------------------- |
| 7 | // PERSON_URL INDEX |
| 8 | |
| 9 | inline REGISTRY_PERSON_URL *registry_person_url_index_find(REGISTRY_PERSON *p, STRING *url) { |
| 10 | netdata_log_debug(D_REGISTRY, "Registry: registry_person_url_index_find('%s', '%s')", p->guid, string2str(url)); |
| 11 | |
| 12 | REGISTRY_PERSON_URL *pu; |
| 13 | for(pu = p->person_urls ; pu ;pu = pu->next) |
| 14 | if(pu->url == url) |
| 15 | break; |
| 16 | |
| 17 | return pu; |
| 18 | } |
| 19 | |
| 20 | inline REGISTRY_PERSON_URL *registry_person_url_index_add(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { |
| 21 | DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(p->person_urls, pu, prev, next); |
| 22 | return pu; |
| 23 | } |
| 24 | |
| 25 | inline REGISTRY_PERSON_URL *registry_person_url_index_del(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { |
| 26 | DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(p->person_urls, pu, prev, next); |
| 27 | return pu; |
| 28 | } |
| 29 | |
| 30 | // ---------------------------------------------------------------------------- |
| 31 | // PERSON_URL |
| 32 | |
| 33 | REGISTRY_PERSON_URL *registry_person_url_allocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when) { |
| 34 | netdata_log_debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, string2str(url), sizeof(REGISTRY_PERSON_URL) + machine_name_len); |
| 35 | |
| 36 | // protection from too big names |
| 37 | if(machine_name_len > registry.max_name_length) |
| 38 | machine_name_len = registry.max_name_length; |
| 39 | |
| 40 | REGISTRY_PERSON_URL *pu = aral_mallocz(registry.person_urls_aral); |
| 41 | |
| 42 | // a simple strcpy() should do the job, |
| 43 | // but I prefer to be safe, since the caller specified name_len |
| 44 | pu->machine_name = string_strdupz(machine_name); |
| 45 | |
| 46 | pu->machine = m; |
| 47 | pu->first_t = pu->last_t = (uint32_t)when; |
| 48 | pu->usages = 1; |
| 49 | pu->url = string_dup(url); |
| 50 | pu->flags = REGISTRY_URL_FLAGS_DEFAULT; |
| 51 | m->links++; |
| 52 | |
| 53 | netdata_log_debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): indexing URL in person", p->guid, m->guid, string2str(url)); |
| 54 | REGISTRY_PERSON_URL *tpu = registry_person_url_index_add(p, pu); |
| 55 | if(tpu != pu) { |
| 56 | netdata_log_error("Registry: Attempted to add duplicate person url '%s' with name '%s' to person '%s'", string2str(url), machine_name, p->guid); |
| 57 | string_freez(pu->machine_name); |
| 58 | string_freez(pu->url); |
| 59 | aral_freez(registry.person_urls_aral, pu); |
| 60 | pu = tpu; |
| 61 | } |
| 62 | |
| 63 | return pu; |
| 64 | } |
| 65 | |
| 66 | void registry_person_url_deindex_and_free(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { |
| 67 | netdata_log_debug(D_REGISTRY, "registry_person_url_deindex_and_free('%s', '%s')", p->guid, string2str(pu->url)); |
| 68 | |
| 69 | REGISTRY_PERSON_URL *tpu = registry_person_url_index_del(p, pu); |
| 70 | if(tpu) { |
| 71 | string_freez(tpu->machine_name); |
| 72 | string_freez(tpu->url); |
| 73 | tpu->machine->links--; |
| 74 | aral_freez(registry.person_urls_aral, tpu); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | // this function is needed to change the name of a PERSON_URL |
| 79 | REGISTRY_PERSON_URL *registry_person_url_reallocate(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when, REGISTRY_PERSON_URL *pu) { |
| 80 | netdata_log_debug(D_REGISTRY, "registry_person_url_reallocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, string2str(url), sizeof(REGISTRY_PERSON_URL) + machine_name_len); |
| 81 | |
| 82 | // keep a backup |
| 83 | REGISTRY_PERSON_URL pu2 = { |
| 84 | .first_t = pu->first_t, |
| 85 | .last_t = pu->last_t, |
| 86 | .usages = pu->usages, |
| 87 | .flags = pu->flags, |
| 88 | .machine = pu->machine, |
| 89 | .machine_name = NULL |
| 90 | }; |
| 91 | |
| 92 | // remove the existing one from the index |
| 93 | registry_person_url_deindex_and_free(p, pu); |
| 94 | pu = &pu2; |
| 95 | |
| 96 | // allocate a new one |
| 97 | REGISTRY_PERSON_URL *tpu = registry_person_url_allocate(p, m, url, machine_name, machine_name_len, when); |
| 98 | tpu->first_t = pu->first_t; |
| 99 | tpu->last_t = pu->last_t; |
| 100 | tpu->usages = pu->usages; |
| 101 | tpu->flags = pu->flags; |
| 102 | |
| 103 | return tpu; |
| 104 | } |
| 105 | |
| 106 | |
| 107 | // ---------------------------------------------------------------------------- |
| 108 | // PERSON |
| 109 | |
| 110 | REGISTRY_PERSON *registry_person_find(const char *person_guid) { |
| 111 | netdata_log_debug(D_REGISTRY, "Registry: registry_person_find('%s')", person_guid); |
| 112 | return dictionary_get(registry.persons, person_guid); |
| 113 | } |
| 114 | |
| 115 | REGISTRY_PERSON *registry_person_allocate(const char *person_guid, time_t when) { |
| 116 | netdata_log_debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(REGISTRY_PERSON)); |
| 117 | |
| 118 | REGISTRY_PERSON *p = aral_mallocz(registry.persons_aral); |
| 119 | if(!person_guid) { |
| 120 | for(;;) { |
| 121 | nd_uuid_t uuid; |
| 122 | uuid_generate(uuid); |
| 123 | uuid_unparse_lower(uuid, p->guid); |
| 124 | |
| 125 | netdata_log_debug(D_REGISTRY, "Registry: Checking if the generated person guid '%s' is unique", p->guid); |
| 126 | if (!dictionary_get(registry.persons, p->guid)) { |
| 127 | netdata_log_debug(D_REGISTRY, "Registry: generated person guid '%s' is unique", p->guid); |
| 128 | break; |
| 129 | } |
| 130 | else |
| 131 | netdata_log_info("Registry: generated person guid '%s' found in the registry. Retrying...", p->guid); |
| 132 | } |
| 133 | } |
| 134 | else |
| 135 | strncpyz(p->guid, person_guid, GUID_LEN); |
| 136 | |
| 137 | p->person_urls = NULL; |
| 138 | |
| 139 | p->first_t = p->last_t = (uint32_t)when; |
| 140 | p->usages = 0; |
| 141 | |
| 142 | registry.persons_count++; |
| 143 | dictionary_set(registry.persons, p->guid, p, sizeof(REGISTRY_PERSON)); |
| 144 | |
| 145 | return p; |
| 146 | } |
| 147 | |
| 148 | |
| 149 | // 1. validate person GUID |
| 150 | // 2. if it is valid, find it |
| 151 | // 3. if it is not valid, create a new one |
| 152 | // 4. return it |
| 153 | REGISTRY_PERSON *registry_person_find_or_create(const char *person_guid, time_t when, bool is_dummy) { |
| 154 | netdata_log_debug(D_REGISTRY, "Registry: registry_person_find_or_create('%s'): creating dictionary of urls", person_guid); |
| 155 | |
| 156 | char buf[GUID_LEN + 1]; |
| 157 | REGISTRY_PERSON *p = NULL; |
| 158 | |
| 159 | if(person_guid && *person_guid) { |
| 160 | // validate it is a GUID |
| 161 | if(unlikely(regenerate_guid(person_guid, buf) == -1)) { |
| 162 | netdata_log_info("Registry: person guid '%s' is not a valid guid. Ignoring it.", person_guid); |
| 163 | person_guid = NULL; |
| 164 | } |
| 165 | else { |
| 166 | person_guid = buf; |
| 167 | p = registry_person_find(person_guid); |
| 168 | if(!p && !is_dummy) |
| 169 | person_guid = NULL; |
| 170 | } |
| 171 | } |
| 172 | else |
| 173 | person_guid = NULL; |
| 174 | |
| 175 | if(!p) p = registry_person_allocate(person_guid, when); |
| 176 | |
| 177 | return p; |
| 178 | } |
| 179 | |
| 180 | // ---------------------------------------------------------------------------- |
| 181 | // LINKING OF OBJECTS |
| 182 | |
| 183 | REGISTRY_PERSON_URL *registry_person_link_to_url(REGISTRY_PERSON *p, REGISTRY_MACHINE *m, STRING *url, char *machine_name, size_t machine_name_len, time_t when) { |
| 184 | netdata_log_debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): searching for URL in person", p->guid, m->guid, string2str(url)); |
| 185 | |
| 186 | REGISTRY_PERSON_URL *pu = registry_person_url_index_find(p, url); |
| 187 | if(!pu) { |
| 188 | netdata_log_debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): not found", p->guid, m->guid, string2str(url)); |
| 189 | pu = registry_person_url_allocate(p, m, url, machine_name, machine_name_len, when); |
| 190 | registry.persons_urls_count++; |
| 191 | } |
| 192 | else { |
| 193 | netdata_log_debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): found", p->guid, m->guid, string2str(url)); |
| 194 | pu->usages++; |
| 195 | if(likely(pu->last_t < (uint32_t)when)) pu->last_t = (uint32_t)when; |
| 196 | |
| 197 | if(pu->machine != m) { |
| 198 | REGISTRY_MACHINE_URL *mu = registry_machine_url_find(pu->machine, url); |
| 199 | if(mu) { |
| 200 | netdata_log_debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): URL switched machines (old was '%s') - expiring it from previous machine.", |
| 201 | p->guid, m->guid, string2str(url), pu->machine->guid); |
| 202 | mu->flags |= REGISTRY_URL_FLAGS_EXPIRED; |
| 203 | } |
| 204 | else { |
| 205 | netdata_log_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.", |
| 206 | p->guid, m->guid, string2str(url), pu->machine->guid); |
| 207 | } |
| 208 | |
| 209 | pu->machine->links--; |
| 210 | pu->machine = m; |
| 211 | } |
| 212 | |
| 213 | if(strcmp(string2str(pu->machine_name), machine_name) != 0) { |
| 214 | // the name of the PERSON_URL has changed ! |
| 215 | pu = registry_person_url_reallocate(p, m, url, machine_name, machine_name_len, when, pu); |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | p->usages++; |
| 220 | if(likely(p->last_t < (uint32_t)when)) p->last_t = (uint32_t)when; |
| 221 | |
| 222 | if(pu->flags & REGISTRY_URL_FLAGS_EXPIRED) { |
| 223 | netdata_log_debug(D_REGISTRY, "registry_person_link_to_url('%s', '%s', '%s'): accessing an expired URL. Re-enabling URL.", p->guid, m->guid, string2str(url)); |
| 224 | pu->flags &= ~REGISTRY_URL_FLAGS_EXPIRED; |
| 225 | } |
| 226 | |
| 227 | return pu; |
| 228 | } |
| 229 | |
| 230 | void registry_person_unlink_from_url(REGISTRY_PERSON *p, REGISTRY_PERSON_URL *pu) { |
| 231 | registry_person_url_deindex_and_free(p, pu); |
| 232 | } |