blob: ff6430078b98373d971681d7d72723495ca71487 [file] [log] [blame]
/**
* @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;
if (!node->schema) {
return LY_SUCCESS;
}
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 || !node->schema || !node->parent->schema) {
/* 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);
}
}