Skip to content

Commit b7f865d

Browse files
committed
context UPDATE support sharing context data
Useful for schema-mount contexts.
1 parent 358282d commit b7f865d

File tree

10 files changed

+81
-71
lines changed

10 files changed

+81
-71
lines changed

src/context.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,8 +1486,10 @@ ly_ctx_destroy(struct ly_ctx *ctx)
14861486
}
14871487

14881488
if (ctx->opts & LY_CTX_INT_IMMUTABLE) {
1489-
/* ctx data */
1490-
ly_ctx_data_del(ctx);
1489+
if (!ctx->parent_ctx) {
1490+
/* ctx data */
1491+
ly_ctx_data_del(ctx);
1492+
}
14911493
lyplg_clean();
14921494
return;
14931495
}
@@ -1519,8 +1521,10 @@ ly_ctx_destroy(struct ly_ctx *ctx)
15191521
/* leftover unres */
15201522
lys_unres_glob_erase(&ctx->unres);
15211523

1522-
/* ctx data */
1523-
ly_ctx_data_del(ctx);
1524+
if (!ctx->parent_ctx) {
1525+
/* ctx data */
1526+
ly_ctx_data_del(ctx);
1527+
}
15241528

15251529
/* dictionary */
15261530
lydict_clean(&ctx->dict);

src/log.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -200,26 +200,6 @@ ly_err_last(const struct ly_ctx *ctx)
200200
return ctx_data->errs ? ctx_data->errs->prev : NULL;
201201
}
202202

203-
void
204-
ly_err_move(struct ly_ctx *src_ctx, struct ly_ctx *trg_ctx)
205-
{
206-
struct ly_ctx_private_data *src_data, *trg_data;
207-
struct ly_err_item *errs = NULL;
208-
209-
/* get src context errs */
210-
src_data = ly_ctx_private_data_get_or_create(src_ctx);
211-
errs = src_data->errs;
212-
src_data->errs = NULL;
213-
214-
/* get and free the trg context errs */
215-
trg_data = ly_ctx_private_data_get_or_create(trg_ctx);
216-
ly_err_free(trg_data->errs);
217-
218-
/* set them for trg */
219-
ly_err_free(trg_data->errs);
220-
trg_data->errs = errs;
221-
}
222-
223203
LIBYANG_API_DEF void
224204
ly_err_free(void *ptr)
225205
{

src/ly_common.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ ly_ctx_private_data_get_or_create(const struct ly_ctx *ctx)
255255
struct ly_ctx_private_data *private_data;
256256
LY_ERR r;
257257

258+
while (ctx->parent_ctx) {
259+
/* find the right context */
260+
ctx = ctx->parent_ctx;
261+
}
262+
258263
/* RD LOCK */
259264
pthread_rwlock_rdlock(&ly_ctx_data_rwlock);
260265

@@ -414,6 +419,11 @@ ly_ctx_shared_data_get(const struct ly_ctx *ctx)
414419
{
415420
struct ly_ctx_shared_data *shared_data;
416421

422+
while (ctx->parent_ctx) {
423+
/* find the right context */
424+
ctx = ctx->parent_ctx;
425+
}
426+
417427
/* RD LOCK */
418428
pthread_rwlock_rdlock(&ly_ctx_data_rwlock);
419429

src/ly_common.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,6 @@ LY_ERR ly_vlog_build_data_path(const struct ly_ctx *ctx, char **path);
113113
*/
114114
void ly_vlog(const struct ly_ctx *ctx, const char *apptag, LY_VECODE code, const char *format, ...) _FORMAT_PRINTF(4, 5);
115115

116-
/**
117-
* @brief Move error items from source to target context replacing any previous ones.
118-
*
119-
* @param[in] src_ctx Source context to read errors from.
120-
* @param[in] trg_ctx Target context to set the errors for.
121-
*/
122-
void ly_err_move(struct ly_ctx *src_ctx, struct ly_ctx *trg_ctx);
123-
124116
/**
125117
* @brief Logger location data setter.
126118
*
@@ -401,6 +393,7 @@ struct ly_ctx {
401393

402394
struct ly_set plugins_types; /**< context specific set of type plugins */
403395
struct ly_set plugins_extensions; /**< contets specific set of extension plugins */
396+
struct ly_ctx *parent_ctx; /**< pointer to the parent context whose shared and private data to use, if set */
404397
};
405398

406399
/**

src/parser_common.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -299,18 +299,11 @@ LY_ERR
299299
lyd_parser_create_term(struct lyd_ctx *lydctx, const struct lysc_node *schema, const void *value, uint32_t value_bits_len,
300300
ly_bool *dynamic, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, struct lyd_node **node)
301301
{
302-
LY_ERR r;
303302
ly_bool incomplete;
304303
ly_bool store_only = (lydctx->parse_opts & LYD_PARSE_STORE_ONLY) == LYD_PARSE_STORE_ONLY ? 1 : 0;
305304

306-
if ((r = lyd_create_term(schema, value, value_bits_len, 1, store_only, dynamic, format, prefix_data, hints,
307-
lydctx->ext, &incomplete, node))) {
308-
if (lydctx->data_ctx->ctx != schema->module->ctx) {
309-
/* move errors to the main context */
310-
ly_err_move(schema->module->ctx, (struct ly_ctx *)lydctx->data_ctx->ctx);
311-
}
312-
return r;
313-
}
305+
LY_CHECK_RET(lyd_create_term(schema, value, value_bits_len, 1, store_only, dynamic, format, prefix_data, hints,
306+
lydctx->ext, &incomplete, node));
314307

