blob: d1756d9f5561610deb8695647130770071bdbde5 [file] [log] [blame]
Radek Krejcie7b95092019-05-15 11:03:07 +02001/**
2 * @file tree_data_hash.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Functions to manipulate with the data node's hashes.
5 *
6 * Copyright (c) 2019 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 */
Radek Krejci535ea9f2020-05-29 16:01:05 +020014
Michal Vaskob104f112020-07-17 09:54:54 +020015#include <assert.h>
Radek Krejci535ea9f2020-05-29 16:01:05 +020016#include <stdint.h>
17#include <stdlib.h>
18#include <string.h>
19
Radek Krejcie7b95092019-05-15 11:03:07 +020020#include "common.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020021#include "config.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020022#include "hash_table.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020023#include "log.h"
Radek Krejci1f05b6a2019-07-18 16:15:06 +020024#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020025#include "tree.h"
26#include "tree_data.h"
27#include "tree_schema.h"
Radek Krejci1f05b6a2019-07-18 16:15:06 +020028
29static void
30lyd_hash_keyless_list_dfs(struct lyd_node *child, uint32_t *hash)
31{
32 struct lyd_node *iter;
33
34 LY_LIST_FOR(child, iter) {
35 switch (iter->schema->nodetype) {
36 case LYS_CONTAINER:
37 case LYS_LIST:
38 lyd_hash_keyless_list_dfs(((struct lyd_node_inner*)iter)->child, hash);
39 break;
40 case LYS_LEAFLIST:
41 case LYS_ANYXML:
42 case LYS_ANYDATA:
43 case LYS_LEAF:
44 *hash = dict_hash_multi(*hash, (char *)&iter->hash, sizeof iter->hash);
45 break;
46 default:
47 LOGINT(NULL);
48 }
49 }
50}
51
52LY_ERR
53lyd_hash(struct lyd_node *node)
54{
55 struct lyd_node *iter;
56
Michal Vasko52927e22020-03-16 17:26:14 +010057 if (!node->schema) {
58 return LY_SUCCESS;
59 }
60
Radek Krejci1f05b6a2019-07-18 16:15:06 +020061 node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
62 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
63
64 if (node->schema->nodetype == LYS_LIST) {
65 struct lyd_node_inner *list = (struct lyd_node_inner*)node;
Radek Krejci0fe9b512019-07-26 17:51:05 +020066 if (!(node->schema->flags & LYS_KEYLESS)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +020067 /* list's hash is made of its keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +020068 struct lysc_node *key;
69 for (key = ((struct lysc_node_list*)node->schema)->child, iter = list->child;
70 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY) && iter;
71 key = key->next, iter = iter->next) {
72 for ( ; iter && iter->schema != key; iter = iter->next);
73 if (!iter) {
74 break;
75 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020076 int dynamic = 0;
Michal Vaskob104f112020-07-17 09:54:54 +020077 const char *value = lyd_value2str((struct lyd_node_term *)iter, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020078 node->hash = dict_hash_multi(node->hash, value, strlen(value));
79 if (dynamic) {
Michal Vaskob104f112020-07-17 09:54:54 +020080 free((char *)value);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020081 }
82 }
83 } else {
84 /* keyless status list */
85 lyd_hash_keyless_list_dfs(list->child, &node->hash);
86 }
87 } else if (node->schema->nodetype == LYS_LEAFLIST) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +020088 int dynamic = 0;
Michal Vaskob104f112020-07-17 09:54:54 +020089 const char *value = lyd_value2str((struct lyd_node_term *)node, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020090 node->hash = dict_hash_multi(node->hash, value, strlen(value));
91 if (dynamic) {
92 free((char*)value);
93 }
94 }
95 /* finish the hash */
96 node->hash = dict_hash_multi(node->hash, NULL, 0);
97
98 return LY_SUCCESS;
99}
100
101static int
102lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
103{
104 struct lyd_node *val1, *val2;
105
106 val1 = *((struct lyd_node **)val1_p);
107 val2 = *((struct lyd_node **)val2_p);
108
109 if (mod) {
110 if (val1 == val2) {
111 return 1;
112 } else {
113 return 0;
114 }
115 }
116
Michal Vaskoda859032020-07-14 12:20:14 +0200117 if (val1->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
118 /* match on exact instance */
Michal Vasko8f359bf2020-07-28 10:41:15 +0200119 if (!lyd_compare_single(val1, val2, 0)) {
Michal Vaskoda859032020-07-14 12:20:14 +0200120 return 1;
121 }
122 } else if (val1->schema == val2->schema) {
123 /* just schema match */
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200124 return 1;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200125 }
Michal Vaskoda859032020-07-14 12:20:14 +0200126 return 0;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200127}
128
Michal Vaskob104f112020-07-17 09:54:54 +0200129/**
130 * @brief Add single node into children hash table.
131 *
132 * @param[in] ht Children hash table.
133 * @param[in] node Node to insert.
134 * @param[in] empty_ht Whether we started with an empty HT meaning no nodes were inserted yet.
135 * @return LY_ERR value.
136 */
137static LY_ERR
138lyd_insert_hash_add(struct hash_table *ht, struct lyd_node *node, int empty_ht)
139{
140 uint32_t hash;
141
142 assert(ht && node && node->schema);
143
144 /* add node itself */
145 if (lyht_insert(ht, &node, node->hash, NULL)) {
146 LOGINT(LYD_NODE_CTX(node));
147 return LY_EINT;
148 }
149
150 /* add first instance of a (leaf-)list */
151 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))
152 && (!node->prev->next || (node->prev->schema != node->schema))) {
153 /* get the simple hash */
154 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
155 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
156 hash = dict_hash_multi(hash, NULL, 0);
157
158 /* remove any previous stored instance, only if we did not start with an empty HT */
159 if (!empty_ht && node->next && (node->next->schema == node->schema)) {
160 if (lyht_remove(ht, &node->next, hash)) {
161 LOGINT(LYD_NODE_CTX(node));
162 return LY_EINT;
163 }
164 }
165
166 /* insert this instance as the first (leaf-)list instance */
167 if (lyht_insert(ht, &node, hash, NULL)) {
168 LOGINT(LYD_NODE_CTX(node));
169 return LY_EINT;
170 }
171 }
172
173 return LY_SUCCESS;
174}
175
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200176LY_ERR
177lyd_insert_hash(struct lyd_node *node)
178{
179 struct lyd_node *iter;
Michal Vaskob104f112020-07-17 09:54:54 +0200180 uint32_t u;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200181
Michal Vasko52927e22020-03-16 17:26:14 +0100182 if (!node->parent || !node->schema || !node->parent->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200183 /* nothing to do */
184 return LY_SUCCESS;
185 }
186
187 /* create parent hash table if required, otherwise just add the new child */
188 if (!node->parent->children_ht) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200189 /* the hash table is created only when the number of children in a node exceeds the
Michal Vasko60ea6352020-06-29 13:39:39 +0200190 * defined minimal limit LYD_HT_MIN_ITEMS
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200191 */
Michal Vaskob104f112020-07-17 09:54:54 +0200192 u = 0;
193 LY_LIST_FOR(node->parent->child, iter) {
194 if (iter->schema) {
195 ++u;
196 }
197 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200198 if (u >= LYD_HT_MIN_ITEMS) {
199 /* create hash table, insert all the children */
200 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
201 LY_LIST_FOR(node->parent->child, iter) {
Michal Vaskob104f112020-07-17 09:54:54 +0200202 if (iter->schema) {
203 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, iter, 1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200204 }
205 }
206 }
207 } else {
Michal Vaskob104f112020-07-17 09:54:54 +0200208 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, node, 0));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200209 }
210
211 return LY_SUCCESS;
212}
Radek Krejcie7b95092019-05-15 11:03:07 +0200213
214void
215lyd_unlink_hash(struct lyd_node *node)
216{
Michal Vaskob104f112020-07-17 09:54:54 +0200217 uint32_t hash;
218
219 if (!node->parent || !node->schema || !node->parent->schema || !node->parent->children_ht) {
220 /* not in any HT */
221 return;
222 }
223
224 /* remove from the parent HT */
225 if (lyht_remove(node->parent->children_ht, &node, node->hash)) {
226 LOGINT(LYD_NODE_CTX(node));
227 return;
228 }
229
230 /* first instance of the (leaf-)list, needs to be removed from HT */
231 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (!node->prev->next || (node->prev->schema != node->schema))) {
232 /* get the simple hash */
233 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
234 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
235 hash = dict_hash_multi(hash, NULL, 0);
236
237 /* remove the instance */
238 if (lyht_remove(node->parent->children_ht, &node, hash)) {
239 LOGINT(LYD_NODE_CTX(node));
240 return;
241 }
242
243 /* add the next instance */
244 if (node->next && (node->next->schema == node->schema)) {
245 if (lyht_insert(node->parent->children_ht, &node->next, hash, NULL)) {
246 LOGINT(LYD_NODE_CTX(node));
247 return;
248 }
249 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200250 }
251}