From 56606597c25e3e41095998b5b971db567dfcd94f Mon Sep 17 00:00:00 2001
From: anttil <anttil>
Date: Tue, 9 Aug 2016 13:22:01 +0000
Subject: [PATCH] SSDM-4003: New DSS FS (FTP / CIFS) resolvers: implemented a
 short-lived cache for resolve requests.

SVN: 36887
---
 .../openbis/dss/generic/server/ftp/Cache.java | 29 +++++++++++-----
 .../ftp/v3/V3FtpPathResolverRegistry.java     | 33 ++++++++++++++-----
 2 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java
index a03bd96f9ee..5f428676c31 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/Cache.java
@@ -23,9 +23,10 @@ import java.util.Map;
 import org.apache.ftpserver.ftplet.FtpFile;
 
 import ch.systemsx.cisd.common.utilities.ITimeProvider;
+import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpFile;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 
 /**
  * Helper class to cache objects retrieved from remote services. Used by {@link FtpPathResolverContext}.
@@ -48,13 +49,13 @@ public class Cache
             this.timestamp = timestamp;
         }
     }
-    
+
     private final Map<String, TimeStampedObject<FtpFile>> filesByPath = new HashMap<>();
 
     private final Map<String, TimeStampedObject<DataSet>> dataSetsByCode = new HashMap<String, Cache.TimeStampedObject<DataSet>>();
 
     private final Map<String, TimeStampedObject<List<AbstractExternalData>>> dataSetsByExperiment = new HashMap<>();
-    
+
     private final Map<String, TimeStampedObject<AbstractExternalData>> externalData =
             new HashMap<String, Cache.TimeStampedObject<AbstractExternalData>>();
 
@@ -62,26 +63,28 @@ public class Cache
 
     private final ITimeProvider timeProvider;
 
+    private final Map<String, TimeStampedObject<V3FtpFile>> v3Responses = new HashMap<>();
+
     public Cache(ITimeProvider timeProvider)
     {
         this.timeProvider = timeProvider;
     }
-    
+
     void putFile(FtpFile file, String path)
     {
         filesByPath.put(path, timestamp(file));
     }
-    
+
     FtpFile getFile(String path)
     {
         return getObject(filesByPath, path);
     }
-    
+
     void putDataSetsForExperiment(List<AbstractExternalData> dataSets, String experimentPermId)
     {
         dataSetsByExperiment.put(experimentPermId, timestamp(dataSets));
     }
-    
+
     List<AbstractExternalData> getDataSetsByExperiment(String experimentPermId)
     {
         return getObject(dataSetsByExperiment, experimentPermId);
@@ -117,6 +120,16 @@ public class Cache
         experiments.put(experiment.getIdentifier(), timestamp(experiment));
     }
 
+    public V3FtpFile getResponse(String key)
+    {
+        return getObject(v3Responses, key);
+    }
+
+    public void putResponse(String key, V3FtpFile file)
+    {
+        v3Responses.put(key, timestamp(file));
+    }
+
     private <T> TimeStampedObject<T> timestamp(T object)
     {
         return new TimeStampedObject<T>(object, timeProvider.getTimeInMilliseconds());
@@ -127,7 +140,7 @@ public class Cache
         TimeStampedObject<T> timeStampedObject = map.get(key);
         return timeStampedObject == null
                 || timeProvider.getTimeInMilliseconds() - timeStampedObject.timestamp > LIVE_TIME ? null
-                : timeStampedObject.object;
+                        : timeStampedObject.object;
     }
 
 }
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3FtpPathResolverRegistry.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3FtpPathResolverRegistry.java
index ff4da3517c5..71bd571d3b2 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3FtpPathResolverRegistry.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3FtpPathResolverRegistry.java
@@ -27,10 +27,12 @@ import org.apache.log4j.Logger;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.dss.generic.server.ftp.Cache;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverConfig;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverContext;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.IFtpPathResolverRegistry;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpDirectoryResponse;
+import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpFile;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpNonExistingFile;
 import ch.systemsx.cisd.openbis.dss.generic.shared.Constants;
 
@@ -80,35 +82,50 @@ public class V3FtpPathResolverRegistry implements IFtpPathResolverRegistry
         }
     }
 
-    // note to self - the resolver context is created fresh for each request
     @Override
     public FtpFile resolve(String path, FtpPathResolverContext resolverContext)
     {
-        System.err.println(path + " Resolver registry: " + this.hashCode());
+        
+        String responseCacheKey = resolverContext.getSessionToken() + "$" + path;
+        Cache cache = resolverContext.getCache();
+        V3FtpFile response = cache.getResponse(responseCacheKey);
+        if (response != null)
+        {
+            operationLog.info("Path "+path+" requested (found in cache).");
+            return response;
+        }
+
+        operationLog.info("Path "+path+" requested.");
+
         String[] split = path.equals("/") ? new String[] {} : path.substring(1).split("/");
         try
         {
             if (plugins.size() > 0)
             {
-                return resolvePlugins(path, split, resolverContext);
+
+                response = resolvePlugins(path, split, resolverContext);
             } else
             {
-                return resolveDefault(path, resolverContext, split);
+                response = resolveDefault(path, resolverContext, split);
             }
         } catch (Exception e)
         {
-            operationLog.warn("Resolving "+path+" failed", e);
+            operationLog.warn("Resolving " + path + " failed", e);
+            response = new V3FtpNonExistingFile(path, "Error when retrieving path");
         }
-        return new V3FtpNonExistingFile(path, "Error when retrieving path");
+
+        cache.putResponse(responseCacheKey, response);
+        return response;
+
     }
 
-    private FtpFile resolveDefault(String path, FtpPathResolverContext resolverContext, String[] split)
+    private V3FtpFile resolveDefault(String path, FtpPathResolverContext resolverContext, String[] split)
     {
         V3RootLevelResolver resolver = new V3RootLevelResolver();
         return resolver.resolve(path, split, resolverContext);
     }
 
-    private FtpFile resolvePlugins(String path, String[] subPath, FtpPathResolverContext resolverContext)
+    private V3FtpFile resolvePlugins(String path, String[] subPath, FtpPathResolverContext resolverContext)
     {
         if (subPath.length == 0)
         {
-- 
GitLab