/** * @file lyb.c * @author Michal Vasko * @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 #include #include #include #include #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; }