]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
sysrepo: integration to cache-gc
authorAleš Mrázek <ales.mrazek@nic.cz>
Fri, 17 Jan 2020 12:33:20 +0000 (13:33 +0100)
committerAleš <ales.mrazek@nic.cz>
Mon, 20 Jul 2020 14:54:35 +0000 (16:54 +0200)
modules/sysrepo/common/helpers.c [new file with mode: 0644]
modules/sysrepo/common/helpers.h [new file with mode: 0644]
modules/sysrepo/meson.build
utils/cache_gc/kr_cache_gc.h
utils/cache_gc/main.c

diff --git a/modules/sysrepo/common/helpers.c b/modules/sysrepo/common/helpers.c
new file mode 100644 (file)
index 0000000..3a470be
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+#include <string.h>
+#include "helpers.h"
+
+/// Source: https://stackoverflow.com/questions/47116974/remove-a-substring-from-a-string-in-c
+char *remove_substr(char *str, const char *substr) {
+    char *p, *q, *r;
+    if ((q = r = strstr(str, substr)) != NULL) {
+        size_t len = strlen(substr);
+        while ((r = strstr(p = r + len, substr)) != NULL) {
+            while (p < r)
+                *q++ = *p++;
+        }
+        while ((*q++ = *p++) != '\0')
+            continue;
+    }
+    return str;
+}
+
+char *replace_char(char *str, const char subchar, const char repchar) {
+    for(int i = 0; str[i] != '\0'; i++)
+        if(str[i] == subchar) str[i] = repchar;
+    return str;
+}
+
+int starts_with(char *str, const char *start_str){
+    int rc = strncmp(str, start_str, strlen(start_str));
+    return rc;
+}
diff --git a/modules/sysrepo/common/helpers.h b/modules/sysrepo/common/helpers.h
new file mode 100644 (file)
index 0000000..370e4e7
--- /dev/null
@@ -0,0 +1,5 @@
+char *remove_substr(char *str, const char *substr);
+
+char *replace_char(char *str, const char subchar, const char repchar);
+
+int starts_with(char *str, const char *start_str);
index 87b9ac3e0d2f40179cb08c056afdb41d79aa0001..1808a97289a98fc86e53a3ea4dddad71cdb7536e 100644 (file)
@@ -8,6 +8,8 @@ c_src_lint += sysrepo_src
 sysrepo_common_src = files([
     'common/sysrepo_conf.c',
     'common/sysrepo_conf.h',
+       'common/helpers.h',
+       'common/helpers.c',
 ])
 c_src_lint += sysrepo_common_src
 
