Author: ssmiweve
Date: 2008-09-24 18:57:10 +0200 (Wed, 24 Sep 2008)
New Revision: 6831

Modified:
   
trunk/query-api/src/main/java/no/sesat/search/query/token/AbstractEvaluatorFactory.java
   
trunk/query-api/src/main/java/no/sesat/search/query/token/TokenEvaluationEngineImpl.java
Log:
Performance improvements fixing degradation introduced with SKER3540 Token 
Evaluator SPI 
These two caches:
  - AbstractEvaluatorFactory has a static weak cache of Constructors 
  -  TokenEvaluatorEngineImpl has a instance map of TokenEvaluators
; improved the time it took to run the test TestVisitor from >20 minutes down 
to 1 minute!


Modified: 
trunk/query-api/src/main/java/no/sesat/search/query/token/AbstractEvaluatorFactory.java
===================================================================
--- 
trunk/query-api/src/main/java/no/sesat/search/query/token/AbstractEvaluatorFactory.java
     2008-09-24 16:51:26 UTC (rev 6830)
+++ 
trunk/query-api/src/main/java/no/sesat/search/query/token/AbstractEvaluatorFactory.java
     2008-09-24 16:57:10 UTC (rev 6831)
@@ -16,12 +16,15 @@
  */
 
 package no.sesat.search.query.token;
+import java.lang.ref.Reference;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import no.schibstedsok.commons.ioc.BaseContext;
+import no.sesat.commons.ref.ReferenceMap;
 import no.sesat.search.query.QueryStringContext;
 import no.sesat.search.site.Site;
 import no.sesat.search.site.SiteContext;
@@ -69,6 +72,18 @@
 
     private final Context context;
 
+
+
+    private static final int WEAK_CACHE_INITIAL_CAPACITY = 16;
+    private static final float WEAK_CACHE_LOAD_FACTOR = 0.5f;
+    private static final int WEAK_CACHE_CONCURRENCY_LEVEL = 16;
+
+    /**
+     * Unsynchronized are there are no 'changing values', just existance or 
not of the Constructor in the system.
+     */
+    private static final Map<Site,ReferenceMap<String,Constructor<? extends 
AbstractEvaluatorFactory>>> WEAK_CACHE
+            = new ConcurrentHashMap<Site,ReferenceMap<String,Constructor<? 
extends AbstractEvaluatorFactory>>>();
+
     // Static --------------------------------------------------------
 
     /** find the appropriate factory subclass to use given the context.
@@ -76,23 +91,44 @@
      * @param cxt supplied context.
      * @return the appropriate factory subclass.
      */
