blob: 2d6913a63da1f5ba8cca352e7823f74b7261cab5 [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
49 node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name));
50 node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name));
51
52 if (node->schema->nodetype == LYS_LIST) {
53 struct lyd_node_inner *list = (struct lyd_node_inner*)node;
54 if (((struct lysc_node_list*)node->schema)->keys) {
55 /* list's hash is made of its keys */
56 unsigned int keys_count = LY_ARRAY_SIZE(((struct lysc_node_list*)node->schema)->keys);
57 for (iter = list->child; keys_count; --keys_count, iter = iter->next) {
58 int dynamic = 0;
59 struct lysc_type *type = ((struct lysc_node_leaf*)iter->schema)->type;
60 const char *value = type->plugin->print(&((struct lyd_node_term*)iter)->value, LYD_JSON, 0, &dynamic);
61 node->hash = dict_hash_multi(node->hash, value, strlen(value));
62 if (dynamic) {
63 free((char*)value);
64 }
65 }
66 } else {
67 /* keyless status list */
68 lyd_hash_keyless_list_dfs(list->child, &node->hash);
69 }
70 } else if (node->schema->nodetype == LYS_LEAFLIST) {
71 struct lyd_node_term *llist = (struct lyd_node_term*)node;
72 int dynamic = 0;
73 const char *value = ((struct lysc_node_leaflist*)node->schema)->type->plugin->print(&llist->value, LYD_JSON, 0, &dynamic);
74 node->hash = dict_hash_multi(node->hash, value, strlen(value));
75 if (dynamic) {
76 free((char*)value);
77 }
78 }
79 /* finish the hash */
80 node->hash = dict_hash_multi(node->hash, NULL, 0);
81
82 return LY_SUCCESS;
83}
84
85static int
86lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
87{
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
101 if (!lyd_compare(val1, val2, 0)) {
102 return 1;
103 } else {
104 return 0;
105 }
106}
107
108LY_ERR
109lyd_insert_hash(struct lyd_node *node)
110{
111 struct lyd_node *iter;
112
113 if (!node->parent) {
114 /* nothing to do */
115 return LY_SUCCESS;
116 }
117
118 /* create parent hash table if required, otherwise just add the new child */
119 if (!node->parent->children_ht) {
120 unsigned int u;
121
122 /* the hash table is created only when the number of children in a node exceeds the
123 * defined minimal limit LY_CACHE_HT_MIN_CHILDREN
124 */
125 for (u = 0, iter = node->parent->child; iter; ++u, iter = iter->next);
126 if (u >= LYD_HT_MIN_ITEMS) {
127 /* create hash table, insert all the children */
128 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
129 LY_LIST_FOR(node->parent->child, iter) {
130 if (lyht_insert(node->parent->children_ht, &iter, iter->hash, NULL)) {
131 LOGINT(node->schema->module->ctx);
132 return LY_EINT;
133 }
134 }
135 }
136 } else {
137 if (lyht_insert(node->parent->children_ht, &node, node->hash, NULL)) {
138 LOGINT(node->schema->module->ctx);
139 return LY_EINT;
140 }
141 }
142
143 return LY_SUCCESS;
144}
Radek Krejcie7b95092019-05-15 11:03:07 +0200145
146void
147lyd_unlink_hash(struct lyd_node *node)
148{
149 if (node->parent && node->parent->children_ht) {
150 lyht_remove(node->parent->children_ht, &node, node->hash);
151 }
152}