netdata/database/engine/global_uuid_map/global_uuid_map.c

276 lines
8.7 KiB
C

// SPDX-License-Identifier: GPL-3.0-or-later
#include "global_uuid_map.h"
static Pvoid_t JGUID_map = (Pvoid_t) NULL;
static Pvoid_t JGUID_object_map = (Pvoid_t) NULL;
static uv_rwlock_t guid_lock;
static uv_rwlock_t object_lock;
static uv_rwlock_t global_lock;
void dump_object(uuid_t *index, void *object)
{
char uuid_s[36 + 1];
uuid_unparse_lower(*index, uuid_s);
char local_object[3 * 36 + 2 + 1];
switch (*(char *) object) {
case GUID_TYPE_CHAR:
debug(D_GUIDLOG, "OBJECT GUID %s on [%s]", uuid_s, (char *)object + 1);
break;
case GUID_TYPE_CHART:
uuid_unparse_lower((const unsigned char *)object + 1, local_object);
uuid_unparse_lower((const unsigned char *)object + 17, local_object+37);
local_object[36] = ':';
local_object[74] = '\0';
debug(D_GUIDLOG, "CHART GUID %s on [%s]", uuid_s, local_object);
break;
case GUID_TYPE_DIMENSION:
uuid_unparse_lower((const unsigned char *)object + 1, local_object);
uuid_unparse_lower((const unsigned char *)object + 17, local_object + 37);
uuid_unparse_lower((const unsigned char *)object + 33, local_object + 74);
local_object[36] = ':';
local_object[73] = ':';
local_object[110] = '\0';
debug(D_GUIDLOG, "DIM GUID %s on [%s]", uuid_s, local_object);
break;
default:
debug(D_GUIDLOG, "Unknown object");
}
}
/* Returns 0 if it successfully stores the uuid-object mapping or if an identical mapping already exists */
static inline int guid_store_nolock(uuid_t *uuid, void *object, GUID_TYPE object_type)
{
char *existing_object;
GUID_TYPE existing_object_type;
if (unlikely(!object) || uuid == NULL)
return 0;
Pvoid_t *PValue;
PValue = JudyHSIns(&JGUID_map, (void *) uuid, (Word_t) sizeof(uuid_t), PJE0);
if (PPJERR == PValue)
fatal("JudyHSIns() fatal error.");
if (*PValue) {
existing_object = *PValue;
existing_object_type = existing_object[0];
if (existing_object_type != object_type)
return 1;
switch (existing_object_type) {
case GUID_TYPE_DIMENSION:
if (memcmp(existing_object, object, 1 + 16 + 16 + 16))
return 1;
break;
case GUID_TYPE_CHART:
if (memcmp(existing_object, object, 1 + 16 + 16))
return 1;
break;
case GUID_TYPE_CHAR:
if (strcmp(existing_object + 1, (char *)object))
return 1;
break;
default:
return 1;
}
freez(existing_object);
}
*PValue = (Pvoid_t *) object;
PValue = JudyHSIns(&JGUID_object_map, (void *)object, (Word_t) object_type?(object_type * 16)+1:strlen((char *) object+1)+2, PJE0);
if (PPJERR == PValue)
fatal("JudyHSIns() fatal error.");
if (*PValue == NULL) {
uuid_t *value = (uuid_t *) mallocz(sizeof(uuid_t));
uuid_copy(*value, *uuid);
*PValue = value;
}
#ifdef NETDATA_INTERNAL_CHECKS
static uint32_t count = 0;
count++;
char uuid_s[36 + 1];
uuid_unparse_lower(*uuid, uuid_s);
debug(D_GUIDLOG,"GUID added item %" PRIu32" [%s] as:", count, uuid_s);
dump_object(uuid, object);
#endif
return 0;
}
inline int guid_store(uuid_t *uuid, char *object, GUID_TYPE object_type)
{
uv_rwlock_wrlock(&global_lock);
int rc = guid_store_nolock(uuid, object, object_type);
uv_rwlock_wrunlock(&global_lock);
return rc;
}
/*
* This can be used to bulk load entries into the global map
*
* A lock must be aquired since it will call guid_store_nolock
* with a "no lock" parameter.
*
* Note: object memory must be allocated by caller and not released
*/
int guid_bulk_load(char *uuid, char *object)
{
uuid_t target_uuid;
if (likely(!uuid_parse(uuid, target_uuid))) {
#ifdef NETDATA_INTERNAL_CHECKS
debug(D_GUIDLOG,"Mapping GUID [%s] on [%s]", uuid, object);
#endif
return guid_store_nolock(&target_uuid, object, GUID_TYPE_CHAR);
}
return 1;
}
/*
* Given a GUID, find if an object is stored
* - Optionally return the object
*/
GUID_TYPE find_object_by_guid(uuid_t *uuid, char *object, size_t max_bytes)
{
Pvoid_t *PValue;
GUID_TYPE value_type;
uv_rwlock_rdlock(&global_lock);
PValue = JudyHSGet(JGUID_map, (void *) uuid, (Word_t) sizeof(uuid_t));
if (unlikely(!PValue)) {
uv_rwlock_rdunlock(&global_lock);
return GUID_TYPE_NOTFOUND;
}
value_type = *(char *) *PValue;
if (likely(object && max_bytes)) {
switch (value_type) {
case GUID_TYPE_CHAR:
if (unlikely(max_bytes - 1 < strlen((char *) *PValue+1)))
return GUID_TYPE_NOSPACE;
strncpyz(object, (char *) *PValue+1, max_bytes - 1);
break;
case GUID_TYPE_HOST:
case GUID_TYPE_CHART:
case GUID_TYPE_DIMENSION:
if (unlikely(max_bytes < (size_t) value_type * 16))
return GUID_TYPE_NOSPACE;
memcpy(object, *PValue+1, value_type * 16);
break;
default:
uv_rwlock_rdunlock(&global_lock);
return GUID_TYPE_NOTFOUND;
}
}
#ifdef NETDATA_INTERNAL_CHECKS
dump_object(uuid, *PValue);
#endif
uv_rwlock_rdunlock(&global_lock);
return value_type;
}
/*
* Find a GUID of an object
* - Optionally return the GUID
*
*/
int find_guid_by_object(char *object, uuid_t *uuid, GUID_TYPE object_type)
{
Pvoid_t *PValue;
uv_rwlock_rdlock(&global_lock);
PValue = JudyHSGet(JGUID_object_map, (void *)object, (Word_t)object_type?object_type*16+1:strlen(object+1)+2);
if (unlikely(!PValue)) {
uv_rwlock_rdunlock(&global_lock);
return 1;
}
if (likely(uuid))
uuid_copy(*uuid, *PValue);
uv_rwlock_rdunlock(&global_lock);
return 0;
}
int find_or_generate_guid(void *object, uuid_t *uuid, GUID_TYPE object_type, int replace_instead_of_generate)
{
char *target_object;
uuid_t temp_uuid;
int rc;
switch (object_type) {
case GUID_TYPE_DIMENSION:
if (unlikely(find_or_generate_guid((void *) ((RRDDIM *)object)->id, &temp_uuid, GUID_TYPE_CHAR, 0)))
return 1;
target_object = mallocz(49);
target_object[0] = object_type;
memcpy(target_object + 1, ((RRDDIM *)object)->rrdset->rrdhost->host_uuid, 16);
memcpy(target_object + 17, ((RRDDIM *)object)->rrdset->chart_uuid, 16);
memcpy(target_object + 33, temp_uuid, 16);
break;
case GUID_TYPE_CHART:
if (unlikely(find_or_generate_guid((void *) ((RRDSET *)object)->id, &temp_uuid, GUID_TYPE_CHAR, 0)))
return 1;
target_object = mallocz(33);
target_object[0] = object_type;
memcpy(target_object + 1, (((RRDSET *)object))->rrdhost->host_uuid, 16);
memcpy(target_object + 17, temp_uuid, 16);
break;
case GUID_TYPE_HOST:
target_object = mallocz(17);
target_object[0] = object_type;
memcpy(target_object + 1, (((RRDHOST *)object))->host_uuid, 16);
break;
case GUID_TYPE_CHAR:
target_object = mallocz(strlen((char *) object)+2);
target_object[0] = object_type;
strcpy(target_object+1, (char *) object);
break;
default:
return 1;
}
rc = find_guid_by_object(target_object, uuid, object_type);
if (rc) {
if (!replace_instead_of_generate) /* else take *uuid as user input */
uuid_generate(*uuid);
uv_rwlock_wrlock(&global_lock);
int rc = guid_store_nolock(uuid, target_object, object_type);
uv_rwlock_wrunlock(&global_lock);
return rc;
}
//uv_rwlock_wrunlock(&global_lock);
#ifdef NETDATA_INTERNAL_CHECKS
dump_object(uuid, target_object);
#endif
return 0;
}
void init_global_guid_map()
{
static int init = 0;
if (init)
return;
init = 1;
info("Configuring locking mechanism for global GUID map");
fatal_assert(0 == uv_rwlock_init(&guid_lock));
fatal_assert(0 == uv_rwlock_init(&object_lock));
fatal_assert(0 == uv_rwlock_init(&global_lock));
// int rc = guid_bulk_load("6fc56a64-05d7-47a7-bc82-7f3235d8cbda","d6b37186-74db-11ea-88b2-0bf5095b1f9e/cgroup_qemu_ubuntu18.04.cpu_per_core/cpu3");
// rc = guid_bulk_load("75c6fa02-97cc-40c1-aacd-a0132190472e","d6b37186-74db-11ea-88b2-0bf5095b1f9e/services.throttle_io_ops_write/system.slice_setvtrgb.service");
// if (rc == 0)
// info("BULK GUID load successful");
return;
}