blob: 37d63375930f360c6d6878fbd6c37e7d5c988ec9 [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);
Radek Krejci22ebdba2019-07-25 13:59:43 +020057 for (iter = list->child; iter && keys_count; --keys_count, iter = iter->next) {
Radek Krejci1f05b6a2019-07-18 16:15:06 +020058 int dynamic = 0;
59 struct lysc_type *type = ((struct lysc_node_leaf*)iter->schema)->type;
Radek Krejci13a57b62019-07-19 13:04:09 +020060 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 +020061 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;
Radek Krejci13a57b62019-07-19 13:04:09 +020073 const char *value = ((struct lysc_node_leaflist*)node->schema)->type->plugin->print(&llist->value, LYD_JSON,
74 json_print_get_prefix, NULL, &dynamic);
Radek Krejci1f05b6a2019-07-18 16:15:06 +020075 node->hash = dict_hash_multi(node->hash, value, strlen(value));
76 if (dynamic) {
77 free((char*)value);
78 }
79 }
80 /* finish the hash */
81 node->hash = dict_hash_multi(node->hash, NULL, 0);
82
83 return LY_SUCCESS;
84}
85
86static int
87lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
88{
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
102 if (!lyd_compare(val1, val2, 0)) {
103 return 1;
104 } else {
105 return 0;
106 }
107}
108
109LY_ERR
110lyd_insert_hash(struct lyd_node *node)
111{
112 struct lyd_node *iter;
113
114 if (!node->parent) {
115 /* nothing to do */
116 return LY_SUCCESS;
117 }
118
119 /* create parent hash table if required, otherwise just add the new child */
120 if (!node->parent->children_ht) {
121 unsigned int u;
122
123 /* the hash table is created only when the number of children in a node exceeds the
124 * defined minimal limit LY_CACHE_HT_MIN_CHILDREN
125 */
126 for (u = 0, iter = node->parent->child; iter; ++u, iter = iter->next);
127 if (u >= LYD_HT_MIN_ITEMS) {
128 /* create hash table, insert all the children */
129 node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1);
130 LY_LIST_FOR(node->parent->child, iter) {
131 if (lyht_insert(node->parent->children_ht, &iter, iter->hash, NULL)) {
132 LOGINT(node->schema->module->ctx);
133 return LY_EINT;
134 }
135 }
136 }
137 } else {
138 if (lyht_insert(node->parent->children_ht, &node, node->hash, NULL)) {
139 LOGINT(node->schema->module->ctx);
140 return LY_EINT;
141 }
142 }
143
144 return LY_SUCCESS;
145}
Radek Krejcie7b95092019-05-15 11:03:07 +0200146
147void
148lyd_unlink_hash(struct lyd_node *node)
149{
150 if (node->parent && node->parent->children_ht) {
151 lyht_remove(node->parent->children_ht, &node, node->hash);
152 }
153}