Browse Source

array allocator for dbengine page descriptors (#13312)

* array allocator for dbengine page descriptors

* full implementation of array allocator with cleanup

* faster deallocations

* eliminate entierely the need for loops during free

* addressed comments

* lower the min number of elements to 10
Costa Tsaousis 2 years ago
parent
commit
a6da6beb71

+ 2 - 0
CMakeLists.txt

@@ -370,6 +370,8 @@ set(LIBNETDATA_FILES
         libnetdata/adaptive_resortable_list/adaptive_resortable_list.h
         libnetdata/config/appconfig.c
         libnetdata/config/appconfig.h
+        libnetdata/arrayalloc/arrayalloc.c
+        libnetdata/arrayalloc/arrayalloc.h
         libnetdata/avl/avl.c
         libnetdata/avl/avl.h
         libnetdata/buffer/buffer.c

+ 2 - 0
Makefile.am

@@ -136,6 +136,8 @@ LIBNETDATA_FILES = \
     libnetdata/adaptive_resortable_list/adaptive_resortable_list.h \
     libnetdata/config/appconfig.c \
     libnetdata/config/appconfig.h \
+    libnetdata/arrayalloc/arrayalloc.c \
+    libnetdata/arrayalloc/arrayalloc.h \
     libnetdata/avl/avl.c \
     libnetdata/avl/avl.h \
     libnetdata/buffer/buffer.c \

+ 1 - 0
configure.ac

@@ -1724,6 +1724,7 @@ AC_CONFIG_FILES([
     libnetdata/Makefile
     libnetdata/tests/Makefile
     libnetdata/adaptive_resortable_list/Makefile
+    libnetdata/arrayalloc/Makefile
     libnetdata/avl/Makefile
     libnetdata/buffer/Makefile
     libnetdata/clocks/Makefile

+ 47 - 3
database/engine/pagecache.c

@@ -3,6 +3,50 @@
 
 #include "rrdengine.h"
 
+ARAL page_descr_aral = {
+    .element_size = sizeof(struct rrdeng_page_descr),
+    .elements = 20000,
+    .filename = "page_descriptors",
+    .cache_dir = &netdata_configured_cache_dir,
+    .use_mmap = false,
+    .internal.initialized = false
+};
+
+void rrdeng_page_descr_aral_go_singlethreaded(void) {
+    page_descr_aral.internal.lockless = true;
+}
+void rrdeng_page_descr_aral_go_multithreaded(void) {
+    page_descr_aral.internal.lockless = false;
+}
+
+struct rrdeng_page_descr *rrdeng_page_descr_mallocz(void) {
+    struct rrdeng_page_descr *descr;
+    descr = arrayalloc_mallocz(&page_descr_aral);
+    return descr;
+}
+
+void rrdeng_page_descr_freez(struct rrdeng_page_descr *descr) {
+    arrayalloc_freez(&page_descr_aral, descr);
+}
+
+void rrdeng_page_descr_use_malloc(void) {
+    if(page_descr_aral.internal.initialized)
+        error("DBENGINE: cannot change ARAL allocation policy after it has been initialized.");
+    else
+        page_descr_aral.use_mmap = false;
+}
+
+void rrdeng_page_descr_use_mmap(void) {
+    if(page_descr_aral.internal.initialized)
+        error("DBENGINE: cannot change ARAL allocation policy after it has been initialized.");
+    else
+        page_descr_aral.use_mmap = true;
+}
+
+bool rrdeng_page_descr_is_mmap(void) {
+    return page_descr_aral.use_mmap;
+}
+
 /* Forward declarations */
 static int pg_cache_try_evict_one_page_unsafe(struct rrdengine_instance *ctx);
 
@@ -81,7 +125,7 @@ struct rrdeng_page_descr *pg_cache_create_descr(void)
 {
     struct rrdeng_page_descr *descr;
 
-    descr = mallocz(sizeof(*descr));
+    descr = rrdeng_page_descr_mallocz();
     descr->page_length = 0;
     descr->start_time = INVALID_TIME;
     descr->end_time = INVALID_TIME;
@@ -494,7 +538,7 @@ uint8_t pg_cache_punch_hole(struct rrdengine_instance *ctx, struct rrdeng_page_d
         (void)sleep_usec(1000); /* 1 msec */
     }
 destroy:
-    freez(descr);
+    rrdeng_page_descr_freez(descr);
     pg_cache_update_metric_times(page_index);
 
     return can_delete_metric;
@@ -1312,7 +1356,7 @@ void free_page_cache(struct rrdengine_instance *ctx)
             else
                 metric_single_point_pages++;
 
-            freez(descr);
+            rrdeng_page_descr_freez(descr);
             pages_bytes += sizeof(*descr);
             pages_number++;
 

+ 8 - 0
database/engine/pagecache.h

@@ -195,6 +195,14 @@ extern unsigned long pg_cache_hard_limit(struct rrdengine_instance *ctx);
 extern unsigned long pg_cache_soft_limit(struct rrdengine_instance *ctx);
 extern unsigned long pg_cache_committed_hard_limit(struct rrdengine_instance *ctx);
 
+extern void rrdeng_page_descr_aral_go_singlethreaded(void);
+extern void rrdeng_page_descr_aral_go_multithreaded(void);
+extern void rrdeng_page_descr_use_malloc(void);
+extern void rrdeng_page_descr_use_mmap(void);
+extern bool rrdeng_page_descr_is_mmap(void);
+extern struct rrdeng_page_descr *rrdeng_page_descr_mallocz(void);
+extern void rrdeng_page_descr_freez(struct rrdeng_page_descr *descr);
+
 static inline void
     pg_cache_atomic_get_pg_info(struct rrdeng_page_descr *descr, usec_t *end_timep, uint32_t *page_lengthp)
 {

+ 1 - 1
database/engine/rrdengineapi.c

@@ -211,7 +211,7 @@ void rrdeng_store_metric_flush_current_page(STORAGE_COLLECT_HANDLE *collection_h
     } else {
         dbengine_page_free(descr->pg_cache_descr->page);
         rrdeng_destroy_pg_cache_descr(ctx, descr->pg_cache_descr);
-        freez(descr);
+        rrdeng_page_descr_freez(descr);
     }
     handle->descr = NULL;
 }

+ 9 - 0
database/rrdhost.c

@@ -768,6 +768,11 @@ int rrd_init(char *hostname, struct rrdhost_system_info *system_info) {
         default_rrdeng_page_fetch_retries = 1;
         config_set_number(CONFIG_SECTION_DB, "dbengine page fetch retries", default_rrdeng_page_fetch_retries);
     }
+
+    if(config_get_boolean(CONFIG_SECTION_DB, "dbengine page descriptors in file mapped memory", rrdeng_page_descr_is_mmap()) == CONFIG_BOOLEAN_YES)
+        rrdeng_page_descr_use_mmap();
+    else
+        rrdeng_page_descr_use_malloc();
 #endif
 
     rrdset_free_obsolete_time = config_get_number(CONFIG_SECTION_DB, "cleanup obsolete charts after secs", rrdset_free_obsolete_time);
@@ -825,6 +830,8 @@ int rrd_init(char *hostname, struct rrdhost_system_info *system_info) {
     }
 
 #ifdef ENABLE_DBENGINE
+    rrdeng_page_descr_aral_go_singlethreaded();
+
     int created_tiers = 0;
     char dbenginepath[FILENAME_MAX + 1];
     char dbengineconfig[200 + 1];
@@ -905,6 +912,8 @@ int rrd_init(char *hostname, struct rrdhost_system_info *system_info) {
         rrd_unlock();
         fatal("DBENGINE: Failed to be initialized.");
     }
+
+    rrdeng_page_descr_aral_go_multithreaded();
 #else
     storage_tiers = config_get_number(CONFIG_SECTION_DB, "storage tiers", 1);
     if(storage_tiers != 1) {

+ 1 - 0
libnetdata/Makefile.am

@@ -5,6 +5,7 @@ MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
 
 SUBDIRS = \
     adaptive_resortable_list \
+    arrayalloc \
     avl \
     buffer \
     clocks \

+ 8 - 0
libnetdata/arrayalloc/Makefile.am

@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+AUTOMAKE_OPTIONS = subdir-objects
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+dist_noinst_DATA = \
+    README.md \
+    $(NULL)

+ 7 - 0
libnetdata/arrayalloc/README.md

@@ -0,0 +1,7 @@
+<!--
+title: "Array Allocator"
+custom_edit_url: https://github.com/netdata/netdata/edit/master/libnetdata/arrayalloc/README.md
+-->
+
+# Array Allocator
+

Some files were not shown because too many files changed in this diff