+    @SuppressWarnings("unchecked")
     public static final AbstractEvaluatorFactory instanceOf(final Context cxt) 
{
 
+        final Site site = cxt.getSite();
         final String clsName = cxt.getEvaluatorFactoryClassName();
 
+        ReferenceMap<String,Constructor<? extends AbstractEvaluatorFactory>> 
weakCache = WEAK_CACHE.get(site);
+        if(null == weakCache){
+
+            weakCache = new ReferenceMap<String,Constructor<? extends 
AbstractEvaluatorFactory>>(
+                    ReferenceMap.Type.WEAK,
+                    new ConcurrentHashMap<String,Reference<Constructor<? 
extends AbstractEvaluatorFactory>>>(
+                        WEAK_CACHE_INITIAL_CAPACITY,
+                        WEAK_CACHE_LOAD_FACTOR,
+                        WEAK_CACHE_CONCURRENCY_LEVEL));
+
+            WEAK_CACHE.put(site, weakCache);
+        }
+        Constructor<? extends AbstractEvaluatorFactory> s = 
weakCache.get(clsName);
+
         // We cannot cache the EvaluatorFactory instances so easily because 
each depends on the QueryString.
         //  the cache would then need to be keyed on 
Site->FactoryClassName->QueryString
         //  Effective and safe caching becomes difficult when each QueryString 
has such a short lifespan.
         // It is more effective than to let each EvaluatorFactory provide it's 
own QueryString caching.
 
+        // Note: The TokenEvaluationEnginImpl instance does contain a weak 
cache
+        // since the instance is based on a Site and QueryString combination.
+
         try {
 
-            final SiteClassLoaderFactory f = 
SiteClassLoaderFactory.instanceOf(createClassLoadingContext(cxt));
+            if(null == s){
+                final SiteClassLoaderFactory f = 
SiteClassLoaderFactory.instanceOf(createClassLoadingContext(cxt));
 
-            final Class clazz = f.getClassLoader().loadClass(clsName);
+                final Class clazz = f.getClassLoader().loadClass(clsName);
 
-            @SuppressWarnings("unchecked")
-            final Constructor<? extends AbstractEvaluatorFactory> s = 
clazz.getConstructor(Context.class);
+                s = clazz.getConstructor(Context.class);
+                weakCache.put(clsName, s);
+            }
 
             return s.newInstance(cxt);
 

Modified: 
trunk/query-api/src/main/java/no/sesat/search/query/token/TokenEvaluationEngineImpl.java
===================================================================
--- 
trunk/query-api/src/main/java/no/sesat/search/query/token/TokenEvaluationEngineImpl.java
    2008-09-24 16:51:26 UTC (rev 6830)
+++ 
trunk/query-api/src/main/java/no/sesat/search/query/token/TokenEvaluationEngineImpl.java
    2008-09-24 16:57:10 UTC (rev 6831)
@@ -18,10 +18,13 @@
 package no.sesat.search.query.token;
 
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import no.schibstedsok.commons.ioc.BaseContext;
 import no.schibstedsok.commons.ioc.ContextWrapper;
 import no.sesat.search.query.Clause;
@@ -58,6 +61,14 @@
     private State state;
     private volatile Thread owningThread = Thread.currentThread();
 
+
+    private final transient Map<TokenPredicate,TokenEvaluator> evaluatorCache
+            = new HashMap<TokenPredicate,TokenEvaluator>();
+
+    /** threading lock to the cache maps since they are not synchronised,
+     * and it's overkill to make them Hashtables. **/
+    private final transient ReentrantReadWriteLock evaluatorCacheGate = new 
ReentrantReadWriteLock();
+
     // Constructors -----------------------------------------------------
 
     /**
@@ -80,24 +91,50 @@
 
     public TokenEvaluator getEvaluator(final TokenPredicate token) throws 
EvaluationException {
 
-        for(EvaluatorType type : EvaluatorType.getInstances()){
+        TokenEvaluator result = null;
 
-            final AbstractEvaluatorFactory factory = 
AbstractEvaluatorFactory.instanceOf(
-                    ContextWrapper.wrap(
-                    AbstractEvaluatorFactory.Context.class,
-                    context,
-                    type
-            ));
+        try{
+            evaluatorCacheGate.readLock().lock();
 
-            if(factory.isResponsibleFor(token)){
-                LOG.trace("Evaluator for " + token + " found by " + 
type.getEvaluatorFactoryClassName());
-                return factory.getEvaluator(token);
+            result = evaluatorCache.get(token);
+
+        }finally{
+            evaluatorCacheGate.readLock().unlock();
+        }
+
+        if(null == result){
+
+            try{
+                evaluatorCacheGate.writeLock().lock();
+
+
+                for(EvaluatorType type : EvaluatorType.getInstances()){
+
+                    final AbstractEvaluatorFactory factory = 
AbstractEvaluatorFactory.instanceOf(
+                            ContextWrapper.wrap(
+                            AbstractEvaluatorFactory.Context.class,
+                            context,
+                            type
+                    ));
+
+                    if(factory.isResponsibleFor(token)){
+                        LOG.trace("Evaluator for " + token + " found by " + 
type.getEvaluatorFactoryClassName());
+                        result = factory.getEvaluator(token);
+                        break;
+                    }
+                }
+
+                if(null == result){
+                    // no evaluator has been defined for this predicate. it 
must always be false then.
+                    result = ALWAYS_FALSE_EVALUATOR;
+                }
+                evaluatorCache.put(token, result);
+
+            }finally{
+                evaluatorCacheGate.writeLock().unlock();
             }
         }
-
-        // no evaluator has been defined for this predicate. it must always be 
false then.
-        return ALWAYS_FALSE_EVALUATOR;
-        //throw new IllegalArgumentException(ERR_TOKENTYPE_WIHOUT_IMPL + 
token);
+        return result;
     }
 
     public String getQueryString() {

_______________________________________________
Kernel-commits mailing list
[email protected]
http://sesat.no/mailman/listinfo/kernel-commits

Reply via email to