schema tree REFACTOR overloaded implemented flag (#1223)
It no longer needs to be overloaded by
marking modules that are currently being
implemented. Instead, there is a set with
al such modules.
diff --git a/src/common.h b/src/common.h
index 559a4f9..2002c96 100644
--- a/src/common.h
+++ b/src/common.h
@@ -219,7 +219,9 @@
struct ly_ctx {
struct dict_table dict; /**< dictionary to effectively store strings used in the context related structures */
struct ly_set search_paths; /**< set of directories where to search for schema's imports/includes */
- struct ly_set list; /**< set of YANG schemas */
+ struct ly_set list; /**< set of loaded YANG schemas */
+ struct ly_set implementing; /**< set of YANG schemas being atomically implemented (compiled); the first added
+ module is always the explcitly implemented module, the other ones are dependencies */
ly_module_imp_clb imp_clb; /**< Optional callback for retrieving missing included or imported models in a custom way. */
void *imp_clb_data; /**< Optional private data for imp_clb() */
uint16_t module_set_id; /**< ID of the current set of schemas */
diff --git a/src/path.c b/src/path.c
index fe6adeb..4b0ec07 100644
--- a/src/path.c
+++ b/src/path.c
@@ -398,7 +398,7 @@
LOGVAL_P(ctx, cur_node, LYVE_XPATH, "Not implemented module \"%s\" in path.", (*mod)->name);
return LY_EVALID;
}
- LY_CHECK_RET(lys_set_implemented_internal((struct lys_module *)*mod, ctx->module_set_id));
+ LY_CHECK_RET(lys_set_implemented((struct lys_module *)*mod));
}
} else {
switch (format) {
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 49e2dd6..5f11d5b 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -811,44 +811,75 @@
return LY_SUCCESS;
}
-LY_ERR
-lys_set_implemented_internal(struct lys_module *mod, uint8_t value)
+API LY_ERR
+lys_set_implemented(struct lys_module *mod)
{
+ LY_ERR ret = LY_SUCCESS, r;
struct lys_module *m;
+ uint32_t i, idx;
LY_CHECK_ARG_RET(NULL, mod, LY_EINVAL);
if (mod->implemented) {
+ /* mod is already implemented */
return LY_SUCCESS;
}
/* we have module from the current context */
m = ly_ctx_get_module_implemented(mod->ctx, mod->name);
if (m) {
- if (m != mod) {
- /* check collision with other implemented revision */
- LOGERR(mod->ctx, LY_EDENIED, "Module \"%s\" is present in the context in other implemented revision (%s).",
- mod->name, mod->revision ? mod->revision : "module without revision");
- return LY_EDENIED;
- } else {
- /* mod is already implemented */
- return LY_SUCCESS;
- }
+ assert(m != mod);
+
+ /* check collision with other implemented revision */
+ LOGERR(mod->ctx, LY_EDENIED, "Module \"%s%s%s\" is present in the context in other implemented revision (%s).",
+ mod->name, mod->revision ? "@" : "", mod->revision ? mod->revision : "", m->revision ? m->revision : "none");
+ return LY_EDENIED;
}
+ /* add the module into newly implemented module set */
+ LY_CHECK_RET(ly_set_add(&mod->ctx->implementing, mod, LY_SET_OPT_USEASLIST, NULL));
+
/* mark the module implemented, check for collision was already done */
- mod->implemented = value;
+ mod->implemented = 1;
/* compile the schema */
- LY_CHECK_RET(lys_compile(mod, LYSC_OPT_INTERNAL));
+ ret = lys_compile(mod, 0);
- return LY_SUCCESS;
-}
+ if (mod == mod->ctx->implementing.objs[0]) {
+ /* the first module being implemented, consolidate the set */
+ if (ret) {
+ /* failure, full compile revert */
+ for (i = 0; i < mod->ctx->list.count; ++i) {
+ m = mod->ctx->list.objs[i];
+ if (ly_set_contains(&mod->ctx->implementing, m, &idx)) {
+ assert(m->implemented);
-API LY_ERR
-lys_set_implemented(struct lys_module *mod)
-{
- return lys_set_implemented_internal(mod, 1);
+ /* make the module correctly non-implemented again */
+ m->implemented = 0;
+ ly_set_rm_index(&mod->ctx->implementing, idx, NULL);
+ lys_precompile_augments_deviations_revert(mod->ctx, m);
+ }
+
+ /* free the compiled version of the module, if any */
+ lysc_module_free(m->compiled, NULL);
+ m->compiled = NULL;
+
+ if (m->implemented) {
+ /* recompile, must succeed because it was already compiled; hide messages because any
+ * warnings were already printed, are not really relevant, and would hide the real error */
+ uint32_t prev_lo = ly_log_options(0);
+ r = lys_compile(m, 0);
+ ly_log_options(prev_lo);
+ if (r) {
+ LOGERR(mod->ctx, r, "Recompilation of module \"%s\" failed.", m->name);
+ }
+ }
+ }
+ }
+
+ ly_set_erase(&mod->ctx->implementing, NULL);
+ }
+ return ret;
}
static LY_ERR
@@ -1048,9 +1079,6 @@
ret = LY_EDENIED;
goto error;
}
-
- /* being implemented */
- mod->implemented = ctx->module_set_id;
}
/* check for duplicity in the context */
@@ -1118,7 +1146,7 @@
lys_parser_fill_filepath(ctx, in, &mod->filepath);
- if (!mod->implemented) {
+ if (!implement) {
/* pre-compile features and identities of the module */
LY_CHECK_GOTO(ret = lys_feature_precompile(NULL, ctx, mod, mod->parsed->features, &mod->features), error);
LY_CHECK_GOTO(ret = lys_identity_precompile(NULL, ctx, mod, mod->parsed->identities, &mod->identities), error);
@@ -1137,7 +1165,7 @@
/* resolve imports and includes */
LY_CHECK_GOTO(ret = lys_resolve_import_include(pctx, mod->parsed), error_ctx);
- if (!mod->implemented) {
+ if (!implement) {
/* pre-compile features and identities of any submodules */
LY_ARRAY_FOR(mod->parsed->includes, u) {
LY_CHECK_GOTO(ret = lys_feature_precompile(NULL, ctx, mod, mod->parsed->includes[u].submodule->features,
@@ -1150,10 +1178,9 @@
/* check name collisions - typedefs and TODO groupings */
LY_CHECK_GOTO(ret = lysp_check_typedefs(pctx, mod->parsed), error_ctx);
- /* compile */
- if (!mod->compiled) {
- ret = lys_compile(mod, 0);
- LY_CHECK_GOTO(ret, error_ctx);
+ if (implement) {
+ /* implement (compile) */
+ LY_CHECK_GOTO(ret = lys_set_implemented(mod), error_ctx);
}
if (format == LYS_IN_YANG) {
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 85bfc33..f27df91 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1124,10 +1124,9 @@
#define LYSC_OPT_RPC_OUTPUT LYS_CONFIG_R /**< Internal option when compiling schema tree of RPC/action output */
#define LYSC_OPT_RPC_MASK LYS_CONFIG_MASK /**< mask for the internal RPC options */
#define LYSC_OPT_FREE_SP 0x04 /**< Free the input printable schema */
-#define LYSC_OPT_INTERNAL 0x08 /**< Internal compilation caused by dependency */
-#define LYSC_OPT_NOTIFICATION 0x10 /**< Internal option when compiling schema tree of Notification */
+#define LYSC_OPT_NOTIFICATION 0x08 /**< Internal option when compiling schema tree of Notification */
-#define LYSC_OPT_GROUPING 0x20 /** Compiling (validation) of a non-instantiated grouping.
+#define LYSC_OPT_GROUPING 0x10 /** Compiling (validation) of a non-instantiated grouping.
In this case not all the restrictions are checked since they can be valid only
in the real placement of the grouping. TODO - what specifically is not done */
/** @} scflags */
@@ -1857,10 +1856,7 @@
struct lys_module **augmented_by;/**< List of modules that augment this module ([sized array](@ref sizedarrays)) */
struct lys_module **deviated_by; /**< List of modules that deviate this module ([sized array](@ref sizedarrays)) */
- uint8_t implemented; /**< flag if the module is implemented, not just imported. The module is implemented if
- the flag has non-zero value. Specific values are used internally:
- 1 - implemented module
- >1 - recently implemented module by dependency, it can be reverted in rollback procedure */
+ ly_bool implemented; /**< flag if the module is implemented, not just imported */
uint8_t latest_revision; /**< flag to mark the latest available revision:
1 - the latest revision in searchdirs was not searched yet and this is the
latest revision in the current context
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index b7d449e..7e23961 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -4667,7 +4667,7 @@
/* all the modules must be implemented */
if (!mod->implemented) {
- ret = lys_set_implemented_internal(mod, ctx->ctx->module_set_id);
+ ret = lys_set_implemented(mod);
LY_CHECK_GOTO(ret, cleanup);
}
}
@@ -7143,7 +7143,8 @@
/**
* @brief Compile top-level augments and deviations defined in the current module.
- * Generally, just add the module refence to the target modules.
+ * Generally, just add the module refence to the target modules. But in case
+ * of foreign augments, they are directly applied.
*
* @param[in] ctx Compile context.
* @return LY_ERR value.
@@ -7161,13 +7162,18 @@
uint16_t flags;
uint32_t idx, opt_prev = ctx->options;
- mod_p = ctx->mod->parsed;
-
- if (mod_p->mod->implemented == 1) {
+ for (idx = 0; idx < ctx->ctx->implementing.count; ++idx) {
+ if (ctx->mod == ctx->ctx->implementing.objs[idx]) {
+ break;
+ }
+ }
+ if (idx == ctx->ctx->implementing.count) {
/* it was already implemented and all the augments and deviations fully applied */
return LY_SUCCESS;
}
+ mod_p = ctx->mod->parsed;
+
LY_ARRAY_FOR(mod_p->augments, u) {
lysc_update_path(ctx, NULL, "{augment}");
lysc_update_path(ctx, NULL, mod_p->augments[u].nodeid);
@@ -7288,7 +7294,7 @@
if (mod->implemented) {
/* compile */
- LY_CHECK_GOTO(ret = lys_compile(mod, LYSC_OPT_INTERNAL), cleanup);
+ LY_CHECK_GOTO(ret = lys_compile(mod, 0), cleanup);
}
}
@@ -8030,22 +8036,15 @@
return LY_SUCCESS;
}
-/**
- * @brief Revert precompilation of module augments and deviations. Meaning remove its reference from
- * all the target modules.
- *
- * @param[in] ctx Compile context.
- * @param[in] mod Mod whose precompilation to revert.
- */
-static void
-lys_precompile_augments_deviations_revert(struct lysc_ctx *ctx, const struct lys_module *mod)
+void
+lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod)
{
uint32_t i;
LY_ARRAY_COUNT_TYPE u, count;
struct lys_module *m;
- for (i = 0; i < ctx->ctx->list.count; ++i) {
- m = ctx->ctx->list.objs[i];
+ for (i = 0; i < ctx->list.count; ++i) {
+ m = ctx->list.objs[i];
if (m->augmented_by) {
count = LY_ARRAY_COUNT(m->augmented_by);
@@ -8176,7 +8175,6 @@
struct lysp_submodule *submod;
struct lysp_node *pnode;
struct lysp_grp *grps;
- struct lys_module *m;
LY_ARRAY_COUNT_TYPE u, v;
uint32_t i;
LY_ERR ret = LY_SUCCESS;
@@ -8323,20 +8321,10 @@
mod->parsed = NULL;
}
- if (!(ctx.options & LYSC_OPT_INTERNAL)) {
- /* remove flag of the modules implemented by dependency */
- for (i = 0; i < ctx.ctx->list.count; ++i) {
- m = ctx.ctx->list.objs[i];
- if (m->implemented > 1) {
- m->implemented = 1;
- }
- }
- }
-
return LY_SUCCESS;
error:
- lys_precompile_augments_deviations_revert(&ctx, mod);
+ lys_precompile_augments_deviations_revert(ctx.ctx, mod);
lys_feature_precompile_revert(&ctx, mod);
for (i = 0; i < ctx.dflts.count; ++i) {
lysc_unres_dflt_free(ctx.ctx, ctx.dflts.objs[i]);
@@ -8365,31 +8353,5 @@
lysc_module_free(mod_c, NULL);
mod->compiled = NULL;
- /* revert compilation of modules implemented by dependency */
- if (!(ctx.options & LYSC_OPT_INTERNAL)) {
- for (i = 0; i < ctx.ctx->list.count; ++i) {
- m = ctx.ctx->list.objs[i];
- if (m->implemented > 1) {
- /* make the module non-implemented */
- m->implemented = 0;
- }
-
- /* free the compiled version of the module, if any */
- lysc_module_free(m->compiled, NULL);
- m->compiled = NULL;
-
- if (m->implemented) {
- /* recompile, must succeed because it was already compiled; hide messages because any
- * warnings were already printed, are not really relevant, and would hide the real error */
- uint32_t prev_lo = ly_log_options(0);
- LY_ERR r = lys_compile(m, LYSC_OPT_INTERNAL);
- ly_log_options(prev_lo);
- if (r) {
- LOGERR(ctx.ctx, r, "Recompilation of module \"%s\" failed.", m->name);
- }
- }
- }
- }
-
return ret;
}
diff --git a/src/tree_schema_internal.h b/src/tree_schema_internal.h
index 0a1d5ab..5d9bb9c 100644
--- a/src/tree_schema_internal.h
+++ b/src/tree_schema_internal.h
@@ -407,6 +407,15 @@
void lysp_notif_free(struct ly_ctx *ctx, struct lysp_notif *notif);
/**
+ * @brief Revert precompilation of module augments and deviations. Meaning remove its reference from
+ * all the target modules.
+ *
+ * @param[in] ctx libyang context.
+ * @param[in] mod Mod whose precompilation to revert.
+ */
+void lys_precompile_augments_deviations_revert(struct ly_ctx *ctx, const struct lys_module *mod);
+
+/**
* @brief Compile printable schema into a validated schema linking all the references.
*
* @param[in] mod Pointer to the schema structure holding pointers to both schema structure types. The ::lys_module#parsed
@@ -834,16 +843,6 @@
void lys_module_free(struct lys_module *module, void (*private_destructor)(const struct lysc_node *node, void *priv));
/**
- * @brief Make the specific module implemented, use the provided value as flag.
- *
- * @param[in] mod Module to make implemented. It is not an error to provide already implemented module, it just does nothing.
- * @param[in] implemented Flag value for the ::lys_module::implemented item.
- * @return LY_SUCCESS or LY_EDENIED in case the context contains some other revision of the
- * same module which is already implemented.
- */
-LY_ERR lys_set_implemented_internal(struct lys_module *mod, uint8_t implemented);
-
-/**
* @brief match yang keyword
*
* @param[in] ctx yang parser context for logging, can be NULL if keyword is from YIN data.