dbertoni    00/07/25 08:12:10

  Modified:    c/src/XSLT StylesheetExecutionContextDefault.cpp
                        StylesheetExecutionContextDefault.hpp
  Log:
  Added caching if match patterns created at runtime.
  
  Revision  Changes    Path
  1.23      +199 -4    
xml-xalan/c/src/XSLT/StylesheetExecutionContextDefault.cpp
  
  Index: StylesheetExecutionContextDefault.cpp
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/c/src/XSLT/StylesheetExecutionContextDefault.cpp,v
  retrieving revision 1.22
  retrieving revision 1.23
  diff -u -r1.22 -r1.23
  --- StylesheetExecutionContextDefault.cpp     2000/07/21 19:52:57     1.22
  +++ StylesheetExecutionContextDefault.cpp     2000/07/25 15:12:06     1.23
  @@ -141,7 +141,8 @@
        m_textOutputStreams(),
        m_collationCompareFunctor(&s_defaultFunctor),
        m_liveVariablesStack(),
  -     m_variablesStack()
  +     m_variablesStack(),
  +     m_matchPatternCache()
   {
        m_liveVariablesStack.reserve(eDefaultVariablesStackSize);
   }
  @@ -183,6 +184,8 @@
        clearLiveVariablesStack();
   
        m_variablesStack.reset();
  +
  +     assert(m_matchPatternCache.size() == 0);
   }
   
   
  @@ -454,7 +457,44 @@
                        const XalanDOMString&   str,
                        const PrefixResolver&   resolver)
   {
  -     return m_xsltProcessor.createMatchPattern(str, resolver);
  +     XPath*  theResult = 0;
  +
  +     // We won't cache any xpath that has a namespace, since
  +     // we have no idea how that might be resolved.  We could
  +     // enhance XPath so that we can tell if str would match
  +     // the XPath, once the namespace is resolved, but it may
  +     // not be worth it...
  +     const unsigned int      index = indexOf(str, ':');
  +     const unsigned int      len = length(str);
  +
  +     // If we found a ':' before the end of the string, and
  +     // it's by itself (:: would indicate an axis), don't
  +     // try to cache the XPath...
  +     if (index < len - 1 && (charAt(str, index + 1) != ':'))
  +     {
  +             theResult = m_xsltProcessor.createMatchPattern(str, resolver);
  +     }
  +     else
  +     {
  +             const XPathCacheMapType::iterator       i =
  +                     m_matchPatternCache.find(str);
  +
  +             if (i != m_matchPatternCache.end())
  +             {
  +                     // Update hit time...
  +                     i->second.second = clock();
  +
  +                     theResult = i->second.first;
  +             }
  +             else
  +             {
  +                     theResult = m_xsltProcessor.createMatchPattern(str, 
resolver);
  +
  +                     addToXPathCache(str, theResult);
  +             }
  +     }
  +
  +     return theResult;
   }
   
   
  @@ -462,7 +502,10 @@
   void
   StylesheetExecutionContextDefault::returnXPath(XPath*        xpath)
   {
  -     m_xsltProcessor.returnXPath(xpath);
  +     if (isCached(xpath) == false)
  +     {
  +             m_xsltProcessor.returnXPath(xpath);
  +     }
   }
   
   
  @@ -735,7 +778,7 @@
                                                        mode);
                                }
   
  -                             
theParams.push_back(ParamsVectorType::value_type(xslParamElement->getQName(), 
theXObject));
  +                             
