blob: 177a3941efe6a659b1bb9a74181f37bff364f331 [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
Michal Vaskoc5a22832020-08-20 13:21:33 +020020#include "compat.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "common.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:
Michal Vasko22df3f02020-08-24 13:29:22 +020038 lyd_hash_keyless_list_dfs(((struct lyd_node_inner *)iter)->child, hash);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020039 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) {
Michal Vasko22df3f02020-08-24 13:29:22 +020065 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 */
Michal Vaskoba99a3e2020-08-18 15:50:05 +020068 for (iter = list->child; iter && (iter->schema->flags & LYS_KEY); iter = iter->next) {
Michal Vaskob7be7a82020-08-20 09:09:04 +020069 const char *value = LYD_CANON_VALUE(iter);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020070 node->hash = dict_hash_multi(node->hash, value, strlen(value));
Radek Krejci1f05b6a2019-07-18 16:15:06 +020071 }
72 } else {
73 /* keyless status list */
74 lyd_hash_keyless_list_dfs(list->child, &node->hash);
75 }
76 } else if (node->schema->nodetype == LYS_LEAFLIST) {
Michal Vaskob7be7a82020-08-20 09:09:04 +020077 const char *value = LYD_CANON_VALUE(node);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020078 node->hash = dict_hash_multi(node->hash, value, strlen(value));
Radek Krejci1f05b6a2019-07-18 16:15:06 +020079 }
80 /* finish the hash */
81 node->hash = dict_hash_multi(node->hash, NULL, 0);
82
83 return LY_SUCCESS;
84}
85
Radek Krejci1deb5be2020-08-26 16:43:36 +020086static uint8_t
87lyd_hash_table_val_equal(void *val1_p, void *val2_p, uint8_t mod, void *UNUSED(cb_data))
Radek Krejci1f05b6a2019-07-18 16:15:06 +020088{
89 struct lyd_node *val1, *val2;
90
91 val1 = *((struct lyd_node **)val1_p);
92 val2 = *((struct lyd_node **)val2_p);
93
94 if (mod) {
95 if (val1 == val2) {
96 return 1;
97 } else {
98 return 0;
99 }
100 }
101
Michal Vaskoda859032020-07-14 12:20:14 +0200102 if (val1->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) {
103 /* match on exact instance */
Michal Vasko8f359bf2020-07-28 10:41:15 +0200104 if (!lyd_compare_single(val1, val2, 0)) {
Michal Vaskoda859032020-07-14 12:20:14 +0200105 return 1;
106 }
107 } else if (val1->schema == val2->schema) {
108 /* just schema match */
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200109 return 1;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200110 }
Michal Vaskoda859032020-07-14 12:20:14 +0200111 return 0;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200112}
113
Michal Vaskob104f112020-07-17 09:54:54 +0200114/**
115 * @brief Add single node into children hash table.
116 *
117 * @param[in] ht Children hash table.
118 * @param[in] node Node to insert.
119 * @param[in] empty_ht Whether we started with an empty HT meaning no nodes were inserted yet.
120 * @return LY_ERR value.
121 */
122static LY_ERR
Radek Krejci1deb5be2020-08-26 16:43:36 +0200123lyd_insert_hash_add(struct hash_table *ht, struct lyd_node *node, uint8_t empty_ht)
Michal Vaskob104f112020-07-17 09:54:54 +0200124{
125 uint32_t hash;
126
127 assert(ht && node && node->schema);
128
129 /* add node itself */
130 if (lyht_insert(ht, &node, node->hash, NULL)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200131 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200132 return LY_EINT;
133 }
134
135 /* add first instance of a (leaf-)list */
136 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST))
137 && (!node->prev->next || (node->prev->schema != node->schema))) {
138 /* get the simple hash */
139 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
140 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
141 hash = dict_hash_multi(hash, NULL, 0);
142
143 /* remove any previous stored instance, only if we did not start with an empty HT */
144 if (!empty_ht && node->next && (node->next->schema == node->schema)) {
145 if (lyht_remove(ht, &node->next, hash)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200146 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200147 return LY_EINT;
148 }
149 }
150
151 /* insert this instance as the first (leaf-)list instance */
152 if (lyht_insert(ht, &node, hash, NULL)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200153 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200154 return LY_EINT;
155 }
156 }
157
158 return LY_SUCCESS;
159}
160
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200161LY_ERR
162lyd_insert_hash(struct lyd_node *node)
163{
164 struct lyd_node *iter;
Michal Vaskob104f112020-07-17 09:54:54 +0200165 uint32_t u;
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200166
Michal Vasko52927e22020-03-16 17:26:14 +0100167 if (!node->parent || !node->schema || !node->parent->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200168 /* nothing to do */
169 return LY_SUCCESS;
170 }
171
172 /* create parent hash table if required, otherwise just add the new child */
173 if (!node->parent->children_ht) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200174 /* the hash table is created only when the number of children in a node exceeds the
Michal Vasko60ea6352020-06-29 13:39:39 +0200175 * defined minimal limit LYD_HT_MIN_ITEMS
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200176 */
Michal Vaskob104f112020-07-17 09:54:54 +0200177 u = 0;
178 LY_LIST_FOR(node->parent->child, iter) {
179 if (iter->schema) {
180 ++u;
181 }
182 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200183 if (u >= LYD_HT_MIN_ITEMS) {
184 /* create hash table, insert all the children */
185 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
186 LY_LIST_FOR(node->parent->child, iter) {
Michal Vaskob104f112020-07-17 09:54:54 +0200187 if (iter->schema) {
188 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, iter, 1));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200189 }
190 }
191 }
192 } else {
Michal Vaskob104f112020-07-17 09:54:54 +0200193 LY_CHECK_RET(lyd_insert_hash_add(node->parent->children_ht, node, 0));
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200194 }
195
196 return LY_SUCCESS;
197}
Radek Krejcie7b95092019-05-15 11:03:07 +0200198
199void
200lyd_unlink_hash(struct lyd_node *node)
201{
Michal Vaskob104f112020-07-17 09:54:54 +0200202 uint32_t hash;
203
204 if (!node->parent || !node->schema || !node->parent->schema || !node->parent->children_ht) {
205 /* not in any HT */
206 return;
207 }
208
209 /* remove from the parent HT */
210 if (lyht_remove(node->parent->children_ht, &node, node->hash)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200211 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200212 return;
213 }
214
215 /* first instance of the (leaf-)list, needs to be removed from HT */
216 if ((node->schema->nodetype & (LYS_LIST | LYS_LEAFLIST)) && (!node->prev->next || (node->prev->schema != node->schema))) {
217 /* get the simple hash */
218 hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
219 hash = dict_hash_multi(hash, node->schema->name, strlen(node->schema->name));
220 hash = dict_hash_multi(hash, NULL, 0);
221
222 /* remove the instance */
223 if (lyht_remove(node->parent->children_ht, &node, hash)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200224 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200225 return;
226 }
227
228 /* add the next instance */
229 if (node->next && (node->next->schema == node->schema)) {
230 if (lyht_insert(node->parent->children_ht, &node->next, hash, NULL)) {
Michal Vaskob7be7a82020-08-20 09:09:04 +0200231 LOGINT(LYD_CTX(node));
Michal Vaskob104f112020-07-17 09:54:54 +0200232 return;
233 }
234 }
Radek Krejcie7b95092019-05-15 11:03:07 +0200235 }
236}