From 0a563da05e7ae3ed40a25912528e1ad1cf07e4a7 Mon Sep 17 00:00:00 2001
From: anttil <anttil>
Date: Thu, 11 Aug 2016 13:40:17 +0000
Subject: [PATCH] SSDM-4003: New DSS FS (FTP / CIFS) resolvers: More caching,
 fix bug with CIFS session breaking on unavailable file

SVN: 36897
---
 .../server/cifs/DSSFileSearchContext.java     |  8 ++---
 .../generic/server/cifs/DataSetCifsView.java  | 15 +++++++---
 .../openbis/dss/generic/server/ftp/Cache.java | 25 ++++++++++++++++
 .../ftp/v3/V3DataSetContentResolver.java      | 29 +++++++++++++++----
 4 files changed, 61 insertions(+), 16 deletions(-)

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DSSFileSearchContext.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DSSFileSearchContext.java
index 49a0a348a00..24c4326a82c 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DSSFileSearchContext.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DSSFileSearchContext.java
@@ -40,7 +40,7 @@ public class DSSFileSearchContext extends SearchContext
 
     private int index;
 
-    public DSSFileSearchContext(DSSFileSystemView view, String normalizedSearchPath, int fileAttributes, 
+    public DSSFileSearchContext(DSSFileSystemView view, String normalizedSearchPath, int fileAttributes,
             Cache cache) throws FileNotFoundException
     {
         String[] pathStr = FileName.splitPath(normalizedSearchPath, java.io.File.separatorChar);
@@ -77,7 +77,7 @@ public class DSSFileSearchContext extends SearchContext
         FtpFile file = view.getFile(path, cache);
         if (file instanceof NonExistingFtpFile)
         {
-            throw new FtpException(file.getAbsolutePath() + " doesn't exist. Reason: " 
+            throw new FtpException(file.getAbsolutePath() + " doesn't exist. Reason: "
                     + ((NonExistingFtpFile) file).getErrorMessage());
         }
         return file;
@@ -114,8 +114,6 @@ public class DSSFileSearchContext extends SearchContext
     @Override
     public String nextFileName()
     {
-        System.out.println("DSSFileSearchContext.nextFileName()");
-        // TODO Auto-generated method stub
         return null;
     }
 
@@ -133,8 +131,6 @@ public class DSSFileSearchContext extends SearchContext
     @Override
     public boolean restartAt(FileInfo info)
     {
-        System.out.println("DSSFileSearchContext.restartAt() "+info);
-        // TODO Auto-generated method stub
         return false;
     }
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DataSetCifsView.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DataSetCifsView.java
index 392f9ddbe5b..23942db5f66 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DataSetCifsView.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/cifs/DataSetCifsView.java
@@ -30,6 +30,7 @@ import org.alfresco.jlan.server.filesys.DiskInterface;
 import org.alfresco.jlan.server.filesys.FileAttribute;
 import org.alfresco.jlan.server.filesys.FileInfo;
 import org.alfresco.jlan.server.filesys.FileName;
+import org.alfresco.jlan.server.filesys.FileOfflineException;
 import org.alfresco.jlan.server.filesys.FileOpenParams;
 import org.alfresco.jlan.server.filesys.FileStatus;
 import org.alfresco.jlan.server.filesys.NetworkFile;
@@ -226,12 +227,18 @@ public class DataSetCifsView implements DiskInterface
         }
         operationLog.debug("Read from virtual file '" + file.getFullName() + "' at position " + filePos + " "
                 + size + " bytes into the buffer of size " + buf.length + " at position " + bufPos + ".");
-        int rdlen = file.readFile(buf, size, bufPos, filePos);
-        if (rdlen == -1)
+        try
+        {
+            int rdlen = file.readFile(buf, size, bufPos, filePos);
+            if (rdlen == -1)
+            {
+                rdlen = 0;
+            }
+            return rdlen;
+        } catch (RuntimeException e)
         {
-            rdlen = 0;
+            throw new FileOfflineException();
         }
-        return rdlen;
     }
 
     @Override
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 5f428676c31..4ad07497625 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,6 +23,7 @@ import java.util.Map;
 import org.apache.ftpserver.ftplet.FtpFile;
 
 import ch.systemsx.cisd.common.utilities.ITimeProvider;
+import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
 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.AbstractExternalData;
@@ -65,6 +66,10 @@ public class Cache
 
     private final Map<String, TimeStampedObject<V3FtpFile>> v3Responses = new HashMap<>();
 
+    private final Map<String, TimeStampedObject<IHierarchicalContent>> contents = new HashMap<>();
+
+    private final Map<String, TimeStampedObject<Boolean>> accessData = new HashMap<>();
+
     public Cache(ITimeProvider timeProvider)
     {
         this.timeProvider = timeProvider;
@@ -130,6 +135,26 @@ public class Cache
         v3Responses.put(key, timestamp(file));
     }
 
+    public IHierarchicalContent getContent(String key)
+    {
+        return getObject(contents, key);
+    }
+
+    public void putContent(String key, IHierarchicalContent content)
+    {
+        contents.put(key, timestamp(content));
+    }
+
+    public Boolean getAccess(String dataSetCode)
+    {
+        return getObject(accessData, dataSetCode);
+    }
+
+    public void putAccess(String dataSetCode, Boolean access)
+    {
+        accessData.put(dataSetCode, timestamp(access));
+    }
+
     private <T> TimeStampedObject<T> timestamp(T object)
     {
         return new TimeStampedObject<T>(object, timeProvider.getTimeInMilliseconds());
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3DataSetContentResolver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3DataSetContentResolver.java
index 212ea49ce4b..2e6fa6cdfb9 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3DataSetContentResolver.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/ftp/v3/V3DataSetContentResolver.java
@@ -24,6 +24,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetc
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.DataSetPermId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
 import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContent;
+import ch.systemsx.cisd.openbis.dss.generic.server.ftp.Cache;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.FtpPathResolverContext;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpFile;
 import ch.systemsx.cisd.openbis.dss.generic.server.ftp.v3.file.V3FtpNonExistingFile;
@@ -45,17 +46,33 @@ public class V3DataSetContentResolver implements V3Resolver
     @Override
     public V3FtpFile resolve(String fullPath, String[] subPath, FtpPathResolverContext context)
     {
-        // this fetching of data set is for authorization purposes, as content provider doesn't check if user has access to data set
-        IDataSetId id = new DataSetPermId(dataSetCode);
-        Map<IDataSetId, DataSet> dataSets =
-                context.getV3Api().getDataSets(context.getSessionToken(), Collections.singletonList(id), new DataSetFetchOptions());
+        Cache cache = context.getCache();
 
-        if (dataSets.get(id) == null)
+        Boolean hasAccess = cache.getAccess(dataSetCode);
+        if (hasAccess == null)
+        {
+
+            // this fetching of data set is for authorization purposes, as content provider doesn't check if user has access to data set
+            IDataSetId id = new DataSetPermId(dataSetCode);
+            Map<IDataSetId, DataSet> dataSets =
+                    context.getV3Api().getDataSets(context.getSessionToken(), Collections.singletonList(id), new DataSetFetchOptions());
+
+            hasAccess = dataSets.containsKey(id);
+            cache.putAccess(dataSetCode, hasAccess);
+        }
+
+        if (hasAccess.booleanValue() == false)
         {
             return new V3FtpNonExistingFile(fullPath, "Path doesn't exist or unauthorized");
         }
 
-        IHierarchicalContent content = context.getContentProvider().asContent(dataSetCode);
+        IHierarchicalContent content = cache.getContent(dataSetCode);
+        if (content == null)
+        {
+            content = context.getContentProvider().asContentWithoutModifyingAccessTimestamp(dataSetCode);
+            cache.putContent(dataSetCode, content);
+        }
+
         V3HierarchicalContentResolver resolver = new V3HierarchicalContentResolver(content);
         return resolver.resolve(fullPath, subPath, context);
     }
-- 
GitLab