1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2024-10-26 12:25:09 +03:00

While investigating bug #350247, I noticed that xmlSchemaIDCMatcher

* xmlschemas.c: While investigating bug #350247, I noticed
  that xmlSchemaIDCMatcher structs are massively recreated
  although only a maximum of 3 structs is used at the same
  time; added a cache for those structures to the
  validation context.
This commit is contained in:
Kasimier T. Buchcik 2006-08-15 12:52:30 +00:00
parent 6f9b0878c0
commit deb58713d7
2 changed files with 278 additions and 32 deletions

View File

@ -1,3 +1,11 @@
Tue Aug 15 14:49:18 CEST 2006 Kasimier Buchcik <libxml2-cvs@cazic.net>
* xmlschemas.c: While investigating bug #350247, I noticed
that xmlSchemaIDCMatcher structs are massively recreated
although only a maximum of 3 structs is used at the same
time; added a cache for those structures to the
validation context.
Sat Aug 12 16:12:53 CEST 2006 Daniel Veillard <daniel@veillard.com>
* xmlschemas.c: applied patch from Marton Illes to fix an allocation

View File

@ -84,6 +84,8 @@
/* #define DEBUG_IDC_NODE_TABLE */
/* #define WXS_ELEM_DECL_CONS_ENABLED */
#ifdef DEBUG_IDC
#ifndef DEBUG_IDC_NODE_TABLE
#define DEBUG_IDC_NODE_TABLE
@ -183,6 +185,8 @@ static const xmlChar *xmlNamespaceNs = (const xmlChar *)
#define WXS_PARTICLE_TERM(p) (WXS_PARTICLE(p))->children
#define WXS_PARTICLE_TERM_AS_ELEM(p) (WXS_ELEM_CAST WXS_PARTICLE_TERM(p))
#define WXS_PARTICLE_MODEL(p) WXS_MODEL_GROUP_CAST WXS_PARTICLE(p)->children
/*
* Macros for model groups definitions.
@ -242,6 +246,10 @@ static const xmlChar *xmlNamespaceNs = (const xmlChar *)
#define WXS_IS_TYPE_NOT_FIXED_1(item) \
(((item)->type != XML_SCHEMA_TYPE_BASIC) && \
(((item)->flags & XML_SCHEMAS_TYPE_FIXUP_1) == 0))
#define WXS_TYPE_IS_GLOBAL(t) ((t)->flags & XML_SCHEMAS_TYPE_GLOBAL)
#define WXS_TYPE_IS_LOCAL(t) (((t)->flags & XML_SCHEMAS_TYPE_GLOBAL) == 0)
/*
* Macros for exclusively for complex types.
*/
@ -836,12 +844,12 @@ struct _xmlSchemaIDCMatcher {
int type;
int depth; /* the tree depth at creation time */
xmlSchemaIDCMatcherPtr next; /* next in the list */
xmlSchemaIDCMatcherPtr nextCached; /* next in the cache list */
xmlSchemaIDCAugPtr aidc; /* the augmented IDC item */
int idcType;
xmlSchemaPSVIIDCKeyPtr **keySeqs; /* the key-sequences of the target
elements */
int sizeKeySeqs;
int targetDepth;
xmlSchemaItemListPtr targets; /* list of target-node
(xmlSchemaPSVIIDCNodePtr) entries */
};
@ -993,6 +1001,7 @@ struct _xmlSchemaValidCtxt {
xmlSchemaIDCStateObjPtr xpathStates; /* first active state object. */
xmlSchemaIDCStateObjPtr xpathStatePool; /* first stored state object. */
xmlSchemaIDCMatcherPtr idcMatcherCache; /* Cache for IDC matcher objects. */
xmlSchemaPSVIIDCNodePtr *idcNodes; /* list of all IDC node-table entries*/
int nbIdcNodes;
@ -19744,6 +19753,123 @@ add_member:
}
}
#ifdef WXS_ELEM_DECL_CONS_ENABLED /* enable when finished */
/**
* xmlSchemaCheckElementDeclComponent
* @pctxt: the schema parser context
* @ctxtComponent: the context component (an element declaration)
* @ctxtParticle: the first particle of the context component
* @searchParticle: the element declaration particle to be analysed
*
* Schema Component Constraint: Element Declarations Consistent
*/
static int
xmlSchemaCheckElementDeclConsistent(xmlSchemaParserCtxtPtr pctxt,
xmlSchemaBasicItemPtr ctxtComponent,
xmlSchemaParticlePtr ctxtParticle,
xmlSchemaParticlePtr searchParticle,
xmlSchemaParticlePtr curParticle,
int search)
{
return(0);
int ret = 0;
xmlSchemaParticlePtr cur = curParticle;
if (curParticle == NULL) {
return(0);
}
if (WXS_PARTICLE_TERM(curParticle) == NULL) {
/*
* Just return in this case. A missing "term" of the particle
* might arise due to an invalid "term" component.
*/
return(0);
}
while (cur != NULL) {
switch (WXS_PARTICLE_TERM(cur)->type) {
case XML_SCHEMA_TYPE_ANY:
break;
case XML_SCHEMA_TYPE_ELEMENT:
if (search == 0) {
ret = xmlSchemaCheckElementDeclConsistent(pctxt,
ctxtComponent, ctxtParticle, cur, ctxtParticle, 1);
if (ret != 0)
return(ret);
} else {
xmlSchemaElementPtr elem =
WXS_ELEM_CAST(WXS_PARTICLE_TERM(cur));
/*
* SPEC Element Declarations Consistent:
* "If the {particles} contains, either directly,
* indirectly (that is, within the {particles} of a
* contained model group, recursively) or ·implicitly·
* two or more element declaration particles with
* the same {name} and {target namespace}, then
* all their type definitions must be the same
* top-level definition [...]"
*/
if (xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->name,
WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->name) &&
xmlStrEqual(WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace,
WXS_PARTICLE_TERM_AS_ELEM(searchParticle)->targetNamespace))
{
xmlChar *strA = NULL, *strB = NULL;
xmlSchemaCustomErr(ACTXT_CAST pctxt,
/* TODO: error code */
XML_SCHEMAP_COS_NONAMBIG,
WXS_ITEM_NODE(cur), NULL,
"In the content model of %s, there are multiple "
"element declarations for '%s' with different "
"type definitions",
xmlSchemaGetComponentDesignation(&strA,
ctxtComponent),
xmlSchemaFormatQName(&strB,
WXS_PARTICLE_TERM_AS_ELEM(cur)->targetNamespace,
WXS_PARTICLE_TERM_AS_ELEM(cur)->name));
FREE_AND_NULL(strA);
FREE_AND_NULL(strB);
return(XML_SCHEMAP_COS_NONAMBIG);
}
}
break;
case XML_SCHEMA_TYPE_SEQUENCE: {
break;
}
case XML_SCHEMA_TYPE_CHOICE:{
/*
xmlSchemaTreeItemPtr sub;
sub = WXS_PARTICLE_TERM(particle)->children; (xmlSchemaParticlePtr)
while (sub != NULL) {
ret = xmlSchemaCheckElementDeclConsistent(pctxt, ctxtComponent,
ctxtParticle, ctxtElem);
if (ret != 0)
return(ret);
sub = sub->next;
}
*/
break;
}
case XML_SCHEMA_TYPE_ALL:
break;
case XML_SCHEMA_TYPE_GROUP:
break;
default:
xmlSchemaInternalErr2(ACTXT_CAST pctxt,
"xmlSchemaCheckElementDeclConsistent",
"found unexpected term of type '%s' in content model",
WXS_ITEM_TYPE_NAME(WXS_PARTICLE_TERM(cur)), NULL);
return(-1);
}
cur = (xmlSchemaParticlePtr) cur->next;
}
exit:
return(ret);
}
#endif
/**
* xmlSchemaCheckElementDeclComponent
* @item: an schema element declaration/particle
@ -19751,8 +19877,7 @@ add_member:
* @name: the name of the attribute
*
* Validates the value constraints of an element declaration.
*
* Fixes finish doing the computations on the element declarations.
* Adds substitution group members.
*/
static void
xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl,
@ -19763,8 +19888,12 @@ xmlSchemaCheckElementDeclComponent(xmlSchemaElementPtr elemDecl,
if (elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED)
return;
elemDecl->flags |= XML_SCHEMAS_ELEM_INTERNAL_CHECKED;
if (xmlSchemaCheckElemPropsCorrect(ctxt, elemDecl) == 0)
xmlSchemaCheckElemSubstGroup(ctxt, elemDecl);
if (xmlSchemaCheckElemPropsCorrect(ctxt, elemDecl) == 0) {
/*
* Adds substitution group members.
*/
xmlSchemaCheckElemSubstGroup(ctxt, elemDecl);
}
}
/**
@ -20587,6 +20716,7 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
xmlSchemaTreeItemPtr item, *items;
int nbItems, i, ret = 0;
xmlSchemaBucketPtr oldbucket = con->bucket;
xmlSchemaElementPtr elemDecl;
#define FIXHFAILURE if (pctxt->err == XML_SCHEMAP_INTERNAL) goto exit_failure;
@ -20860,7 +20990,7 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
if (pctxt->nberrors != 0)
goto exit_error;
/*
* At this point we need all simple types to be builded and checked.
* At this point we need build and check all simple types.
*/
/*
* Apply contraints for attribute declarations.
@ -20927,8 +21057,8 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
if (pctxt->nberrors != 0)
goto exit_error;
/*
* Fixup complex types.
/*
* Complex types are builded and checked.
*/
for (i = 0; i < nbItems; i++) {
item = con->pending->items[i];
@ -20951,11 +21081,8 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
* will create particles and model groups in some cases.
*/
items = (xmlSchemaTreeItemPtr *) con->pending->items;
nbItems = con->pending->nbItems;
/*
* At this point all complex types need to be builded and checked.
*/
nbItems = con->pending->nbItems;
/*
* Apply some constraints for element declarations.
*/
@ -20963,13 +21090,30 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
item = items[i];
switch (item->type) {
case XML_SCHEMA_TYPE_ELEMENT:
elemDecl = (xmlSchemaElementPtr) item;
if ((((xmlSchemaElementPtr) item)->flags &
XML_SCHEMAS_ELEM_INTERNAL_CHECKED) == 0) {
if ((elemDecl->flags & XML_SCHEMAS_ELEM_INTERNAL_CHECKED) == 0)
{
xmlSchemaCheckElementDeclComponent(
(xmlSchemaElementPtr) item, pctxt);
(xmlSchemaElementPtr) elemDecl, pctxt);
FIXHFAILURE;
}
#ifdef WXS_ELEM_DECL_CONS_ENABLED
/*
* Schema Component Constraint: Element Declarations Consistent
* Apply this constraint to local types of element declarations.
*/
if ((WXS_ELEM_TYPEDEF(elemDecl) != NULL) &&
(WXS_IS_COMPLEX(WXS_ELEM_TYPEDEF(elemDecl))) &&
(WXS_TYPE_IS_LOCAL(WXS_ELEM_TYPEDEF(elemDecl))))
{
xmlSchemaCheckElementDeclConsistent(pctxt,
WXS_BASIC_CAST elemDecl,
WXS_TYPE_PARTICLE(WXS_ELEM_TYPEDEF(elemDecl)),
NULL, NULL, 0);
}
#endif
break;
default:
break;
@ -20977,6 +21121,7 @@ xmlSchemaFixupComponents(xmlSchemaParserCtxtPtr pctxt,
}
if (pctxt->nberrors != 0)
goto exit_error;
/*
* Finally we can build the automaton from the content model of
* complex types.
@ -22013,7 +22158,7 @@ xmlSchemaIDCFreeMatcherList(xmlSchemaIDCMatcherPtr matcher)
while (matcher != NULL) {
next = matcher->next;
if (matcher->keySeqs != NULL) {
if (matcher->keySeqs != NULL) {
int i;
for (i = 0; i < matcher->sizeKeySeqs; i++)
if (matcher->keySeqs[i] != NULL)
@ -22043,6 +22188,63 @@ xmlSchemaIDCFreeMatcherList(xmlSchemaIDCMatcherPtr matcher)
}
}
/**
* xmlSchemaIDCReleaseMatcherList:
* @vctxt: the WXS validation context
* @matcher: the first IDC matcher in the list
*
* Caches a list of IDC matchers for reuse.
*/
static void
xmlSchemaIDCReleaseMatcherList(xmlSchemaValidCtxtPtr vctxt,
xmlSchemaIDCMatcherPtr matcher)
{
xmlSchemaIDCMatcherPtr next;
while (matcher != NULL) {
next = matcher->next;
if (matcher->keySeqs != NULL) {
int i;
/*
* Don't free the array, but only the content.
*/
for (i = 0; i < matcher->sizeKeySeqs; i++)
if (matcher->keySeqs[i] != NULL) {
xmlFree(matcher->keySeqs[i]);
matcher->keySeqs[i] = NULL;
}
}
if (matcher->targets) {
if (matcher->idcType == XML_SCHEMA_TYPE_IDC_KEYREF) {
int i;
xmlSchemaPSVIIDCNodePtr idcNode;
/*
* Node-table items for keyrefs are not stored globally
* to the validation context, since they are not bubbled.
* We need to free them here.
*/
for (i = 0; i < matcher->targets->nbItems; i++) {
idcNode =
(xmlSchemaPSVIIDCNodePtr) matcher->targets->items[i];
xmlFree(idcNode->keys);
xmlFree(idcNode);
}
}
xmlSchemaItemListFree(matcher->targets);
matcher->targets = NULL;
}
matcher->next = NULL;
/*
* Cache the matcher.
*/
if (vctxt->idcMatcherCache != NULL)
matcher->nextCached = vctxt->idcMatcherCache;
vctxt->idcMatcherCache = matcher;
matcher = next;
}
}
/**
* xmlSchemaIDCAddStateObject:
* @vctxt: the WXS validation context
@ -22823,7 +23025,7 @@ deregister_check:
/*
* Link it to the pool of reusable state objects.
*/
vctxt->xpathStatePool = sto;
vctxt->xpathStatePool = sto;
sto = nextsto;
} else
sto = sto->next;
@ -22920,14 +23122,23 @@ xmlSchemaIDCRegisterMatchers(xmlSchemaValidCtxtPtr vctxt,
/*
* Create an IDC matcher for every IDC definition.
*/
matcher = (xmlSchemaIDCMatcherPtr)
xmlMalloc(sizeof(xmlSchemaIDCMatcher));
if (matcher == NULL) {
xmlSchemaVErrMemory(vctxt,
"allocating an IDC matcher", NULL);
return (-1);
if (vctxt->idcMatcherCache != NULL) {
/*
* Reuse a cached matcher.
*/
matcher = vctxt->idcMatcherCache;
vctxt->idcMatcherCache = matcher->nextCached;
matcher->nextCached = NULL;
} else {
matcher = (xmlSchemaIDCMatcherPtr)
xmlMalloc(sizeof(xmlSchemaIDCMatcher));
if (matcher == NULL) {
xmlSchemaVErrMemory(vctxt,
"allocating an IDC matcher", NULL);
return (-1);
}
memset(matcher, 0, sizeof(xmlSchemaIDCMatcher));
}
memset(matcher, 0, sizeof(xmlSchemaIDCMatcher));
if (last == NULL)
vctxt->inode->idcMatchers = matcher;
else
@ -23673,8 +23884,14 @@ xmlSchemaValidatorPushAttribute(xmlSchemaValidCtxtPtr vctxt,
return (0);
}
/**
* xmlSchemaClearElemInfo:
* @vctxt: the WXS validation context
* @ielem: the element information item
*/
static void
xmlSchemaClearElemInfo(xmlSchemaNodeInfoPtr ielem)
xmlSchemaClearElemInfo(xmlSchemaValidCtxtPtr vctxt,
xmlSchemaNodeInfoPtr ielem)
{
ielem->hasKeyrefs = 0;
ielem->appliedXPath = 0;
@ -23700,9 +23917,13 @@ xmlSchemaClearElemInfo(xmlSchemaNodeInfoPtr ielem)
}
if (ielem->idcMatchers != NULL) {
/*
* URGENT OPTIMIZE TODO: Use a pool of IDC matchers.
* REVISIT OPTIMIZE TODO: Use a pool of IDC matchers.
* Does it work?
*/
xmlSchemaIDCReleaseMatcherList(vctxt, ielem->idcMatchers);
#if 0
xmlSchemaIDCFreeMatcherList(ielem->idcMatchers);
#endif
ielem->idcMatchers = NULL;
}
if (ielem->idcTable != NULL) {
@ -26068,7 +26289,7 @@ end_elem:
* VAL TODO: Don't free the PSVI IDC tables if they are
* requested for the PSVI.
*/
xmlSchemaClearElemInfo(inode);
xmlSchemaClearElemInfo(vctxt, inode);
/*
* Skip further processing if we are on the validation root.
*/
@ -27168,6 +27389,18 @@ xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt)
} while (cur != NULL);
vctxt->aidcs = NULL;
}
if (vctxt->idcMatcherCache != NULL) {
xmlSchemaIDCMatcherPtr matcher = vctxt->idcMatcherCache, tmp;
while (matcher) {
tmp = matcher;
matcher = matcher->nextCached;
xmlSchemaIDCFreeMatcherList(tmp);
}
vctxt->idcMatcherCache = NULL;
}
if (vctxt->idcNodes != NULL) {
int i;
xmlSchemaPSVIIDCNodePtr item;
@ -27180,6 +27413,7 @@ xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt)
xmlFree(vctxt->idcNodes);
vctxt->idcNodes = NULL;
vctxt->nbIdcNodes = 0;
vctxt->sizeIdcNodes = 0;
}
/*
* Note that we won't delete the XPath state pool here.
@ -27205,7 +27439,7 @@ xmlSchemaClearValidCtxt(xmlSchemaValidCtxtPtr vctxt)
ei = vctxt->elemInfos[i];
if (ei == NULL)
break;
xmlSchemaClearElemInfo(ei);
xmlSchemaClearElemInfo(vctxt, ei);
}
}
xmlSchemaItemListClear(vctxt->nodeQNames);
@ -27251,10 +27485,14 @@ xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
xmlFree(ctxt->idcKeys);
}
if (ctxt->xpathStates != NULL)
if (ctxt->xpathStates != NULL) {
xmlSchemaFreeIDCStateObjList(ctxt->xpathStates);
if (ctxt->xpathStatePool != NULL)
ctxt->xpathStates = NULL;
}
if (ctxt->xpathStatePool != NULL) {
xmlSchemaFreeIDCStateObjList(ctxt->xpathStatePool);
ctxt->xpathStatePool = NULL;
}
/*
* Augmented IDC information.
@ -27288,7 +27526,7 @@ xmlSchemaFreeValidCtxt(xmlSchemaValidCtxtPtr ctxt)
ei = ctxt->elemInfos[i];
if (ei == NULL)
break;
xmlSchemaClearElemInfo(ei);
xmlSchemaClearElemInfo(ctxt, ei);
xmlFree(ei);
}
xmlFree(ctxt->elemInfos);