blob: 87806c807f488544fb861b066da6542bc7bc5638 [file] [log] [blame]
Michal Vasko11f76c82021-04-15 14:36:14 +02001/**
2 * @file lyb.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief LYB format common functionality.
5 *
6 * Copyright (c) 2021 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15#include "lyb.h"
16
17#include <assert.h>
18#include <pthread.h>
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "common.h"
24#include "compat.h"
25#include "tree_schema.h"
26
27/**
28 * @brief Generate single hash for a schema node to be used for LYB data.
29 *
30 * @param[in] node Node to hash.
31 * @param[in] collision_id Collision ID of the hash to generate.
32 * @return Generated hash.
33 */
34static LYB_HASH
35lyb_generate_hash(const struct lysc_node *node, uint8_t collision_id)
36{
37 const struct lys_module *mod = node->module;
38 uint32_t full_hash;
39 LYB_HASH hash;
40
41 /* generate full hash */
42 full_hash = dict_hash_multi(0, mod->name, strlen(mod->name));
43 full_hash = dict_hash_multi(full_hash, node->name, strlen(node->name));
44 if (collision_id) {
45 size_t ext_len;
46
47 if (collision_id > strlen(mod->name)) {
48 /* fine, we will not hash more bytes, just use more bits from the hash than previously */
49 ext_len = strlen(mod->name);
50 } else {
51 /* use one more byte from the module name than before */
52 ext_len = collision_id;
53 }
54 full_hash = dict_hash_multi(full_hash, mod->name, ext_len);
55 }
56 full_hash = dict_hash_multi(full_hash, NULL, 0);
57
58 /* use the shortened hash */
59 hash = full_hash & (LYB_HASH_MASK >> collision_id);
60 /* add collision identificator */
61 hash |= LYB_HASH_COLLISION_ID >> collision_id;
62
63 return hash;
64}
65
66LYB_HASH
67lyb_get_hash(const struct lysc_node *node, uint8_t collision_id)
68{
69 /* hashes must be cached */
70 assert(node->hash[0]);
71
72 if (collision_id < LYS_NODE_HASH_COUNT) {
73 /* read from cache */
74 return node->hash[collision_id];
75 }
76
77 /* generate */
78 return lyb_generate_hash(node, collision_id);
79}
80
81/**
82 * @brief Module DFS callback filling all cached hashes of a schema node.
83 */
84static LY_ERR
85lyb_cache_node_hash_cb(struct lysc_node *node, void *UNUSED(data), ly_bool *UNUSED(dfs_continue))
86{
87 if (node->hash[0]) {
88 /* already cached, stop the DFS */
89 return LY_EEXIST;
90 }
91
92 for (uint8_t i = 0; i < LYS_NODE_HASH_COUNT; ++i) {
93 /* store the hash in the cache */
94 node->hash[i] = lyb_generate_hash(node, i);
95 }
96
97 return LY_SUCCESS;
98}
99
100void
101lyb_cache_module_hash(const struct lys_module *mod)
102{
103 /* LOCK */
104 pthread_mutex_lock(&mod->ctx->lyb_hash_lock);
105
106 /* store all cached hashes for all the nodes */
107 lysc_module_dfs_full(mod, lyb_cache_node_hash_cb, NULL);
108
109 /* UNLOCK */
110 pthread_mutex_unlock(&mod->ctx->lyb_hash_lock);
111}
112
113ly_bool
114lyb_has_schema_model(const struct lysc_node *node, const struct lys_module **models)
115{
116 LY_ARRAY_COUNT_TYPE u;
117
118 LY_ARRAY_FOR(models, u) {
119 if (node->module == models[u]) {
120 return 1;
121 }
122 }
123
124 return 0;
125}