From: Aleš Mrázek Date: Fri, 17 Jan 2020 12:33:20 +0000 (+0100) Subject: sysrepo: integration to cache-gc X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=521e34b0fb1d1995d6743c8ed3a704cd6f061362;p=thirdparty%2Fknot-resolver.git sysrepo: integration to cache-gc --- diff --git a/modules/sysrepo/common/helpers.c b/modules/sysrepo/common/helpers.c new file mode 100644 index 000000000..3a470bee1 --- /dev/null +++ b/modules/sysrepo/common/helpers.c @@ -0,0 +1,29 @@ +#include +#include +#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 index 000000000..370e4e7bb --- /dev/null +++ b/modules/sysrepo/common/helpers.h @@ -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); diff --git a/modules/sysrepo/meson.build b/modules/sysrepo/meson.build index 87b9ac3e0..1808a9728 100644 --- a/modules/sysrepo/meson.build +++ b/modules/sysrepo/meson.build @@ -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 diff --git a/utils/cache_gc/kr_cache_gc.h b/utils/cache_gc/kr_cache_gc.h index c0ca0ccc1..1aac6c497 100644 --- a/utils/cache_gc/kr_cache_gc.h +++ b/utils/cache_gc/kr_cache_gc.h @@ -14,7 +14,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) diff --git a/utils/cache_gc/main.c b/utils/cache_gc/main.c index ec96585e3..ab95300a6 100644 --- a/utils/cache_gc/main.c +++ b/utils/cache_gc/main.c @@ -7,11 +7,32 @@ #include #include +#include "kresconfig.h" #include "kr_cache_gc.h" + +#ifdef ENABLE_SYSREPO + +#include +#include + +#include +#include + #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; @@ -53,6 +74,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, KR_CACHE_GC_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 v. %s\n", KR_CACHE_GC_VERSION); @@ -63,12 +197,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) { @@ -116,18 +244,82 @@ int main(int argc, char *argv[]) return 1; } + #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); // ENOENT: kresd may not be started yet or cleared the cache now if (ret && ret != -ENOENT) { printf("Error (%s)\n", knot_strerror(ret)); - return 10; + #ifdef ENABLE_SYSREPO + rv = 10; + goto cleanup; + #else + return 10; + #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); - return 0; + #ifdef ENABLE_SYSREPO + sr_error: + if (rv != SR_ERR_OK) + printf("Error (%s)\n", sr_strerror(rv)); + + cleanup: + sr_disconnect(sr_connection); + + return rv; + #else + return 0; + #endif }