diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/SegmentedStoreShufflingTask.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/SegmentedStoreShufflingTask.java index e3424168f408b66866777ac752bd8333afc0f4a8..d6be00f6a2bff2cfe6699b2dc4295ea3b662602a 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/SegmentedStoreShufflingTask.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/plugins/SegmentedStoreShufflingTask.java @@ -20,6 +20,7 @@ import static ch.systemsx.cisd.common.logging.LogLevel.INFO; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Properties; import java.util.Set; @@ -201,7 +202,8 @@ public class SegmentedStoreShufflingTask implements IDataStoreLockingMaintenance operationLog.info("Starting segmented store shuffling."); List<Share> shares = SegmentedStoreUtils.getDataSetsPerShare(storeRoot, dataStoreCode, - freeSpaceProvider, service, operationLogger); + Collections.<String> emptySet(), freeSpaceProvider, service, + operationLogger); List<Share> sourceShares = new ArrayList<Share>(); for (Share share : shares) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTask.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTask.java index 927e0f9da3c651a59822dfc0241d4c969e6960b4..de6edbb79d00796ea8da6da2597c952dfd1fdb4c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTask.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/EagerShufflingTask.java @@ -148,12 +148,8 @@ public class EagerShufflingTask extends AbstractPostRegistrationTask public ICleanupTask createCleanupTask() { List<Share> shares = - SegmentedStoreUtils.getDataSetsPerShare(storeRoot, dataStoreCode, + SegmentedStoreUtils.getDataSetsPerShare(storeRoot, dataStoreCode, incomingShares, freeSpaceProvider, service, logger); - for (Share share : shares) - { - share.setIncoming(incomingShares.contains(share.getShareId())); - } dataSet = findDataSet(shares, dataSetCode); shareWithMostFreeOrNull = finder.tryToFindShare(dataSet, shares); if (shareWithMostFreeOrNull == null) diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/IShareFinder.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/IShareFinder.java index 970ac083cf73ce35313973455c44ebb1bac793fe..731a1d53b31073ae8fb0f47b956592d6834830e7 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/IShareFinder.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/postregistration/IShareFinder.java @@ -34,7 +34,7 @@ public interface IShareFinder * Tries to find a share from the specified shares to whom the specified data set can be moved. * * @param dataSet with known size and old share ID. - * @param shares All shares. Share instances know whether they are icoming or external. + * @param shares All shares. Share instances know whether they are incoming or external. * @return <code>null</code> if no share could be found. */ public Share tryToFindShare(SimpleDataSetInformationDTO dataSet, List<Share> shares); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractArchiverProcessingPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractArchiverProcessingPlugin.java index ac8220d0cffe71fec06906df734a342295e23e35..362601a0b8ec86cdf8f54ef448e79a9827536c1f 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractArchiverProcessingPlugin.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/AbstractArchiverProcessingPlugin.java @@ -26,20 +26,38 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; +import org.apache.commons.io.FileUtils; + +import ch.rinn.restrictions.Private; import ch.systemsx.cisd.common.collections.CollectionUtils; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.filesystem.BooleanStatus; +import ch.systemsx.cisd.common.filesystem.IFreeSpaceProvider; +import ch.systemsx.cisd.common.filesystem.SimpleFreeSpaceProvider; +import ch.systemsx.cisd.common.logging.Log4jSimpleLogger; +import ch.systemsx.cisd.common.utilities.ClassUtils; +import ch.systemsx.cisd.common.utilities.PropertyParametersUtil; +import ch.systemsx.cisd.etlserver.ETLDaemon; +import ch.systemsx.cisd.etlserver.postregistration.IShareFinder; import ch.systemsx.cisd.openbis.dss.generic.shared.ArchiverTaskContext; import ch.systemsx.cisd.openbis.dss.generic.shared.IArchiverPlugin; import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetDeleter; +import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetDirectoryProvider; +import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; +import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; import ch.systemsx.cisd.openbis.dss.generic.shared.ProcessingStatus; import ch.systemsx.cisd.openbis.dss.generic.shared.QueueingDataSetStatusUpdaterService; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetCodesWithStatus; +import ch.systemsx.cisd.openbis.dss.generic.shared.utils.SegmentedStoreUtils; +import ch.systemsx.cisd.openbis.dss.generic.shared.utils.Share; +import ch.systemsx.cisd.openbis.generic.server.business.bo.SimpleDataSetHelper; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetArchivingStatus; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DeletedDataSet; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; +import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO; /** * The base class for archiving. @@ -53,9 +71,15 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore private static final long serialVersionUID = 1L; + @Private public static final String SHARE_FINDER_KEY = "share-finder"; + private final IStatusChecker archivePrerequisiteOrNull; private final IStatusChecker unarchivePrerequisiteOrNull; + + private transient IShareIdManager shareIdManager; + + private transient IEncapsulatedOpenBISService service; public AbstractArchiverProcessingPlugin(Properties properties, File storeRoot, IStatusChecker archivePrerequisiteOrNull, IStatusChecker unarchivePrerequisiteOrNull) @@ -64,7 +88,7 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore this.archivePrerequisiteOrNull = archivePrerequisiteOrNull; this.unarchivePrerequisiteOrNull = unarchivePrerequisiteOrNull; } - + /** * NOTE: this method is not allowed to throw exception as this will leave data sets in the * openBIS database with an inconsistent status. @@ -97,6 +121,18 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore { operationLog.info("Archiving of the following datasets has been requested: " + CollectionUtils.abbreviate(datasets, 10)); + for (DatasetDescription dataset : datasets) + { + if (dataset.getDataSetSize() == null) + { + String dataSetCode = dataset.getDatasetCode(); + String shareId = getShareIdManager().getShareId(dataSetCode); + File shareFolder = new File(storeRoot, shareId); + String dataSetLocation = dataset.getDataSetLocation(); + long size = FileUtils.sizeOfDirectory(new File(shareFolder, dataSetLocation)); + getService().updateShareIdAndSize(dataSetCode, shareId, size); + } + } DatasetProcessingStatuses statuses = safeArchive(datasets, context, removeFromDataStore); @@ -212,14 +248,15 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore IDataSetDeleter dataSetDeleter = ServiceProvider.getDataStoreService().getDataSetDeleter(); dataSetDeleter.scheduleDeletionOfDataSets(datasets); } - + public ProcessingStatus unarchive(List<DatasetDescription> datasets, - final ArchiverTaskContext context) + ArchiverTaskContext context) { operationLog.info("Unarchiving of the following datasets has been requested: " + CollectionUtils.abbreviate(datasets, 10)); - - DatasetProcessingStatuses statuses = safeUnarchive(datasets, context); + + DatasetProcessingStatuses statuses = + safeUnarchive(datasets, createUnarchivingContext(context)); asyncUpdateStatuses(statuses.getSuccessfulDatasetCodes(), AVAILABLE, true); asyncUpdateStatuses(statuses.getFailedDatasetCodes(), ARCHIVED, true); @@ -227,6 +264,30 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore return statuses.getProcessingStatus(); } + private ArchiverTaskContext createUnarchivingContext(ArchiverTaskContext context) + { + Properties props = + PropertyParametersUtil.extractSingleSectionProperties(properties, SHARE_FINDER_KEY, + false).getProperties(); + if (props.isEmpty()) + { + return context; + } + + String dataStoreCode = ServiceProvider.getConfigProvider().getDataStoreCode(); + Set<String> incomingShares = ETLDaemon.getIdsOfIncomingShares(); + IFreeSpaceProvider freeSpaceProvider = new SimpleFreeSpaceProvider(); + List<Share> shares = + SegmentedStoreUtils.getDataSetsPerShare(storeRoot, dataStoreCode, incomingShares, + freeSpaceProvider, getService(), new Log4jSimpleLogger(operationLog)); + IShareFinder shareFinder = + ClassUtils.create(IShareFinder.class, props.getProperty("class"), props); + DataSetDirectoryProviderForUnarchiving directoryProvider = + new DataSetDirectoryProviderForUnarchiving(context.getDirectoryProvider(), + shareFinder, getService(), shares); + return new ArchiverTaskContext(directoryProvider); + } + /** * a 'safe' method that never throws any exceptions. */ @@ -444,6 +505,82 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore return new GroupedDatasets(present, notPresent); } + + private IShareIdManager getShareIdManager() + { + if (shareIdManager == null) + { + shareIdManager = ServiceProvider.getShareIdManager(); + } + return shareIdManager; + } + + private IEncapsulatedOpenBISService getService() + { + if (service == null) + { + service = ServiceProvider.getOpenBISService(); + } + return service; + } + + /** + * Data set directory provider which might change share in accordance with a + * {@link IShareFinder}. + * + * @author Franz-Josef Elmer + */ + private static final class DataSetDirectoryProviderForUnarchiving implements + IDataSetDirectoryProvider + { + private final IDataSetDirectoryProvider provider; + + private final IShareFinder shareFinder; + + private final IEncapsulatedOpenBISService service; + + private final List<Share> shares; + + DataSetDirectoryProviderForUnarchiving(IDataSetDirectoryProvider provider, + IShareFinder shareFinder, IEncapsulatedOpenBISService service, List<Share> shares) + { + this.provider = provider; + this.shareFinder = shareFinder; + this.service = service; + this.shares = shares; + } + + public File getStoreRoot() + { + return provider.getStoreRoot(); + } + + public IShareIdManager getShareIdManager() + { + return provider.getShareIdManager(); + } + + public File getDataSetDirectory(DatasetDescription dataSet) + { + SimpleDataSetInformationDTO translatedDataSet = SimpleDataSetHelper.translate(dataSet); + String dataSetCode = dataSet.getDatasetCode(); + IShareIdManager shareIdManager = getShareIdManager(); + String shareId = shareIdManager.getShareId(dataSetCode); + translatedDataSet.setDataSetShareId(shareId); + Share share = shareFinder.tryToFindShare(translatedDataSet, shares); + if (share != null) + { + String newShareId = share.getShareId(); + if (newShareId.equals(shareId) == false) + { + service.updateShareIdAndSize(dataSetCode, newShareId, dataSet.getDataSetSize()); + shareIdManager.setShareId(dataSetCode, newShareId); + } + } + return provider.getDataSetDirectory(dataSet); + } + + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetFileOperationsManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetFileOperationsManager.java index 770dc5cedc4f7c57bb6d3997ad61c68a3d9c9034..467a966f3b87d524c088ae15d300cd42a7f310f2 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetFileOperationsManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/DataSetFileOperationsManager.java @@ -160,9 +160,11 @@ public class DataSetFileOperationsManager { File destinationFolder = new File(destination, dataset.getDataSetLocation()); checkDestinationExists(destinationFolder); + File folder = originalData.getParentFile(); operationLog.info("Retrieve data set '" + dataset.getDatasetCode() + "' from '" - + destinationFolder.getPath() + "' to '" + originalData.getParentFile()); - executor.retrieveDataSetFromDestination(originalData.getParentFile(), destinationFolder); + + destinationFolder.getPath() + "' to '" + folder); + folder.mkdirs(); + executor.retrieveDataSetFromDestination(folder, destinationFolder); return Status.OK; } catch (ExceptionWithStatus ex) { 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 599921c0d988539f61283f72bba68b595349c233..3cc24255e2c342ac6655d8649bdc0f01a579c9a1 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 @@ -26,6 +26,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.io.FileUtils; @@ -141,17 +142,24 @@ public class SegmentedStoreUtils * and updates the size of all data sets if necessary. * * @param dataStoreCode Code of the data store to which the root belongs. + * @param incomingShares Set of IDs of incoming shares. Will be used to mark {@link Share} + * object in the returned list. * @param freeSpaceProvider Provider of free space used for all shares. * @param service Access to openBIS API in order to get all data sets and to update data set * size. * @param log Logger for logging size calculations. */ public static List<Share> getDataSetsPerShare(File storeRoot, String dataStoreCode, - IFreeSpaceProvider freeSpaceProvider, IEncapsulatedOpenBISService service, - ISimpleLogger log) + Set<String> incomingShares, IFreeSpaceProvider freeSpaceProvider, + IEncapsulatedOpenBISService service, ISimpleLogger log) { - return getDataSetsPerShare(storeRoot, dataStoreCode, freeSpaceProvider, service, log, + List<Share> shares = getDataSetsPerShare(storeRoot, dataStoreCode, freeSpaceProvider, service, log, SystemTimeProvider.SYSTEM_TIME_PROVIDER); + for (Share share : shares) + { + share.setIncoming(incomingShares.contains(share.getShareId())); + } + return shares; } static List<Share> getDataSetsPerShare(File storeRoot, String dataStoreCode, diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SimpleDataSetHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SimpleDataSetHelper.java index 5a057cd6350c4accd21f9918402332b9a0a4675e..3e6ca338fe6470c65371e298aec85684b01ac5e7 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SimpleDataSetHelper.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/SimpleDataSetHelper.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.List; import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; +import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; import ch.systemsx.cisd.openbis.generic.shared.dto.SimpleDataSetInformationDTO; @@ -74,4 +75,19 @@ public class SimpleDataSetHelper return result; } + + public static SimpleDataSetInformationDTO translate(DatasetDescription datasetDescription) + { + SimpleDataSetInformationDTO result = new SimpleDataSetInformationDTO(); + result.setDatabaseInstanceCode(datasetDescription.getDatabaseInstanceCode()); + result.setDataSetCode(datasetDescription.getDatasetCode()); + result.setDataSetLocation(datasetDescription.getDataSetLocation()); + result.setDataSetSize(datasetDescription.getDataSetSize()); + result.setDataSetType(datasetDescription.getDatasetTypeCode()); + result.setExperimentCode(datasetDescription.getExperimentCode()); + result.setGroupCode(datasetDescription.getSpaceCode()); + result.setProjectCode(datasetDescription.getProjectCode()); + result.setSampleCode(datasetDescription.getSampleCode()); + return result; + } }