index ee360abbce8965e611b4054dfb0dfea82646cf4c..7c7297120ada62de552b6e6cda760a08b8ef8a31 100644 (file)
@@ -15,7 +15,7 @@ typedef struct {
 } gc_record_info_t;
 
 typedef struct {
-       const char *cache_path; // path to the LMDB with resolver cache
+       char *cache_path;       // path to the LMDB with resolver cache
        unsigned long gc_interval;      // waiting time between two whole garbage collections in usecs (0 = just one-time cleanup)
 
        size_t temp_keys_space; // maximum amount of temporary memory for copied keys in bytes (0 = unlimited)
index 32f2b0e1810bbee356aa1f5e700b24d5b07e75c6..ea9293f0ea05415ed3b2be271142e96597bf0d9b 100644 (file)
 
 #include "kresconfig.h"
 #include "kr_cache_gc.h"
+
+#ifdef ENABLE_SYSREPO
+
+#include <poll.h>
+#include <string.h>
+
+#include <sysrepo.h>
+#include <libyang/libyang.h>
+
 #include "modules/sysrepo/common/sysrepo_conf.h"
+#include "modules/sysrepo/common/helpers.h"
+
+#define XPATH_GC    XPATH_BASE"/cache/"YM_KRES":garbage-collector"
+
+#endif
 
 volatile static int killed = 0;
 
+kr_cache_gc_cfg_t cfg = {
+       .rw_txn_items = 100,
+       .cache_max_usage = 80,
+       .cache_to_be_freed = 10
+};
+
 static void got_killed(int signum)
 {
        (void)signum;
@@ -55,6 +75,119 @@ static long get_nonneg_optarg()
        exit(2);
 }
 
+#ifdef ENABLE_SYSREPO
+
+static int get_gc_version_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath,
+const char *request_xpath, uint32_t request_id, struct lyd_node **parent, void *private_data)
+{
+       const char *gc_version_xpath = XPATH_GC"/version";
+
+       if (!strcmp(module_name, YM_COMMON) && !strcmp(xpath, gc_version_xpath))
+       {
+               lyd_new_path(*parent, NULL, gc_version_xpath, PACKAGE_VERSION, 0, 0);
+       }
+       return SR_ERR_OK;
+}
+
+static int cache_storage_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath,
+sr_event_t event, uint32_t request_id, void *private_data)
+{
+       if(event == SR_EV_CHANGE)
+       {
+               /* validation actions*/
+       }
+       else if (event == SR_EV_DONE)
+       {
+               int sr_err = SR_ERR_OK;
+               sr_change_oper_t oper;
+               sr_val_t *old_value = NULL;
+               sr_val_t *new_value = NULL;
+               sr_change_iter_t *it = NULL;
+
+               sr_err = sr_get_changes_iter(session, XPATH_BASE"/cache/"YM_KRES":storage" , &it);
+               if (sr_err != SR_ERR_OK) goto cleanup;
+
+               while ((sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
+
+                       strcpy(cfg.cache_path , new_value->data.string_val);
+
+                       sr_free_val(old_value);
+                       sr_free_val(new_value);
+               }
+
+               cleanup:
+               sr_free_change_iter(it);
+
+               if(sr_err != SR_ERR_OK && sr_err != SR_ERR_NOT_FOUND)
+                       printf("Error: %s\n",sr_strerror(sr_err));
+       }
+       else if(event == SR_EV_ABORT)
+       {
+               /* abortion actions */
+       }
+       return SR_ERR_OK;
+}
+
+static int cache_gc_change_cb(sr_session_ctx_t *session, const char *module_name, const char *xpath,
+sr_event_t event, uint32_t request_id, void *private_data)
+{
+       if(event == SR_EV_CHANGE)
+       {
+               /* validation actions*/
+       }
+       else if (event == SR_EV_DONE)
+       {
+               int sr_err = SR_ERR_OK;
+               sr_change_oper_t oper;
+               sr_val_t *old_value = NULL;
+               sr_val_t *new_value = NULL;
+               sr_change_iter_t *it = NULL;
+
+               sr_err = sr_get_changes_iter(session, XPATH_GC"/*/." , &it);
+               if (sr_err != SR_ERR_OK) goto cleanup;
+
+               while ((sr_get_change_next(session, it, &oper, &old_value, &new_value)) == SR_ERR_OK) {
+
+                       const char *leaf = remove_substr(new_value->xpath, XPATH_GC"/");
+
+                       if (!strcmp(leaf, "interval"))
+                               cfg.gc_interval = new_value->data.uint64_val*1000;
+                       else if (!strcmp(leaf, "threshold"))
+                               cfg.cache_max_usage = new_value->data.uint8_val;
+                       else if (!strcmp(leaf, "release-percentage"))
+                               cfg.cache_to_be_freed = new_value->data.uint8_val;
+                       else if (!strcmp(leaf, "temporary-keys-space"))
+                               cfg.temp_keys_space = new_value->data.uint64_val*1048576;
+                       else if (!strcmp(leaf, "rw-items"))
+                               cfg.rw_txn_items = new_value->data.uint64_val;
+                       else if (!strcmp(leaf, "rw-duration"))
+                               cfg.rw_txn_duration = new_value->data.uint64_val;
+                       else if (!strcmp(leaf, "rw-delay"))
+                               cfg.rw_txn_delay = new_value->data.uint64_val;
+                       else if (!strcmp(leaf, "dry-run"))
+                               cfg.dry_run = new_value->data.bool_val;
+                       else
+                               printf("Uknown configuration option: %s\n", leaf);
+
+                       sr_free_val(old_value);
+                       sr_free_val(new_value);
+               }
+
+               cleanup:
+               sr_free_change_iter(it);
+
+               if(sr_err != SR_ERR_OK && sr_err != SR_ERR_NOT_FOUND)
+                       printf("Error: %s\n",sr_strerror(sr_err));
+       }
+       else if(event == SR_EV_ABORT)
+       {
+               /* abortion actions */
+       }
+       return SR_ERR_OK;
+}
+
+#endif
+
 int main(int argc, char *argv[])
 {
        printf("Knot Resolver Cache Garbage Collector, version %s\n", PACKAGE_VERSION);
@@ -70,12 +203,6 @@ int main(int argc, char *argv[])
        signal(SIGCHLD, got_killed);
        signal(SIGINT, got_killed);
 
-       kr_cache_gc_cfg_t cfg = {
-               .rw_txn_items = 100,
-               .cache_max_usage = 80,
-               .cache_to_be_freed = 10
-       };
-
        int o;
        while ((o = getopt(argc, argv, "hnc:d:l:m:u:f:w:t:")) != -1) {
                switch (o) {
@@ -125,20 +252,85 @@ int main(int argc, char *argv[])
 
        int exit_code = 0;
        kr_cache_gc_state_t *gc_state = NULL;
+       #ifdef ENABLE_SYSREPO
+       int fd;
+       int rv = SR_ERR_OK;
+       struct pollfd fds[1];
+       sr_conn_ctx_t *sr_connection = NULL;
+       sr_session_ctx_t *sr_session = NULL;
+       sr_subscription_ctx_t *sr_subscription = NULL;
+
+       rv = sr_connect(0, &sr_connection);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       rv = sr_connection_recover(sr_connection);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       rv = sr_session_start(sr_connection, SR_DS_RUNNING, &sr_session);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       /* config data subscriptions*/
+       rv = sr_module_change_subscribe(sr_session, YM_COMMON, XPATH_GC, cache_gc_change_cb, NULL, 0, SR_SUBSCR_NO_THREAD|SR_SUBSCR_ENABLED, &sr_subscription);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       rv = sr_module_change_subscribe(sr_session, YM_COMMON, XPATH_BASE"/cache/"YM_KRES":storage", cache_storage_change_cb, NULL, 0, SR_SUBSCR_NO_THREAD|SR_SUBSCR_ENABLED|SR_SUBSCR_CTX_REUSE, &sr_subscription);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       /* state data subscriptions*/
+       rv = sr_oper_get_items_subscribe(sr_session, YM_COMMON, XPATH_GC"/version", get_gc_version_cb, NULL, SR_SUBSCR_NO_THREAD|SR_SUBSCR_CTX_REUSE, &sr_subscription);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       /* get file descriptor */
+       rv = sr_get_event_pipe(sr_subscription, &fd);
+       if (rv != SR_ERR_OK) goto sr_error;
+
+       fds[0].fd = fd;
+       fds[0].events = POLLIN;
+
+       #endif
+
        do {
                int ret = kr_cache_gc(&cfg, &gc_state);
                // ENOENT: kresd may not be started yet or cleared the cache now
                if (ret && ret != -ENOENT) {
                        printf("Error (%s)\n", knot_strerror(ret));
                        exit_code = 10;
-                       break;
+
+                       #ifdef ENABLE_SYSREPO
+                               goto cleanup;
+                       #else
+                               break;
+                       #endif
                }
 
-               sysrepo_repo_config();
+               #ifdef ENABLE_SYSREPO
+                       int poll_res = poll(fds, 1, (int)cfg.gc_interval/1000);
+                       if(poll_res > 0)
+                               sr_process_events(sr_subscription, sr_session, NULL);
+                       else if (poll_res < 0){
+                               rv = errno;
+                               if (rv && rv != EINTR)
+                                       printf("Error (%s)\n", strerror(rv));
+                               goto cleanup;
+                       }
+               #else
+                       usleep(cfg.gc_interval);
+               #endif
 
-               usleep(cfg.gc_interval);
        } while (cfg.gc_interval > 0 && !killed);
 
+       #ifdef ENABLE_SYSREPO
+               sr_error:
+               if (rv != SR_ERR_OK) {
+                       exit_code = rv;
+                       printf("Error (%s)\n", sr_strerror(rv));
+               }
+
+               cleanup:
+               sr_disconnect(sr_connection);
+
+       #endif
+
        kr_cache_gc_free_state(&gc_state);
 
        return exit_code;