315308
if (incomplete && !(lydctx->parse_opts & LYD_PARSE_ONLY)) {
316309
LY_CHECK_RET(ly_set_add(&lydctx->node_types, *node, 1, NULL));

src/plugins_exts.c

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Michal Vasko <[email protected]>
55
* @brief helper functions for extension plugins
66
*
7-
* Copyright (c) 2019 - 2024 CESNET, z.s.p.o.
7+
* Copyright (c) 2019 - 2025 CESNET, z.s.p.o.
88
*
99
* This source code is licensed under BSD 3-Clause License (the "License").
1010
* You may not use this file except in compliance with the License.
@@ -737,3 +737,37 @@ lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext
737737
pthread_mutex_unlock(&ctx_data->ext_clb_lock);
738738
return rc;
739739
}
740+
741+
LIBYANG_API_DEF LY_ERR
742+
lyplg_ext_set_parent_ctx(struct ly_ctx *ctx, const struct ly_ctx *parent_ctx)
743+
{
744+
const struct ly_ctx *c;
745+
746+
LY_CHECK_ARG_RET(ctx, ctx, LY_EINVAL);
747+
748+
if (ctx->parent_ctx == parent_ctx) {
749+
return LY_SUCCESS;
750+
}
751+
752+
/* prevent circular reference chain */
753+
c = parent_ctx;
754+
do {
755+
if (c->parent_ctx == ctx) {
756+
LOGERR(ctx, LY_EDENIED, "Circular references of parent contexts.");
757+
return LY_EDENIED;
758+
}
759+
760+
c = c->parent_ctx;
761+
} while (c);
762+
763+
if (!ctx->parent_ctx) {
764+
/* remove its shared and private data */
765+
ly_ctx_data_del(ctx);
766+
} else if (!parent_ctx) {
767+
/* create its shared and private data */
768+
LY_CHECK_RET(ly_ctx_data_add(ctx));
769+
}
770+
771+
ctx->parent_ctx = (struct ly_ctx *)parent_ctx;
772+
return LY_SUCCESS;
773+
}

