From 31a32b4479dd50d58a579589b49399ef0f36b456 Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Mon, 3 Nov 2014 15:18:55 +0000
Subject: [PATCH] SSDM-1010: New Share property introduced
 'unarchiving-scratch-share' which is used in SegmentedStoreUtils.freeSpace()
 and SegmentedStoreUtils.moveDataSetToAnotherShare(). Tests added to
 SegmentedStoreUtilsTest.

SVN: 32708
---
 .../shared/utils/SegmentedStoreUtils.java     |  19 ++++
 .../dss/generic/shared/utils/Share.java       |  12 +++
 .../generic/shared/utils/ShareFactory.java    |  41 ++++---
 .../shared/utils/SegmentedStoreUtilsTest.java | 101 +++++++++++++++++-
 4 files changed, 156 insertions(+), 17 deletions(-)

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtils.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtils.java
index 2b08fc7daf9..97082bff56f 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtils.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtils.java
@@ -230,6 +230,13 @@ public class SegmentedStoreUtils
             List<DatasetDescription> dataSets, IDataSetDirectoryProvider dataSetDirectoryProvider, 
             IShareIdManager shareIdManager, ISimpleLogger logger)
     {
+        if (unarchivingScratchShare.isUnarchivingScratchShare() == false)
+        {
+            throw new EnvironmentFailureException("Share '" + unarchivingScratchShare.getShareId() 
+                    + "' isn't an unarchving scratch share. Such a share has the property " 
+                    + ShareFactory.UNARCHIVING_SCRATCH_SHARE_PROP + " of the file " 
+                    + ShareFactory.SHARE_PROPS_FILE + " set to 'true'.");
+        }
         List<DatasetDescription> filteredDataSets = new ArrayList<DatasetDescription>(dataSets);
         List<SimpleDataSetInformationDTO> filteredDataSetsInShare 
                 = new ArrayList<SimpleDataSetInformationDTO>(unarchivingScratchShare.getDataSetsOrderedBySize());
@@ -403,6 +410,8 @@ public class SegmentedStoreUtils
             {
                 return;
             }
+            assertNoUnarchivingScratchShare(oldShare, logger);
+            assertNoUnarchivingScratchShare(share, logger);
             File dataSetDirInNewShare = new File(share, relativePath);
             dataSetDirInNewShare.mkdirs();
             copyToShare(dataSetDirInStore, dataSetDirInNewShare, logger);
@@ -420,6 +429,16 @@ public class SegmentedStoreUtils
         }
         deleteDataSet(dataSetCode, dataSetDirInStore, shareIdManager, logger);
     }
