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