src/plugins_exts.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,16 @@ LIBYANG_API_DECL LY_ERR lyplg_ext_parsed_get_storage(const struct lysc_ext_insta
11121112
LIBYANG_API_DECL LY_ERR lyplg_ext_get_data(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext,
11131113
const struct lyd_node *parent, void **ext_data, ly_bool *ext_data_free);
11141114

1115+
/**
1116+
* @brief Set parent context of a context. Errors and callbacks of the parent context will then always be used.
1117+
*
1118+
* @param[in] ctx Context to change.
1119+
* @param[in] parent_ctx Parent context to set.
1120+
* @return LY_SUCCESS on success.
1121+
* @return LY_ERR on error.
1122+
*/
1123+
LIBYANG_API_DECL LY_ERR lyplg_ext_set_parent_ctx(struct ly_ctx *ctx, const struct ly_ctx *parent_ctx);
1124+
11151125
/**
11161126
* @brief Insert extension instance data into a parent.
11171127
*

src/plugins_exts/schema_mount.c

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ schema_mount_create_ctx(const struct lysc_ext_instance *ext, const struct lyd_no
347347
}
348348
}
349349

350+
/* set the parent context */
351+
lyplg_ext_set_parent_ctx(*ext_ctx, ext->module->ctx);
352+
350353
cleanup:
351354
free(sdirs);
352355
return rc;
@@ -1060,8 +1063,7 @@ schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, c
10601063
enum lyd_type data_type, uint32_t val_opts, struct lyd_node **diff)
10611064
{
10621065
LY_ERR ret = LY_SUCCESS;
1063-
uint32_t *prev_lo, temp_lo = LY_LOSTORE_LAST, i;
1064-
const struct ly_err_item *err;
1066+
uint32_t i;
10651067
struct lyd_node *iter, *ext_data = NULL, *ref_first = NULL, *orig_parent = lyd_parent(sibling), *op_tree;
10661068
struct lyd_node *ext_diff = NULL, *diff_parent = NULL;
10671069
ly_bool ext_data_free = 0;
@@ -1107,9 +1109,6 @@ schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, c
11071109
}
11081110
}
11091111

1110-
/* only store messages in the context, log as an extension */
1111-
prev_lo = ly_temp_log_options(&temp_lo);
1112-
11131112
if (data_type == LYD_TYPE_DATA_YANG) {
11141113
/* validate all the modules with data */
11151114
ret = lyd_validate_all(&sibling, NULL, val_opts | LYD_VALIDATE_PRESENT, diff ? &ext_diff : NULL);
@@ -1118,9 +1117,6 @@ schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, c
11181117
ret = lyd_validate_op(op_tree, dep_tree, data_type, diff ? &ext_diff : NULL);
11191118
}
11201119

