blob: bc0a0a350fc3e7a2c2d061006c14a9bd6aab7b4a [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
15#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
18
Radek Krejcie7b95092019-05-15 11:03:07 +020019#include "common.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020020#include "config.h"
Radek Krejcie7b95092019-05-15 11:03:07 +020021#include "hash_table.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020022#include "log.h"
Radek Krejci1f05b6a2019-07-18 16:15:06 +020023#include "plugins_types.h"
Radek Krejci535ea9f2020-05-29 16:01:05 +020024#include "tree.h"
25#include "tree_data.h"
26#include "tree_schema.h"
Radek Krejci1f05b6a2019-07-18 16:15:06 +020027
28static void
29lyd_hash_keyless_list_dfs(struct lyd_node *child, uint32_t *hash)
30{
31 struct lyd_node *iter;
32
33 LY_LIST_FOR(child, iter) {
34 switch (iter->schema->nodetype) {
35 case LYS_CONTAINER:
36 case LYS_LIST:
37 lyd_hash_keyless_list_dfs(((struct lyd_node_inner*)iter)->child, hash);
38 break;
39 case LYS_LEAFLIST:
40 case LYS_ANYXML:
41 case LYS_ANYDATA:
42 case LYS_LEAF:
43 *hash = dict_hash_multi(*hash, (char *)&iter->hash, sizeof iter->hash);
44 break;
45 default:
46 LOGINT(NULL);
47 }
48 }
49}
50
51LY_ERR
52lyd_hash(struct lyd_node *node)
53{
54 struct lyd_node *iter;
55
Michal Vasko52927e22020-03-16 17:26:14 +010056 if (!node->schema) {
57 return LY_SUCCESS;
58 }
59
Radek Krejci1f05b6a2019-07-18 16:15:06 +020060 node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
61 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
62
63 if (node->schema->nodetype == LYS_LIST) {
64 struct lyd_node_inner *list = (struct lyd_node_inner*)node;
Radek Krejci0fe9b512019-07-26 17:51:05 +020065 if (!(node->schema->flags & LYS_KEYLESS)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +020066 /* list's hash is made of its keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +020067 struct lysc_node *key;
68 for (key = ((struct lysc_node_list*)node->schema)->child, iter = list->child;
69 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY) && iter;
70 key = key->next, iter = iter->next) {
71 for ( ; iter && iter->schema != key; iter = iter->next);
72 if (!iter) {
73 break;
74 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020075 int dynamic = 0;
76 struct lysc_type *type = ((struct lysc_node_leaf*)iter->schema)->type;
Radek Krejci13a57b62019-07-19 13:04:09 +020077 const char *value = type->plugin->print(&((struct lyd_node_term*)iter)->value, LYD_JSON, json_print_get_prefix, NULL, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020078 node->hash = dict_hash_multi(node->hash, value, strlen(value));
79 if (dynamic) {
80 free((char*)value);
81 }
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) {
88 struct lyd_node_term *llist = (struct lyd_node_term*)node;
89 int dynamic = 0;
Radek Krejci13a57b62019-07-19 13:04:09 +020090 const char *value = ((struct lysc_node_leaflist*)node->schema)->type->plugin->print(&llist->value, LYD_JSON,
91 json_print_get_prefix, NULL, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020092 node->hash = dict_hash_multi(node->hash, value, strlen(value));
93 if (dynamic) {
94 free((char*)value);
95 }
96 }
97 /* finish the hash */
98 node->hash = dict_hash_multi(node->hash, NULL, 0);
99
100 return LY_SUCCESS;
101}
102
103static int
104lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
105{
106 struct lyd_node *val1, *val2;
107
108 val1 = *((struct lyd_node **)val1_p);
109 val2 = *((struct lyd_node **)val2_p);
110
111 if (mod) {
112 if (val1 == val2) {
113 return 1;
114 } else {
115 return 0;
116 }
117 }
118
119 if (!lyd_compare(val1, val2, 0)) {
120 return 1;
121 } else {
122 return 0;
123 }
124}
125
126LY_ERR
127lyd_insert_hash(struct lyd_node *node)
128{
129 struct lyd_node *iter;
130
Michal Vasko52927e22020-03-16 17:26:14 +0100131 if (!node->parent || !node->schema || !node->parent->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200132 /* nothing to do */
133 return LY_SUCCESS;
134 }
135
136 /* create parent hash table if required, otherwise just add the new child */
137 if (!node->parent->children_ht) {
138 unsigned int u;
139
140 /* the hash table is created only when the number of children in a node exceeds the
141 * defined minimal limit LY_CACHE_HT_MIN_CHILDREN
142 */
143 for (u = 0, iter = node->parent->child; iter; ++u, iter = iter->next);
144 if (u >= LYD_HT_MIN_ITEMS) {
145 /* create hash table, insert all the children */
146 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
147 LY_LIST_FOR(node->parent->child, iter) {
148 if (lyht_insert(node->parent->children_ht, &iter, iter->hash, NULL)) {
149 LOGINT(node->schema->module->ctx);
150 return LY_EINT;
151 }
152 }
153 }
154 } else {
155 if (lyht_insert(node->parent->children_ht, &node, node->hash, NULL)) {
156 LOGINT(node->schema->module->ctx);
157 return LY_EINT;
158 }
159 }
160
161 return LY_SUCCESS;
162}
Radek Krejcie7b95092019-05-15 11:03:07 +0200163
164void
165lyd_unlink_hash(struct lyd_node *node)
166{
Michal Vasko413c7f22020-05-05 12:34:06 +0200167 if (node->parent && node->parent->schema && node->parent->children_ht) {
Radek Krejcie7b95092019-05-15 11:03:07 +0200168 lyht_remove(node->parent->children_ht, &node, node->hash);
169 }
170}