theParams.push_back(ParamsVectorType::value_type(&xslParamElement->getQName(), 
theXObject));
                        }
   
                        child = child->getNextSiblingElem();
  @@ -808,6 +851,9 @@
        // This matches the pushContextMarker in
        // resolveTopLevelParams().
        popContextMarker();
  +
  +     // Clear any cached XPaths...
  +     clearXPathCache();
   }
   
   
  @@ -1774,3 +1820,152 @@
        }
   }
   
  +
  +
  +bool
  +StylesheetExecutionContextDefault::isCached(const XPath*     theXPath)
  +{
  +     XPathCacheMapType::const_iterator       i =
  +             m_matchPatternCache.begin();
  +
  +     const XPathCacheMapType::const_iterator         theEnd =
  +             m_matchPatternCache.end();
  +
  +     while(i != theEnd)
  +     {
  +             if (i->second.first == theXPath)
  +             {
  +                     return true;
  +             }
  +             else
  +             {
  +                     ++i;
  +             }
  +     }
  +
  +     return false;
  +}
  +
  +
  +
  +// I should be able to make this out of a
  +// bunch of compose<> and select2nd<> adapters...
  +template<class Type>
  +class XPathCacheReturnFunctor
  +{
  +public:
  +
  +     XPathCacheReturnFunctor(XSLTEngineImpl&         xsltProcessor) :
  +             m_xsltProcessor(xsltProcessor)
  +     {
  +     }
  +
  +     void
  +     operator()(const Type&  theCacheEntry)
  +     {
  +             m_xsltProcessor.returnXPath(theCacheEntry.second.first);
  +     }
  +
  +private:
  +
  +     XSLTEngineImpl&         m_xsltProcessor;
  +};
  +
  +
  +
  +void
  +StylesheetExecutionContextDefault::clearXPathCache()
  +{
  +#if !defined(XALAN_NO_NAMESPACES)
  +     using std::for_each;
  +#endif
  +
  +     for_each(m_matchPatternCache.begin(),
  +                      m_matchPatternCache.end(),
  +                      
XPathCacheReturnFunctor<XPathCacheMapType::value_type>(m_xsltProcessor));
  +
  +     m_matchPatternCache.clear();
  +}
  +
  +
  +
  +// I should be able to make this out of a
  +// bunch of compose<> and select2nd<> adapters...
  +template<class Type>
  +class XPathCacheEarliestPredicate
  +{
  +public:
  +
  +     XPathCacheEarliestPredicate(XSLTEngineImpl&             xsltProcessor) :
  +             m_xsltProcessor(xsltProcessor)
  +     {
  +     }
  +
  +     void
  +     operator()(const Type&  theCacheEntry)
  +     {
  +             m_xsltProcessor.returnXPath(theCacheEntry.second.first);
  +     }
  +
  +private:
  +
  +     XSLTEngineImpl&         m_xsltProcessor;
  +};
  +
  +
  +
  +
  +
  +
  +void
  +StylesheetExecutionContextDefault::addToXPathCache(
  +                     const XalanDOMString&   pattern,
  +                     XPath*                                  theXPath)
  +{
  +     clock_t         addClock = clock();
  +
  +     if (m_matchPatternCache.size() == eXPathCacheMax)
  +     {
  +             // OK, we need to clear something out of the cache...
  +
  +             // Initialize the lowest clock time found so far
  +             // with the current clock...
  +             clock_t         lowest = addClock;
  +
  +             // Get some iterators ready to search the cache...
  +             XPathCacheMapType::iterator             i =
  +                     m_matchPatternCache.begin();
  +
  +             const XPathCacheMapType::iterator       theEnd =
  +                     m_matchPatternCache.end();
  +
  +             XPathCacheMapType::iterator             earliest(theEnd);
  +
  +             while(i != theEnd)
  +             {
  +                     const clock_t   current = i->second.second;
  +
  +                     if (current < lowest)
  +                     {
  +                             // OK, found a lower clock time, so
  +                             // update the everything...
  +                             lowest = current;
  +
  +                             earliest = i;
  +                     }
  +                     else
  +                     {
  +                             ++i;
  +                     }
  +             }
  +             assert(earliest != theEnd);
  +
  +             // Return the XPath and erase it from the cache.
  +             m_xsltProcessor.returnXPath(earliest->second.first);
  +
  +             m_matchPatternCache.erase(earliest);
  +     }
  +
  +     // Add the XPath with the current clock
  +     m_matchPatternCache.insert(XPathCacheMapType::value_type(pattern, 
XPathCacheEntry(theXPath, addClock)));
  +}
  
  
  
  1.21      +45 -3     
