diff --git a/include/clixon_custom.h b/include/clixon_custom.h index eb8d56b8..bc37338d 100644 --- a/include/clixon_custom.h +++ b/include/clixon_custom.h @@ -233,3 +233,16 @@ * A more intelligent algorithm is needed */ #define XML_DEFAULT_WHEN_TWICE + +/*! If set, make optimized lookup of yspec + namespace -> module + * + * see yang_find_module_by_namespace + */ +#define OPTIMIZE_YSPEC_NAMESPACE + +/*! If set, make optimization of non-presence default container + * + * Save the default XML in YANG and reuse next time + * see xml_default + */ +#define OPTIMIZE_NO_PRESENCE_CONTAINER diff --git a/lib/clixon/clixon_map.h b/lib/clixon/clixon_map.h index 66d9a666..7f450045 100644 --- a/lib/clixon/clixon_map.h +++ b/lib/clixon/clixon_map.h @@ -54,19 +54,27 @@ static const map_str2int atmap[] = { * @see clicon_str2int */ struct map_str2int{ - char *ms_str; - int ms_int; + char *ms_str; + int ms_int; }; typedef struct map_str2int map_str2int; /*! Struct used to map between two strings. */ struct map_str2str{ - char *ms_s0; - char *ms_s1; + char *ms_s0; + char *ms_s1; }; typedef struct map_str2str map_str2str; +/*! Struct used to map from string to pointer + */ +struct map_str2ptr{ + char *mp_str; + void *mp_ptr; +}; +typedef struct map_str2ptr map_str2ptr; + /*! Map from ptr to ptr */ struct map_ptr2ptr{ @@ -82,6 +90,9 @@ const char *clicon_int2str(const map_str2int *mstab, int i); int clicon_str2int(const map_str2int *mstab, char *str); int clicon_str2int_search(const map_str2int *mstab, char *str, int upper); char *clicon_str2str(const map_str2str *mstab, char *str); +void clixon_str2ptr_sort(map_str2ptr *mptab, size_t len); +void *clixon_str2ptr(map_str2ptr *mptab, char *str, size_t len); +int clixon_str2ptr_print(FILE *f, map_str2ptr *mptab); void *clixon_ptr2ptr(map_ptr2ptr *mptab, void *ptr); int clixon_ptr2ptr_add(map_ptr2ptr **mptab, void *ptr0, void *ptr1); diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index 7fd828b6..16f6bbb3 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -354,6 +354,10 @@ int yang_sort_subelements(yang_stmt *ys); int yang_single_child_type(yang_stmt *ys, enum rfc_6020 subkeyw); void *yang_action_cb_get(yang_stmt *ys); int yang_action_cb_add(yang_stmt *ys, void *rc); +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER +void *yang_nopresence_cache_get(yang_stmt *ys); +int yang_nopresence_cache_set(yang_stmt *ys, void *x); +#endif int ys_populate_feature(clixon_handle h, yang_stmt *ys); int yang_init(clixon_handle h); int yang_start(clixon_handle h); diff --git a/lib/clixon/clixon_yang_parse_lib.h b/lib/clixon/clixon_yang_parse_lib.h index f97e337b..8b980d5a 100644 --- a/lib/clixon/clixon_yang_parse_lib.h +++ b/lib/clixon/clixon_yang_parse_lib.h @@ -65,5 +65,10 @@ int yang_spec_load_dir(clixon_handle h, char *dir, yang_stmt *yspec); int ys_parse_date_arg(char *datearg, uint32_t *dateint); cg_var *ys_parse(yang_stmt *ys, enum cv_type cvtype); int ys_parse_sub(yang_stmt *ys, const char *filename, char *extra); +#ifdef OPTIMIZE_YSPEC_NAMESPACE +int yspec_nscache_clear(yang_stmt *yspec); +yang_stmt *yspec_nscache_get(yang_stmt *yspec, char *ns); +int yspec_nscache_new(yang_stmt *yspec); +#endif #endif /* _CLIXON_YANG_LIB_H_ */ diff --git a/lib/src/clixon_map.c b/lib/src/clixon_map.c index 05e22015..1d99edf7 100644 --- a/lib/src/clixon_map.c +++ b/lib/src/clixon_map.c @@ -55,6 +55,7 @@ #include "clixon_yang.h" #include "clixon_xml.h" #include "clixon_err.h" +#include "clixon_string.h" /*! Map from int to string using str2int map * @@ -116,9 +117,9 @@ str2int_search1(const map_str2int *mstab, int len, int *found) { - const struct map_str2int *ms; - int mid; - int cmp; + const map_str2int *ms; + int mid; + int cmp; if (upper < low) return 0; /* not found */ @@ -136,10 +137,58 @@ str2int_search1(const map_str2int *mstab, return str2int_search1(mstab, str, mid+1, upper, len, found); } +/*! Map from string to ptr using binary (alphatical) search + * + * Assumes sorted strings, tree search. If two are equal take first + * @param[in] ms String, integer map + * @param[in] str Input string + * @param[in] low Lower bound index + * @param[in] upper Upper bound index + * @param[in] len Length of array (max) + * @param[out] found element + * @retval 1 Found with "found" value set. + * @retval 0 Not found + + */ +static int +str2ptr_search1(const map_str2ptr *mptab, + char *str, + size_t low, + size_t upper, + size_t len, + map_str2ptr **found) +{ + const map_str2ptr *mp; + int mid; + int cmp; + int i; + + if (upper < low) + return 0; /* not found */ + mid = (low + upper) / 2; + if (mid >= len) /* beyond range */ + return 0; /* not found */ + mp = &mptab[mid]; + if ((cmp = clicon_strcmp(str, mp->mp_str)) == 0){ + i = mid; + while (i >= 0 && clicon_strcmp(str, mptab[i].mp_str) == 0){ + mp = &mptab[i]; + i--; + } + *found = (map_str2ptr *)mp; + return 1; /* found */ + } + else if (cmp < 0) + return str2ptr_search1(mptab, str, low, mid-1, len, found); + else + return str2ptr_search1(mptab, str, mid+1, upper, len, found); +} + /*! Map from string to int using str2int map * * @param[in] ms String, integer map * @param[in] str Input string + * @param[in] len * @retval int Value * @retval -1 Error, not found * @note Assumes sorted strings, tree search @@ -176,6 +225,67 @@ clicon_str2str(const map_str2str *mstab, return NULL; } +static int +str2ptr_qsort(const void* arg1, + const void* arg2) +{ + map_str2ptr *mp1 = (map_str2ptr*)arg1; + map_str2ptr *mp2 = (map_str2ptr*)arg2; + int eq; + yang_stmt *yrev; + char *rev1 = NULL; + char *rev2 = NULL; + + eq = clicon_strcmp(mp1->mp_str, mp2->mp_str); + if (0 && eq == 0){ + if ((yrev = yang_find(mp1->mp_ptr, Y_REVISION, NULL)) != NULL) + rev1 = yang_argument_get(yrev); + if ((yrev = yang_find(mp2->mp_ptr, Y_REVISION, NULL)) != NULL) + rev2 = yang_argument_get(yrev); + eq = clicon_strcmp(rev1, rev2); + } + return eq; +} + +void +clixon_str2ptr_sort(map_str2ptr *mptab, + size_t len) +{ + qsort(mptab, len, sizeof(*mptab), str2ptr_qsort); +} + +/*! Map from string to string using str2str map + * + * @param[in] mptab String to ptr map + * @param[in] str Input string + * @retval ptr Output pointer + * @retval NULL Error, not found + */ +void* +clixon_str2ptr(map_str2ptr *mptab, + char *str, + size_t len) +{ + map_str2ptr *mp = NULL; + + if (str2ptr_search1(mptab, str, 0, len, len, &mp)) + return mp->mp_ptr; + return NULL; /* not found */ +} + +int +clixon_str2ptr_print(FILE *f, + map_str2ptr *mptab) +{ + map_str2ptr *mp = NULL; + int i; + + i = 0; + for (mp = &mptab[0]; mp->mp_str; mp++) + fprintf(f, "%d %s %p\n", i++, mp->mp_str, mp->mp_ptr); + return 0; +} + /*! Map from pointer to pointer using mptab map * * @param[in] mptab Ptr to ptr map diff --git a/lib/src/clixon_xml_default.c b/lib/src/clixon_xml_default.c index 1186f98f..1a90c9e9 100644 --- a/lib/src/clixon_xml_default.c +++ b/lib/src/clixon_xml_default.c @@ -297,6 +297,9 @@ xml_default(yang_stmt *yt, int retval = -1; yang_stmt *yc; cxobj *xc; +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + cxobj *xc1; +#endif int top = 0; /* Top symbol (set default namespace) */ int create = 0; int nr = 0; @@ -361,19 +364,37 @@ xml_default(yang_stmt *yt, * defaults. */ if (xml_find_type(xt, NULL, yang_argument_get(yc), CX_ELMNT) == NULL){ - /* No such container exist, recursively try if needed */ - if (xml_nopresence_try(yc, state, &create) < 0) - goto done; - if (create){ - /* Retval shows there is a default value need to create the - * container */ - if (xml_default_create1(yc, xt, &xc) < 0) +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + if ((xc = yang_nopresence_cache_get(yc)) != NULL){ + if ((xc1 = xml_dup(xc)) == NULL) + goto done; + if (xml_addsub(xt, xc1) < 0) goto done; xml_sort(xt); - /* Then call it recursively */ - if (xml_default(yc, xc, state) < 0) - goto done; } + else +#endif + { + /* No such container exist, recursively try if needed */ + if (xml_nopresence_try(yc, state, &create) < 0) + goto done; + if (create){ + /* Retval shows there is a default value need to create the + * container */ + if (xml_default_create1(yc, xt, &xc) < 0) + goto done; + xml_sort(xt); + /* Then call it recursively */ + if (xml_default(yc, xc, state) < 0) + goto done; +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + if ((xc1 = xml_dup(xc)) == NULL) + goto done; + if (yang_nopresence_cache_set(yc, xc1) < 0) + goto done; +#endif + } + } } } break; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 5908c514..67c10c3c 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1090,6 +1090,19 @@ ys_free1(yang_stmt *ys, if (ys->ys_filename) free(ys->ys_filename); break; +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + case Y_CONTAINER: + if (ys->ys_nopres_cache) + xml_free(ys->ys_nopres_cache); + break; +#endif +#ifdef OPTIMIZE_YSPEC_NAMESPACE + case Y_SPEC: + if (ys->ys_nscache) + free(ys->ys_nscache); + break; +#endif + default: break; } @@ -1220,6 +1233,11 @@ yn_realloc(yang_stmt *yn) return -1; } yn->ys_stmt[yn->ys_len - 1] = NULL; /* init field */ +#ifdef OPTIMIZE_YSPEC_NAMESPACE + if (yn->ys_keyword == Y_SPEC && yn->ys_nscache){ /* Clear cache */ + yspec_nscache_clear(yn); + } +#endif return 0; } @@ -1336,6 +1354,16 @@ ys_cp_one(yang_stmt *ynew, if (yang_typecache_get(yold)) /* Dont copy type cache, use only original */ yang_typecache_set(ynew, NULL); break; +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + case Y_CONTAINER: + yold->ys_nopres_cache = NULL; + break; +#endif +#ifdef OPTIMIZE_YSPEC_NAMESPACE + case Y_SPEC: + yold->ys_nscache = NULL; + break; +#endif default: break; } @@ -4034,11 +4062,12 @@ int yang_config(yang_stmt *ys) { yang_stmt *ym; + cg_var *cv; if ((ym = yang_find(ys, Y_CONFIG, NULL)) != NULL){ - if (yang_cv_get(ym) == NULL) /* shouldnt happen */ + if ((cv = yang_cv_get(ym)) == NULL) /* shouldnt happen */ return 1; - return cv_bool_get(yang_cv_get(ym)); + return cv_bool_get(cv); } return 1; } @@ -4610,6 +4639,24 @@ yang_action_cb_add(yang_stmt *ys, return 0; } +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER +void * +yang_nopresence_cache_get(yang_stmt *ys) +{ + return ys->ys_nopres_cache; +} + +int +yang_nopresence_cache_set(yang_stmt *ys, + void *x) +{ + if (ys->ys_nopres_cache) + xml_free(ys->ys_nopres_cache); + ys->ys_nopres_cache = x; + return 0; +} +#endif + /*! Init yang code. Called before any yang code, before options * * Add two external tables for YANGs diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index 7e8b4080..2d812f36 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -114,7 +114,12 @@ struct yang_stmt { rpc_callback_t *ysu_action_cb; /* Y_ACTION: Action callback list*/ char *ysu_filename; /* Y_MODULE/Y_SUBMODULE: For debug/errors: filename */ yang_type_cache *ysu_typecache; /* Y_TYPE: cache all typedef data except unions */ - +#ifdef OPTIMIZE_YSPEC_NAMESPACE + map_str2ptr *ysu_nscache; /* Y_SPEC: namespace to module cache */ +#endif +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER + cxobj *ysu_nopres_cache; /* Y_CONTAINER: no-presence XML cache */ +#endif } u; }; @@ -122,5 +127,11 @@ struct yang_stmt { #define ys_action_cb u.ysu_action_cb #define ys_filename u.ysu_filename #define ys_typecache u.ysu_typecache +#ifdef OPTIMIZE_YSPEC_NAMESPACE +#define ys_nscache u.ysu_nscache +#endif +#ifdef OPTIMIZE_NO_PRESENCE_CONTAINER +#define ys_nopres_cache u.ysu_nopres_cache +#endif #endif /* _CLIXON_YANG_INTERNAL_H_ */ diff --git a/lib/src/clixon_yang_module.c b/lib/src/clixon_yang_module.c index 9a3c8d6e..b2ed943f 100644 --- a/lib/src/clixon_yang_module.c +++ b/lib/src/clixon_yang_module.c @@ -609,6 +609,9 @@ yang_stmt * yang_find_module_by_namespace(yang_stmt *yspec, char *ns) { +#ifdef OPTIMIZE_YSPEC_NAMESPACE + return yspec_nscache_get(yspec, ns); +#else yang_stmt *ymod = NULL; int inext; @@ -621,6 +624,7 @@ yang_find_module_by_namespace(yang_stmt *yspec, } done: return ymod; +#endif } /*! Given a yang spec, a namespace and revision, return yang module diff --git a/lib/src/clixon_yang_parse_lib.c b/lib/src/clixon_yang_parse_lib.c index ee28ec56..a635c900 100644 --- a/lib/src/clixon_yang_parse_lib.c +++ b/lib/src/clixon_yang_parse_lib.c @@ -903,6 +903,9 @@ yang_parse_str(char *str, /* Add filename for debugging and errors, see also ys_linenum on (each symbol?) */ if (yang_filename_set(ymod, name) < 0) goto done; +#ifdef OPTIMIZE_YSPEC_NAMESPACE + yspec_nscache_clear(yspec); +#endif done: clixon_debug(CLIXON_DBG_PARSE, "retval:%p", ymod); ystack_pop(&yy); @@ -2109,3 +2112,57 @@ ys_parse_sub(yang_stmt *ys, free(extra); return retval; } + +#ifdef OPTIMIZE_YSPEC_NAMESPACE +int +yspec_nscache_clear(yang_stmt *yspec) +{ + if (yspec->ys_nscache){ /* Clear cache */ + free(yspec->ys_nscache); + yspec->ys_nscache = NULL; + } + return 0; +} + +/*! + */ +yang_stmt * +yspec_nscache_get(yang_stmt *yspec, + char *ns) +{ + if (yspec->ys_nscache == NULL){ + if (yspec_nscache_new(yspec) < 0) + return NULL; + } + return clixon_str2ptr(yspec->ys_nscache, ns, yang_len_get(yspec)+1); +} + +/*! + */ +int +yspec_nscache_new(yang_stmt *yspec) +{ + int retval = -1; + map_str2ptr *mp; + yang_stmt *ym; + int i; + + yspec_nscache_clear(yspec); + if ((yspec->ys_nscache = calloc(yang_len_get(yspec)+1, sizeof(*yspec->ys_nscache))) == NULL){ + clixon_err(OE_UNIX, errno, "calloc"); + goto done; + } + for (i=0; iys_nscache[i]; + mp->mp_str = yang_find_mynamespace(ym); + mp->mp_ptr = ym; + } + clixon_str2ptr_sort(yspec->ys_nscache, yang_len_get(yspec)+1); + retval = 0; + done: + return retval; +} +#endif