summaryrefslogtreecommitdiffstats
path: root/src/lyb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lyb.c')
-rw-r--r--src/lyb.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/lyb.c b/src/lyb.c
new file mode 100644
index 0000000..87806c8
--- /dev/null
+++ b/src/lyb.c
@@ -0,0 +1,125 @@
+/**
+ * @file lyb.c
+ * @author Michal Vasko <mvasko@cesnet.cz>
+ * @brief LYB format common functionality.
+ *
+ * Copyright (c) 2021 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include "lyb.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "compat.h"
+#include "tree_schema.h"
+
+/**
+ * @brief Generate single hash for a schema node to be used for LYB data.
+ *
+ * @param[in] node Node to hash.
+ * @param[in] collision_id Collision ID of the hash to generate.
+ * @return Generated hash.
+ */
+static LYB_HASH
+lyb_generate_hash(const struct lysc_node *node, uint8_t collision_id)
+{
+ const struct lys_module *mod = node->module;
+ uint32_t full_hash;
+ LYB_HASH hash;
+
+ /* generate full hash */
+ full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
+ full_hash = dict_hash_multi(full_hash, node->name, strlen(node->name));
+ if (collision_id) {
+ size_t ext_len;
+
+ if (collision_id > strlen(mod->name)) {
+ /* fine, we will not hash more bytes, just use more bits from the hash than previously */
+ ext_len = strlen(mod->name);
+ } else {
+ /* use one more byte from the module name than before */
+ ext_len = collision_id;
+ }
+ full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
+ }
+ full_hash = dict_hash_multi(full_hash, NULL, 0);
+
+ /* use the shortened hash */
+ hash = full_hash & (LYB_HASH_MASK >> collision_id);
+ /* add collision identificator */
+ hash |= LYB_HASH_COLLISION_ID >> collision_id;
+
+ return hash;
+}
+
+LYB_HASH
+lyb_get_hash(const struct lysc_node *node, uint8_t collision_id)
+{
+ /* hashes must be cached */
+ assert(node->hash[0]);
+
+ if (collision_id < LYS_NODE_HASH_COUNT) {
+ /* read from cache */
+ return node->hash[collision_id];
+ }
+
+ /* generate */
+ return lyb_generate_hash(node, collision_id);
+}
+
+/**
+ * @brief Module DFS callback filling all cached hashes of a schema node.
+ */
+static LY_ERR
+lyb_cache_node_hash_cb(struct lysc_node *node, void *UNUSED(data), ly_bool *UNUSED(dfs_continue))
+{
+ if (node->hash[0]) {
+ /* already cached, stop the DFS */
+ return LY_EEXIST;
+ }
+
+ for (uint8_t i = 0; i < LYS_NODE_HASH_COUNT; ++i) {
+ /* store the hash in the cache */
+ node->hash[i] = lyb_generate_hash(node, i);
+ }
+
+ return LY_SUCCESS;
+}
+
+void
+lyb_cache_module_hash(const struct lys_module *mod)
+{
+ /* LOCK */
+ pthread_mutex_lock(&mod->ctx->lyb_hash_lock);
+
+ /* store all cached hashes for all the nodes */
+ lysc_module_dfs_full(mod, lyb_cache_node_hash_cb, NULL);
+
+ /* UNLOCK */
+ pthread_mutex_unlock(&mod->ctx->lyb_hash_lock);
+}
+
+ly_bool
+lyb_has_schema_model(const struct lysc_node *node, const struct lys_module **models)
+{
+ LY_ARRAY_COUNT_TYPE u;
+
+ LY_ARRAY_FOR(models, u) {
+ if (node->module == models[u]) {
+ return 1;
+ }
+ }
+
+ return 0;
+}