Skip to content

Commit 55e87ce

Browse files
fredrik-perssonmichalvasko
authored andcommitted
validation OPTIMIZE drop diff nodes created and deleted in one run
When a when condition turns out false, the default nodes created speculatively before it was resolved are auto-deleted again. Recording that deletion went through lyd_diff_merge_all(), which duplicated the deleted subtree and reconciled it node by node, only for the entries to end up as "none" and be dropped as redundant. Recognise the case directly: if the diff already holds a create for the node, and nothing in that subtree was set explicitly, the create and the delete cancel out, so remove the subtree together with any ancestor left without a change.
1 parent fe7a6f9 commit 55e87ce

3 files changed

Lines changed: 83 additions & 0 deletions

File tree

‎src/diff.c‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,69 @@ lyd_diff_is_redundant(struct lyd_node *diff)
27322732
return 0;
27332733
}
27342734

2735+
/**
2736+
* @brief Check whether a diff subtree was created by validation only, so that deleting the
2737+
* corresponding data nodes cancels it out.
2738+
*
2739+
* @param[in] diff_node Diff subtree to check.
2740+
* @return Whether it can be dropped.
2741+
*/
2742+
static ly_bool
2743+
lyd_diff_val_subtree_created(const struct lyd_node *diff_node)
2744+
{
2745+
const struct lyd_node *elem;
2746+
struct lyd_meta *meta;
2747+
struct lyd_attr *attr;
2748+
2749+
LYD_TREE_DFS_BEGIN(diff_node, elem) {
2750+
if (!elem->schema) {
2751+
/* cannot reason about opaque nodes */
2752+
return 0;
2753+
}
2754+
2755+
lyd_diff_find_meta(elem, "operation", &meta, &attr);
2756+
if (attr) {
2757+
return 0;
2758+
}
2759+
if (meta && (lyd_diff_str2op(lyd_get_meta_value(meta)) != LYD_DIFF_OP_CREATE)) {
2760+
return 0;
2761+
}
2762+
2763+
/* a non-default term was set explicitly, deleting it is a real change */
2764+
if ((elem->schema->nodetype & LYD_NODE_TERM) && !(elem->flags & LYD_DEFAULT)) {
2765+
return 0;
2766+
}
2767+
2768+
LYD_TREE_DFS_END(diff_node, elem);
2769+
}
2770+
2771+
return 1;
2772+
}
2773+
2774+
LY_ERR
2775+
lyd_diff_val_del_created(struct lyd_node *diff_node, struct lyd_node **diff)
2776+
{
2777+
struct lyd_node *parent;
2778+
enum lyd_diff_op op;
2779+
2780+
LY_CHECK_RET(lyd_diff_get_op(diff_node, &op, NULL));
2781+
if ((op != LYD_DIFF_OP_CREATE) || !lyd_diff_val_subtree_created(diff_node)) {
2782+
return LY_ENOT;
2783+
}
2784+
2785+
/* drop it, then any ancestor left without a change */
2786+
do {
2787+
parent = lyd_parent(diff_node);
2788+
if (diff_node == *diff) {
2789+
*diff = (*diff)->next;
2790+
}
2791+
lyd_free_tree(diff_node);
2792+
diff_node = parent;
2793+
} while (diff_node && lyd_diff_is_redundant(diff_node));
2794+
2795+
return LY_SUCCESS;
2796+
}
2797+
27352798
/**
27362799
* @brief Merge all diff metadata found on a source diff node.
27372800
*

‎src/diff.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,14 @@ LIBYANG_API_DECL LY_ERR lyd_diff_add(const struct lyd_node *node, enum lyd_diff_
8787
LY_ERR lyd_diff_add_explicit_op(const struct lyd_node *node, enum lyd_diff_op op, const char *key,
8888
const char *value, const char *position, struct lyd_node **diff);
8989

90+
/**
91+
* @brief Drop a diff subtree that validation created, when its data nodes are being deleted again.
92+
*
93+
* @param[in] diff_node Diff node of the data node being deleted.
94+
* @param[in,out] diff Diff @p diff_node belongs to.
95+
* @return LY_SUCCESS if the subtree was dropped.
96+
* @return LY_ENOT if it has to be merged instead.
97+
*/
98+
LY_ERR lyd_diff_val_del_created(struct lyd_node *diff_node, struct lyd_node **diff);
99+
90100
#endif /* LY_DIFF_H_ */

‎src/validation.c‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,16 @@ lyd_val_diff_add(const struct lyd_node *node, enum lyd_diff_op op, struct lyd_no
248248
goto cleanup;
249249
}
250250

251+
/* a create followed by a delete cancels out; merging would reconcile the whole subtree to
252+
* "none" only to drop it as redundant */
253+
if (op == LYD_DIFF_OP_DELETE) {
254+
ret = lyd_diff_val_del_created(match, diff);
255+
if (ret != LY_ENOT) {
256+
goto cleanup;
257+
}
258+
ret = LY_SUCCESS;
259+
}
260+
251261
/* create new diff tree */
252262
LY_CHECK_GOTO(ret = lyd_diff_add(node, op, NULL, NULL, key, value, position, NULL, NULL, &new_diff, NULL), cleanup);
253263

0 commit comments

Comments
 (0)