| /** |
| * @file tree_data_hash.c |
| * @author Radek Krejci <rkrejci@cesnet.cz> |
| * @brief Functions to manipulate with the data node's hashes. |
| * |
| * Copyright (c) 2019 CESNET, z.s.p.o. |
| * |
| * This source code is licensed under BSD 3-Clause License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * https://opensource.org/licenses/BSD-3-Clause |
| */ |
| #include "common.h" |
| |
| #include "hash_table.h" |
| #include "tree_data.h" |
| #include "plugins_types.h" |
| |
| |
| static void |
| lyd_hash_keyless_list_dfs(struct lyd_node *child, uint32_t *hash) |
| { |
| struct lyd_node *iter; |
| |
| LY_LIST_FOR(child, iter) { |
| switch (iter->schema->nodetype) { |
| case LYS_CONTAINER: |
| case LYS_LIST: |
| lyd_hash_keyless_list_dfs(((struct lyd_node_inner*)iter)->child, hash); |
| break; |
| case LYS_LEAFLIST: |
| case LYS_ANYXML: |
| case LYS_ANYDATA: |
| case LYS_LEAF: |
| *hash = dict_hash_multi(*hash, (char *)&iter->hash, sizeof iter->hash); |
| break; |
| default: |
| LOGINT(NULL); |
| } |
| } |
| } |
| |
| LY_ERR |
| lyd_hash(struct lyd_node *node) |
| { |
| struct lyd_node *iter; |
| |
| node->hash = dict_hash_multi(0, node->schema->module->name, strlen(node->schema->module->name)); |
| node->hash = dict_hash_multi(node->hash, node->schema->name, strlen(node->schema->name)); |
| |
| if (node->schema->nodetype == LYS_LIST) { |
| struct lyd_node_inner *list = (struct lyd_node_inner*)node; |
| if (!(node->schema->flags & LYS_KEYLESS)) { |
| /* list's hash is made of its keys */ |
| struct lysc_node *key; |
| for (key = ((struct lysc_node_list*)node->schema)->child, iter = list->child; |
| key && key->nodetype == LYS_LEAF && (key->flags & LYS_KEY) && iter; |
| key = key->next, iter = iter->next) { |
| for ( ; iter && iter->schema != key; iter = iter->next); |
| if (!iter) { |
| break; |
| } |
| int dynamic = 0; |
| struct lysc_type *type = ((struct lysc_node_leaf*)iter->schema)->type; |
| const char *value = type->plugin->print(&((struct lyd_node_term*)iter)->value, LYD_JSON, json_print_get_prefix, NULL, &dynamic); |
| node->hash = dict_hash_multi(node->hash, value, strlen(value)); |
| if (dynamic) { |
| free((char*)value); |
| } |
| } |
| } else { |
| /* keyless status list */ |
| lyd_hash_keyless_list_dfs(list->child, &node->hash); |
| } |
| } else if (node->schema->nodetype == LYS_LEAFLIST) { |
| struct lyd_node_term *llist = (struct lyd_node_term*)node; |
| int dynamic = 0; |
| const char *value = ((struct lysc_node_leaflist*)node->schema)->type->plugin->print(&llist->value, LYD_JSON, |
| json_print_get_prefix, NULL, &dynamic); |
| node->hash = dict_hash_multi(node->hash, value, strlen(value)); |
| if (dynamic) { |
| free((char*)value); |
| } |
| } |
| /* finish the hash */ |
| node->hash = dict_hash_multi(node->hash, NULL, 0); |
| |
| return LY_SUCCESS; |
| } |
| |
| static int |
| lyd_hash_table_val_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data)) |
| { |
| struct lyd_node *val1, *val2; |
| |
| val1 = *((struct lyd_node **)val1_p); |
| val2 = *((struct lyd_node **)val2_p); |
| |
| if (mod) { |
| if (val1 == val2) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if (!lyd_compare(val1, val2, 0)) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| |
| LY_ERR |
| lyd_insert_hash(struct lyd_node *node) |
| { |
| struct lyd_node *iter; |
| |
| if (!node->parent) { |
| /* nothing to do */ |
| return LY_SUCCESS; |
| } |
| |
| /* create parent hash table if required, otherwise just add the new child */ |
| if (!node->parent->children_ht) { |
| unsigned int u; |
| |
| /* the hash table is created only when the number of children in a node exceeds the |
| * defined minimal limit LY_CACHE_HT_MIN_CHILDREN |
| */ |
| for (u = 0, iter = node->parent->child; iter; ++u, iter = iter->next); |
| if (u >= LYD_HT_MIN_ITEMS) { |
| /* create hash table, insert all the children */ |
| node->parent->children_ht = lyht_new(1, sizeof(struct lyd_node *), lyd_hash_table_val_equal, NULL, 1); |
| LY_LIST_FOR(node->parent->child, iter) { |
| if (lyht_insert(node->parent->children_ht, &iter, iter->hash, NULL)) { |
| LOGINT(node->schema->module->ctx); |
| return LY_EINT; |
| } |
| } |
| } |
| } else { |
| if (lyht_insert(node->parent->children_ht, &node, node->hash, NULL)) { |
| LOGINT(node->schema->module->ctx); |
| return LY_EINT; |
| } |
| } |
| |
| return LY_SUCCESS; |
| } |
| |
| void |
| lyd_unlink_hash(struct lyd_node *node) |
| { |
| if (node->parent && node->parent->children_ht) { |
| lyht_remove(node->parent->children_ht, &node, node->hash); |
| } |
| } |