From 6fbada119a9cfc70d53ac26f74979fdfd94051bd Mon Sep 17 00:00:00 2001 From: jakubs <jakubs> Date: Mon, 3 Nov 2014 15:27:29 +0000 Subject: [PATCH] SSDM-1081 implement basic unarchiving SVN: 32709 --- .../dss/generic/server/DataStoreService.java | 10 +- .../server/DataStoreServiceLogger.java | 13 +- .../AbstractArchiverProcessingPlugin.java | 7 +- .../IMultiDataSetFileOperationsManager.java | 3 + .../archiver/IMultiDataSetPackageManager.java | 31 ++++ .../MultiDataSetFileOperationsManager.java | 31 +++- .../archiver/MultiDataSetPackageManager.java | 77 +++++++++ .../archiver/MultiDatasetArchiver.java | 146 +++++++++++++++++- ...IMultiDataSetArchiverReadonlyQueryDAO.java | 2 +- .../IMultiDatasetArchiverDBTransaction.java | 2 - .../MultiDataSetArchiverDataSetDTO.java | 2 +- .../MultiDatasetArchiverDBTransaction.java | 14 +- .../MultiDatasetArchiverDataSourceUtil.java | 41 +++++ .../dss/generic/shared/IArchiverPlugin.java | 22 ++- .../archiver/MultiDatasetArchiverTest.java | 45 ++++-- 15 files changed, 384 insertions(+), 62 deletions(-) create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetPackageManager.java create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetPackageManager.java create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDataSourceUtil.java diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java index abe8fcd4543..4c4921cd888 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java @@ -362,6 +362,13 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic userEmailOrNull); } + @Override + public List<String> getDataSetCodesForUnarchiving(String sessionToken, String userSessionToken, List<String> datasets, String userId) + { + sessionTokenManager.assertValidSessionToken(sessionToken); + return getArchiverPlugin().getDataSetCodesForUnarchiving(datasets); + } + @Override public void archiveDatasets(String sessionToken, String userSessionToken, List<DatasetDescription> datasets, String userId, String userEmailOrNull, @@ -544,8 +551,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic sessionTokenManager.assertValidSessionToken(sessionToken); PluginTaskProvider<ISearchDomainService> provider = pluginTaskInfoProvider.getSearchDomainServiceProvider(); - DatastoreServiceDescription serviceDescription - = findSearchDomainService(provider, preferredSequenceDatabaseOrNull); + DatastoreServiceDescription serviceDescription = findSearchDomainService(provider, preferredSequenceDatabaseOrNull); if (serviceDescription != null) { ISearchDomainService service = provider.getPluginInstance(serviceDescription.getKey()); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java index 4d92847e6a2..fc6dd9a69b2 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java @@ -164,6 +164,13 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable datasets.size(), userId, userEmailOrNull, removeFromDataStore); } + @Override + public List<String> getDataSetCodesForUnarchiving(String sessionToken, String userSessionToken, List<String> datasets, String userId) + { + log("getDataSetCodesForUnarchiving", "NO_OF_DATASETS(%s)", datasets.size()); + return null; + } + @Override public LinkModel retrieveLinkFromDataSet(String sessionToken, String serviceKey, DatasetDescription dataSet) @@ -198,11 +205,11 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable } @Override - public List<SearchDomainSearchResult> searchForDataSetsWithSequences(String sessionToken, - String preferredSequenceDatabaseOrNull, String sequenceSnippet, + public List<SearchDomainSearchResult> searchForDataSetsWithSequences(String sessionToken, + String preferredSequenceDatabaseOrNull, String sequenceSnippet, Map<String, String> optionalParametersOrNull) { - log("searchForDataSetsWithSequences", "SEQUENCE_DATABASE(%s) SEQUENCE_SNIPPET(%s)", + log("searchForDataSetsWithSequences", "SEQUENCE_DATABASE(%s) SEQUENCE_SNIPPET(%s)", preferredSequenceDatabaseOrNull, sequenceSnippet); return null; } 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 085532b1eb5..57b3b504399 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 @@ -636,7 +636,7 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore } } - private IShareIdManager getShareIdManager() + protected IShareIdManager getShareIdManager() { if (shareIdManager == null) { @@ -748,4 +748,9 @@ public abstract class AbstractArchiverProcessingPlugin extends AbstractDatastore return maximumBatchSizeInBytes; } + @Override + public List<String> getDataSetCodesForUnarchiving(List<String> dataSetCodes) + { + return dataSetCodes; + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetFileOperationsManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetFileOperationsManager.java index b97c7ee1534..f42e6743161 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetFileOperationsManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetFileOperationsManager.java @@ -37,6 +37,9 @@ public interface IMultiDataSetFileOperationsManager Status deleteContainerFromStage(String containerPath); + /** + * Get's the content of archived content in final destination. + */ IHierarchicalContent getContainerAsHierarchicalContent(String containerPath); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetPackageManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetPackageManager.java new file mode 100644 index 00000000000..f9e64ad3e11 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/IMultiDataSetPackageManager.java @@ -0,0 +1,31 @@ +/* + * Copyright 2014 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver; + +import java.io.File; +import java.util.HashMap; + +import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IPackageManager; + +/** + * @author Jakub Straszewski + */ +public interface IMultiDataSetPackageManager extends IPackageManager +{ + Status extractMultiDataSets(File packageFile, HashMap<String, File> dataSetCodeToDirectory); +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetFileOperationsManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetFileOperationsManager.java index cc6e1baac43..f86b35a62b3 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetFileOperationsManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetFileOperationsManager.java @@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver; import java.io.File; import java.io.Serializable; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Properties; @@ -39,10 +40,8 @@ import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchical import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.openbis.dss.archiveverifier.batch.VerificationError; import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager; -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IPackageManager; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IPathCopierFactory; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.ISshCommandExecutorFactory; -import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.TarPackageManager; import ch.systemsx.cisd.openbis.dss.generic.shared.IShareIdManager; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; @@ -73,7 +72,7 @@ public class MultiDataSetFileOperationsManager extends AbstractDataSetFileOperat private final boolean withSharding; - protected IPackageManager packageManager; + protected IMultiDataSetPackageManager packageManager; // TODO: some features existing in rsync archiver: // - ignore existing @@ -81,7 +80,7 @@ public class MultiDataSetFileOperationsManager extends AbstractDataSetFileOperat public MultiDataSetFileOperationsManager(Properties properties, IPathCopierFactory pathCopierFactory, ISshCommandExecutorFactory sshCommandExecutorFactory) { - this.packageManager = new TarPackageManager(properties); + this.packageManager = new MultiDataSetPackageManager(properties); this.withSharding = PropertyUtils.getBoolean(properties, WITH_SHARDING_KEY, false); @@ -142,6 +141,22 @@ public class MultiDataSetFileOperationsManager extends AbstractDataSetFileOperat return success ? Status.OK : Status.createError("Couldn't delete archive container '" + containerPath); } + public Status restoreDataSetsFromContainerInFinalDestination(String containerPath, String unarchivingShareId, + List<DatasetDescription> dataSetDescriptions) + { + HashMap<String, File> dataSetToLocation = new HashMap<String, File>(); + for (DatasetDescription datasetDescription : dataSetDescriptions) + { + File location = getDirectoryProvider().getDataSetDirectory(unarchivingShareId, datasetDescription.getDataSetLocation()); + dataSetToLocation.put(datasetDescription.getDataSetCode(), location); + } + + File stageArchiveContainerFile = new File(getFinalArchive().getDestination(), containerPath); + packageManager.extractMultiDataSets(stageArchiveContainerFile, dataSetToLocation); + + return Status.OK; + } + @Override public Status createContainerInStage(String containerPath, List<DatasetDescription> datasetDescriptions) { @@ -158,16 +173,16 @@ public class MultiDataSetFileOperationsManager extends AbstractDataSetFileOperat shareIdManager.lock(dataSet.getCode()); operationLog.info("Archive dataset " + dataSet.getCode() + " in " + containerPath); } - + boolean result = createFolderIfNotExists(stageArchive, stageArchiveContainerFile.getParentFile()); - + // TODO: react somehow? if (result) { operationLog.warn("File already exists in archive " + stageArchiveContainerFile.getParentFile()); } - - packageManager.create(stageArchiveContainerFile, dataSets); // packagemanager + + packageManager.create(stageArchiveContainerFile, dataSets); } catch (Exception ex) { status = Status.createError(ex.toString()); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetPackageManager.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetPackageManager.java new file mode 100644 index 00000000000..7f3035b13ab --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDataSetPackageManager.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Properties; + +import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; +import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.filesystem.tar.Untar; +import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDataSetPackager; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.TarPackageManager; + +/** + * @author Jakub Straszewski + */ +public class MultiDataSetPackageManager extends TarPackageManager implements IMultiDataSetPackageManager +{ + + public MultiDataSetPackageManager(Properties properties) + { + super(properties); + } + + @Override + public Status extractMultiDataSets(File packageFile, HashMap<String, File> dataSetCodeToDirectory) + { + Untar untar = null; + try + { + untar = new Untar(packageFile); + untar.extract(dataSetCodeToDirectory); + + for (File location : dataSetCodeToDirectory.values()) + { + File metadataFile = new File(location, AbstractDataSetPackager.META_DATA_FILE_NAME); + if (metadataFile.exists() && metadataFile.isFile()) + { + FileUtilities.delete(metadataFile); + } + } + return Status.OK; + } catch (Exception ex) + { + return Status.createError(ex.toString()); + } finally + { + if (untar != null) + { + try + { + untar.close(); + } catch (IOException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + } + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiver.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiver.java index 71d5d8119eb..11fcd67a9b0 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiver.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiver.java @@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver; import java.io.File; import java.io.Serializable; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -35,12 +36,16 @@ import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.AbstractArch import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.RsyncArchiveCopierFactory; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.RsyncArchiver; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.SshCommandExecutorFactory; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.IMultiDataSetArchiverReadonlyQueryDAO; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.IMultiDatasetArchiverDBTransaction; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDataSetArchiverContainerDTO; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDataSetArchiverDataSetDTO; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDatasetArchiverDBTransaction; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDatasetArchiverDataSourceUtil; import ch.systemsx.cisd.openbis.dss.generic.shared.ArchiverTaskContext; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AbstractExternalData; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocation; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PhysicalDataSet; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; /** @@ -85,12 +90,19 @@ public class MultiDatasetArchiver extends AbstractArchiverProcessingPlugin private IMultiDatasetArchiverDBTransaction transaction; + private IMultiDataSetArchiverReadonlyQueryDAO readonlyQuery; + + public static final String UNARCHIVING_SHARE_ID = "unarchiving-share-id"; + + private final String unarchivingShareId; + public MultiDatasetArchiver(Properties properties, File storeRoot) { super(properties, storeRoot, null, null); this.minimumContainerSize = PropertyUtils.getLong(properties, MINIMUM_CONTAINER_SIZE_IN_BYTES, DEFAULT_MINIMUM_CONTAINER_SIZE_IN_BYTES); this.maximumContainerSize = PropertyUtils.getLong(properties, MAXIMUM_CONTAINER_SIZE_IN_BYTES, DEFAULT_MAXIMUM_CONTAINER_SIZE_IN_BYTES); this.fileOperationsFactory = new FileOperationsManagerFactory(properties); + this.unarchivingShareId = PropertyUtils.getMandatoryProperty(properties, UNARCHIVING_SHARE_ID); } @Override @@ -310,13 +322,124 @@ public class MultiDatasetArchiver extends AbstractArchiverProcessingPlugin } @Override - protected DatasetProcessingStatuses doUnarchive(List<DatasetDescription> datasets, ArchiverTaskContext context) + public List<String> getDataSetCodesForUnarchiving(List<String> dataSetCodes) + { + assertAllDataSetsInTheSameContainer(dataSetCodes); + return getCodesOfAllDataSetsInContainer(dataSetCodes); + } + + @Override + protected DatasetProcessingStatuses doUnarchive(List<DatasetDescription> parameterDataSets, ArchiverTaskContext context) + { + List<String> dataSetCodes = translateToDataSetCodes(parameterDataSets); + long containerId = assertAllDataSetsInTheSameContainer(dataSetCodes); + List<PhysicalDataSet> dataSets = translateToPhysicalDataSets(dataSetCodes); + assertNoAvailableDatasets(dataSets); + + for (PhysicalDataSet physicalDataSet : dataSets) + { + String dataSetCode = physicalDataSet.getCode(); + + String shareId = getShareIdManager().getShareId(dataSetCode); + if (shareId.equals(unarchivingShareId) == false) + { + getService().updateShareIdAndSize(dataSetCode, unarchivingShareId, physicalDataSet.getSize()); + getShareIdManager().setShareId(dataSetCode, unarchivingShareId); + } + + } + + MultiDataSetArchiverContainerDTO container = getReadonlyQuery().getContainerForId(containerId); + + ((MultiDataSetFileOperationsManager) getFileOperations()).restoreDataSetsFromContainerInFinalDestination( + container.getPath(), + + unarchivingShareId, parameterDataSets); + + DatasetProcessingStatuses result = new DatasetProcessingStatuses(); + result.addResult(parameterDataSets, Status.OK, Operation.UNARCHIVE); + return result; + } + + private void assertNoAvailableDatasets(List<PhysicalDataSet> dataSets) + { + for (PhysicalDataSet physicalDataSet : dataSets) + { + if (physicalDataSet.isAvailable()) + { + throw new IllegalArgumentException("Dataset '" + physicalDataSet.getCode() + "'specified for unarchiving is available"); + } + } + } + + private List<String> getCodesOfAllDataSetsInContainer(List<String> dataSetCodes) + { + + MultiDataSetArchiverDataSetDTO dataset = getReadonlyQuery().getDataSetForCode(dataSetCodes.get(0)); + Long containerId = dataset.getContainerId(); + List<MultiDataSetArchiverDataSetDTO> dbDataSets = getReadonlyQuery().listDataSetsForContainerId(containerId); + + List<String> enhancedDataSetCodes = new LinkedList<String>(); + for (MultiDataSetArchiverDataSetDTO dbDataSet : dbDataSets) + { + enhancedDataSetCodes.add(dbDataSet.getCode()); + } + return enhancedDataSetCodes; + } + + private List<PhysicalDataSet> translateToPhysicalDataSets(List<String> dataSetCodes) + { + List<PhysicalDataSet> result = new LinkedList<PhysicalDataSet>(); + for (AbstractExternalData dataSet : getService().listDataSetsByCode(dataSetCodes)) + { + if (dataSet.tryGetAsDataSet() != null) + { + result.add(dataSet.tryGetAsDataSet()); + } + else + { + throw new IllegalStateException("All data sets in container are expected to be physical datasets, but data set '" + dataSet.getCode() + + "' is not "); + } + } + return result; + } + + private List<String> translateToDataSetCodes(List<? extends IDatasetLocation> dataSets) + { + LinkedList<String> result = new LinkedList<String>(); + for (IDatasetLocation dataSet : dataSets) + { + result.add(dataSet.getDataSetCode()); + } + return result; + } + + /** + * @return ID of container that groups all listed data sets + * @throws exception if not all data sets are in the same container + */ + private long assertAllDataSetsInTheSameContainer(List<String> dataSetCodes) { - if (datasets.size() > 0) + HashSet<Long> containerIds = new HashSet<Long>(); + long containerId = -1; + for (String code : dataSetCodes) + { + MultiDataSetArchiverDataSetDTO dataSet = getTransaction().getDataSetForCode(code); + if (dataSet == null) + { + throw new IllegalArgumentException("Dataset " + code + + " was selected for unarchiving, but is not present in the archive"); + } + containerIds.add(dataSet.getContainerId()); + containerId = dataSet.getContainerId(); + } + if (containerIds.size() > 1) { - throw new NotImplementedException("Unarchiving is not yet implemented for multi dataset archiver"); + throw new IllegalArgumentException("Datasets selected for unarchiving do not all belong to one container, but to " + containerIds.size() + + " different containers"); } - return new DatasetProcessingStatuses(); + return containerId; } @Override @@ -353,7 +476,8 @@ public class MultiDatasetArchiver extends AbstractArchiverProcessingPlugin return dataSetInArchiveDB != null; } - @Private IMultiDataSetFileOperationsManager getFileOperations() + @Private + IMultiDataSetFileOperationsManager getFileOperations() { if (fileOperations == null) { @@ -362,7 +486,8 @@ public class MultiDatasetArchiver extends AbstractArchiverProcessingPlugin return fileOperations; } - @Private IMultiDatasetArchiverDBTransaction getTransaction() + @Private + IMultiDatasetArchiverDBTransaction getTransaction() { if (transaction == null) { @@ -370,4 +495,13 @@ public class MultiDatasetArchiver extends AbstractArchiverProcessingPlugin } return transaction; } + + IMultiDataSetArchiverReadonlyQueryDAO getReadonlyQuery() + { + if (readonlyQuery == null) + { + readonlyQuery = MultiDatasetArchiverDataSourceUtil.getReadonlyQueryDAO(); + } + return readonlyQuery; + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDataSetArchiverReadonlyQueryDAO.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDataSetArchiverReadonlyQueryDAO.java index 31c0c393ab5..12eee012fb5 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDataSetArchiverReadonlyQueryDAO.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDataSetArchiverReadonlyQueryDAO.java @@ -31,7 +31,7 @@ public interface IMultiDataSetArchiverReadonlyQueryDAO extends BaseQuery * SELECT CONTAINER */ final static String SELECT_CONTAINER = - " SELECT id, path" + " SELECT id, path " + "FROM containers "; @Select(sql = SELECT_CONTAINER + "WHERE id = ?{1}") diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDatasetArchiverDBTransaction.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDatasetArchiverDBTransaction.java index 4d72ee67b2a..bf86efbe9a7 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDatasetArchiverDBTransaction.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/IMultiDatasetArchiverDBTransaction.java @@ -21,8 +21,6 @@ import java.util.List; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; /** - * - * * @author Franz-Josef Elmer */ public interface IMultiDatasetArchiverDBTransaction diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDataSetArchiverDataSetDTO.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDataSetArchiverDataSetDTO.java index 1243583172e..e77121c331e 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDataSetArchiverDataSetDTO.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDataSetArchiverDataSetDTO.java @@ -28,7 +28,7 @@ public class MultiDataSetArchiverDataSetDTO private String code; - @ResultColumn("CNTR_ID") + @ResultColumn("CTNR_ID") private long containerId; @ResultColumn("SIZE_IN_BYTES") diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDBTransaction.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDBTransaction.java index bcdd19235ca..191e77f3796 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDBTransaction.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDBTransaction.java @@ -18,11 +18,6 @@ package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.da import java.util.List; -import javax.sql.DataSource; - -import net.lemnik.eodsql.QueryTool; - -import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; /** @@ -31,18 +26,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; public class MultiDatasetArchiverDBTransaction implements IMultiDatasetArchiverDBTransaction { - private static DataSource dataSource = ServiceProvider.getDataSourceProvider().getDataSource("multi-dataset-archiver-db"); - private IMultiDataSetArchiverQueryDAO transaction; public MultiDatasetArchiverDBTransaction() { - this.transaction = getTransactionalQuery(); - } - - private static IMultiDataSetArchiverQueryDAO getTransactionalQuery() - { - return QueryTool.getQuery(dataSource, IMultiDataSetArchiverQueryDAO.class); + this.transaction = MultiDatasetArchiverDataSourceUtil.getTransactionalQuery(); } @Override diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDataSourceUtil.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDataSourceUtil.java new file mode 100644 index 00000000000..2dcf48d0c8c --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/dataaccess/MultiDatasetArchiverDataSourceUtil.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess; + +import javax.sql.DataSource; + +import net.lemnik.eodsql.QueryTool; + +import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; + +/** + * @author Jakub Straszewski + */ +public class MultiDatasetArchiverDataSourceUtil +{ + private static DataSource dataSource = ServiceProvider.getDataSourceProvider().getDataSource("multi-dataset-archiver-db"); + + static IMultiDataSetArchiverQueryDAO getTransactionalQuery() + { + return QueryTool.getQuery(dataSource, IMultiDataSetArchiverQueryDAO.class); + } + + public static IMultiDataSetArchiverReadonlyQueryDAO getReadonlyQueryDAO() + { + return QueryTool.getQuery(dataSource, IMultiDataSetArchiverReadonlyQueryDAO.class); + } +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IArchiverPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IArchiverPlugin.java index d7aad7b503b..4aac4c281aa 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IArchiverPlugin.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IArchiverPlugin.java @@ -27,15 +27,15 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription; * * @author Piotr Buczek * @author Kaloyan Enimanev + * @author Jakub Straszewski */ public interface IArchiverPlugin extends Serializable { /** * Asynchronously processes archiving of the specified datasets. * - * @returns {@link ProcessingStatus} of the finished processing with statuses of processing for - * all scheduled data sets or null if processing succeeded for all datasets and no - * additional information is provided. + * @returns {@link ProcessingStatus} of the finished processing with statuses of processing for all scheduled data sets or null if processing + * succeeded for all datasets and no additional information is provided. */ ProcessingStatus archive(List<DatasetDescription> datasets, ArchiverTaskContext context, boolean removeFromDataStore); @@ -43,17 +43,23 @@ public interface IArchiverPlugin extends Serializable /** * Asynchronously processes unarchiving of the specified datasets. * - * @returns {@link ProcessingStatus} of the finished processing with statuses of processing for - * all scheduled data sets or null if processing succeeded for all datasets and no - * additional information is provided. + * @returns {@link ProcessingStatus} of the finished processing with statuses of processing for all scheduled data sets or null if processing + * succeeded for all datasets and no additional information is provided. */ ProcessingStatus unarchive(List<DatasetDescription> datasets, ArchiverTaskContext context); + /** + * Enhances the list of data set codes, so that it contains all datasets that should be unarchived together in one batch. + * + * @returns the list that should be a superset {@code dataSetCodes} + */ + List<String> getDataSetCodesForUnarchiving(List<String> dataSetCodes); + /** * Delete data sets from the archive. * - * @returns {@link ProcessingStatus} containing the deletion statuses for all data sets or null - * if processing succeeded for all datasets and no additional information is provided. + * @returns {@link ProcessingStatus} containing the deletion statuses for all data sets or null if processing succeeded for all datasets and no + * additional information is provided. */ ProcessingStatus deleteFromArchive(List<DatasetLocation> datasets); } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiverTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiverTest.java index 208b1c9d2e7..5cdbc941cf5 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiverTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/standard/archiver/MultiDatasetArchiverTest.java @@ -20,12 +20,12 @@ import static ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archi import static ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.MultiDataSetFileOperationsManager.STAGING_DESTINATION_KEY; import static ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.MultiDatasetArchiver.MAXIMUM_CONTAINER_SIZE_IN_BYTES; import static ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.MultiDatasetArchiver.MINIMUM_CONTAINER_SIZE_IN_BYTES; +import static ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.MultiDatasetArchiver.UNARCHIVING_SHARE_ID; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -33,8 +33,6 @@ import java.util.Comparator; import java.util.List; import java.util.Properties; -import javassist.bytecode.analysis.MultiArrayType; - import org.apache.log4j.Level; import org.jmock.Expectations; import org.jmock.Mockery; @@ -54,6 +52,7 @@ import ch.systemsx.cisd.common.time.TimingParameters; import ch.systemsx.cisd.openbis.common.io.hierarchical_content.TarBasedHierarchicalContent; import ch.systemsx.cisd.openbis.common.io.hierarchical_content.api.IHierarchicalContentNode; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.MockDataSetDirectoryProvider; +import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.IMultiDataSetArchiverReadonlyQueryDAO; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.IMultiDatasetArchiverDBTransaction; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDataSetArchiverContainerDTO; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.archiver.dataaccess.MultiDataSetArchiverDataSetDTO; @@ -208,14 +207,16 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase private IMultiDataSetFileOperationsManager fileManager; + private IMultiDataSetArchiverReadonlyQueryDAO readonlyDAO; + public MockMultiDatasetArchiver(Properties properties, File storeRoot, IEncapsulatedOpenBISService openBISService, IShareIdManager shareIdManager, IDataSetStatusUpdater statusUpdater, IMultiDatasetArchiverDBTransaction transaction, - IMultiDataSetFileOperationsManager fileManager) + IMultiDataSetFileOperationsManager fileManager, IMultiDataSetArchiverReadonlyQueryDAO readonlyDAO) { super(properties, storeRoot); this.transaction = transaction; - this.fileManager = fileManager; + this.readonlyDAO = readonlyDAO; setService(openBISService); setShareIdManager(shareIdManager); setStatusUpdater(statusUpdater); @@ -232,6 +233,12 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase { return transaction; } + + @Override + IMultiDataSetArchiverReadonlyQueryDAO getReadonlyQuery() + { + return readonlyDAO; + } } private static final String EXPERIMENT_IDENTIFIER = "/S/P/E"; @@ -242,6 +249,8 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase private IMultiDatasetArchiverDBTransaction transaction; + private IMultiDataSetArchiverReadonlyQueryDAO readonlyDAO; + private IDataSetDirectoryProvider directoryProvider; private IHierarchicalContentProvider hierarchicalContentProvider; @@ -311,9 +320,11 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase properties = new Properties(); properties.setProperty(STAGING_DESTINATION_KEY, staging.getAbsolutePath()); properties.setProperty(FINAL_DESTINATION_KEY, archive.getAbsolutePath()); + properties.setProperty(UNARCHIVING_SHARE_ID, "2"); directoryProvider = new MockDataSetDirectoryProvider(store, share.getName(), shareIdManager); archiverContext = new ArchiverTaskContext(directoryProvider, hierarchicalContentProvider); experiment = new ExperimentBuilder().identifier(EXPERIMENT_IDENTIFIER).type("MET").getExperiment(); + readonlyDAO = context.mock(IMultiDataSetArchiverReadonlyQueryDAO.class); context.checking(new Expectations() { { @@ -341,28 +352,28 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase // To following line of code should also be called at the end of each test method. // Otherwise one does not known which test failed. context.assertIsSatisfied(); - + ServiceProviderTestWrapper.restoreApplicationContext(); } - + @Test public void testArchiveDataSetsWhichAreTooSmall() { prepareUpdateShareIdAndSize(ds1, 10); prepareUpdateShareIdAndSize(ds2, 20); properties.setProperty(MINIMUM_CONTAINER_SIZE_IN_BYTES, "35"); - + MultiDatasetArchiver archiver = createArchiver(null); ProcessingStatus status = archiver.archive(Arrays.asList(ds1, ds2), archiverContext, false); - + assertEquals("[ERROR: \"Set of data sets specified for archiving is too small (30 bytes) " - + "to be archived with multi dataset archiver because minimum size is 35 bytes.\"]", + + "to be archived with multi dataset archiver because minimum size is 35 bytes.\"]", status.getErrorStatuses().toString()); assertEquals("[ds1, ds2]: AVAILABLE false\n", statusUpdater.toString()); assertEquals("Containers:\nData sets:\ncomitted: false, rolledBack: true, closed: true", transaction.toString()); context.assertIsSatisfied(); } - + @Test public void testArchiveDataSetsWhichAreTooBig() { @@ -370,12 +381,12 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase prepareUpdateShareIdAndSize(ds2, 20); properties.setProperty(MINIMUM_CONTAINER_SIZE_IN_BYTES, "25"); properties.setProperty(MAXIMUM_CONTAINER_SIZE_IN_BYTES, "27"); - + MultiDatasetArchiver archiver = createArchiver(null); ProcessingStatus status = archiver.archive(Arrays.asList(ds1, ds2), archiverContext, false); - + assertEquals("[ERROR: \"Set of data sets specified for archiving is too big (30 bytes) " - + "to be archived with multi dataset archiver because maximum size is 27 bytes.\"]", + + "to be archived with multi dataset archiver because maximum size is 27 bytes.\"]", status.getErrorStatuses().toString()); assertEquals("[ds1, ds2]: AVAILABLE false\n", statusUpdater.toString()); assertEquals("Containers:\nData sets:\ncomitted: false, rolledBack: true, closed: true", transaction.toString()); @@ -651,8 +662,8 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase context.checking(new Expectations() { { - one(dataSetDeleter).scheduleDeletionOfDataSets(Arrays.asList(dataSets), - TimingParameters.DEFAULT_MAXIMUM_RETRY_COUNT, + one(dataSetDeleter).scheduleDeletionOfDataSets(Arrays.asList(dataSets), + TimingParameters.DEFAULT_MAXIMUM_RETRY_COUNT, TimingParameters.DEFAULT_INTERVAL_TO_WAIT_AFTER_FAILURE_SECONDS); } }); @@ -704,7 +715,7 @@ public class MultiDatasetArchiverTest extends AbstractFileSystemTestCase private MultiDatasetArchiver createArchiver(IMultiDataSetFileOperationsManager fileManagerOrNull) { return new MockMultiDatasetArchiver(properties, store, openBISService, shareIdManager, statusUpdater, - transaction, fileManagerOrNull); + transaction, fileManagerOrNull, readonlyDAO); } private DatasetDescription dataSet(final String code, String content) -- GitLab