1121-
/* restore logging */
1122-
ly_temp_log_options(prev_lo);
1123-
11241120
/* restore sibling tree */
11251121
for (i = 0; i < ref_set->count; ++i) {
11261122
if (ref_set->dnodes[i] == sibling) {
@@ -1134,17 +1130,6 @@ schema_mount_validate(struct lysc_ext_instance *ext, struct lyd_node *sibling, c
11341130
lyplg_ext_insert(orig_parent, sibling);
11351131

11361132
if (ret) {
1137-
/* log the error in the original context */
1138-
err = ly_err_first(LYD_CTX(sibling));
1139-
if (!err) {
1140-
lyplg_ext_compile_log(NULL, ext, LY_LLERR, ret, "Unknown validation error (err code %d).", ret);
1141-
} else {
1142-
while (err) {
1143-
lyplg_ext_compile_log_err(err, ext);
1144-
err = err->next;
1145-
}
1146-
ly_err_clean((struct ly_ctx *)LYD_CTX(sibling), NULL);
1147-
}
11481133
goto cleanup;
11491134
}
11501135

@@ -1587,6 +1572,7 @@ schema_mount_compiled_print(const struct lysc_ext_instance *orig_ext, struct lys
15871572
ctx_mem = *mem;
15881573
LY_CHECK_RET(ly_ctx_compiled_print(orig_sm_data->shared->schemas[i].ctx, ctx_mem, mem));
15891574
LY_CHECK_RET(ly_ctx_new_printed(ctx_mem, &sm_data->shared->schemas[i].ctx));
1575+
LY_CHECK_RET(lyplg_ext_set_parent_ctx(ctx_mem, ext->module->ctx));
15901576
sm_data->shared->schemas[i].ctx = ctx_mem;
15911577

15921578
/* mount_point */

src/printer_context.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,9 @@ ly_ctx_compiled_print_context(const struct ly_ctx *orig_ctx, struct ly_ctx *ctx,
17901790
/* no dynamic plugin support */
17911791
memset(&ctx->plugins_types, 0, sizeof ctx->plugins_types);
17921792
memset(&ctx->plugins_extensions, 0, sizeof ctx->plugins_extensions);
1793+
1794+
/* parent context, needs to be set manually */
1795+
ctx->parent_ctx = NULL;
17931796
}
17941797

17951798
LY_ERR

tests/utests/extensions/test_schema_mount.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -410,22 +410,22 @@ test_parse_invalid(void **state)
410410
" </mount-point>"
411411
"</schema-mounts>");
412412
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
413-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": Mandatory node \"type\" instance does not exist.",
413+
CHECK_LOG_CTX("Mandatory node \"type\" instance does not exist.",
414414
"/ietf-interfaces:interfaces/interface[name='bu']", 0);
415415
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
416-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": Mandatory node \"type\" instance does not exist.",
416+
CHECK_LOG_CTX("Mandatory node \"type\" instance does not exist.",
417417
"/ietf-interfaces:interfaces/interface[name='bu']", 0);
418418

419419
/* same validation fail in separate validation */
420420
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
421421
assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL));
422-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": Mandatory node \"type\" instance does not exist.",
422+
CHECK_LOG_CTX("Mandatory node \"type\" instance does not exist.",
423423
"/ietf-interfaces:interfaces/interface[name='bu']", 0);
424424
lyd_free_siblings(data);
425425

426426
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT | LYD_PARSE_ONLY, 0, LY_SUCCESS, data);
427427
assert_int_equal(LY_EVALID, lyd_validate_all(&data, NULL, LYD_VALIDATE_PRESENT, NULL));
428-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": Mandatory node \"type\" instance does not exist.",
428+
CHECK_LOG_CTX("Mandatory node \"type\" instance does not exist.",
429429
"/ietf-interfaces:interfaces/interface[name='bu']", 0);
430430
lyd_free_siblings(data);
431431

@@ -1130,8 +1130,7 @@ test_parse_shared_parent_ref(void **state)
11301130
"</root3>\n"
11311131
"<target xmlns=\"urn:sm\">wrong-target-value</target>\n";
11321132
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
1133-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": "
1134-
"Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
1133+
CHECK_LOG_CTX("Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
11351134
"/ietf-interfaces:interfaces/interface[name='bu']/sm:sm-name", 0);
11361135

11371136
json =
@@ -1155,8 +1154,7 @@ test_parse_shared_parent_ref(void **state)
11551154
" \"sm:target\": \"wrong-target-value\"\n"
11561155
"}\n";
11571156
CHECK_PARSE_LYD_PARAM(json, LYD_JSON, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
1158-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": "
1159-
"Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
1157+
CHECK_LOG_CTX("Invalid leafref value \"target-value\" - no target instance \"/sm:target\" with the same value.",
11601158
"/ietf-interfaces:interfaces/interface[name='bu']/sm:sm-name", 0);
11611159

11621160
/* success */
@@ -1859,8 +1857,7 @@ test_xpath(void **state)
18591857
" </root>\n"
18601858
"</root>\n";
18611859
CHECK_PARSE_LYD_PARAM(xml, LYD_XML, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, LY_EVALID, data);
1862-
CHECK_LOG_CTX("Ext plugin \"ly2 schema mount\": "
1863-
"Must condition \"/m:root/l1 = 'valid'\" not satisfied.",
1860+
CHECK_LOG_CTX("Must condition \"/m:root/l1 = 'valid'\" not satisfied.",
18641861
"/mount:root/l1", 0);
18651862

18661863
/* non-existing instance-identifier */

0 commit comments

Comments
 (0)