changeset 644:02c0cce0e469

Introduce a cache for the distance-info service flys-artifacts/trunk@2028 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 30 May 2011 11:34:06 +0000
parents a9bde508824a
children 433f67a076aa
files flys-artifacts/ChangeLog flys-artifacts/doc/conf/cache.xml flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java
diffstat 4 files changed, 90 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/flys-artifacts/ChangeLog	Mon May 30 09:19:57 2011 +0000
+++ b/flys-artifacts/ChangeLog	Mon May 30 11:34:06 2011 +0000
@@ -1,3 +1,20 @@
+2011-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
+
+	* doc/conf/cache.xml: Introduced cache to store the distance info per river.
+	  This boosts performance in following ab setup from  3.61 to 39.91 requests/secs.
+
+	  $ ab -c 20 -n 1000 -p distances.xml http://127.0.0.1:8181/service/distanceinfo
+
+	  $ cat distances.xml
+	    <?xml version="1.0" encoding="UTF-8"?>
+	    <art:river xmlns:art="http://www.intevation.de/2009/artifacts">Elbe</art:river>
+
+	* src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java: Added
+	  an iterator result to avoid construction expensive interim lists.
+
+	* src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java: Use
+	  the cache if configured.
+
 2011-05-30	Sascha L. Teichmann	<sascha.teichmann@intevation.de>
 
 	flys/issue82
--- a/flys-artifacts/doc/conf/cache.xml	Mon May 30 09:19:57 2011 +0000
+++ b/flys-artifacts/doc/conf/cache.xml	Mon May 30 11:34:06 2011 +0000
@@ -27,4 +27,13 @@
            diskPersistent="true"
            memoryStoreEvictionPolicy="LRU"
            />
+
+    <!-- This one is used to cache the distance infos per river -->
+    <cache name="service-distanceinfo"
+           maxElementsInMemory="20"
+           eternal="false"
+           timeToIdleSeconds="360"
+           timeToLiveSeconds="86400"
+           memoryStoreEvictionPolicy="LFU"
+           />
 </ehcache>
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java	Mon May 30 09:19:57 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/model/AnnotationsFactory.java	Mon May 30 11:34:06 2011 +0000
@@ -1,6 +1,7 @@
 package de.intevation.flys.artifacts.model;
 
 import java.util.List;
+import java.util.Iterator;
 
 import de.intevation.flys.backend.SessionHolder;
 import de.intevation.flys.model.Annotation;
@@ -33,5 +34,20 @@
         query.setParameterList("ranges", ranges);
         return query.list();
     }
+
+
+    public static Iterator<Annotation> getAnnotationsIterator(String river) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query rangesQuery = session.createQuery(
+            "from Range where river.name=:name");
+        rangesQuery.setParameter("name", river);
+        List<Range> ranges = rangesQuery.list();
+
+        Query query = session.createQuery(
+            "from Annotation where range in (:ranges) order by range.a");
+        query.setParameterList("ranges", ranges);
+        return (Iterator<Annotation>)query.iterate();
+    }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :
--- a/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java	Mon May 30 09:19:57 2011 +0000
+++ b/flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/DistanceInfoService.java	Mon May 30 11:34:06 2011 +0000
@@ -1,7 +1,7 @@
 package de.intevation.flys.artifacts.services;
 
 import java.math.BigDecimal;
-import java.util.List;
+import java.util.Iterator;
 
 import org.apache.log4j.Logger;
 
@@ -26,6 +26,10 @@
 
 import org.hibernate.Session;
 
+import de.intevation.flys.artifacts.cache.CacheFactory;
+
+import net.sf.ehcache.Cache;
+
 /**
  * This service provides information about distances of a specified river.
  *
@@ -36,6 +40,10 @@
     /** The logger used in this service.*/
     private static Logger logger = Logger.getLogger(DistanceInfoService.class);
 
+    public static final String CACHE_NAME = "service-distanceinfo";
+
+    public static final String RIVER_XPATH = "/art:river/text()";
+
 
     /**
      * The default constructor.
@@ -51,40 +59,62 @@
     {
         logger.debug("DistanceInfoService.process");
 
-        Document result = XMLUtils.newDocument();
-
         String river = XMLUtils.xpathString(
-            data, "/art:river/text()", ArtifactNamespaceContext.INSTANCE);
+            data, RIVER_XPATH, ArtifactNamespaceContext.INSTANCE);
 
-        if (river == null || river.trim().length() == 0) {
+        if (river == null || (river = river.trim()).length() == 0) {
             logger.warn("No river specified. Cannot return distance info!");
-            return result;
+            return XMLUtils.newDocument();
         }
 
         logger.debug("Search distances for river: " + river);
 
+        Cache cache = CacheFactory.getCache(CACHE_NAME);
+
+        if (cache == null) {
+            logger.debug("no cache configured for distance info");
+            return getUncached(river);
+        }
+
+        net.sf.ehcache.Element element = cache.get(river);
+
+        if (element != null) {
+            logger.debug("distance info found in cache");
+            return (Document)element.getValue();
+        }
+
+        Document result = getUncached(river);
+
+        element = new net.sf.ehcache.Element(river, result);
+
+        logger.debug("store distance info found into cache");
+
+        cache.put(element);
+
+        return result;
+    }
+
+    protected Document getUncached(String river) {
+
+        Document result = XMLUtils.newDocument();
+
         ElementCreator ec = new ElementCreator(
             result,
             ArtifactNamespaceContext.NAMESPACE_URI,
             ArtifactNamespaceContext.NAMESPACE_PREFIX);
 
         Session session = SessionHolder.acquire();
-        try {
-            List<Annotation> annotations = AnnotationsFactory.getAnnotations(river);
 
-            if (annotations == null || annotations.size() == 0) {
-                logger.warn("No information found for the specified river!");
-                return result;
-            }
+        try {
+            Iterator<Annotation> iter =
+                AnnotationsFactory.getAnnotationsIterator(river);
 
             Element all = ec.create("distances");
 
-            for (Annotation a: annotations) {
+            while (iter.hasNext()) {
+                Annotation a = iter.next();
                 Element distance = buildDistanceNode(ec, a);
-
-                if (distance != null) {
-                    all.appendChild(distance);
-                }
+                all.appendChild(distance);
             }
 
             result.appendChild(all);
@@ -106,7 +136,7 @@
      *
      * @return an Element that contains information about a distance.
      */
-    protected Element buildDistanceNode(ElementCreator ec, Annotation anno) {
+    protected static Element buildDistanceNode(ElementCreator ec, Annotation anno) {
         Position  pos   = anno.getPosition();
         Range     range = anno.getRange();
         Attribute attr  = anno.getAttribute();

http://dive4elements.wald.intevation.org