+    
+    private static void assertNoUnarchivingScratchShare(File share, ISimpleLogger logger)
+    {
+        if (new ShareFactory().createShare(share, null, logger).isUnarchivingScratchShare())
+        {
+            throw new EnvironmentFailureException("Share '" + share.getName() 
+                    + "' is a scratch share for unarchiving purposes. "
+                    + "No data sets can be moved from/to such a share.");
+        }
+    }
 
     /**
      * Deletes specified data set at specified location. This methods waits until any locks on the
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/Share.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/Share.java
index 272d6fc947a..5ad2bc679c7 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/Share.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/Share.java
@@ -89,6 +89,8 @@ public final class Share
 
     private boolean withdrawShare;
     
+    private boolean unarchivingScratchShare;
+    
     private boolean ignoredForShuffling;
 
     private Set<String> experimentIdentifiers;
@@ -229,6 +231,16 @@ public final class Share
         this.withdrawShare = withdrawShare;
     }
 
+    public boolean isUnarchivingScratchShare()
+    {
+        return unarchivingScratchShare;
+    }
+
+    public void setUnarchivingScratchShare(boolean unarchivingScratchShare)
+    {
+        this.unarchivingScratchShare = unarchivingScratchShare;
+    }
+
     public boolean isIgnoredForShuffling()
     {
         return ignoredForShuffling;
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ShareFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ShareFactory.java
index e605502d66e..97bd2df4995 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ShareFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/ShareFactory.java
@@ -48,7 +48,6 @@ public class ShareFactory
     @Private
     static final String SPEED_FILE = "speed";
 
-    @Private
     public static final String SHARE_PROPS_FILE = "share.properties";
 
     @Private
@@ -60,6 +59,8 @@ public class ShareFactory
     public static final String WITHDRAW_SHARE_PROP = "withdraw-share";
     
     public static final String IGNORED_FOR_SHUFFLING_PROP = "ignored-for-shuffling";
+    
+    public static final String UNARCHIVING_SCRATCH_SHARE_PROP = "unarchiving-scratch-share";
 
     public static final String EXPERIMENTS_PROP = "experiments";
 
@@ -71,6 +72,8 @@ public class ShareFactory
 
     private boolean ignoredForShuffling;
     
+    private boolean unarchivingScratchShare;
+    
     private Set<String> experimentIdentifiers = Collections.emptySet();
 
     Share createShare(final SharesHolder sharesHolder, File shareRoot,
@@ -81,6 +84,7 @@ public class ShareFactory
         Share share = new Share(sharesHolder, shareRoot, speed, freeSpaceProvider);
         share.setShufflePriority(shufflePriority);
         share.setWithdrawShare(withdrawShare);
+        share.setUnarchivingScratchShare(unarchivingScratchShare);
         share.setIgnoredForShuffling(ignoredForShuffling);
         share.setExperimentIdentifiers(experimentIdentifiers);
         return share;
@@ -99,20 +103,7 @@ public class ShareFactory
         File propsFile = new File(shareRoot, SHARE_PROPS_FILE);
         if (propsFile.isFile())
         {
-            Properties props = new Properties();
-            FileInputStream fis = null;
-            try
-            {
-                fis = new FileInputStream(propsFile);
-                props.load(fis);
-            } catch (IOException ioex)
-            {
-                log.log(LogLevel.WARN, "Error while reading from " + propsFile.getAbsolutePath()
-                        + " : " + ioex.getMessage());
-            } finally
-            {
-                IOUtils.closeQuietly(fis);
-            }
+            Properties props = loadShareProperties(propsFile, log);
 
             if (props.containsKey(SPEED_HINT_PROP))
             {
@@ -148,6 +139,7 @@ public class ShareFactory
 
             withdrawShare = PropertyUtils.getBoolean(props, WITHDRAW_SHARE_PROP, false);
             ignoredForShuffling = PropertyUtils.getBoolean(props, IGNORED_FOR_SHUFFLING_PROP, false);
+            unarchivingScratchShare = PropertyUtils.getBoolean(props, UNARCHIVING_SCRATCH_SHARE_PROP, false);
             experimentIdentifiers =
                     new HashSet<String>(Arrays.asList(PropertyParametersUtil.parseItemisedProperty(
                             props.getProperty(EXPERIMENTS_PROP, ""), EXPERIMENTS_PROP)));
@@ -155,6 +147,25 @@ public class ShareFactory
 
     }
 
+    private Properties loadShareProperties(File propsFile, ISimpleLogger log)
+    {
+        Properties props = new Properties();
+        FileInputStream fis = null;
+        try
+        {
+            fis = new FileInputStream(propsFile);
+            props.load(fis);
+        } catch (IOException ioex)
+        {
+            log.log(LogLevel.WARN, "Error while reading from " + propsFile.getAbsolutePath()
+                    + " : " + ioex.getMessage());
+        } finally
+        {
+            IOUtils.closeQuietly(fis);
+        }
+        return props;
+    }
+
     private void readSpeedFile(File shareRoot, ISimpleLogger log)
     {
         File speedFile = new File(shareRoot, SPEED_FILE);
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtilsTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtilsTest.java
index b8a6ce3b762..6a7365c75db 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtilsTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/SegmentedStoreUtilsTest.java
@@ -131,16 +131,37 @@ public class SegmentedStoreUtilsTest extends AbstractFileSystemTestCase
         }
     }
 
+    @Test
+    public void testFreeSpaceForAShareWhichIsNotAnUnarchivingScratchShare()
+    {
+        SimpleDataSetInformationDTO ds1 = dataSet(1, 11 * FileUtils.ONE_KB);
+        Share share = new Share(shareFolder, 0, freeSpaceProvider);
+
+        try
+        {
+            SegmentedStoreUtils.freeSpace(share, service, asDatasetDescriptions(ds1), dataSetDirectoryProvider,
+                    shareIdManager, log);
+            fail("EnvironmentFailureException expected.");
+        } catch (EnvironmentFailureException ex)
+        {
+            assertEquals("Share '1' isn't an unarchving scratch share. Such a share has the property "
+                    + "unarchiving-scratch-share of the file share.properties set to 'true'.", ex.getMessage());
+        }
+
+        assertEquals("", log.toString());
+    }
+    
     @Test
     public void testFreeSpaceNothingToDo()
     {
         SimpleDataSetInformationDTO ds1 = dataSet(1, 11 * FileUtils.ONE_KB);
         Share share = new Share(shareFolder, 0, freeSpaceProvider);
+        share.setUnarchivingScratchShare(true);
         RecordingMatcher<HostAwareFile> recordingFileMatcher = prepareFreeSpace(12L);
-
+        
         SegmentedStoreUtils.freeSpace(share, service, asDatasetDescriptions(ds1), dataSetDirectoryProvider,
                 shareIdManager, log);
-
+        
         assertEquals(shareFolder.getPath(), recordingFileMatcher.recordedObject().getPath());
         assertEquals("INFO: Free space on unarchiving scratch share '1': 12.00 KB, "
                 + "requested space for unarchiving 1 data sets: 11.00 KB\n", log.toString());
@@ -155,6 +176,7 @@ public class SegmentedStoreUtilsTest extends AbstractFileSystemTestCase
         SimpleDataSetInformationDTO ds4 = dataSet(4, 11 * FileUtils.ONE_KB);
         SimpleDataSetInformationDTO ds5 = dataSet(5, 14 * FileUtils.ONE_KB);
         Share share = new Share(shareFolder, 0, freeSpaceProvider);
+        share.setUnarchivingScratchShare(true);
         share.addDataSet(ds5);
         share.addDataSet(ds3);
         share.addDataSet(ds1);
@@ -190,6 +212,7 @@ public class SegmentedStoreUtilsTest extends AbstractFileSystemTestCase
         SimpleDataSetInformationDTO ds4 = dataSet(4, 11 * FileUtils.ONE_KB);
         SimpleDataSetInformationDTO ds5 = dataSet(5, 14 * FileUtils.ONE_KB);
         Share share = new Share(shareFolder, 0, freeSpaceProvider);
+        share.setUnarchivingScratchShare(true);
         share.addDataSet(ds5);
         share.addDataSet(ds3);
         share.addDataSet(ds1);
@@ -225,6 +248,7 @@ public class SegmentedStoreUtilsTest extends AbstractFileSystemTestCase
         SimpleDataSetInformationDTO ds4 = dataSet(4, 11 * FileUtils.ONE_KB);
         SimpleDataSetInformationDTO ds5 = dataSet(5, 14 * FileUtils.ONE_KB);
         Share share = new Share(shareFolder, 0, freeSpaceProvider);
+        share.setUnarchivingScratchShare(true);
         share.addDataSet(ds3);
         share.addDataSet(ds2);
         share.addDataSet(ds1);
@@ -523,6 +547,79 @@ public class SegmentedStoreUtilsTest extends AbstractFileSystemTestCase
 
         fail();
     }
+    
+    @Test
+    public void testMoveDataSetToAnotherShareWhichIsAnUnarchivingScratchShare()
+    {
+        File share1 = new File(workingDirectory, "store/1");
+        File share1uuid01 = new File(share1, "uuid/01");
+        File dataSetDirInStore = new File(share1uuid01, "02/03/ds-1");
+        File original = new File(dataSetDirInStore, "original");
+        original.mkdirs();
+        final File helloFile = new File(original, "hello.txt");
+        FileUtilities.writeToFile(helloFile, "hello world");
+        File share2 = new File(workingDirectory, "store/2");
+        share2.mkdirs();
+        FileUtilities.writeToFile(new File(share2, ShareFactory.SHARE_PROPS_FILE), 
+                ShareFactory.UNARCHIVING_SCRATCH_SHARE_PROP + "=true");
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).tryGetDataSet("ds-1");
+                    will(returnValue(new PhysicalDataSet()));
+
+                    one(shareIdManager).lock("ds-1");
+                    one(shareIdManager).releaseLock("ds-1");
+                }
+            });
+        
+        try
+        {
+            SegmentedStoreUtils.moveDataSetToAnotherShare(dataSetDirInStore, share2, service,
+                    shareIdManager, checksumProvider, log);
+            fail("EnvironmentFailureException expected");
+        } catch (EnvironmentFailureException ex)
+        {
+            assertEquals("Share '2' is a scratch share for unarchiving purposes. "
+                    + "No data sets can be moved from/to such a share.", ex.getMessage());
+        }
+    }
+    
+    @Test
+    public void testMoveDataSetFromAnUnarchivingScratchShareToAnotherShare()
+    {
+        File share1 = new File(workingDirectory, "store/1");
+        File share1uuid01 = new File(share1, "uuid/01");
+        File dataSetDirInStore = new File(share1uuid01, "02/03/ds-1");
+        File original = new File(dataSetDirInStore, "original");
+        original.mkdirs();
+        FileUtilities.writeToFile(new File(share1, ShareFactory.SHARE_PROPS_FILE), 
+                ShareFactory.UNARCHIVING_SCRATCH_SHARE_PROP + "=true");
+        final File helloFile = new File(original, "hello.txt");
+        FileUtilities.writeToFile(helloFile, "hello world");
+        File share2 = new File(workingDirectory, "store/2");
+        context.checking(new Expectations()
+            {
+                {
+                    one(service).tryGetDataSet("ds-1");
+                    will(returnValue(new PhysicalDataSet()));
+
+                    one(shareIdManager).lock("ds-1");
+                    one(shareIdManager).releaseLock("ds-1");
+                }
+            });
+
+        try
+        {
+            SegmentedStoreUtils.moveDataSetToAnotherShare(dataSetDirInStore, share2, service,
+                    shareIdManager, checksumProvider, log);
+            fail("EnvironmentFailureException expected");
+        } catch (EnvironmentFailureException ex)
+        {
+            assertEquals("Share '1' is a scratch share for unarchiving purposes. "
+                    + "No data sets can be moved from/to such a share.", ex.getMessage());
+        }
+    }
 
     @Test
     public void testCleanupOld()
-- 
GitLab