blob: cc6696712f5e65b7a69a40e87c552d9a1ec80116 [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"
Michal Vasko69730152020-10-09 16:30:07 +020021#include "compat.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 Krejci813c02d2021-04-26 10:29:19 +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
Radek Krejci1f05b6a2019-07-18 16:15:06 +020029LY_ERR
30lyd_hash(struct lyd_node *node)
31{
32 struct lyd_node *iter;
Radek Krejci813c02d2021-04-26 10:29:19 +020033 const void *hash_key;
34 ly_bool dyn;
35 size_t key_len;
Radek Krejci1f05b6a2019-07-18 16:15:06 +020036
Michal Vasko52927e22020-03-16 17:26:14 +010037 if (!node->schema) {
38 return LY_SUCCESS;
39 }
40
Michal Vaskoe78faec2021-04-08 17:24:43 +020041 /* hash always starts with the module and schema name */
Radek Krejci1f05b6a2019-07-18 16:15:06 +020042 node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
43 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
44
45 if (node->schema->nodetype == LYS_LIST) {
Michal Vaskoe78faec2021-04-08 17:24:43 +020046 if (node->schema->flags & LYS_KEYLESS) {
47 /* key-less list simply adds its schema name again to the hash, just so that it differs from the first-instance hash */
48 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
49 } else {
50 struct lyd_node_inner *list = (struct lyd_node_inner *)node;
51
52 /* list hash is made up from its keys */
Michal Vaskoba99a3e2020-08-18 15:50:05 +020053 for (iter = list->child; iter && (iter->schema->flags & LYS_KEY); iter = iter->next) {
Radek Krejci813c02d2021-04-26 10:29:19 +020054 struct lyd_node_term *key = (struct lyd_node_term *)iter;
55
Michal Vaskodcfac2c2021-05-10 11:36:37 +020056 hash_key = key->value.realtype->plugin->print(NULL, &key->value, LY_VALUE_LYB, NULL, &dyn, &key_len);
Radek Krejci813c02d2021-04-26 10:29:19 +020057 node->hash = dict_hash_multi(node->hash, hash_key, key_len);
58 if (dyn) {
59 free((void *)hash_key);
60 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020061 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020062 }
63 } else if (node->schema->nodetype == LYS_LEAFLIST) {
Radek Krejci813c02d2021-04-26 10:29:19 +020064 /* leaf-list adds its hash key */
65 struct lyd_node_term *llist = (struct lyd_node_term *)node;
66
Michal Vaskodcfac2c2021-05-10 11:36:37 +020067 hash_key = llist->value.realtype->plugin->print(NULL, &llist->value, LY_VALUE_LYB, NULL, &dyn, &key_len);
Radek Krejci813c02d2021-04-26 10:29:19 +020068 node->hash = dict_hash_multi(node->hash, hash_key, key_len);
69 if (dyn) {
70 free((void *)hash_key);
71 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020072 }
Michal Vaskoe78faec2021-04-08 17:24:43 +020073
Radek Krejci1f05b6a2019-07-18 16:15:06 +020074 /* finish the hash */
75 node->hash = dict_hash_multi(node->hash, NULL, 0);
76
77 return LY_SUCCESS;
78}
79
Radek Krejci857189e2020-09-01 13:26:36 +020080/**
81 * @brief Compare callback for values in hash table.
82 *
Michal Vasko62524a92021-02-26 10:08:50 +010083 * Implementation of ::lyht_value_equal_cb.
Radek Krejci857189e2020-09-01 13:26:36 +020084 */
85static ly_bool
86lyd_hash_table_val_equal(void *val1_p, void *val2_p, ly_bool mod, void *UNUSED(cb_data))
Radek Krejci1f05b6a2019-07-18 16:15:06 +020087{
88 struct lyd_node *val1, *val2;
89
90 val1 = *((struct lyd_node **)val1_p);
91 val2 = *((struct lyd_node **)val2_p);
92
93 if (mod) {
94 if (val1 == val2) {
95 return 1;
96 } else {
97 return 0;
98 }
99 }
100
Michal Vaskoda859032020-07-14 12:20:14 +0200101 if (val1->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
102 /* match on exact instance */
Michal Vasko8f359bf2020-07-28 10:41:15 +0200103 if (!lyd_compare_single(val1, val2, 0)) {
Michal Vaskoda859032020-07-14 12:20:14 +0200104 return 1;
105 }
106 } else if (val1->schema == val2->schema) {
107 /* just schema match */
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200108 return 1;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200109 }
Michal Vaskoda859032020-07-14 12:20:14 +0200110 return 0;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200111}
112
Michal Vaskob104f112020-07-17 09:54:54 +0200113/**
114 * @brief Add single node into children hash table.
115 *
116 * @param[in] ht Children hash table.
117 * @param[in] node Node to insert.
118 * @param[in] empty_ht Whether we started with an empty HT meaning no nodes were inserted yet.
119 * @return LY_ERR value.
120 */
121static LY_ERR
Radek Krejci857189e2020-09-01 13:26:36 +0200122lyd_insert_hash_add(struct hash_table *ht, struct lyd_node *node, ly_bool empty_ht)
Michal Vaskob104f112020-07-17 09:54:54 +0200123{
124 uint32_t hash;
125
126 assert(ht && node && node->schema);
127
128 /* add node itself */
129 if (lyht_insert(ht, &node, node->hash, NULL)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +0200130 LOGINT_RET(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200131 }
132
133 /* add first instance of a (leaf-)list */
Michal Vasko69730152020-10-09 16:30:07 +0200134 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) &&
135 (!node->prev->next || (node->prev->schema != node->schema))) {
Michal Vaskob104f112020-07-17 09:54:54 +0200136 /* get the simple hash */
137 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
138 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
139 hash = dict_hash_multi(hash, NULL, 0);
140
141 /* remove any previous stored instance, only if we did not start with an empty HT */
142 if (!empty_ht && node->next && (node->next->schema == node->schema)) {
143 if (lyht_remove(ht, &node->next, hash)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +0200144 LOGINT_RET(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200145 }
146 }
147
Michal Vaskoe78faec2021-04-08 17:24:43 +0200148 /* in this case there would be the exact same value twice in the hash table, not supported (by the HT) */
149 assert(hash != node->hash);
Michal Vasko47718292021-02-26 10:12:44 +0100150
Michal Vaskob104f112020-07-17 09:54:54 +0200151 /* insert this instance as the first (leaf-)list instance */
152 if (lyht_insert(ht, &node, hash, NULL)) {
Michal Vaskoe78faec2021-04-08 17:24:43 +0200153 LOGINT_RET(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200154 }
155 }
156
Michal Vaskoe78faec2021-04-08 17:24:43 +0200157 return LY_SUCCESS;
Michal Vaskob104f112020-07-17 09:54:54 +0200158}
159
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200160LY_ERR
161lyd_insert_hash(struct lyd_node *node)
162{
163 struct lyd_node *iter;
Michal Vaskob104f112020-07-17 09:54:54 +0200164 uint32_t u;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200165
Michal Vasko52927e22020-03-16 17:26:14 +0100166 if (!node->parent || !node->schema || !node->parent->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200167 /* nothing to do */
168 return LY_SUCCESS;
169 }
170
171 /* create parent hash table if required, otherwise just add the new child */
172 if (!node->parent->children_ht) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200173 /* the hash table is created only when the number of children in a node exceeds the
Michal Vasko60ea6352020-06-29 13:39:39 +0200174 * defined minimal limit LYD_HT_MIN_ITEMS
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200175 */
Michal Vaskob104f112020-07-17 09:54:54 +0200176 u = 0;
177 LY_LIST_FOR(node->parent->child, iter) {
178 if (iter->schema) {
179 ++u;
180 }
181 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200182 if (u >= LYD_HT_MIN_ITEMS) {
183 /* create hash table, insert all the children */
184 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
185 LY_LIST_FOR(node->parent->child, iter) {
Michal Vaskob104f112020-07-17 09:54:54 +0200186 if (iter->schema) {
187 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, iter, 1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200188 }
189 }
190 }
191 } else {
Michal Vaskob104f112020-07-17 09:54:54 +0200192 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, node, 0));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200193 }
194
195 return LY_SUCCESS;
196}
Radek Krejcie7b95092019-05-15 11:03:07 +0200197
198void
199lyd_unlink_hash(struct lyd_node *node)
200{
Michal Vaskob104f112020-07-17 09:54:54 +0200201 uint32_t hash;
202
203 if (!node->parent || !node->schema || !node->parent->schema || !node->parent->children_ht) {
204 /* not in any HT */
205 return;
206 }
207
208 /* remove from the parent HT */
209 if (lyht_remove(node->parent->children_ht, &node, node->hash)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200210 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200211 return;
212 }
213
214 /* first instance of the (leaf-)list, needs to be removed from HT */
215 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (!node->prev->next || (node->prev->schema != node->schema))) {
216 /* get the simple hash */
217 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
218 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
219 hash = dict_hash_multi(hash, NULL, 0);
220
221 /* remove the instance */
222 if (lyht_remove(node->parent->children_ht, &node, hash)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200223 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200224 return;
225 }
226
227 /* add the next instance */
228 if (node->next && (node->next->schema == node->schema)) {
229 if (lyht_insert(node->parent->children_ht, &node->next, hash, NULL)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200230 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200231 return;
232 }
233 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200234 }
235}