Commit a7248443 authored by Kasimier T. Buchcik's avatar Kasimier T. Buchcik

Added an XPath object cache. It sits on an xmlXPathContext and need to be

* xpath.c include/libxml/xpath.h: Added an XPath object cache.
  It sits on an xmlXPathContext and need to be explicitely
  activated (or deactivated again) with
  xmlXPathContextSetObjectCache(). The cache consists of 5
  lists for node-set, string, number, boolean and misc XPath
  objects. Internally the xpath.c module will use object-
  deposition and -acquisition functions which will try to reuse
  as many XPath objects as possible, and fallback to normal
  free/create behaviour if no cache is available or if the cache
  is full.
* runsuite.c: Adjusted to deactivate the cache for XML Schema
  tests if a cache-creation is turned on by default for the whole
  library, e.g. for testing purposes of the cache. It is
  deactivated here in order to avoid confusion of the memory leak
  detection in runsuite.c.
parent 984a9aed
Mon May 29 18:06:17 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* xpath.c include/libxml/xpath.h: Added an XPath object cache.
It sits on an xmlXPathContext and need to be explicitely
activated (or deactivated again) with
xmlXPathContextSetObjectCache(). The cache consists of 5
lists for node-set, string, number, boolean and misc XPath
objects. Internally the xpath.c module will use object-
deposition and -acquisition functions which will try to reuse
as many XPath objects as possible, and fallback to normal
free/create behaviour if no cache is available or if the cache
is full.
* runsuite.c: Adjusted to deactivate the cache for XML Schema
tests if a cache-creation is turned on by default for the whole
library, e.g. for testing purposes of the cache. It is
deactivated here in order to avoid confusion of the memory leak
detection in runsuite.c.
Wed May 24 10:54:25 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* xpath.c: Removed a memcpy if xmlXPathNodeSetMerge(); it
......
......@@ -35,6 +35,7 @@ extern "C" {
#endif /* LIBXML_XPATH_ENABLED or LIBXML_SCHEMAS_ENABLED */
#ifdef LIBXML_XPATH_ENABLED
typedef struct _xmlXPathContext xmlXPathContext;
typedef xmlXPathContext *xmlXPathContextPtr;
typedef struct _xmlXPathParserContext xmlXPathParserContext;
......@@ -343,6 +344,7 @@ struct _xmlXPathContext {
xmlDictPtr dict; /* dictionnary if any */
int flags; /* flags to control compilation */
void *objCache; /* Cache for reusal of XPath objects. */
};
/*
......@@ -485,9 +487,13 @@ XMLPUBFUN xmlXPathObjectPtr XMLCALL
*/
XMLPUBFUN xmlXPathContextPtr XMLCALL
xmlXPathNewContext (xmlDocPtr doc);
XMLPUBFUN void XMLCALL
XMLPUBFUN void XMLCALL
xmlXPathFreeContext (xmlXPathContextPtr ctxt);
XMLPUBFUN int XMLCALL
xmlXPathContextSetObjectCache(xmlXPathContextPtr ctxt,
int active,
int maxNumberPerSlot,
int options);
/**
* Evaluation functions.
*/
......
......@@ -225,6 +225,16 @@ initializeLibxml2(void) {
xmlInitParser();
xmlSetExternalEntityLoader(testExternalEntityLoader);
ctxtXPath = xmlXPathNewContext(NULL);
/*
* Deactivate the cache if created; otherwise we have to create/free it
* for every test, since it will confuse the memory leak detection.
* Note that normally this need not be done, since the cache is not
* created until set explicitely with xmlXPathContextSetObjectCache();
* but for test purposes it is sometimes usefull to activate the
* cache by default for the whole library.
*/
if (ctxtXPath->objCache != NULL)
xmlXPathContextSetObjectCache(ctxtXPath, 0, -1, 0);
/* used as default nanemspace in xstc tests */
xmlXPathRegisterNs(ctxtXPath, BAD_CAST "ts", BAD_CAST "TestSuite");
xmlXPathRegisterNs(ctxtXPath, BAD_CAST "xlink",
......@@ -1158,7 +1168,6 @@ main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
printf("Total %d tests, %d errors, %d leaks\n",
nb_tests, nb_errors, nb_leaks);
}
xmlXPathFreeContext(ctxtXPath);
xmlCleanupParser();
xmlMemoryDump();
......
......@@ -2,7 +2,7 @@
* xpath.c: XML Path Language implementation
* XPath is a language for addressing parts of an XML document,
* designed to be used by both XSLT and XPointer
*
*f
* Reference: W3C Recommendation 16 November 1999
* http://www.w3.org/TR/1999/REC-xpath-19991116
* Public reference:
......@@ -94,6 +94,13 @@
*/
#define XP_OPTIMIZED_FILTER_FIRST
/*
* XP_DEBUG_OBJ_USAGE:
* Internal flag to enable tracking of how much XPath objects have been
* created.
*/
/* #define XP_DEBUG_OBJ_USAGE */
/*
* TODO:
* There are a few spots where some tests are done which depend upon ascii
......@@ -102,6 +109,16 @@
*/
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
/************************************************************************
* *
* Forward declarations *
* *
************************************************************************/
static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
/************************************************************************
* *
* Floating point stuff *
......@@ -388,6 +405,101 @@ xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
xmlXPathErr(ctxt, no);
}
/************************************************************************
* *
* Utilities *
* *
************************************************************************/
/**
* xsltPointerList:
*
* Pointer-list for various purposes.
*/
typedef struct _xmlPointerList xmlPointerList;
typedef xmlPointerList *xmlPointerListPtr;
struct _xmlPointerList {
void **items;
int number;
int size;
};
/*
* TODO: Since such a list-handling is used in xmlschemas.c and libxslt
* and here, we should make the functions public.
*/
static int
xmlPointerListAddSize(xmlPointerListPtr list,
void *item,
int initialSize)
{
if (list->items == NULL) {
if (initialSize <= 0)
initialSize = 1;
list->items = (void **) xmlMalloc(
initialSize * sizeof(void *));
if (list->items == NULL) {
xmlXPathErrMemory(NULL,
"xmlPointerListCreate: allocating item\n");
return(-1);
}
list->number = 0;
list->size = initialSize;
} else if (list->size <= list->number) {
list->size *= 2;
list->items = (void **) xmlRealloc(list->items,
list->size * sizeof(void *));
if (list->items == NULL) {
xmlXPathErrMemory(NULL,
"xmlPointerListCreate: re-allocating item\n");
list->size = 0;
return(-1);
}
}
list->items[list->number++] = item;
return(0);
}
/**
* xsltPointerListCreate:
*
* Creates an xsltPointerList structure.
*
* Returns a xsltPointerList structure or NULL in case of an error.
*/
static xmlPointerListPtr
xmlPointerListCreate(int initialSize)
{
xmlPointerListPtr ret;
ret = xmlMalloc(sizeof(xmlPointerList));
if (ret == NULL) {
xmlXPathErrMemory(NULL,
"xmlPointerListCreate: allocating item\n");
return (NULL);
}
memset(ret, 0, sizeof(xmlPointerList));
if (initialSize > 0) {
xmlPointerListAddSize(ret, NULL, initialSize);
ret->number = 0;
}
return (ret);
}
/**
* xsltPointerListFree:
*
* Frees the xsltPointerList structure. This does not free
* the content of the list.
*/
static void
xmlPointerListFree(xmlPointerListPtr list)
{
if (list == NULL)
return;
if (list->items != NULL)
xmlFree(list->items);
xmlFree(list);
}
/************************************************************************
* *
......@@ -690,6 +802,58 @@ xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
(val), (val2), 0 ,NULL ,NULL)
/************************************************************************
* *
* XPath object cache structures *
* *
************************************************************************/
/* #define XP_DEFAULT_CACHE_ON */
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->objCache != NULL))
typedef struct _xmlXPathObjectCache xmlXPathObjectCache;
typedef xmlXPathObjectCache *xmlXPathObjectCachePtr;
struct _xmlXPathObjectCache {
xmlPointerListPtr nodesetObjs;
xmlPointerListPtr stringObjs;
xmlPointerListPtr booleanObjs;
xmlPointerListPtr numberObjs;
xmlPointerListPtr miscObjs;
int maxNodeset;
int maxString;
int maxBoolean;
int maxNumber;
int maxMisc;
#ifdef XP_DEBUG_OBJ_USAGE
int dbgCachedAll;
int dbgCachedNodeset;
int dbgCachedString;
int dbgCachedBool;
int dbgCachedNumber;
int dbgCachedPoint;
int dbgCachedRange;
int dbgCachedLocset;
int dbgCachedUsers;
int dbgCachedXSLTTree;
int dbgCachedUndefined;
int dbgReusedAll;
int dbgReusedNodeset;
int dbgReusedString;
int dbgReusedBool;
int dbgReusedNumber;
int dbgReusedPoint;
int dbgReusedRange;
int dbgReusedLocset;
int dbgReusedUsers;
int dbgReusedXSLTTree;
int dbgReusedUndefined;
#endif
};
/************************************************************************
* *
* Debugging related functions *
......@@ -1102,42 +1266,1123 @@ xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
default:
fprintf(output, "UNKNOWN %d\n", op->op); return;
}
fprintf(output, "\n");
finish:
if (op->ch1 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
if (op->ch2 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
fprintf(output, "\n");
finish:
if (op->ch1 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
if (op->ch2 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
}
/**
* xmlXPathDebugDumpCompExpr:
* @output: the FILE * for the output
* @comp: the precompiled XPath expression
* @depth: the indentation level.
*
* Dumps the tree of the compiled XPath expression.
*/
void
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
int depth) {
int i;
char shift[100];
if ((output == NULL) || (comp == NULL)) return;
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
fprintf(output, shift);
fprintf(output, "Compiled Expression : %d elements\n",
comp->nbStep);
i = comp->last;
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
}
#ifdef XP_DEBUG_OBJ_USAGE
/*
* XPath object usage related debugging variables.
*/
static int xmlXPathDebugObjCounterUndefined = 0;
static int xmlXPathDebugObjCounterNodeset = 0;
static int xmlXPathDebugObjCounterBool = 0;
static int xmlXPathDebugObjCounterNumber = 0;
static int xmlXPathDebugObjCounterString = 0;
static int xmlXPathDebugObjCounterPoint = 0;
static int xmlXPathDebugObjCounterRange = 0;
static int xmlXPathDebugObjCounterLocset = 0;
static int xmlXPathDebugObjCounterUsers = 0;
static int xmlXPathDebugObjCounterXSLTTree = 0;
static int xmlXPathDebugObjCounterAll = 0;
static int xmlXPathDebugObjTotalUndefined = 0;
static int xmlXPathDebugObjTotalNodeset = 0;
static int xmlXPathDebugObjTotalBool = 0;
static int xmlXPathDebugObjTotalNumber = 0;
static int xmlXPathDebugObjTotalString = 0;
static int xmlXPathDebugObjTotalPoint = 0;
static int xmlXPathDebugObjTotalRange = 0;
static int xmlXPathDebugObjTotalLocset = 0;
static int xmlXPathDebugObjTotalUsers = 0;
static int xmlXPathDebugObjTotalXSLTTree = 0;
static int xmlXPathDebugObjTotalAll = 0;
static int xmlXPathDebugObjMaxUndefined = 0;
static int xmlXPathDebugObjMaxNodeset = 0;
static int xmlXPathDebugObjMaxBool = 0;
static int xmlXPathDebugObjMaxNumber = 0;
static int xmlXPathDebugObjMaxString = 0;
static int xmlXPathDebugObjMaxPoint = 0;
static int xmlXPathDebugObjMaxRange = 0;
static int xmlXPathDebugObjMaxLocset = 0;
static int xmlXPathDebugObjMaxUsers = 0;
static int xmlXPathDebugObjMaxXSLTTree = 0;
static int xmlXPathDebugObjMaxAll = 0;
/* REVISIT TODO: Make this static when committing */
static void
xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
{
if (ctxt != NULL) {
if (ctxt->objCache != NULL) {
xmlXPathObjectCachePtr cache =
(xmlXPathObjectCachePtr) ctxt->objCache;
cache->dbgCachedAll = 0;
cache->dbgCachedNodeset = 0;
cache->dbgCachedString = 0;
cache->dbgCachedBool = 0;
cache->dbgCachedNumber = 0;
cache->dbgCachedPoint = 0;
cache->dbgCachedRange = 0;
cache->dbgCachedLocset = 0;
cache->dbgCachedUsers = 0;
cache->dbgCachedXSLTTree = 0;
cache->dbgCachedUndefined = 0;
cache->dbgReusedAll = 0;
cache->dbgReusedNodeset = 0;
cache->dbgReusedString = 0;
cache->dbgReusedBool = 0;
cache->dbgReusedNumber = 0;
cache->dbgReusedPoint = 0;
cache->dbgReusedRange = 0;
cache->dbgReusedLocset = 0;
cache->dbgReusedUsers = 0;
cache->dbgReusedXSLTTree = 0;
cache->dbgReusedUndefined = 0;
}
}
xmlXPathDebugObjCounterUndefined = 0;
xmlXPathDebugObjCounterNodeset = 0;
xmlXPathDebugObjCounterBool = 0;
xmlXPathDebugObjCounterNumber = 0;
xmlXPathDebugObjCounterString = 0;
xmlXPathDebugObjCounterPoint = 0;
xmlXPathDebugObjCounterRange = 0;
xmlXPathDebugObjCounterLocset = 0;
xmlXPathDebugObjCounterUsers = 0;
xmlXPathDebugObjCounterXSLTTree = 0;
xmlXPathDebugObjCounterAll = 0;
xmlXPathDebugObjTotalUndefined = 0;
xmlXPathDebugObjTotalNodeset = 0;
xmlXPathDebugObjTotalBool = 0;
xmlXPathDebugObjTotalNumber = 0;
xmlXPathDebugObjTotalString = 0;
xmlXPathDebugObjTotalPoint = 0;
xmlXPathDebugObjTotalRange = 0;
xmlXPathDebugObjTotalLocset = 0;
xmlXPathDebugObjTotalUsers = 0;
xmlXPathDebugObjTotalXSLTTree = 0;
xmlXPathDebugObjTotalAll = 0;
xmlXPathDebugObjMaxUndefined = 0;
xmlXPathDebugObjMaxNodeset = 0;
xmlXPathDebugObjMaxBool = 0;
xmlXPathDebugObjMaxNumber = 0;
xmlXPathDebugObjMaxString = 0;
xmlXPathDebugObjMaxPoint = 0;
xmlXPathDebugObjMaxRange = 0;
xmlXPathDebugObjMaxLocset = 0;
xmlXPathDebugObjMaxUsers = 0;
xmlXPathDebugObjMaxXSLTTree = 0;
xmlXPathDebugObjMaxAll = 0;
}
static void
xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
xmlXPathObjectType objType)
{
int isCached = 0;
if (ctxt != NULL) {
if (ctxt->objCache != NULL) {
xmlXPathObjectCachePtr cache =
(xmlXPathObjectCachePtr) ctxt->objCache;
isCached = 1;
cache->dbgReusedAll++;
switch (objType) {
case XPATH_UNDEFINED:
cache->dbgReusedUndefined++;
break;
case XPATH_NODESET:
cache->dbgReusedNodeset++;
break;
case XPATH_BOOLEAN:
cache->dbgReusedBool++;
break;
case XPATH_NUMBER:
cache->dbgReusedNumber++;
break;
case XPATH_STRING:
cache->dbgReusedString++;
break;
case XPATH_POINT:
cache->dbgReusedPoint++;
break;
case XPATH_RANGE:
cache->dbgReusedRange++;
break;
case XPATH_LOCATIONSET:
cache->dbgReusedLocset++;
break;
case XPATH_USERS:
cache->dbgReusedUsers++;
break;
case XPATH_XSLT_TREE:
cache->dbgReusedXSLTTree++;
break;
default:
break;
}
}
}
switch (objType) {
case XPATH_UNDEFINED:
if (! isCached)
xmlXPathDebugObjTotalUndefined++;
xmlXPathDebugObjCounterUndefined++;
if (xmlXPathDebugObjCounterUndefined >
xmlXPathDebugObjMaxUndefined)
xmlXPathDebugObjMaxUndefined =
xmlXPathDebugObjCounterUndefined;
break;
case XPATH_NODESET:
if (! isCached)
xmlXPathDebugObjTotalNodeset++;
xmlXPathDebugObjCounterNodeset++;
if (xmlXPathDebugObjCounterNodeset >
xmlXPathDebugObjMaxNodeset)
xmlXPathDebugObjMaxNodeset =
xmlXPathDebugObjCounterNodeset;
break;
case XPATH_BOOLEAN:
if (! isCached)
xmlXPathDebugObjTotalBool++;
xmlXPathDebugObjCounterBool++;
if (xmlXPathDebugObjCounterBool >
xmlXPathDebugObjMaxBool)
xmlXPathDebugObjMaxBool =
xmlXPathDebugObjCounterBool;
break;
case XPATH_NUMBER:
if (! isCached)
xmlXPathDebugObjTotalNumber++;
xmlXPathDebugObjCounterNumber++;
if (xmlXPathDebugObjCounterNumber >
xmlXPathDebugObjMaxNumber)
xmlXPathDebugObjMaxNumber =
xmlXPathDebugObjCounterNumber;
break;
case XPATH_STRING:
if (! isCached)
xmlXPathDebugObjTotalString++;
xmlXPathDebugObjCounterString++;
if (xmlXPathDebugObjCounterString >
xmlXPathDebugObjMaxString)
xmlXPathDebugObjMaxString =
xmlXPathDebugObjCounterString;
break;
case XPATH_POINT:
if (! isCached)
xmlXPathDebugObjTotalPoint++;
xmlXPathDebugObjCounterPoint++;
if (xmlXPathDebugObjCounterPoint >
xmlXPathDebugObjMaxPoint)
xmlXPathDebugObjMaxPoint =
xmlXPathDebugObjCounterPoint;
break;
case XPATH_RANGE:
if (! isCached)
xmlXPathDebugObjTotalRange++;
xmlXPathDebugObjCounterRange++;
if (xmlXPathDebugObjCounterRange >
xmlXPathDebugObjMaxRange)
xmlXPathDebugObjMaxRange =
xmlXPathDebugObjCounterRange;
break;
case XPATH_LOCATIONSET:
if (! isCached)
xmlXPathDebugObjTotalLocset++;
xmlXPathDebugObjCounterLocset++;
if (xmlXPathDebugObjCounterLocset >
xmlXPathDebugObjMaxLocset)
xmlXPathDebugObjMaxLocset =
xmlXPathDebugObjCounterLocset;
break;
case XPATH_USERS:
if (! isCached)
xmlXPathDebugObjTotalUsers++;
xmlXPathDebugObjCounterUsers++;
if (xmlXPathDebugObjCounterUsers >
xmlXPathDebugObjMaxUsers)
xmlXPathDebugObjMaxUsers =
xmlXPathDebugObjCounterUsers;
break;
case XPATH_XSLT_TREE:
if (! isCached)
xmlXPathDebugObjTotalXSLTTree++;
xmlXPathDebugObjCounterXSLTTree++;
if (xmlXPathDebugObjCounterXSLTTree >
xmlXPathDebugObjMaxXSLTTree)
xmlXPathDebugObjMaxXSLTTree =
xmlXPathDebugObjCounterXSLTTree;
break;
default:
break;
}
if (! isCached)
xmlXPathDebugObjTotalAll++;
xmlXPathDebugObjCounterAll++;
if (xmlXPathDebugObjCounterAll >
xmlXPathDebugObjMaxAll)
xmlXPathDebugObjMaxAll =
xmlXPathDebugObjCounterAll;
}
static void
xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
xmlXPathObjectType objType)
{
int isCached = 0;
if (ctxt != NULL) {
if (ctxt->objCache != NULL) {
xmlXPathObjectCachePtr cache =
(xmlXPathObjectCachePtr) ctxt->objCache;
isCached = 1;
cache->dbgCachedAll++;
switch (objType) {
case XPATH_UNDEFINED:
cache->dbgCachedUndefined++;
break;
case XPATH_NODESET:
cache->dbgCachedNodeset++;
break;
case XPATH_BOOLEAN:
cache->dbgCachedBool++;
break;
case XPATH_NUMBER:
cache->dbgCachedNumber++;
break;
case XPATH_STRING:
cache->dbgCachedString++;
break;
case XPATH_POINT:
cache->dbgCachedPoint++;
break;
case XPATH_RANGE:
cache->dbgCachedRange++;
break;
case XPATH_LOCATIONSET:
cache->dbgCachedLocset++;
break;
case XPATH_USERS:
cache->dbgCachedUsers++;
break;
case XPATH_XSLT_TREE:
cache->dbgCachedXSLTTree++;
break;
default:
break;
}