jkesselm 02/01/23 14:53:47
Modified: java/src/org/apache/xalan/templates ElemTemplate.java
java/src/org/apache/xalan/transformer TransformerImpl.java
java/src/org/apache/xml/dtm DTMManager.java
java/src/org/apache/xml/dtm/ref DTMDefaultBase.java
DTMManagerDefault.java
java/src/org/apache/xml/dtm/ref/sax2dtm SAX2DTM.java
java/src/org/apache/xpath XPathContext.java
Added: java/src/org/apache/xml/dtm/ref/sax2dtm SAX2RTFDTM.java
Log:
These changes allow us to store multiple Result Tree Fragment (RTF)
document trees (used when an XSLT variable contains a constructed
set of nodes) into a single DTM object rather than using a new DTM
for each RTF. They also permit "tail-pruning" this shared DTM to
reuse that space as the variables go out of scope.
The result is a slight performance improvement, and a much more
significant improvement in storage efficiency. Stylesheets which
use RTFs heavily should now run in much less memory; in
one testcase, our "working set" heap size (storage actually in
use, not counting objects released but not yet GC'd) dropped
from 12-15MB down to 3-6MB, and heap churn (how quickly
storage was being allocated and discarded) also reduced
substantially.
The code changes needed to support this new scheme are
surprisingly small. And I believe it may be possible to reduce them
further, if we're willing to merge the SAX2RTFDTM subclass back
into its SAX2DTM superclass. I believe that could be done with
very little adverse impact on other uses of SAX2DTM... but I felt it
was safer to defer that decision for now.
Revision Changes Path
1.14 +6 -2
xml-xalan/java/src/org/apache/xalan/templates/ElemTemplate.java
Index: ElemTemplate.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/templates/ElemTemplate.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- ElemTemplate.java 12 Jun 2001 19:15:11 -0000 1.13
+++ ElemTemplate.java 23 Jan 2002 22:53:46 -0000 1.14
@@ -91,7 +91,6 @@
*/
public class ElemTemplate extends ElemTemplateElement
{
-
/** The public identifier for the current document event.
* @serial */
private String m_publicId;
@@ -424,6 +423,9 @@
if (TransformerImpl.S_DEBUG)
transformer.getTraceManager().fireTraceEvent(this);
+ XPathContext xctxt = transformer.getXPathContext();
+ xctxt.pushRTFContext();
+
// %REVIEW% commenting out of the code below.
// if (null != sourceNode)
// {
@@ -437,7 +439,9 @@
//
// //"sourceNode is null in handleApplyTemplatesInstruction!");
// }
- }
+
+ xctxt.popRTFContext();
+ }
/**
* This function is called during recomposition to
1.117 +21 -5
xml-xalan/java/src/org/apache/xalan/transformer/TransformerImpl.java
Index: TransformerImpl.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xalan/transformer/TransformerImpl.java,v
retrieving revision 1.116
retrieving revision 1.117
diff -u -r1.116 -r1.117
--- TransformerImpl.java 6 Nov 2001 16:50:48 -0000 1.116
+++ TransformerImpl.java 23 Jan 2002 22:53:46 -0000 1.117
@@ -1704,11 +1704,17 @@
{
XPathContext xctxt = m_xcontext;
- DTM dtmFrag = xctxt.getDTM(null, true, this, false, false);
+
+ // Retrieve a DTM to contain the RTF. At this writing, this may be a
+ // multi-document DTM (SAX2RTFDTM).
+ DTM dtmFrag = xctxt.getRTFDTM();
ContentHandler rtfHandler = dtmFrag.getContentHandler();
- // Create a ResultTreeFrag object.
- int resultFragment = resultFragment = dtmFrag.getDocument();
+ // Obtain the ResultTreeFrag's root node.
+ // NOTE: In SAX2RTFDTM, this value isn't available until after
+ // the startDocument has been issued, so assignment has been moved
+ // down a bit in the code.
+ int resultFragment; // not yet reliably = dtmFrag.getDocument();
// Save the current result tree handler.
ResultTreeHandler savedRTreeHandler = this.m_resultTreeHandler;
@@ -1721,7 +1727,12 @@
try
{
rth.startDocument();
-
+
+ // startDocument is "bottlenecked" in RTH. We need it acted upon
immediately,
+ // to set the DTM's state as in-progress, so that if the
xsl:variable's body causes
+ // further RTF activity we can keep that from bashing this DTM.
+ rth.flushPending();
+
try
{
@@ -1730,7 +1741,12 @@
// Make sure everything is flushed!
rth.flushPending();
- }
+
+ // Get the document ID. May not exist until the RTH has not only
+ // recieved, but flushed, the startDocument... so waiting until
+ // just before the end seems simplest/safest.
+ resultFragment = dtmFrag.getDocument();
+ }
finally
{
rth.endDocument();
1.9 +3 -2 xml-xalan/java/src/org/apache/xml/dtm/DTMManager.java
Index: DTMManager.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xml/dtm/DTMManager.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- DTMManager.java 26 Nov 2001 22:08:28 -0000 1.8
+++ DTMManager.java 23 Jan 2002 22:53:47 -0000 1.9
@@ -215,8 +215,9 @@
* always be returned. Otherwise it is up to the DTMManager to return a
* new instance or an instance that it already created and may be being
used
* by someone else.
- * (I think more parameters will need to be added for error handling, and
entity
- * resolution).
+ *
+ * (More parameters may eventually need to be added for error handling
+ * and entity resolution, and to better control selection of
implementations.)
*
* @param source the specification of the source object, which may be null,
* in which case it is assumed that node construction will
take
1.25 +8 -7
xml-xalan/java/src/org/apache/xml/dtm/ref/DTMDefaultBase.java
Index: DTMDefaultBase.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/DTMDefaultBase.java,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -r1.24 -r1.25
--- DTMDefaultBase.java 18 Dec 2001 21:55:33 -0000 1.24
+++ DTMDefaultBase.java 23 Jan 2002 22:53:47 -0000 1.25
@@ -1138,15 +1138,13 @@
}
else
{
- // Most recent?
+ // Most recent. May be -1 (none) if DTM was pruned.
// %OPT% Is there a lastElement() method? Should there be?
int last=m_namespaceDeclSetElements.size()-1;
-
- if(elementNodeIndex==
- m_namespaceDeclSetElements.elementAt(last))
+
+ if(last>=0 &&
elementNodeIndex==m_namespaceDeclSetElements.elementAt(last))
{
nsList=(SuballocatedIntVector)m_namespaceDeclSets.elementAt(last);
-
}
}
if(nsList==null)
@@ -1391,8 +1389,11 @@
}
/**
- * Given a node handle, find the owning document node.
- *
+ * Find the Document node handle for the document currently under
construction.
+ * PLEASE NOTE that most people should use getOwnerDocument(nodeHandle)
instead;
+ * this version of the operation is primarily intended for use during
negotiation
+ * with the DTM Manager.
+ *
* @param nodeHandle the id of the node.
* @return int Node handle of document, which should always be valid.
*/
1.33 +21 -5
xml-xalan/java/src/org/apache/xml/dtm/ref/DTMManagerDefault.java
Index: DTMManagerDefault.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/DTMManagerDefault.java,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -r1.32 -r1.33
--- DTMManagerDefault.java 10 Dec 2001 20:55:50 -0000 1.32
+++ DTMManagerDefault.java 23 Jan 2002 22:53:47 -0000 1.33
@@ -73,6 +73,7 @@
import org.apache.xml.utils.SystemIDResolver;
import org.apache.xml.dtm.ref.dom2dtm.DOM2DTM;
import org.apache.xml.dtm.ref.sax2dtm.SAX2DTM;
+import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
// W3C DOM
import org.w3c.dom.Document;
@@ -190,7 +191,7 @@
}
/**
- * Get the first free DTM ID available.
+ * Get the first free DTM ID available. %OPT% Linear search is inefficient!
*/
public int getFirstFreeDTMID()
{
@@ -229,8 +230,13 @@
* always be returned. Otherwise it is up to the DTMManager to return a
* new instance or an instance that it already created and may be being
used
* by someone else.
+ *
+ * A bit of magic in this implementation: If the source is null, unique is
true,
+ * and incremental and doIndexing are both false, we return an instance of
+ * SAX2RTFDTM, which see.
+ *
* (I think more parameters will need to be added for error handling, and
entity
- * resolution).
+ * resolution, and more explicit control of the RTF situation).
*
* @param source the specification of the source object.
* @param unique true if the returned DTM must be unique, probably because
it
@@ -314,9 +320,19 @@
}
}
- // Create the basic SAX2DTM.
- SAX2DTM dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
- xstringFactory, doIndexing);
+ SAX2DTM dtm;
+ if(source==null && unique && !incremental && !doIndexing)
+ {
+ // Special case to support RTF construction into shared DTM.
+ // It should actually still work for other uses,
+ // but may be slightly deoptimized relative to the base
+ // to allow it to deal with carrying multiple documents.
+ dtm = new SAX2RTFDTM(this, source, documentID,
whiteSpaceFilter,
+ xstringFactory, doIndexing);
+ }
+ else // Create the basic SAX2DTM.
+ dtm = new SAX2DTM(this, source, documentID, whiteSpaceFilter,
+ xstringFactory, doIndexing);
// Go ahead and add the DTM to the lookup table. This needs to be
// done before any parsing occurs.
1.24 +35 -28
xml-xalan/java/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java
Index: SAX2DTM.java
===================================================================
RCS file:
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/ref/sax2dtm/SAX2DTM.java,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- SAX2DTM.java 13 Dec 2001 21:35:40 -0000 1.23
+++ SAX2DTM.java 23 Jan 2002 22:53:47 -0000 1.24
@@ -111,28 +111,39 @@
* %REVIEW% Should this have an option of being shared across DTMs?
* Sequentially only; not threadsafe... Currently, I think not.
*
- * %REVIEW% Initial size should be pushed way down to reduce weight of
RTFs,
- * pending reduction in number of RTFs.
- * However, I've got a bug in whitespace normalization to fix first.
+ * %REVIEW% Initial size was pushed way down to reduce weight of RTFs.
+ * pending reduction in number of RTF DTMs. Now that we're sharing a DTM
+ * between RTFs, and tail-pruning... consider going back to the
larger/faster.
+ *
+ * Made protected rather than private so SAX2RTFDTM can access it.
*/
//private FastStringBuffer m_chars = new FastStringBuffer(13, 13);
- private FastStringBuffer m_chars = new FastStringBuffer(5, 13);
+ protected FastStringBuffer m_chars = new FastStringBuffer(5, 13);
- /** This vector holds offset and length data. */
+ /** This vector holds offset and length data.
+ */
protected SuballocatedIntVector m_data;
- /** The parent stack, needed only for construction. */
- transient private IntStack m_parents = new IntStack();
+ /** The parent stack, needed only for construction.
+ * Made protected rather than private so SAX2RTFDTM can access it.
+ */
+ transient protected IntStack m_parents = new IntStack();
- /** The current previous node, needed only for construction time. */
- transient private int m_previous = 0;
+ /** The current previous node, needed only for construction time.
+ * Made protected rather than private so SAX2RTFDTM can access it.
+ */
+ transient protected int m_previous = 0;
- /** Namespace support, only relevent at construction time. */
- transient private java.util.Vector m_prefixMappings =
+ /** Namespace support, only relevent at construction time.
+ * Made protected rather than private so SAX2RTFDTM can access it.
+ */
+ transient protected java.util.Vector m_prefixMappings =
new java.util.Vector();
- /** Namespace support, only relevent at construction time. */
- transient private IntStack m_contextIndexes = new IntStack();
+ /** Namespace support, only relevent at construction time.
+ * Made protected rather than private so SAX2RTFDTM can access it.
+ */
+ transient protected IntStack m_contextIndexes = new IntStack();
/** Type of next characters() event within text block in prgress. */
transient private int m_textType = DTM.TEXT_NODE;
@@ -155,8 +166,10 @@
/** pool of string values that come as strings. */
private DTMStringPool m_valuesOrPrefixes = new DTMStringPool();
- /** End document has been reached. */
- private boolean m_endDocumentOccured = false;
+ /** End document has been reached.
+ * Made protected rather than private so SAX2RTFDTM can access it.
+ */
+ protected boolean m_endDocumentOccured = false;
/** Data or qualified name values, one array element for each node. */
protected SuballocatedIntVector m_dataOrQName;
@@ -1140,9 +1153,12 @@
*/
public XMLString getStringValue(int nodeHandle)
{
-
int identity = makeNodeIdentity(nodeHandle);
- int type = _type(identity);
+ int type;
+ if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint
it
+ type = DTM.NULL;
+ else
+ type= _type(identity);
if (isTextType(type))
{
@@ -1488,11 +1504,6 @@
/**
* Receive notification of the beginning of the document.
*
- * <p>By default, do nothing. Application writers may override this
- * method in a subclass to take specific actions at the beginning
- * of a document (such as allocating the root node of a tree or
- * creating an output file).</p>
- *
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startDocument
@@ -1516,11 +1527,6 @@
/**
* Receive notification of the end of the document.
*
- * <p>By default, do nothing. Application writers may override this
- * method in a subclass to take specific actions at the end
- * of a document (such as finalising a tree or closing an output
- * file).</p>
- *
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endDocument
@@ -1699,7 +1705,8 @@
int elemNode = addNode(DTM.ELEMENT_NODE, exName,
m_parents.peek(), m_previous, prefixIndex, true);
- indexNode(exName, elemNode);
+ if(m_indexing)
+ indexNode(exName, elemNode);
m_parents.push(elemNode);
1.1
xml-xalan/java/src/org/apache/xml/dtm/ref/sax2dtm/SAX2RTFDTM.java
Index: SAX2RTFDTM.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, Lotus
* Development Corporation., http://www.lotus.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xml.dtm.ref.sax2dtm;
import java.util.Hashtable;
import java.util.Vector;
import javax.xml.transform.Source;
import javax.xml.transform.SourceLocator;
import org.apache.xalan.transformer.XalanProperties;
import org.apache.xalan.res.XSLTErrorResources;
import org.apache.xalan.res.XSLMessages;
import org.apache.xml.dtm.*;
import org.apache.xml.dtm.ref.*;
import org.apache.xml.utils.StringVector;
import org.apache.xml.utils.IntVector;
import org.apache.xml.utils.FastStringBuffer;
import org.apache.xml.utils.IntStack;
import org.apache.xml.utils.SuballocatedIntVector;
import org.apache.xml.utils.SystemIDResolver;
import org.apache.xml.utils.WrappedRuntimeException;
import org.apache.xml.utils.XMLCharacterRecognizer;
import org.apache.xml.utils.XMLString;
import org.apache.xml.utils.XMLStringFactory;
import org.xml.sax.*;
import org.xml.sax.ext.*;
/**
* This is a subclass of SAX2DTM which has been modified to meet the needs of
* Result Tree Frameworks (RTFs). The differences are:
*
* 1) Multiple XML trees may be appended to the single DTM. This means
* that the root node of each document is _not_ node 0. Some code has
* had to be deoptimized to support this mode of operation, and an
* explicit mechanism for obtaining the Node Handle of the root node
* has been provided.
*
* 2) A stack of these documents is maintained, allowing us to "tail-prune"
the
* most recently added trees off the end of the DTM as stylesheet elements
* (and thus variable contexts) are exited.
*
* PLEASE NOTE that this class may be _heavily_ dependent upon the
* internals of the SAX2DTM superclass, and must be maintained in
* parallel with that code. Arguably, they should be conditionals
* within a single class... but they have deen separated for
* performance reasons. (In fact, one could even argue about which is
* the superclass and which is the subclass; the current arrangement
* is as much about preserving stability of existing code during
* development as anything else.)
*
* %REVIEW% In fact, since the differences are so minor, I think it
* may be possible/practical to fold them back into the base
* SAX2DTM. Consider that as a future code-size optimization.
* */
public class SAX2RTFDTM extends SAX2DTM
{
/** Set true to monitor SAX events and similar diagnostic info. */
private static final boolean DEBUG = false;
/** Most recently started Document, or null if the DTM is empty. */
private int m_currentDocumentNode=NULL;
/** Tail-pruning mark: Number of nodes in use */
IntStack mark_size=new IntStack();
/** Tail-pruning mark: Number of data items in use */
IntStack mark_data_size=new IntStack();
/** Tail-pruning mark: Number of size-of-data fields in use */
IntStack mark_char_size=new IntStack();
/** Tail-pruning mark: Number of dataOrQName slots in use */
IntStack mark_doq_size=new IntStack();
/** Tail-pruning mark: Number of namespace declaration sets in use
* %REVIEW% I don't think number of NS sets is ever different from number
* of NS elements. We can probabably reduce these to a single stack and save
* some storage.
* */
IntStack mark_nsdeclset_size=new IntStack();
/** Tail-pruning mark: Number of naespace declaration elements in use
* %REVIEW% I don't think number of NS sets is ever different from number
* of NS elements. We can probabably reduce these to a single stack and save
* some storage.
*/
IntStack mark_nsdeclelem_size=new IntStack();
public SAX2RTFDTM(DTMManager mgr, Source source, int dtmIdentity,
DTMWSFilter whiteSpaceFilter,
XMLStringFactory xstringfactory,
boolean doIndexing)
{
super(mgr, source, dtmIdentity, whiteSpaceFilter,
xstringfactory, doIndexing);
}
/**
* Given a DTM, find the owning document node. In the case of
* SAX2RTFDTM, which may contain multiple documents, this returns
* the <b>most recently started</b> document, or null if the DTM is
* empty or no document is currently under construction.
*
* %REVIEW% Should we continue to report the most recent after
* construction has ended? I think not, given that it may have been
* tail-pruned.
*
* @param nodeHandle the id of the node.
* @return int Node handle of Document node, or null if this DTM does not
* contain an "active" document.
* */
public int getDocument()
{
return makeNodeHandle(m_currentDocumentNode);
}
/**
* Given a node handle, find the owning document node. This has the exact
* same semantics as the DOM Document method of the same name, in that if
* the nodeHandle is a document node, it will return NULL.
*
* <p>%REVIEW% Since this is DOM-specific, it may belong at the DOM
* binding layer. Included here as a convenience function and to
* aid porting of DOM code to DTM.</p>
*
* @param nodeHandle the id of the node.
* @return int Node handle of owning document, or -1 if the nodeHandle is
* a document.
*/
public int getOwnerDocument(int nodeHandle)
{
for(int id=makeNodeIdentity(nodeHandle);
id!=NULL;
id=_parent(id))
if(_type(id)==DTM.DOCUMENT_NODE)
return id;
return DTM.NULL;
}
/**
* Receive notification of the beginning of a new RTF document.
*
* %REVIEW% Y'know, this isn't all that much of a deoptimization. We
* might want to consider folding the start/endDocument changes back
* into the main SAX2DTM so we don't have to expose so many fields
* (even as Protected) and carry the additional code.
*
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startDocument
* */
public void startDocument() throws SAXException
{
// Re-initialize the tree append process
m_endDocumentOccured = false;
m_prefixMappings = new java.util.Vector();
m_contextIndexes = new IntStack();
m_parents = new IntStack();
m_currentDocumentNode=m_size;
super.startDocument();
}
/**
* Receive notification of the end of the document.
*
* %REVIEW% Y'know, this isn't all that much of a deoptimization. We
* might want to consider folding the start/endDocument changes back
* into the main SAX2DTM so we don't have to expose so many fields
* (even as Protected).
*
* @throws SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#endDocument
* */
public void endDocument() throws SAXException
{
charactersFlush();
m_nextsib.setElementAt(NULL,m_currentDocumentNode);
if (m_firstch.elementAt(m_currentDocumentNode) == NOTPROCESSED)
m_firstch.setElementAt(NULL,m_currentDocumentNode);
if (DTM.NULL != m_previous)
m_nextsib.setElementAt(DTM.NULL,m_previous);
m_parents = null;
m_prefixMappings = null;
m_contextIndexes = null;
m_currentDocumentNode= NULL; // no longer open
m_endDocumentOccured = true;
}
/** "Tail-pruning" support for RTFs.
*
* This function pushes information about the current size of the
* DTM's data structures onto a stack, for use by popRewindMark()
* (which see).
*
* %REVIEW% I have no idea how to rewind m_elemIndexes. However,
* RTFs will not be indexed, so I can simply panic if that case
* arises. Hey, it works...
* */
public void pushRewindMark()
{
if(m_indexing || m_elemIndexes!=null)
throw new java.lang.NullPointerException("Coding error; Don't try to
mark/rewind an indexed DTM");
// Values from DTMDefaultBase
// %REVIEW% Can the namespace stack sizes ever differ? If not, save space!
mark_size.push(m_size);
mark_nsdeclset_size.push( (m_namespaceDeclSets==null) ? 0 :
m_namespaceDeclSets.size() );
mark_nsdeclelem_size.push( (m_namespaceDeclSetElements==null) ? 0 :
m_namespaceDeclSetElements.size() );
// Values from SAX2DTM
mark_data_size.push(m_data.size());
mark_char_size.push(m_chars.size());
mark_doq_size.push(m_dataOrQName.size());
}
/** "Tail-pruning" support for RTFs.
*
* This function pops the information previously saved by
* pushRewindMark (which see) and uses it to discard all nodes added
* to the DTM after that time. We expect that this will allow us to
* reuse storage more effectively.
*
* This is _not_ intended to be called while a document is still being
* constructed -- only between endDocument and the next startDocument
*
* %REVIEW% WARNING: This is the first use of some of the truncation
* methods. If Xalan blows up after this is called, that's a likely
* place to check.
*
* %REVIEW% Our original design for DTMs permitted them to share
* string pools. If there any risk that this might be happening, we
* can _not_ rewind and recover the string storage. One solution
* might to assert that DTMs used for RTFs Must Not take advantage
* of that feature, but this seems excessively fragile. Another, much
* less attractive, would be to just let them leak... Nah.
*
* @return true if and only if the pop completely emptied the
* RTF. That response is used when determining how to unspool
* RTF-started-while-RTF-open situations.
* */
public boolean popRewindMark()
{
boolean top=mark_size.empty();
m_size=top ? 0 : mark_size.pop();
m_exptype.setSize(m_size);
m_firstch.setSize(m_size);
m_nextsib.setSize(m_size);
m_prevsib.setSize(m_size);
m_parent.setSize(m_size);
m_elemIndexes=null;
int ds= top ? 0 : mark_nsdeclset_size.pop();
if (m_namespaceDeclSets!=null)
m_namespaceDeclSets.setSize(ds);
int ds1= top ? 0 : mark_nsdeclelem_size.pop();
if (m_namespaceDeclSetElements!=null)
m_namespaceDeclSetElements.setSize(ds1);
// Values from SAX2DTM
m_data.setSize(top ? 0 : mark_data_size.pop());
m_chars.setLength(top ? 0 : mark_char_size.pop());
m_dataOrQName.setSize(top ? 0 : mark_doq_size.pop());
// Return true iff DTM now empty
return m_size==0;
}
/** @return true if a DTM tree is currently under construction.
* */
public boolean isTreeIncomplete()
{
return !m_endDocumentOccured;
}
}
1.32 +123 -1 xml-xalan/java/src/org/apache/xpath/XPathContext.java
Index: XPathContext.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xpath/XPathContext.java,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- XPathContext.java 11 Dec 2001 17:13:31 -0000 1.31
+++ XPathContext.java 23 Jan 2002 22:53:47 -0000 1.32
@@ -61,6 +61,7 @@
import java.io.IOException;
import java.util.Stack;
+import java.util.Vector;
import java.lang.reflect.Method;
@@ -112,6 +113,9 @@
import org.apache.xpath.axes.DescendantIterator;
+// For RTF handling.
+import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
+
/**
* <meta name="usage" content="advanced"/>
* Default class for the runtime execution context for XPath.
@@ -121,6 +125,21 @@
public class XPathContext extends DTMManager // implements ExpressionContext
{
/**
+ * Stack of cached "reusable" DTMs for Result Tree Fragments.
+ * This is a kluge to handle the problem of starting an RTF before
+ * the old one is complete.
+ *
+ * %REVIEW% I'm using a Vector rather than Stack so we can reuse
+ * the DTMs if the problem occurs multiple times. I'm not sure that's
+ * really a net win versus discarding the DTM and starting a new one...
+ * but the retained RTF DTM will have been tail-pruned so should be small.
+ */
+ private Vector m_rtfdtm_stack=null;
+ /** Index of currently active RTF DTM in m_rtfdtm_stack */
+ private int m_which_rtfdtm=-1;
+
+
+ /**
* Though XPathContext context extends
* the DTMManager, it really is a proxy for this object, which
* is the real DTMManager.
@@ -181,7 +200,7 @@
{
return m_dtmManager.getDTM(nodeHandle);
}
-//
+
/**
* Given a W3C DOM node, try and return a DTM handle.
* Note: calling this may be non-optimal.
@@ -224,6 +243,16 @@
*/
public boolean release(DTM dtm, boolean shouldHardDelete)
{
+ // %REVIEW% If it's a DTM which may contain multiple Result Tree
+ // Fragments, we can't discard it unless we know not only that it
+ // is empty, but that the XPathContext itself is going away. So do
+ // _not_ accept the request. (May want to do it as part of
+ // reset(), though.)
+ if(m_rtfdtm_stack.contains(dtm))
+ {
+ return false;
+ }
+
return m_dtmManager.release(dtm, shouldHardDelete);
}
@@ -336,6 +365,11 @@
*/
public void reset()
{
+ // These couldn't be disposed of earlier (see comments in release());
zap them now.
+ if(m_rtfdtm_stack!=null)
+ for (java.util.Enumeration e = m_rtfdtm_stack.elements() ;
e.hasMoreElements() ;)
+ m_dtmManager.release((DTM)e.nextElement(), true);
+
m_dtmManager = DTMManager.newInstance(
org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
}
@@ -1149,4 +1183,92 @@
}
+ /**
+ * Get a DTM to be used as a container for a Result Tree
+ * Fragment. This will always be an instance of (derived from? equivalent
to?)
+ * SAX2DTM, since each RTF is constructed by temporarily redirecting our
SAX
+ * output to it. It may be a single DTM containing for multiple fragments,
+ * if the implementation supports that.
+ *
+ * @return a non-null DTM reference.
+ */
+ public DTM getRTFDTM()
+ {
+ SAX2RTFDTM rtfdtm;
+
+ // We probably should _NOT_ be applying whitespace filtering at this
stage!
+ //
+ // Some magic has been applied in DTMManagerDefault to recognize this
set of options
+ // and generate an instance of DTM which can contain multiple documents
+ // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result,
but
+ // I didn't want to change the manager API at this time, or expose
+ // too many dependencies on its internals. (Ideally, I'd like to move
+ // isTreeIncomplete all the way up to DTM, so we wouldn't need to
explicitly
+ // specify the subclass here.)
+
+ if(m_rtfdtm_stack==null)
+ {
+ m_rtfdtm_stack=new Vector();
+
rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
+ m_rtfdtm_stack.add(rtfdtm);
+ ++m_which_rtfdtm;
+ }
+ else
+ {
+ rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(m_which_rtfdtm);
+
+ // It might already be under construction -- the classic
example would be
+ // an xsl:variable which uses xsl:call-template as part of its
value. To
+ // handle this recursion, we have to start a new RTF DTM,
pushing the old
+ // one onto a stack so we can return to it. It is hoped that
+ // this is an uncommon case!
+ if(rtfdtm.isTreeIncomplete())
+ {
+ if(++m_which_rtfdtm < m_rtfdtm_stack.size())
+
rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(m_which_rtfdtm);
+ else
+ {
+
rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
+ m_rtfdtm_stack.add(rtfdtm);
+ }
+ }
+ }
+ return rtfdtm;
+ }
+
+ /** Push the RTFDTM's context mark, to allows discarding RTFs added after
this
+ * point. (If it doesn't exist we don't push, since we might still be able
to
+ * get away with not creating it. That requires that excessive pops be
harmless.)
+ * */
+ public void pushRTFContext()
+ {
+ if(null!=m_rtfdtm_stack)
+ ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark();
+ }
+
+ /** Pop the RTFDTM's context mark. This discards any RTFs added after the
last
+ * mark was set.
+ *
+ * If there is no RTF DTM, there's nothing to pop so this
+ * becomes a no-op. If pushes were issued before this was called, we count
on
+ * the fact that popRewindMark is defined such that overpopping just resets
+ * to empty.
+ *
+ * Complicating factor: We need to handle the case of popping back to a
previous
+ * RTF DTM, if one of the weird produce-an-RTF-to-build-an-RTF cases arose.
+ * Basically: If pop says this DTM is now empty, then return to the
previous
+ * if one exists, in whatever state we left it in. UGLY, but hopefully the
+ * situation which forces us to consider this will arise exceedingly
rarely.
+ * */
+ public void popRTFContext()
+ {
+ if(null==m_rtfdtm_stack)
+ return;
+
+ boolean
isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(m_which_rtfdtm))).popRewindMark();
+ if(isEmpty && m_which_rtfdtm>0)
+ {
+ --m_which_rtfdtm;
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]