Reduce glibc fragmentation Part 2 (#19390)
* dictionary uses exclusively aral for allocations, except when the dictionary is variable sized * make all fixed size dictionaries use flag DICT_OPTION_FIXED_SIZE * memory accounting for rrd memory slots * use aral for extents * extent page sizes per KiB * test to see if 4KiB is better than 1KiB
Costa Tsaousis committed
Jan 13, 2025 at 17:15 UTC
e2e008e4fa7481686d620f86aa0f2f0564409987
23 files changed
+114
-49
src/collectors/cups.plugin/cups_plugin.c
+1
-1
@@ -227,7 +227,7 @@ int main(int argc, char **argv) {
227
228
errno_clear();
229
230
- dict_dest_job_metrics = dictionary_create(DICT_OPTION_SINGLE_THREADED);
230
+ dict_dest_job_metrics = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct job_metrics));
231
232
// ------------------------------------------------------------------------
233
// the main loop
src/collectors/debugfs.plugin/module-libsensors.c
+1
-1
@@ -1230,7 +1230,7 @@ void *libsensors_thread(void *ptr __maybe_unused) {
1230
}
1231
if(fp) fclose(fp);
1232
1233
- sensors_dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED);
1233
+ sensors_dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, NULL, sizeof(SENSOR));
1234
1235
// preflight to check data collection latency
1236
{
src/collectors/diskspace.plugin/plugin_diskspace.c
+1
-1
@@ -332,7 +332,7 @@ static inline void do_disk_space_stats(struct mountinfo *mi, int update_every) {
332
SIMPLE_PATTERN_EXACT,
333
true);
334
335
- dict_mountpoints = dictionary_create_advanced(DICT_OPTION_NONE, &dictionary_stats_category_collectors, 0);
335
+ dict_mountpoints = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct mount_point_metadata));
336
dictionary_register_delete_callback(dict_mountpoints, mountpoint_delete_cb, NULL);
337
}
338
src/collectors/proc.plugin/sys_block_zram.c
+1
-1
@@ -268,7 +268,7 @@ int do_sys_block_zram(int update_every, usec_t dt) {
268
}
269
procfile_close(ff);
270
271
- devices = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors, 0);
271
+ devices = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(ZRAM_DEVICE));
272
device_count = init_devices(devices, update_every);
273
}
274
src/collectors/proc.plugin/sys_devices_pci_aer.c
+2
-2
@@ -42,7 +42,7 @@ static bool aer_value_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
42
43
static void aer_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
44
struct aer_entry *a = value;
45
- a->values = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
45
+ a->values = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE|DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_value));
46
dictionary_register_conflict_callback(a->values, aer_value_conflict_callback, NULL);
47
}
48
@@ -209,7 +209,7 @@ int do_proc_sys_devices_pci_aer(int update_every, usec_t dt __maybe_unused) {
209
if(!do_root_ports && !do_pci_slots)
210
return 1;
211
212
- aer_root = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
212
+ aer_root = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct aer_entry));
213
dictionary_register_insert_callback(aer_root, aer_insert_callback, NULL);
214
215
AER_TYPE types = ((do_root_ports) ? (AER_ROOTPORT_TOTAL_ERR_COR|AER_ROOTPORT_TOTAL_ERR_FATAL) : 0) |
src/collectors/statsd.plugin/statsd.c
+8
-8
@@ -623,7 +623,7 @@ static inline void statsd_process_dictionary(STATSD_METRIC *m, const char *value
623
statsd_reset_metric(m);
624
625
if (unlikely(!m->dictionary.dict))
626
- m->dictionary.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
626
+ m->dictionary.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC_DICTIONARY_ITEM));
627
628
if(unlikely(value_is_zinit(value))) {
629
// magic loading of metric, without affecting anything
@@ -2455,13 +2455,13 @@ void *statsd_main(void *ptr) {
2455
worker_register_job_name(WORKER_STATSD_FLUSH_DICTIONARIES, "dictionaries");
2456
worker_register_job_name(WORKER_STATSD_FLUSH_STATS, "statistics");
2457
2458
- statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2459
- statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2460
- statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2461
- statsd.histograms.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2462
- statsd.dictionaries.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2463
- statsd.sets.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2464
- statsd.timers.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS, &dictionary_stats_category_collectors, 0);
2458
+ statsd.gauges.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2459
+ statsd.meters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2460
+ statsd.counters.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2461
+ statsd.histograms.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2462
+ statsd.dictionaries.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2463
+ statsd.sets.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2464
+ statsd.timers.dict = dictionary_create_advanced(STATSD_DICTIONARY_OPTIONS | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(STATSD_METRIC));
2465
2466
dictionary_register_insert_callback(statsd.gauges.dict, dictionary_metric_insert_callback, &statsd.gauges);
2467
dictionary_register_insert_callback(statsd.meters.dict, dictionary_metric_insert_callback, &statsd.meters);
src/collectors/tc.plugin/plugin_tc.c
+2
-2
@@ -98,7 +98,7 @@ static bool tc_class_conflict_callback(const DICTIONARY_ITEM *item __maybe_unuse
98
99
static void tc_class_index_init(struct tc_device *d) {
100
if(!d->classes) {
101
- d->classes = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED, &dictionary_stats_category_collectors, 0);
101
+ d->classes = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_collectors, sizeof(struct tc_class));
102
103
dictionary_register_delete_callback(d->classes, tc_class_free_callback, d);
104
dictionary_register_conflict_callback(d->classes, tc_class_conflict_callback, d);
@@ -111,7 +111,7 @@ static void tc_class_index_destroy(struct tc_device *d) {
111
}
112
113
static struct tc_class *tc_class_index_add(struct tc_device *d, struct tc_class *c) {
114
- return dictionary_set(d->classes, string2str(c->id), c, sizeof(*c));
114
+ return dictionary_set(d->classes, string2str(c->id), c, sizeof(struct tc_class));
115
}
116
117
static void tc_class_index_del(struct tc_device *d, struct tc_class *c) {
src/daemon/dyncfg/dyncfg.c
+1
-1
@@ -161,7 +161,7 @@ static bool dyncfg_conflict_cb(const DICTIONARY_ITEM *item __maybe_unused, void
161
162
void dyncfg_init_low_level(bool load_saved) {
163
if(!dyncfg_globals.nodes) {
164
- dyncfg_globals.nodes = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(DYNCFG));
164
+ dyncfg_globals.nodes = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE, &dictionary_stats_category_dyncfg, sizeof(DYNCFG));
165
dictionary_register_insert_callback(dyncfg_globals.nodes, dyncfg_insert_cb, NULL);
166
dictionary_register_react_callback(dyncfg_globals.nodes, dyncfg_react_cb, NULL);
167
dictionary_register_conflict_callback(dyncfg_globals.nodes, dyncfg_conflict_cb, NULL);
src/daemon/pulse/pulse-daemon-memory.c
+15
@@ -4,6 +4,16 @@
4
#include "pulse-daemon-memory.h"
5
#include "streaming/stream-replication-sender.h"
6
7
+static size_t rrd_slot_memory = 0;
8
+
9
+void rrd_slot_memory_added(size_t added) {
10
+ __atomic_add_fetch(&rrd_slot_memory, added, __ATOMIC_RELAXED);
11
+}
12
+
13
+void rrd_slot_memory_removed(size_t added) {
14
+ __atomic_sub_fetch(&rrd_slot_memory, added, __ATOMIC_RELAXED);
15
+}
16
+
17
#define dictionary_stats_memory_total(stats) \
18
((stats).memory.dict + (stats).memory.values + (stats).memory.index)
19
@@ -38,6 +48,7 @@ void pulse_daemon_memory_do(bool extended) {
48
static RRDDIM *rd_workers = NULL;
49
static RRDDIM *rd_aral = NULL;
50
static RRDDIM *rd_judy = NULL;
51
+ static RRDDIM *rd_slots = NULL;
52
static RRDDIM *rd_other = NULL;
53
54
if (unlikely(!st_memory)) {
@@ -79,6 +90,7 @@ void pulse_daemon_memory_do(bool extended) {
90
rd_workers = rrddim_add(st_memory, "workers", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
91
rd_aral = rrddim_add(st_memory, "aral", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
92
rd_judy = rrddim_add(st_memory, "judy", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
93
+ rd_slots = rrddim_add(st_memory, "slots", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
94
rd_other = rrddim_add(st_memory, "other", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
95
}
96
@@ -172,6 +184,9 @@ void pulse_daemon_memory_do(bool extended) {
184
rrddim_set_by_pointer(st_memory, rd_judy,
185
(collected_number) judy_aral_structures());
186
187
+ rrddim_set_by_pointer(st_memory, rd_slots,
188
+ (collected_number)__atomic_load_n(&rrd_slot_memory, __ATOMIC_RELAXED));
189
+
190
rrddim_set_by_pointer(st_memory, rd_other,
191
(collected_number)dictionary_stats_memory_total(dictionary_stats_category_other));
192
src/daemon/pulse/pulse-daemon-memory.h
+3
@@ -26,4 +26,7 @@ extern struct netdata_buffers_statistics {
26
void pulse_daemon_memory_do(bool extended);
27
#endif
28
29
+void rrd_slot_memory_added(size_t added);
30
+void rrd_slot_memory_removed(size_t added);
31
+
32
#endif //NETDATA_PULSE_DAEMON_MEMORY_H
src/daemon/pulse/pulse-dictionary.c
+2
@@ -12,6 +12,7 @@ struct dictionary_stats dictionary_stats_category_rrdlabels = { .name = "labels"
12
struct dictionary_stats dictionary_stats_category_rrdhealth = { .name = "health" };
13
struct dictionary_stats dictionary_stats_category_functions = { .name = "functions" };
14
struct dictionary_stats dictionary_stats_category_replication = { .name = "replication" };
15
+struct dictionary_stats dictionary_stats_category_dyncfg = { .name = "dyncfg" };
16
17
#ifdef DICT_WITH_STATS
18
struct dictionary_categories {
@@ -64,6 +65,7 @@ struct dictionary_categories {
65
{ .stats = &dictionary_stats_category_rrdhealth, },
66
{ .stats = &dictionary_stats_category_functions, },
67
{ .stats = &dictionary_stats_category_replication, },
68
+ { .stats = &dictionary_stats_category_dyncfg, },
69
{ .stats = &dictionary_stats_category_other, },
70
71
// terminator
src/daemon/pulse/pulse-dictionary.h
+1
@@ -14,6 +14,7 @@ extern struct dictionary_stats dictionary_stats_category_rrdlabels;
14
extern struct dictionary_stats dictionary_stats_category_rrdhealth;
15
extern struct dictionary_stats dictionary_stats_category_functions;
16
extern struct dictionary_stats dictionary_stats_category_replication;
17
+extern struct dictionary_stats dictionary_stats_category_dyncfg;
18
19
#if defined(PULSE_INTERNALS)
20
void pulse_dictionary_do(bool extended);
src/database/contexts/api_v2_contexts_alert_config.c
+1
@@ -131,5 +131,6 @@ int contexts_v2_alert_config_to_json(struct web_client *w, const char *config_ha
131
}
132
}
133
134
+ dictionary_destroy(configs);
135
return ret;
136
}
src/database/engine/page.c
+27
-7
@@ -100,13 +100,23 @@ static size_t aral_sizes[] = {
100
sizeof(gorilla_writer_t),
101
sizeof(PGD),
102
103
- 512, 1024, 1536, 2048, 5 * 512, 6 * 512, 7 * 512,
104
- 4 * 1024, 8 * 1024, 12 * 1024, 16 * 1024, 20 * 1024,
105
- 24 * 1024, 28 * 1024, 32 * 1024, 36 * 1024, 40 * 1024,
106
- 44 * 1024, 48 * 1024, 52 * 1024, 56 * 1024, 60 * 1024,
107
- 64 * 1024, 68 * 1024, 72 * 1024, 76 * 1024, 80 * 1024,
108
- 84 * 1024, 88 * 1024, 92 * 1024, 96 * 1024, 100 * 1024,
109
- 104 * 1024, 108 * 1024, 112 * 1024, 116 * 1024, 120 * 1024,
103
+ // per 512B
104
+ 512, 1024, 1536, 2048, 5 * 512, 6 * 512, 7 * 512, 8 * 512, /* 9 * 512, */
105
+
106
+ // per 1KiB
107
+// 5 * 1024, 6 * 1024, 7 * 1024, 8 * 1024, 9 * 1024, 10 * 1024, 11 * 1024,
108
+// 12 * 1024, 13 * 1024, 14 * 1024, 15 * 1024, 16 * 1024, 17 * 1024, 18 * 1024,
109
+// 19 * 1024, 20 * 1024, 21 * 1024, 22 * 1024, 23 * 1024, 24 * 1024, 25 * 1024,
110
+// 26 * 1024, 27 * 1024, 28 * 1024, 29 * 1024, 30 * 1024, 31 * 1024, 32 * 1024,
111
+
112
+ // test to see if 4KiB has less overheads than 1KiB
113
+ 8 * 1024, 12 * 1024, 16 * 1024, 20 * 1024, 24 * 1024, 28 * 1024, 32 * 1024,
114
+
115
+ // per 4KiB
116
+ 36 * 1024, 40 * 1024, 44 * 1024, 48 * 1024, 52 * 1024, 56 * 1024, 60 * 1024,
117
+ 64 * 1024, 68 * 1024, 72 * 1024, 76 * 1024, 80 * 1024, 84 * 1024, 88 * 1024,
118
+ 92 * 1024, 96 * 1024, 100 * 1024, 104 * 1024, 108 * 1024, 112 * 1024, 116 * 1024,
119
+ 120 * 1024, 124 * 1024, 128 * 1024,
120
};
121
static ARAL **arals = NULL;
122
@@ -317,6 +327,16 @@ static size_t pgd_data_footprint(size_t size, size_t partition) {
327
return size;
328
}
329
330
+// ----------------------------------------------------------------------------
331
+
332
+void *dbengine_extent_alloc(size_t size) {
333
+ return pgd_data_alloc(size, 0, false);
334
+}
335
+
336
+void dbengine_extent_free(void *extent, size_t size) {
337
+ pgd_data_free(extent, size, 0);
338
+}
339
+
340
// ----------------------------------------------------------------------------
341
// management api
342
src/database/engine/page.h
+3
@@ -56,6 +56,9 @@ size_t pgd_append_point(PGD *pg,
56
void pgdc_reset(PGDC *pgdc, PGD *pgd, uint32_t position);
57
bool pgdc_get_next_point(PGDC *pgdc, uint32_t expected_position, STORAGE_POINT *sp);
58
59
+void *dbengine_extent_alloc(size_t size);
60
+void dbengine_extent_free(void *extent, size_t size);
61
+
62
#ifdef __cplusplus
63
}
64
#endif
src/database/engine/pdc.c
-2
@@ -1288,12 +1288,10 @@ void epdl_find_extent_and_populate_pages(struct rrdengine_instance *ctx, EPDL *e
1288
void *extent_data = datafile_extent_read(ctx, epdl->file, epdl->extent_offset, epdl->extent_size);
1289
if(extent_data != NULL) {
1290
1291
-#if defined(NETDATA_TRACE_ALLOCATIONS)
1291
void *tmp = dbengine_extent_alloc(epdl->extent_size);
1292
memcpy(tmp, extent_data, epdl->extent_size);
1293
datafile_extent_read_free(extent_data);
1294
extent_data = tmp;
1296
-#endif
1295
1296
if(worker)
1297
worker_is_busy(UV_EVENT_DBENGINE_EXTENT_CACHE_LOOKUP);
src/database/engine/rrdengine.c
-9
@@ -584,15 +584,6 @@ static inline struct rrdeng_cmd rrdeng_deq_cmd(bool from_worker) {
584
585
// ----------------------------------------------------------------------------
586
587
-void *dbengine_extent_alloc(size_t size) {
588
- void *extent = mallocz(size);
589
- return extent;
590
-}
591
-
592
-void dbengine_extent_free(void *extent, size_t size __maybe_unused) {
593
- freez(extent);
594
-}
595
-
587
static void journalfile_extent_build(struct rrdengine_instance *ctx, struct extent_io_descriptor *xt_io_descr) {
588
unsigned count, payload_length, descr_size, size_bytes;
589
void *buf;
src/database/engine/rrdengine.h
-3
@@ -470,9 +470,6 @@ static inline void ctx_last_flush_fileno_set(struct rrdengine_instance *ctx, uns
470
471
#define ctx_is_available_for_queries(ctx) (__atomic_load_n(&(ctx)->quiesce.enabled, __ATOMIC_RELAXED) == false && __atomic_load_n(&(ctx)->quiesce.exit_mode, __ATOMIC_RELAXED) == false)
472
473
-void *dbengine_extent_alloc(size_t size);
474
-void dbengine_extent_free(void *extent, size_t size);
475
-
473
bool rrdeng_ctx_tier_cap_exceeded(struct rrdengine_instance *ctx);
474
int init_rrd_files(struct rrdengine_instance *ctx);
475
void finalize_rrd_files(struct rrdengine_instance *ctx);
src/database/rrdset.c
+11
-4
@@ -34,13 +34,15 @@ static void rrdset_stream_send_chart_slot_release(RRDSET *st) {
34
spinlock_lock(&host->stream.snd.pluginsd_chart_slots.available.spinlock);
35
36
if(host->stream.snd.pluginsd_chart_slots.available.used >= host->stream.snd.pluginsd_chart_slots.available.size) {
37
- uint32_t old_size = host->stream.snd.pluginsd_chart_slots.available.size;
38
- uint32_t new_size = (old_size > 0) ? (old_size * 2) : 1024;
37
+ uint32_t old_slots = host->stream.snd.pluginsd_chart_slots.available.size;
38
+ uint32_t new_slots = (old_slots > 0) ? (old_slots * 2) : 1024;
39
40
host->stream.snd.pluginsd_chart_slots.available.array =
41
- reallocz(host->stream.snd.pluginsd_chart_slots.available.array, new_size * sizeof(uint32_t));
41
+ reallocz(host->stream.snd.pluginsd_chart_slots.available.array, new_slots * sizeof(uint32_t));
42
43
- host->stream.snd.pluginsd_chart_slots.available.size = new_size;
43
+ host->stream.snd.pluginsd_chart_slots.available.size = new_slots;
44
+
45
+ rrd_slot_memory_added((new_slots - old_slots) * sizeof(uint32_t));
46
}
47
48
host->stream.snd.pluginsd_chart_slots.available.array[host->stream.snd.pluginsd_chart_slots.available.used++] =
@@ -51,6 +53,8 @@ static void rrdset_stream_send_chart_slot_release(RRDSET *st) {
53
}
54
55
void rrdhost_pluginsd_send_chart_slots_free(RRDHOST *host) {
56
+ rrd_slot_memory_removed(host->stream.snd.pluginsd_chart_slots.available.size * sizeof(uint32_t));
57
+
58
spinlock_lock(&host->stream.snd.pluginsd_chart_slots.available.spinlock);
59
host->stream.snd.pluginsd_chart_slots.available.ignore = true;
60
freez(host->stream.snd.pluginsd_chart_slots.available.array);
@@ -95,6 +99,7 @@ void rrdset_pluginsd_receive_unslot_and_cleanup(RRDSET *st) {
99
100
rrdset_pluginsd_receive_unslot(st);
101
102
+ rrd_slot_memory_removed(st->pluginsd.size * sizeof(struct pluginsd_rrddim));
103
freez(st->pluginsd.prd_array);
104
st->pluginsd.prd_array = NULL;
105
st->pluginsd.size = 0;
@@ -113,6 +118,8 @@ static void rrdset_pluginsd_receive_slots_initialize(RRDSET *st) {
118
}
119
120
void rrdhost_pluginsd_receive_chart_slots_free(RRDHOST *host) {
121
+ rrd_slot_memory_removed(host->stream.rcv.pluginsd_chart_slots.size * sizeof(uint32_t));
122
+
123
spinlock_lock(&host->stream.rcv.pluginsd_chart_slots.spinlock);
124
125
if(host->stream.rcv.pluginsd_chart_slots.array) {
src/health/health_prototypes.c
+2
-2
@@ -288,7 +288,7 @@ void health_init_prototypes(void) {
288
if(health_globals.prototypes.dict)
289
return;
290
291
- health_globals.prototypes.dict = dictionary_create(DICT_OPTION_DONT_OVERWRITE_VALUE);
291
+ health_globals.prototypes.dict = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE, &dictionary_stats_category_rrdhealth, sizeof(RRD_ALERT_PROTOTYPE));
292
dictionary_register_insert_callback(health_globals.prototypes.dict, health_prototype_insert_cb, NULL);
293
dictionary_register_conflict_callback(health_globals.prototypes.dict, health_prototype_conflict_cb, NULL);
294
dictionary_register_delete_callback(health_globals.prototypes.dict, health_prototype_delete_cb, NULL);
@@ -472,7 +472,7 @@ bool health_prototype_add(RRD_ALERT_PROTOTYPE *ap, char **msg) {
472
// add it to the prototypes
473
dictionary_set_advanced(health_globals.prototypes.dict,
474
string2str(ap->config.name), string_strlen(ap->config.name),
475
- ap, sizeof(*ap),
475
+ ap, sizeof(RRD_ALERT_PROTOTYPE),
476
NULL);
477
478
return true;
src/libnetdata/dictionary/dictionary.c
+28
-4
@@ -20,13 +20,36 @@ inline void dictionary_write_unlock(DICTIONARY *dict) {
20
ll_recursive_unlock(dict, DICTIONARY_LOCK_WRITE);
21
}
22
23
+// ----------------------------------------------------------------------------
24
+// ARAL for dict and hooks
25
+
26
+static ARAL *ar_dict = NULL;
27
+static ARAL *ar_hooks = NULL;
28
+
29
+static void dictionary_init_aral(void) {
30
+ if(ar_dict && ar_hooks) return;
31
+
32
+ static SPINLOCK spinlock = SPINLOCK_INITIALIZER;
33
+ spinlock_lock(&spinlock);
34
+
35
+ if(!ar_dict)
36
+ ar_dict = aral_by_size_acquire(sizeof(DICTIONARY));
37
+
38
+ if(!ar_hooks)
39
+ ar_hooks = aral_by_size_acquire(sizeof(struct dictionary_hooks));
40
+
41
+ spinlock_unlock(&spinlock);
42
+}
43
+
44
// ----------------------------------------------------------------------------
45
// callbacks registration
46
47
static inline void dictionary_hooks_allocate(DICTIONARY *dict) {
48
if(dict->hooks) return;
49
29
- dict->hooks = callocz(1, sizeof(struct dictionary_hooks));
50
+ dictionary_init_aral();
51
+
52
+ dict->hooks = aral_callocz(ar_hooks);
53
dict->hooks->links = 1;
54
55
DICTIONARY_STATS_PLUS_MEMORY(dict, 0, sizeof(struct dictionary_hooks), 0);
@@ -37,7 +60,7 @@ static inline size_t dictionary_hooks_free(DICTIONARY *dict) {
60
61
REFCOUNT links = __atomic_sub_fetch(&dict->hooks->links, 1, __ATOMIC_ACQUIRE);
62
if(links == 0) {
40
- freez(dict->hooks);
63
+ aral_freez(ar_hooks, dict->hooks);
64
dict->hooks = NULL;
65
66
DICTIONARY_STATS_MINUS_MEMORY(dict, 0, sizeof(struct dictionary_hooks), 0);
@@ -268,7 +291,7 @@ static bool dictionary_free_all_resources(DICTIONARY *dict, size_t *mem, bool fo
291
if(dict->value_aral)
292
aral_by_size_release(dict->value_aral);
293
271
- freez(dict);
294
+ aral_freez(ar_dict, dict);
295
296
internal_error(
297
false,
@@ -464,9 +487,10 @@ static bool api_is_name_good_with_trace(DICTIONARY *dict __maybe_unused, const c
487
// API - dictionary management
488
489
static DICTIONARY *dictionary_create_internal(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size) {
490
+ dictionary_init_aral();
491
cleanup_destroyed_dictionaries();
492
469
- DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
493
+ DICTIONARY *dict = aral_callocz(ar_dict);
494
dict->options = options;
495
dict->stats = stats;
496
src/plugins.d/pluginsd_internals.h
+3
@@ -141,6 +141,7 @@ static inline void pluginsd_rrddim_put_to_slot(PARSER *parser, RRDSET *st, RRDDI
141
st->pluginsd.prd_array[i].id = NULL;
142
}
143
144
+ rrd_slot_memory_added((wanted_size - st->pluginsd.size) * sizeof(struct pluginsd_rrddim));
145
st->pluginsd.size = wanted_size;
146
}
147
@@ -301,6 +302,8 @@ static inline void pluginsd_rrdset_cache_put_to_slot(PARSER *parser, RRDSET *st,
302
303
host->stream.rcv.pluginsd_chart_slots.size = new_slots;
304
spinlock_unlock(&host->stream.rcv.pluginsd_chart_slots.spinlock);
305
+
306
+ rrd_slot_memory_added((new_slots - old_slots) * sizeof(uint32_t));
307
}
308
309
host->stream.rcv.pluginsd_chart_slots.array[slot - 1] = st;
src/streaming/stream-replication-sender.c
+1
-1
@@ -1286,7 +1286,7 @@ void replication_sender_delete_pending_requests(struct sender_state *sender) {
1286
1287
void replication_sender_init(struct sender_state *sender) {
1288
sender->replication.requests = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE | DICT_OPTION_FIXED_SIZE,
1289
- NULL, sizeof(struct replication_request));
1289
+ &dictionary_stats_category_replication, sizeof(struct replication_request));
1290
1291
dictionary_register_react_callback(sender->replication.requests, replication_request_react_callback, sender);
1292
dictionary_register_conflict_callback(sender->replication.requests, replication_request_conflict_callback, sender);