/src/libyang/src/tree_data_free.c
Line | Count | Source |
1 | | /** |
2 | | * @file tree_data_free.c |
3 | | * @author Radek Krejci <rkrejci@cesnet.cz> |
4 | | * @brief Freeing functions for data tree structures |
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 | | |
15 | | #include <assert.h> |
16 | | #include <stdlib.h> |
17 | | |
18 | | #include "dict.h" |
19 | | #include "hash_table.h" |
20 | | #include "log.h" |
21 | | #include "ly_common.h" |
22 | | #include "plugins_exts/metadata.h" |
23 | | #include "plugins_internal.h" |
24 | | #include "plugins_types.h" |
25 | | #include "tree.h" |
26 | | #include "tree_data.h" |
27 | | #include "tree_data_internal.h" |
28 | | #include "tree_data_sorted.h" |
29 | | #include "tree_schema.h" |
30 | | |
31 | | static void |
32 | | lyd_free_meta(struct lyd_meta *meta, ly_bool siblings) |
33 | 1.93M | { |
34 | 1.93M | struct lyd_meta *iter; |
35 | | |
36 | 1.93M | if (!meta) { |
37 | 1.90M | return; |
38 | 1.90M | } |
39 | | |
40 | 31.1k | if (meta->parent) { |
41 | 31.1k | if (meta->parent->meta == meta) { |
42 | 31.1k | if (siblings) { |
43 | 31.1k | meta->parent->meta = NULL; |
44 | 31.1k | } else { |
45 | 0 | meta->parent->meta = meta->next; |
46 | 0 | } |
47 | 31.1k | } else { |
48 | 0 | for (iter = meta->parent->meta; iter->next != meta; iter = iter->next) {} |
49 | 0 | if (iter->next) { |
50 | 0 | if (siblings) { |
51 | 0 | iter->next = NULL; |
52 | 0 | } else { |
53 | 0 | iter->next = meta->next; |
54 | 0 | } |
55 | 0 | } |
56 | 0 | } |
57 | 31.1k | } |
58 | | |
59 | 31.1k | if (!siblings) { |
60 | 0 | meta->next = NULL; |
61 | 0 | } |
62 | | |
63 | 67.5k | for (iter = meta; iter; ) { |
64 | 36.3k | meta = iter; |
65 | 36.3k | iter = iter->next; |
66 | | |
67 | 36.3k | lydict_remove(meta->annotation->module->ctx, meta->name); |
68 | 36.3k | LYSC_GET_TYPE_PLG(meta->value.realtype->plugin_ref)->free(meta->annotation->module->ctx, &meta->value); |
69 | 36.3k | free(meta); |
70 | 36.3k | } |
71 | 31.1k | } |
72 | | |
73 | | LIBYANG_API_DEF void |
74 | | lyd_free_meta_single(struct lyd_meta *meta) |
75 | 0 | { |
76 | 0 | lyd_free_meta(meta, 0); |
77 | 0 | } |
78 | | |
79 | | LIBYANG_API_DEF void |
80 | | lyd_free_meta_siblings(struct lyd_meta *meta) |
81 | 1.93M | { |
82 | 1.93M | lyd_free_meta(meta, 1); |
83 | 1.93M | } |
84 | | |
85 | | static void |
86 | | lyd_free_attr(const struct ly_ctx *ctx, struct lyd_attr *attr, ly_bool siblings) |
87 | 939k | { |
88 | 939k | struct lyd_attr *iter; |
89 | | |
90 | 939k | LY_CHECK_ARG_RET(NULL, ctx, ); |
91 | 939k | if (!attr) { |
92 | 939k | return; |
93 | 939k | } |
94 | | |
95 | 113 | if (attr->parent) { |
96 | 113 | if (attr->parent->attr == attr) { |
97 | 113 | if (siblings) { |
98 | 113 | attr->parent->attr = NULL; |
99 | 113 | } else { |
100 | 0 | attr->parent->attr = attr->next; |
101 | 0 | } |
102 | 113 | } else { |
103 | 0 | for (iter = attr->parent->attr; iter->next != attr; iter = iter->next) {} |
104 | 0 | if (iter->next) { |
105 | 0 | if (siblings) { |
106 | 0 | iter->next = NULL; |
107 | 0 | } else { |
108 | 0 | iter->next = attr->next; |
109 | 0 | } |
110 | 0 | } |
111 | 0 | } |
112 | 113 | } |
113 | | |
114 | 113 | if (!siblings) { |
115 | 0 | attr->next = NULL; |
116 | 0 | } |
117 | | |
118 | 2.86k | for (iter = attr; iter; ) { |
119 | 2.74k | attr = iter; |
120 | 2.74k | iter = iter->next; |
121 | | |
122 | 2.74k | ly_free_prefix_data(attr->format, attr->val_prefix_data); |
123 | 2.74k | lydict_remove(ctx, attr->name.name); |
124 | 2.74k | lydict_remove(ctx, attr->name.prefix); |
125 | 2.74k | lydict_remove(ctx, attr->name.module_ns); |
126 | 2.74k | lydict_remove(ctx, attr->value); |
127 | 2.74k | free(attr); |
128 | 2.74k | } |
129 | 113 | } |
130 | | |
131 | | LIBYANG_API_DEF void |
132 | | lyd_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr) |
133 | 0 | { |
134 | 0 | lyd_free_attr(ctx, attr, 0); |
135 | 0 | } |
136 | | |
137 | | LIBYANG_API_DEF void |
138 | | lyd_free_attr_siblings(const struct ly_ctx *ctx, struct lyd_attr *attr) |
139 | 939k | { |
140 | 939k | lyd_free_attr(ctx, attr, 1); |
141 | 939k | } |
142 | | |
143 | | void |
144 | | lyd_free_leafref_links_rec(struct lyd_leafref_links_rec *rec) |
145 | 0 | { |
146 | 0 | LY_ARRAY_COUNT_TYPE u; |
147 | 0 | struct lyd_leafref_links_rec *rec2; |
148 | |
|
149 | 0 | assert(rec); |
150 | | |
151 | | /* remove links of leafref nodes */ |
152 | 0 | LY_ARRAY_FOR(rec->leafref_nodes, u) { |
153 | 0 | if (lyd_get_or_create_leafref_links_record(rec->leafref_nodes[u], &rec2, 0) == LY_SUCCESS) { |
154 | 0 | LY_ARRAY_REMOVE_VALUE(rec2->target_nodes, rec->node); |
155 | 0 | if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) { |
156 | 0 | lyd_free_leafref_nodes(rec->leafref_nodes[u]); |
157 | 0 | } |
158 | 0 | } |
159 | 0 | } |
160 | 0 | LY_ARRAY_FREE(rec->leafref_nodes); |
161 | 0 | rec->leafref_nodes = NULL; |
162 | | |
163 | | /* remove links of target nodes */ |
164 | 0 | LY_ARRAY_FOR(rec->target_nodes, u) { |
165 | 0 | if (lyd_get_or_create_leafref_links_record(rec->target_nodes[u], &rec2, 0) == LY_SUCCESS) { |
166 | 0 | LY_ARRAY_REMOVE_VALUE(rec2->leafref_nodes, rec->node); |
167 | 0 | if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) { |
168 | 0 | lyd_free_leafref_nodes(rec->target_nodes[u]); |
169 | 0 | } |
170 | 0 | } |
171 | 0 | } |
172 | 0 | LY_ARRAY_FREE(rec->target_nodes); |
173 | 0 | rec->target_nodes = NULL; |
174 | 0 | } |
175 | | |
176 | | void |
177 | | lyd_free_leafref_nodes(const struct lyd_node_term *node) |
178 | 1.10M | { |
179 | 1.10M | struct ly_ctx_shared_data *ctx_data; |
180 | 1.10M | uint32_t hash; |
181 | 1.10M | struct lyd_leafref_links_rec *rec; |
182 | | |
183 | 1.10M | assert(node); |
184 | | |
185 | 1.10M | if (lyd_get_or_create_leafref_links_record(node, &rec, 0)) { |
186 | 1.10M | return; |
187 | 1.10M | } |
188 | | |
189 | | /* free entry content */ |
190 | 0 | lyd_free_leafref_links_rec(rec); |
191 | | |
192 | | /* free entry itself from hash table */ |
193 | 0 | ctx_data = ly_ctx_shared_data_get(LYD_CTX(node)); |
194 | 0 | hash = lyht_hash((const char *)&node, sizeof node); |
195 | | |
196 | | /* LL LOCK */ |
197 | 0 | pthread_mutex_lock(&ctx_data->leafref_links_lock); |
198 | |
|
199 | 0 | lyht_remove(ctx_data->leafref_links_ht, &rec, hash); |
200 | | |
201 | | /* LL UNLOCK */ |
202 | 0 | pthread_mutex_unlock(&ctx_data->leafref_links_lock); |
203 | |
|
204 | 0 | free(rec); |
205 | 0 | } |
206 | | |
207 | | /** |
208 | | * @brief Free Data (sub)tree. |
209 | | * |
210 | | * @param[in] node Data node to be freed. |
211 | | */ |
212 | | static void |
213 | | lyd_free_subtree(struct lyd_node *node) |
214 | 1.30M | { |
215 | 1.30M | struct lyd_node *iter, *next; |
216 | 1.30M | struct lyd_node_opaq *opaq = NULL; |
217 | | |
218 | 1.30M | assert(node); |
219 | | |
220 | 1.30M | if (!node->schema) { |
221 | 155k | opaq = (struct lyd_node_opaq *)node; |
222 | | |
223 | | /* free the children */ |
224 | 155k | LY_LIST_FOR_SAFE(lyd_child(node), next, iter) { |
225 | 82.7k | lyd_free_subtree(iter); |
226 | 82.7k | } |
227 | | |
228 | 155k | lydict_remove(LYD_CTX(opaq), opaq->name.name); |
229 | 155k | lydict_remove(LYD_CTX(opaq), opaq->name.prefix); |
230 | 155k | lydict_remove(LYD_CTX(opaq), opaq->name.module_ns); |
231 | 155k | lydict_remove(LYD_CTX(opaq), opaq->value); |
232 | 155k | ly_free_prefix_data(opaq->format, opaq->val_prefix_data); |
233 | 1.15M | } else if (node->schema->nodetype & LYD_NODE_INNER) { |
234 | | /* remove children hash table in case of inner data node */ |
235 | 44.5k | lyht_free(((struct lyd_node_inner *)node)->children_ht, NULL); |
236 | | |
237 | | /* free the children */ |
238 | 1.01M | LY_LIST_FOR_SAFE(lyd_child(node), next, iter) { |
239 | 1.01M | lyd_free_subtree(iter); |
240 | 1.01M | } |
241 | 1.10M | } else if (node->schema->nodetype & LYD_NODE_ANY) { |
242 | | /* only frees the value this way */ |
243 | 0 | lyd_any_copy_value(node, NULL, 0); |
244 | 1.10M | } else if (node->schema->nodetype & LYD_NODE_TERM) { |
245 | 1.10M | struct lyd_node_term *node_term = (struct lyd_node_term *)node; |
246 | | |
247 | 1.10M | LYSC_GET_TYPE_PLG(((struct lysc_node_leaf *)node->schema)->type->plugin_ref)->free(LYD_CTX(node), &node_term->value); |
248 | 1.10M | lyd_free_leafref_nodes(node_term); |
249 | 1.10M | } |
250 | | |
251 | 1.30M | if (!node->schema) { |
252 | 155k | lyd_free_attr_siblings(LYD_CTX(node), opaq->attr); |
253 | 1.15M | } else { |
254 | | /* free the node's metadata */ |
255 | 1.15M | lyd_free_meta_siblings(node->meta); |
256 | 1.15M | } |
257 | | |
258 | 1.30M | free(node); |
259 | 1.30M | } |
260 | | |
261 | | LIBYANG_API_DEF void |
262 | | lyd_free_tree(struct lyd_node *node) |
263 | 81.5k | { |
264 | 81.5k | if (!node) { |
265 | 17.8k | return; |
266 | 17.8k | } |
267 | | |
268 | 63.6k | if (lysc_is_key(node->schema) && node->parent) { |
269 | 0 | LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot free a list key \"%s\", free the list instance instead.", LYD_NAME(node)); |
270 | 0 | return; |
271 | 0 | } |
272 | | |
273 | 63.6k | lyd_unlink(node); |
274 | 63.6k | lyd_free_subtree(node); |
275 | 63.6k | } |
276 | | |
277 | | static void |
278 | | lyd_free_(struct lyd_node *node) |
279 | 3.16k | { |
280 | 3.16k | struct lyd_node *iter, *next, *first_sibling = NULL; |
281 | | |
282 | 3.16k | if (!node) { |
283 | 0 | return; |
284 | 0 | } |
285 | | |
286 | 145k | LY_LIST_FOR_SAFE(lyd_first_sibling(node), next, iter) { |
287 | 145k | if (lysc_is_key(iter->schema) && iter->parent) { |
288 | 0 | LOGERR(LYD_CTX(iter), LY_EINVAL, "Cannot free a list key \"%s\", free the list instance instead.", LYD_NAME(iter)); |
289 | 0 | return; |
290 | 0 | } |
291 | | |
292 | | /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */ |
293 | 145k | if (iter->parent) { |
294 | 0 | lyds_free_metadata(iter); |
295 | 0 | lyd_unlink_ignore_lyds(&first_sibling, iter); |
296 | 0 | } |
297 | 145k | lyd_free_subtree(iter); |
298 | 145k | } |
299 | 3.16k | } |
300 | | |
301 | | LIBYANG_API_DEF void |
302 | | lyd_free_siblings(struct lyd_node *node) |
303 | 0 | { |
304 | 0 | lyd_free_(node); |
305 | 0 | } |
306 | | |
307 | | LIBYANG_API_DEF void |
308 | | lyd_free_all(struct lyd_node *node) |
309 | 27.2k | { |
310 | 27.2k | if (!node) { |
311 | 24.0k | return; |
312 | 24.0k | } |
313 | | |
314 | | /* get top-level node */ |
315 | 3.16k | for ( ; node->parent; node = lyd_parent(node)) {} |
316 | | |
317 | 3.16k | lyd_free_(node); |
318 | 3.16k | } |