xml-xalan/c/src/XSLT/StylesheetExecutionContextDefault.hpp
  
  Index: StylesheetExecutionContextDefault.hpp
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/c/src/XSLT/StylesheetExecutionContextDefault.hpp,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- StylesheetExecutionContextDefault.hpp     2000/07/21 19:52:57     1.20
  +++ StylesheetExecutionContextDefault.hpp     2000/07/25 15:12:07     1.21
  @@ -66,6 +66,7 @@
   
   
   
  +#include <ctime>
   #include <deque>
   #include <memory>
   #include <set>
  @@ -457,11 +458,10 @@
         * @param a pointer to the new factory instance to use.
         * @return a pointer to the old factory instance.
         */
  -     // 
        static XalanNumberFormatFactory*
        installXalanNumberFormatFactory(XalanNumberFormatFactory*       
theFactory);
   
  -     // Trace interface...
  +
        virtual unsigned long
        getTraceListeners() const;
   
  @@ -713,12 +713,46 @@
   
   private:
   
  +     /**
  +      * Pop the top entry from the live variables.
  +      */
        void
        popLiveVariablesStack();
   
  +     /**
  +      * Clear out the entire stack of live variables.
  +      */
        void
        clearLiveVariablesStack();
   
  +     /**
  +      * Determine if the XPath is one that we have cached.
  +      *
  +      * @param theXPath the XPath instance to check
  +      * @return true if the instance has been cached, false if not.
  +      */
  +     bool
  +     isCached(const XPath*   theXPath);
  +
  +     /**
  +      * Clear out the cache of XPath instances.
  +      */
  +     void
  +     clearXPathCache();
  +
  +     /**
  +      * Add an XPath instance to the cache, clearing out an old entry
  +      * if the cache is full.
  +      *
  +      * @param pattern the key for looking up the XPath instance in the 
cache.
  +      * @param theXPath the XPath instance to cache
  +      */
  +     void
  +     addToXPathCache(
  +                     const XalanDOMString&   pattern,
  +                     XPath*                                  theXPath);
  +
  +
        XPathExecutionContextDefault    m_xpathExecutionContextDefault;
   
        // $$ ToDo: Try to remove this dependency, and rely only on 
XSLTProcessor...
  @@ -733,6 +767,8 @@
        typedef set<TextOutputStream*>                                          
TextOutputStreamSetType;
        typedef vector<const XObject*>                                          
VariablesCollectionType;
        typedef vector<VariablesCollectionType>                         
LiveVariablesStackType;
  +     typedef pair<XPath*, clock_t>                                           
XPathCacheEntry;
  +     typedef map<XalanDOMString, XPathCacheEntry>            
XPathCacheMapType;
   #else
        typedef std::deque<const ElemTemplateElement*>          
ElementRecursionStackType;
        typedef std::set<FormatterListener*>                            
FormatterListenerSetType;
  @@ -740,9 +776,13 @@
        typedef std::set<TextOutputStream*>                                     
TextOutputStreamSetType;
        typedef std::vector<const XObject*>                                     
VariablesCollectionType;
        typedef std::vector<VariablesCollectionType>            
LiveVariablesStackType;
  +     typedef std::pair<XPath*, clock_t>                                      
XPathCacheEntry;
  +     typedef std::map<XalanDOMString, XPathCacheEntry>       
XPathCacheMapType;
   #endif
   
  -     enum { eDefaultVariablesCollectionSize = 10, eDefaultVariablesStackSize 
= 200 };
  +     enum { eDefaultVariablesCollectionSize = 10,
  +                eXPathCacheMax = 50,
  +                eDefaultVariablesStackSize = 200 };
   
        ElementRecursionStackType                       m_elementRecursionStack;
   
  @@ -764,6 +804,8 @@
         * Holds all information about variables during execution.
         */
        VariablesStack                                          
m_variablesStack;
  +
  +     XPathCacheMapType                                       
m_matchPatternCache;
   
        static XalanNumberFormatFactory         
s_defaultXalanNumberFormatFactory;
   
  
  
  

Reply via email to