From f5a85f7747f04ae3146f0a2cdf948531fed0d47c Mon Sep 17 00:00:00 2001 From: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> Date: Thu, 20 Aug 2020 18:50:13 +0300 Subject: Added code to release memory used by the global GUID map (#9729) Fixed memory leak issues associated with the global GUID map during agent shutdown --- database/engine/global_uuid_map/global_uuid_map.c | 87 +++++++++++++---------- database/engine/global_uuid_map/global_uuid_map.h | 5 +- database/rrddim.c | 9 ++- database/rrdhost.c | 4 ++ database/rrdset.c | 6 ++ 5 files changed, 71 insertions(+), 40 deletions(-) (limited to 'database') diff --git a/database/engine/global_uuid_map/global_uuid_map.c b/database/engine/global_uuid_map/global_uuid_map.c index 83b9b1c84e..6669517ba1 100644 --- a/database/engine/global_uuid_map/global_uuid_map.c +++ b/database/engine/global_uuid_map/global_uuid_map.c @@ -9,6 +9,51 @@ static uv_rwlock_t object_lock; static uv_rwlock_t global_lock; +void free_global_guid_map() +{ + JudyHSFreeArray(&JGUID_map, PJE0); + JudyHSFreeArray(&JGUID_object_map, PJE0); +} + +static void free_single_uuid(uuid_t *uuid) +{ + Pvoid_t *PValue, *PValue1; + char *existing_object; + Word_t size; + + PValue = JudyHSGet(JGUID_map, (void *) uuid, (Word_t) sizeof(uuid_t)); + if (likely(PValue)) { + existing_object = *PValue; + GUID_TYPE object_type = existing_object[0]; + size = (Word_t)object_type ? (object_type * 16) + 1 : strlen((char *)existing_object + 1) + 2; + PValue1 = JudyHSGet(JGUID_object_map, (void *)existing_object, (Word_t)size); + if (PValue1 && *PValue1) { + freez(*PValue1); + } + JudyHSDel(&JGUID_object_map, (void *)existing_object, + (Word_t)object_type ? (object_type * 16) + 1 : strlen((char *)existing_object + 1) + 2, PJE0); + JudyHSDel(&JGUID_map, (void *)uuid, (Word_t)sizeof(uuid_t), PJE0); + freez(existing_object); + } +} + +void free_uuid(uuid_t *uuid) +{ + GUID_TYPE ret; + char object[49]; + + ret = find_object_by_guid(uuid, object, sizeof(object)); + if (GUID_TYPE_DIMENSION == ret) + free_single_uuid((uuid_t *)(object + 16 + 16)); + + if (GUID_TYPE_CHART == ret) + free_single_uuid((uuid_t *)(object + 16)); + + free_single_uuid(uuid); + return; +} + + void dump_object(uuid_t *index, void *object) { char uuid_s[36 + 1]; @@ -101,34 +146,6 @@ static inline int guid_store_nolock(uuid_t *uuid, void *object, GUID_TYPE object } -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 @@ -151,15 +168,19 @@ GUID_TYPE find_object_by_guid(uuid_t *uuid, char *object, size_t max_bytes) if (likely(object && max_bytes)) { switch (value_type) { case GUID_TYPE_CHAR: - if (unlikely(max_bytes - 1 < strlen((char *) *PValue+1))) + if (unlikely(max_bytes - 1 < strlen((char *) *PValue+1))) { + uv_rwlock_rdunlock(&global_lock); 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)) + if (unlikely(max_bytes < (size_t) value_type * 16)) { + uv_rwlock_rdunlock(&global_lock); return GUID_TYPE_NOSPACE; + } memcpy(object, *PValue+1, value_type * 16); break; default: @@ -265,12 +286,6 @@ void init_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; } diff --git a/database/engine/global_uuid_map/global_uuid_map.h b/database/engine/global_uuid_map/global_uuid_map.h index 3def854baf..f31f3c0079 100644 --- a/database/engine/global_uuid_map/global_uuid_map.h +++ b/database/engine/global_uuid_map/global_uuid_map.h @@ -16,11 +16,10 @@ typedef enum guid_type { GUID_TYPE_NOSPACE } GUID_TYPE; -extern int guid_store(uuid_t *uuid, char *object, GUID_TYPE); extern GUID_TYPE find_object_by_guid(uuid_t *uuid, char *object, size_t max_bytes); extern int find_guid_by_object(char *object, uuid_t *uuid, GUID_TYPE); extern void init_global_guid_map(); extern int find_or_generate_guid(void *object, uuid_t *uuid, GUID_TYPE object_type, int replace_instead_of_generate); - - +extern void free_uuid(uuid_t *uuid); +extern void free_global_guid_map(); #endif //NETDATA_GLOBAL_UUID_MAP_H diff --git a/database/rrddim.c b/database/rrddim.c index 25209dbe24..e2fe519a8c 100644 --- a/database/rrddim.c +++ b/database/rrddim.c @@ -487,7 +487,6 @@ void rrddim_free_custom(RRDSET *st, RRDDIM *rd, int db_rotated) #endif } } - freez(rd->state); if(rd == st->dimensions) st->dimensions = rd->next; @@ -518,6 +517,7 @@ void rrddim_free_custom(RRDSET *st, RRDDIM *rd, int db_rotated) debug(D_RRD_CALLS, "Unmapping dimension '%s'.", rd->name); freez((void *)rd->id); freez(rd->cache_filename); + freez(rd->state); munmap(rd, rd->memsize); break; @@ -527,6 +527,13 @@ void rrddim_free_custom(RRDSET *st, RRDDIM *rd, int db_rotated) debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name); freez((void *)rd->id); freez(rd->cache_filename); +#ifdef ENABLE_DBENGINE + if (rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) { + free_uuid(rd->state->metric_uuid); + freez(rd->state->metric_uuid); + } +#endif + freez(rd->state); freez(rd); break; } diff --git a/database/rrdhost.c b/database/rrdhost.c index f0a5c6b84b..d82a9099b4 100644 --- a/database/rrdhost.c +++ b/database/rrdhost.c @@ -879,6 +879,10 @@ void rrdhost_free(RRDHOST *host) { netdata_rwlock_destroy(&host->labels_rwlock); netdata_rwlock_destroy(&host->health_log.alarm_log_rwlock); netdata_rwlock_destroy(&host->rrdhost_rwlock); + +#ifdef ENABLE_DBENGINE + free_uuid(&host->host_uuid); +#endif freez(host); rrd_hosts_available--; diff --git a/database/rrdset.c b/database/rrdset.c index 4f0b4a160a..d957c1560c 100644 --- a/database/rrdset.c +++ b/database/rrdset.c @@ -388,6 +388,12 @@ void rrdset_free(RRDSET *st) { case RRD_MEMORY_MODE_ALLOC: case RRD_MEMORY_MODE_NONE: case RRD_MEMORY_MODE_DBENGINE: +#ifdef ENABLE_DBENGINE + if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) { + free_uuid(st->chart_uuid); + freez(st->chart_uuid); + } +#endif freez(st); break; } -- cgit v1.2.3