C-API: string to pointer map

Optimization of yspec+namespace lookup
Optimization of non-presence container default tree
This commit is contained in:
Olof hagsand 2024-12-27 17:53:38 +01:00
parent 3be786c211
commit b09e326307
10 changed files with 303 additions and 20 deletions

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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_ */

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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_ */

View file

@ -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

View file

@ -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; i<yang_len_get(yspec); i++){
ym = yang_child_i(yspec, i);
if (yang_keyword_get(ym) != Y_MODULE)
continue;
mp = &yspec->ys_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