blob: ff6430078b98373d971681d7d72723495ca71487 [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 */
14#include "common.h"
15
16#include "hash_table.h"
17#include "tree_data.h"
Radek Krejci1f05b6a2019-07-18 16:15:06 +020018#include "plugins_types.h"
19
20
21static void
22lyd_hash_keyless_list_dfs(struct lyd_node *child, uint32_t *hash)
23{
24 struct lyd_node *iter;
25
26 LY_LIST_FOR(child, iter) {
27 switch (iter->schema->nodetype) {
28 case LYS_CONTAINER:
29 case LYS_LIST:
30 lyd_hash_keyless_list_dfs(((struct lyd_node_inner*)iter)->child, hash);
31 break;
32 case LYS_LEAFLIST:
33 case LYS_ANYXML:
34 case LYS_ANYDATA:
35 case LYS_LEAF:
36 *hash = dict_hash_multi(*hash, (char *)&iter->hash, sizeof iter->hash);
37 break;
38 default:
39 LOGINT(NULL);
40 }
41 }
42}
43
44LY_ERR
45lyd_hash(struct lyd_node *node)
46{
47 struct lyd_node *iter;
48
Michal Vasko52927e22020-03-16 17:26:14 +010049 if (!node->schema) {
50 return LY_SUCCESS;
51 }
52
Radek Krejci1f05b6a2019-07-18 16:15:06 +020053 node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
54 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
55
56 if (node->schema->nodetype == LYS_LIST) {
57 struct lyd_node_inner *list = (struct lyd_node_inner*)node;
Radek Krejci0fe9b512019-07-26 17:51:05 +020058 if (!(node->schema->flags & LYS_KEYLESS)) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +020059 /* list's hash is made of its keys */
Radek Krejci0fe9b512019-07-26 17:51:05 +020060 struct lysc_node *key;
61 for (key = ((struct lysc_node_list*)node->schema)->child, iter = list->child;
62 key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY) && iter;
63 key = key->next, iter = iter->next) {
64 for ( ; iter && iter->schema != key; iter = iter->next);
65 if (!iter) {
66 break;
67 }
Radek Krejci1f05b6a2019-07-18 16:15:06 +020068 int dynamic = 0;
69 struct lysc_type *type = ((struct lysc_node_leaf*)iter->schema)->type;
Radek Krejci13a57b62019-07-19 13:04:09 +020070 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 +020071 node->hash = dict_hash_multi(node->hash, value, strlen(value));
72 if (dynamic) {
73 free((char*)value);
74 }
75 }
76 } else {
77 /* keyless status list */
78 lyd_hash_keyless_list_dfs(list->child, &node->hash);
79 }
80 } else if (node->schema->nodetype == LYS_LEAFLIST) {
81 struct lyd_node_term *llist = (struct lyd_node_term*)node;
82 int dynamic = 0;
Radek Krejci13a57b62019-07-19 13:04:09 +020083 const char *value = ((struct lysc_node_leaflist*)node->schema)->type->plugin->print(&llist->value, LYD_JSON,
84 json_print_get_prefix, NULL, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020085 node->hash = dict_hash_multi(node->hash, value, strlen(value));
86 if (dynamic) {
87 free((char*)value);
88 }
89 }
90 /* finish the hash */
91 node->hash = dict_hash_multi(node->hash, NULL, 0);
92
93 return LY_SUCCESS;
94}
95
96static int
97lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
98{
99 struct lyd_node *val1, *val2;
100
101 val1 = *((struct lyd_node **)val1_p);
102 val2 = *((struct lyd_node **)val2_p);
103
104 if (mod) {
105 if (val1 == val2) {
106 return 1;
107 } else {
108 return 0;
109 }
110 }
111
112 if (!lyd_compare(val1, val2, 0)) {
113 return 1;
114 } else {
115 return 0;
116 }
117}
118
119LY_ERR
120lyd_insert_hash(struct lyd_node *node)
121{
122 struct lyd_node *iter;
123
Michal Vasko52927e22020-03-16 17:26:14 +0100124 if (!node->parent || !node->schema || !node->parent->schema) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +0200125 /* nothing to do */
126 return LY_SUCCESS;
127 }
128
129 /* create parent hash table if required, otherwise just add the new child */
130 if (!node->parent->children_ht) {
131 unsigned int u;
132
133 /* the hash table is created only when the number of children in a node exceeds the
134 * defined minimal limit LY_CACHE_HT_MIN_CHILDREN
135 */
136 for (u = 0, iter = node->parent->child; iter; ++u, iter = iter->next);
137 if (u >= LYD_HT_MIN_ITEMS) {
138 /* create hash table, insert all the children */
139 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
140 LY_LIST_FOR(node->parent->child, iter) {
141 if (lyht_insert(node->parent->children_ht, &iter, iter->hash, NULL)) {
142 LOGINT(node->schema->module->ctx);
143 return LY_EINT;
144 }
145 }
146 }
147 } else {
148 if (lyht_insert(node->parent->children_ht, &node, node->hash, NULL)) {
149 LOGINT(node->schema->module->ctx);
150 return LY_EINT;
151 }
152 }
153
154 return LY_SUCCESS;
155}
Radek Krejcie7b95092019-05-15 11:03:07 +0200156
157void
158lyd_unlink_hash(struct lyd_node *node)
159{
160 if (node->parent && node->parent->children_ht) {
161 lyht_remove(node->parent->children_ht, &node, node->hash);
162 }
163}