experimental xml hash for better performance
This commit is contained in:
parent
687641e944
commit
7a7bfc48a4
18 changed files with 612 additions and 481 deletions
|
|
@ -34,6 +34,10 @@
|
|||
* XML support functions.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -51,7 +55,11 @@
|
|||
#include "clixon_err.h"
|
||||
#include "clixon_log.h"
|
||||
#include "clixon_string.h"
|
||||
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_hash.h"
|
||||
#include "clixon_handle.h"
|
||||
#include "clixon_yang.h"
|
||||
#include "clixon_xml.h"
|
||||
#include "clixon_xml_parse.h"
|
||||
|
||||
|
|
@ -81,6 +89,9 @@ struct xml{
|
|||
void *x_spec; /* Pointer to specification, eg yang, by
|
||||
reference, dont free */
|
||||
cg_var *x_cv; /* If body this contains the typed value */
|
||||
#if (XML_CHILD_HASH==1)
|
||||
clicon_hash_t *x_hash; /* Hash of children */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Mapping between xml type <--> string */
|
||||
|
|
@ -647,6 +658,9 @@ xml_purge(cxobj *xc)
|
|||
int i;
|
||||
cxobj *xp;
|
||||
|
||||
#if (XML_CHILD_HASH==1)
|
||||
xml_hash_op(xc, 0);
|
||||
#endif
|
||||
if ((xp = xml_parent(xc)) != NULL){
|
||||
/* Find child order i in parent*/
|
||||
for (i=0; i<xml_child_nr(xp); i++)
|
||||
|
|
@ -771,6 +785,9 @@ xml_rootchild(cxobj *xp,
|
|||
* @retval NULL if no such node or no body in found node
|
||||
* Note, make a copy of the return value to use it properly
|
||||
* @see xml_find_body
|
||||
* Explaining picture:
|
||||
* xt --> xb (x_type=CX_BODY)
|
||||
* return xb.x_value
|
||||
*/
|
||||
char *
|
||||
xml_body(cxobj *xn)
|
||||
|
|
@ -782,12 +799,18 @@ xml_body(cxobj *xn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*! Get (first) body of xml node, note could be many
|
||||
* @param[in] xt xml tree node
|
||||
* Explaining picture:
|
||||
* xt --> xb (x_type=CX_BODY)
|
||||
* return xb
|
||||
*/
|
||||
cxobj *
|
||||
xml_body_get(cxobj *xn)
|
||||
xml_body_get(cxobj *xt)
|
||||
{
|
||||
cxobj *xb = NULL;
|
||||
|
||||
while ((xb = xml_child_each(xn, xb, CX_BODY)) != NULL)
|
||||
while ((xb = xml_child_each(xt, xb, CX_BODY)) != NULL)
|
||||
return xb;
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -795,22 +818,27 @@ xml_body_get(cxobj *xn)
|
|||
/*! Find and return the value of a sub xml node
|
||||
*
|
||||
* The value can be of an attribute or body.
|
||||
* @param[in] xn xml tree node
|
||||
* @param[in] xt xml tree node
|
||||
* @param[in] name name of xml tree nod (eg attr name or "body")
|
||||
* @retval The returned value as a pointer to the name string
|
||||
* @retval NULL if no such node or no value in found node
|
||||
* @retval val Pointer to the name string
|
||||
* @retval NULL No such node or no value in node
|
||||
*
|
||||
* Note, make a copy of the return value to use it properly
|
||||
* See also xml_find_body
|
||||
* Explaining picture:
|
||||
* xt --> x
|
||||
* x_name=name
|
||||
* return x_value
|
||||
*/
|
||||
char *
|
||||
xml_find_value(cxobj *x_up,
|
||||
xml_find_value(cxobj *xt,
|
||||
char *name)
|
||||
{
|
||||
cxobj *x;
|
||||
cxobj *x = NULL;
|
||||
|
||||
if ((x = xml_find(x_up, name)) != NULL)
|
||||
return xml_value(x);
|
||||
while ((x = xml_child_each(xt, x, -1)) != NULL)
|
||||
if (strcmp(name, xml_name(x)) == 0)
|
||||
return xml_value(x);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -821,18 +849,56 @@ xml_find_value(cxobj *x_up,
|
|||
* @retval NULL if no such node or no body in found node
|
||||
* @note, make a copy of the return value to use it properly
|
||||
* @see xml_find_value
|
||||
* Explaining picture:
|
||||
* xt --> x --> bx (x_type=CX_BODY)
|
||||
* x_name=name return x_value
|
||||
|
||||
*/
|
||||
char *
|
||||
xml_find_body(cxobj *xn,
|
||||
xml_find_body(cxobj *xt,
|
||||
char *name)
|
||||
{
|
||||
cxobj *x;
|
||||
cxobj *x=NULL;
|
||||
|
||||
if ((x = xml_find(xn, name)) != NULL)
|
||||
return xml_body(x);
|
||||
while ((x = xml_child_each(xt, x, -1)) != NULL)
|
||||
if (strcmp(name, xml_name(x)) == 0)
|
||||
return xml_body(x);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Find xml object with matching name and value.
|
||||
*
|
||||
* This can be useful if x is a leaf-list with many subs with same name,
|
||||
* but you need to pick the object with a specific value
|
||||
* @param[in] xt XML tree
|
||||
* @param[in] name Name of child (there can be many with same name)
|
||||
* @param[in] val Value. Must be equal to body of child.
|
||||
* @retval x Child with matching name and body
|
||||
*
|
||||
* Explaining picture:
|
||||
* xt --> x --> bx (x_type=CX_BODY)
|
||||
* x_name=name x_value=val
|
||||
* return x
|
||||
*/
|
||||
cxobj *
|
||||
xml_find_body_obj(cxobj *xt,
|
||||
char *name,
|
||||
char *val)
|
||||
{
|
||||
cxobj *x = NULL;
|
||||
char *bstr;
|
||||
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(name, xml_name(x)))
|
||||
continue;
|
||||
if ((bstr = xml_body(x)) == NULL)
|
||||
continue;
|
||||
if (strcmp(bstr, val) == 0)
|
||||
break; /* x is returned */
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/*! Free an xl sub-tree recursively, but do not remove it from parent
|
||||
* @param[in] x the xml tree to be freed.
|
||||
* @see xml_purge where x is also removed from parent
|
||||
|
|
@ -856,6 +922,10 @@ xml_free(cxobj *x)
|
|||
xml_free(xc);
|
||||
x->x_childvec[i] = NULL;
|
||||
}
|
||||
#if (XML_CHILD_HASH==1)
|
||||
if (x->x_hash)
|
||||
hash_free(x->x_hash);
|
||||
#endif
|
||||
if (x->x_childvec)
|
||||
free(x->x_childvec);
|
||||
free(x);
|
||||
|
|
@ -995,7 +1065,7 @@ clicon_xml2cbuf(cbuf *cb,
|
|||
*/
|
||||
int
|
||||
xml_parse(char *str,
|
||||
cxobj *x_up)
|
||||
cxobj *xt)
|
||||
{
|
||||
int retval = -1;
|
||||
struct xml_parse_yacc_arg ya = {0,};
|
||||
|
|
@ -1004,7 +1074,7 @@ xml_parse(char *str,
|
|||
clicon_err(OE_XML, errno, "%s: strdup", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
ya.ya_xparent = x_up;
|
||||
ya.ya_xparent = xt;
|
||||
ya.ya_skipspace = 1; /* remove all non-terminal bodies (strip pretty-print) */
|
||||
if (clixon_xml_parsel_init(&ya) < 0)
|
||||
goto done;
|
||||
|
|
@ -1641,6 +1711,160 @@ xml_operation2str(enum operation_type op)
|
|||
}
|
||||
}
|
||||
|
||||
#if (XML_CHILD_HASH==1)
|
||||
/*! Return yang hash
|
||||
* Not necessarily set. Either has not been set yet (by xml_spec_set( or anyxml.
|
||||
*/
|
||||
clicon_hash_t *
|
||||
xml_hash(cxobj *x)
|
||||
{
|
||||
return x->x_hash;
|
||||
}
|
||||
|
||||
int
|
||||
xml_hash_init(cxobj *x)
|
||||
{
|
||||
if ((x->x_hash = hash_init()) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
xml_hash_rm(cxobj *x)
|
||||
{
|
||||
if (x && x->x_hash){
|
||||
hash_free(x->x_hash);
|
||||
x->x_hash = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute hash key for xml entry
|
||||
* @param[in] x
|
||||
* @param[in] y
|
||||
* @param[out] key
|
||||
* key: yangtype+x1name
|
||||
* LEAFLIST: b0
|
||||
* LIST: b2vec+b0 -> x0c
|
||||
*/
|
||||
int
|
||||
xml_hash_key(cxobj *x,
|
||||
yang_stmt *y,
|
||||
cbuf *key)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ykey;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *keyname;
|
||||
char *b;
|
||||
char *str;
|
||||
|
||||
switch (y->ys_keyword){
|
||||
case Y_CONTAINER: str = "c"; break;
|
||||
case Y_LEAF: str = "e"; break;
|
||||
case Y_LEAF_LIST: str = "l"; break;
|
||||
case Y_LIST: str = "i"; break;
|
||||
default:
|
||||
str = "xx"; break;
|
||||
break;
|
||||
}
|
||||
cprintf(key, "%s%s", str, xml_name(x));
|
||||
switch (y->ys_keyword){
|
||||
case Y_LEAF_LIST: /* Match with name and value */
|
||||
if ((b = xml_body(x)) == NULL){
|
||||
cbuf_reset(key);
|
||||
goto ok;
|
||||
}
|
||||
cprintf(key, "%s", xml_body(x));
|
||||
break;
|
||||
case Y_LIST: /* Match with key values */
|
||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, y->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
cvi = NULL;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((b = xml_find_body(x, keyname)) == NULL){
|
||||
cbuf_reset(key);
|
||||
goto ok;
|
||||
}
|
||||
cprintf(key, "/%s", b);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cvk)
|
||||
cvec_free(cvk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! XML hash add. Create hash and add key/value to parent
|
||||
*
|
||||
* @param[in] arg -1: rm only hash 0: rm entry, 1: add
|
||||
* Typically called for a whole tree.
|
||||
*/
|
||||
int
|
||||
xml_hash_op(cxobj *x,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xp;
|
||||
clicon_hash_t *ph;
|
||||
yang_stmt *y;
|
||||
cbuf *key = NULL; /* cligen buffer hash key */
|
||||
int op = (int)arg;
|
||||
|
||||
if (xml_hash(x)==NULL){
|
||||
if (op==1)
|
||||
xml_hash_init(x);
|
||||
}
|
||||
else if (op==-1|| op==0)
|
||||
xml_hash_rm(x);
|
||||
if (op==-1)
|
||||
goto ok;
|
||||
if ((xp = xml_parent(x)) == NULL)
|
||||
goto ok;
|
||||
if ((ph = xml_hash(xp))==NULL)
|
||||
goto ok;
|
||||
if ((y = xml_spec(x)) == NULL)
|
||||
goto ok;
|
||||
if ((key = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (xml_hash_key(x, y, key) < 0)
|
||||
goto done;
|
||||
if (cbuf_len(key)){
|
||||
// fprintf(stderr, "%s add %s = 0x%x\n", __FUNCTION__, cbuf_get(key), (unsigned int)x);
|
||||
if (op == 1){
|
||||
if (hash_add(ph, cbuf_get(key), &x, sizeof(x)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
if (hash_del(ph, cbuf_get(key)) < 0)
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (key)
|
||||
cbuf_free(key);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Turn this on to get a xml parse and pretty print test program
|
||||
* Usage: xpath
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue