diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java index ac33d5450cb904538e53f98f570fbaadc7b81f6c..772ef2f24cdb9a267d37eb27ccb1ce8b38bb62d8 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ETLDaemon.java @@ -43,6 +43,7 @@ import ch.systemsx.cisd.common.exceptions.HighLevelException; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.filesystem.DirectoryScanningTimerTask; import ch.systemsx.cisd.common.filesystem.DirectoryScanningTimerTask.IScannedStore; +import ch.systemsx.cisd.common.filesystem.FaultyPathDirectoryScanningHandler.IFaultyPathDirectoryScanningHandlerDelegate; import ch.systemsx.cisd.common.filesystem.FaultyPathDirectoryScanningHandler; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.filesystem.IDirectoryScanningHandler; @@ -325,7 +326,8 @@ public final class ETLDaemon dataSourceQueryService, notifySuccessfulRegistration); final HighwaterMarkDirectoryScanningHandler directoryScanningHandler = createDirectoryScanningHandler(pathHandler, highwaterMarkWatcher, - incomingDataDirectory, threadParameters.reprocessFaultyDatasets()); + incomingDataDirectory, threadParameters.reprocessFaultyDatasets(), + pathHandler); FileFilter fileFilter = createFileFilter(incomingDataDirectory, threadParameters.useIsFinishedMarkerFile(), parameters); @@ -551,25 +553,28 @@ public final class ETLDaemon private final static HighwaterMarkDirectoryScanningHandler createDirectoryScanningHandler( final IStopSignaler stopSignaler, final HighwaterMarkWatcher highwaterMarkWatcher, - final File incomingDataDirectory, boolean reprocessFaultyDatasets) + final File incomingDataDirectory, boolean reprocessFaultyDatasets, + IFaultyPathDirectoryScanningHandlerDelegate faultyPathHandlerDelegate) { final IDirectoryScanningHandler faultyPathHandler = createFaultyPathHandler(stopSignaler, incomingDataDirectory, - reprocessFaultyDatasets); + reprocessFaultyDatasets, faultyPathHandlerDelegate); return new HighwaterMarkDirectoryScanningHandler(faultyPathHandler, highwaterMarkWatcher, incomingDataDirectory); } private static IDirectoryScanningHandler createFaultyPathHandler( final IStopSignaler stopSignaler, final File incomingDataDirectory, - boolean reprocessFaultyDatasets) + boolean reprocessFaultyDatasets, + IFaultyPathDirectoryScanningHandlerDelegate faultyPathHandlerDelegate) { if (reprocessFaultyDatasets) { return createDummyFaultyPathHandler(); } else { - return new FaultyPathDirectoryScanningHandler(incomingDataDirectory, stopSignaler); + return new FaultyPathDirectoryScanningHandler(incomingDataDirectory, stopSignaler, + faultyPathHandlerDelegate); } } @@ -623,7 +628,9 @@ public final class ETLDaemon TimingParameters.setDefault(parameters.getTimingParameters()); if (QueueingPathRemoverService.isRunning() == false) { - QueueingPathRemoverService.start(DssPropertyParametersUtil.getStoreRootDir(parameters.getProperties()), shredderQueueFile); + QueueingPathRemoverService.start( + DssPropertyParametersUtil.getStoreRootDir(parameters.getProperties()), + shredderQueueFile); } if (QueueingDataSetStatusUpdaterService.isRunning() == false) { diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ITopLevelDataSetRegistrator.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ITopLevelDataSetRegistrator.java index faa8d26d7976eff6c2d8d0613250397928c67d7e..c93de2bd194d4ad8bc96cec120733ec611124065 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/ITopLevelDataSetRegistrator.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/ITopLevelDataSetRegistrator.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.concurrent.locks.Lock; import ch.systemsx.cisd.common.filesystem.IPathHandler; +import ch.systemsx.cisd.common.filesystem.FaultyPathDirectoryScanningHandler.IFaultyPathDirectoryScanningHandlerDelegate; import ch.systemsx.cisd.common.utilities.ISelfTestable; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; @@ -28,7 +29,8 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; * * @author Chandrasekhar Ramakrishnan */ -public interface ITopLevelDataSetRegistrator extends IPathHandler, ISelfTestable +public interface ITopLevelDataSetRegistrator extends IPathHandler, ISelfTestable, + IFaultyPathDirectoryScanningHandlerDelegate { /** * A lock used to synchronize shutting down the processing thread of the top-level data set diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java index 0a8cedb44bb57caf44703cedd7e4b8046562dac5..a3a45ba1fb99703cf209b98d7e7bde19d32e0a2f 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/TransferredDataSetHandler.java @@ -347,7 +347,8 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi File incomingDataSetFile, final DataSetInformation dsInfo, DataSetRegistrationAlgorithm.IDataSetInApplicationServerRegistrator registrator) { - IDelegatedActionWithResult<Boolean> cleanAftrewardsAction = new AbstractDelegatedActionWithResult<Boolean>(true); + IDelegatedActionWithResult<Boolean> cleanAftrewardsAction = + new AbstractDelegatedActionWithResult<Boolean>(true); if (registrator != null) { return new OverridingRegistrationHelper(this, incomingDataSetFile, getGlobalState() @@ -546,4 +547,12 @@ public final class TransferredDataSetHandler extends AbstractTopLevelDataSetRegi { return getGlobalState().getStoreRootDir(); } + + /** + * Any path can be added to faulty paths as far as we are concerned. + */ + public boolean shouldNotAddToFaultyPathsOrNull(File storeItem) + { + return false; + } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetServerPluginHolder.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetServerPluginHolder.java index f3ab7d1b475b54eccc8515836cc1f0e2d24e62ec..3922881f6ed5a16a5088c9a505734f98cca621c8 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetServerPluginHolder.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/api/v1/PutDataSetServerPluginHolder.java @@ -86,4 +86,9 @@ public class PutDataSetServerPluginHolder extends AbstractTopLevelDataSetRegistr throw new NotImplementedException(); } + public boolean shouldNotAddToFaultyPathsOrNull(File storeItem) + { + throw new NotImplementedException(); + } + } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java index 14ee954b79ae8d1b1ad5334054bf6afb3d3d56ff..8fc4b2ec2a09ebac165b0298282c1e1adc7e124d 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/AbstractOmniscientTopLevelDataSetRegistrator.java @@ -310,7 +310,7 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat return state.getGlobalState().getStorageRecoveryManager().isRecoveryFile(incoming); } - private boolean hasRecoveryMarkerFile(File incoming) + protected boolean hasRecoveryMarkerFile(File incoming) { return new File(incoming.getAbsolutePath() + IDataSetStorageRecoveryManager.PROCESSING_MARKER).exists(); @@ -362,10 +362,12 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat { public Boolean execute(boolean didOperationSucceed) { - boolean markerDeleteSucceeded = - state.getMarkerFileUtility().deleteAndLogIsFinishedMarkerFile( - incomingDataSetFileOrIsFinishedFile); - return markerDeleteSucceeded; + if (hasRecoveryMarkerFile(incomingDataSetFile)) + { + return true; + } + return state.getMarkerFileUtility().deleteAndLogIsFinishedMarkerFile( + incomingDataSetFileOrIsFinishedFile); } }; } else @@ -487,7 +489,7 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat private void handleRecovery(final File recoveryMarkerFile) { - DataSetStoragePrecommitRecoveryState<T> recoveryState = + final DataSetStoragePrecommitRecoveryState<T> recoveryState = state.getGlobalState().getStorageRecoveryManager() .extractPrecommittedCheckpoint(recoveryMarkerFile); @@ -513,8 +515,19 @@ public abstract class AbstractOmniscientTopLevelDataSetRegistrator<T extends Dat { public Boolean execute(boolean didOperationSucceed) { - recoveryMarkerFile.delete(); - recoveryFile.delete(); + if (didOperationSucceed) + { + File incomingMarkerFile = + MarkerFileUtility.getMarkerFileFromIncoming(recoveryState + .getIncomingDataSetFile().getRealIncomingFile()); + if (incomingMarkerFile.exists()) + { + incomingMarkerFile.delete(); + } + + recoveryMarkerFile.delete(); + recoveryFile.delete(); + } return true; } }; diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java index 128c284309275cf9acb48d2e0f26f4801b698314..2bf89ae0cc3aea35c9e467c7862a99902990d268 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRecoveryManager.java @@ -18,7 +18,12 @@ package ch.systemsx.cisd.etlserver.registrator; import java.io.File; +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.filesystem.FileUtilities; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; /** @@ -28,6 +33,9 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation; */ public class DataSetStorageRecoveryManager implements IDataSetStorageRecoveryManager { + static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + DataSetStorageRecoveryManager.class); + private File dropboxRecoveryStateDir; public <T extends DataSetInformation> void checkpointPrecommittedState( @@ -42,12 +50,20 @@ public class DataSetStorageRecoveryManager implements IDataSetStorageRecoveryMan runner.getDssRegistrationLogger(), runner.getRollbackStack(), incoming); runner.getRollbackStack().setLockedState(true); - + FileUtilities.writeToFile(serializedFile, recoveryState); File processingMarkerFile = getProcessingMarkerFile(runner); FileUtilities.writeToFile(processingMarkerFile, serializedFile.getAbsolutePath()); + operationLog.info("Store precommit recovery checkpoint with markerfile " + + processingMarkerFile); + } + + public <T extends DataSetInformation> void removeCheckpoint( + DataSetStorageAlgorithmRunner<T> runner) + { + cleanup(runner); } private <T extends DataSetInformation> File getProcessingMarkerFile( @@ -72,29 +88,40 @@ public class DataSetStorageRecoveryManager implements IDataSetStorageRecoveryMan String recoveryFilePath = FileUtilities.loadToString(markerFile).trim(); return new File(recoveryFilePath); } - + @SuppressWarnings("unchecked") public <T extends DataSetInformation> DataSetStoragePrecommitRecoveryState<T> extractPrecommittedCheckpoint( File markerFile) { File recoveryFile = getRecoveryFileFromMarker(markerFile); - return FileUtilities.loadToObject(recoveryFile, - DataSetStoragePrecommitRecoveryState.class); + return FileUtilities.loadToObject(recoveryFile, DataSetStoragePrecommitRecoveryState.class); } public <T extends DataSetInformation> void registrationCompleted( DataSetStorageAlgorithmRunner<T> runner) { + cleanup(runner); + } + + public <T extends DataSetInformation> void cleanup(DataSetStorageAlgorithmRunner<T> runner) + { + File markerFile = getProcessingMarkerFile(runner); + File recoveryState = getSerializedFile(runner); + + operationLog.info("Cleanup recovery with marker file "+ markerFile); + runner.getRollbackStack().setLockedState(false); // Cleanup the state we have accumulated - File markerFile = getProcessingMarkerFile(runner); FileUtilities.delete(markerFile); - File recoveryState = getSerializedFile(runner); FileUtilities.delete(recoveryState); } public boolean canRecoverFromError(Throwable ex) { + if (ex instanceof UserFailureException) + { + return false; + } return true; } @@ -107,4 +134,5 @@ public class DataSetStorageRecoveryManager implements IDataSetStorageRecoveryMan { this.dropboxRecoveryStateDir = dropboxRecoveryStateDir; } + } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IDataSetStorageRecoveryManager.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IDataSetStorageRecoveryManager.java index 44d2fe431855cde5d1cadc400edf2e08cf1cfbe8..425813a15c4724e9ddf4f4bce48fb528a045a610 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IDataSetStorageRecoveryManager.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IDataSetStorageRecoveryManager.java @@ -38,6 +38,13 @@ public interface IDataSetStorageRecoveryManager <T extends DataSetInformation> void checkpointPrecommittedState( DataSetStorageAlgorithmRunner<T> runner); + /** + * Remove recovery checkpoint. + */ + <T extends DataSetInformation> void removeCheckpoint( + DataSetStorageAlgorithmRunner<T> runner); + + /** * Note that registration has completed. */ diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IRollbackStack.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IRollbackStack.java index 819f12e70b74a49c90cdcc0d71c9ccb6013ceff8..01a04ddd77365d8c0261e5d5f53891e26251efd5 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IRollbackStack.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/IRollbackStack.java @@ -32,7 +32,7 @@ public interface IRollbackStack /** * Sets the locked state of this rollback stack. Changing this state to true results in creating - * or deleting the marker file. + * or deleting the marker file. If already in a desired state - does nothing. */ public void setLockedState(boolean lockedState); diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetHandler.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetHandler.java index 2d064acb568b6d10f2193fa8caecfc5bbc299464..e4c47cd9499df941811ff19ecab0995c68ba629e 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetHandler.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetHandler.java @@ -304,8 +304,7 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends invokeDidEncounterSecondaryTransactionErrorsFunction(service, transaction, secondaryErrors); } - - //getters for v2 hook functions required for auto-recovery + // getters for v2 hook functions required for auto-recovery public PyFunction tryGetPostRegistrationFunction(DataSetRegistrationService<T> service) { PythonInterpreter interpreter = getInterpreterFromService(service); @@ -313,7 +312,7 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends tryJythonFunction(interpreter, JythonHookFunction.POST_REGISTRATION_FUNCTION_NAME); return function; } - + public PyFunction tryGetPostStorageFunction(DataSetRegistrationService<T> service) { PythonInterpreter interpreter = getInterpreterFromService(service); @@ -330,7 +329,7 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends JythonHookFunction.ROLLBACK_PRE_REGISTRATION_FUNCTION_NAME); return function; } - + /** * If true than the old methods of jython hook functions will also be used (as a fallbacks in * case of the new methods or missing, or normally) @@ -380,9 +379,9 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends DataSetRegistrationTransaction<T> transaction) { PythonInterpreter interpreter = getInterpreterFromService(service); - + PyFunction function = tryGetPostStorageFunction(service); - + if (null != function) { invokeTransactionFunctionWithContext(function, service, transaction); @@ -421,7 +420,6 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends } } - private void invokeDidEncounterSecondaryTransactionErrorsFunction( DataSetRegistrationService<T> service, DataSetRegistrationTransaction<T> transaction, List<SecondaryTransactionFailure> secondaryErrors) @@ -600,4 +598,12 @@ public class JythonTopLevelDataSetHandler<T extends DataSetInformation> extends return super.asSerializableException(throwable); } + /** + * V1 registration framework -- any file can go into faulty paths. + */ + public boolean shouldNotAddToFaultyPathsOrNull(File storeItem) + { + return false; + } + } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java index c2240a884df4cbdc114159d14c23e60c68d2973f..845fab10e0d85cb6f38113124e6413de73f6aad9 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java @@ -446,18 +446,25 @@ public class DataSetRegistrationTransaction<T extends DataSetInformation> implem public void didRollbackStorageAlgorithmRunner(DataSetStorageAlgorithmRunner<T> algorithm, Throwable ex, ErrorType errorType) { + boolean useAutoRecovery = autoRecoverySettings == AutoRecoverySettings.USE_AUTO_RECOVERY; - useAutoRecovery = - useAutoRecovery - && errorType == ErrorType.OPENBIS_REGISTRATION_FAILURE - && registrationService.getRegistratorContext().getGlobalState() - .getStorageRecoveryManager().canRecoverFromError(ex); - if (useAutoRecovery) + + IDataSetStorageRecoveryManager storageRecoveryManager = + registrationService.getRegistratorContext().getGlobalState() + .getStorageRecoveryManager(); + boolean canRecover = + useAutoRecovery && errorType == ErrorType.OPENBIS_REGISTRATION_FAILURE + && storageRecoveryManager.canRecoverFromError(ex); + if (useAutoRecovery && canRecover) { registrationService.registerNonFatalError(ex); state = new RecoveryPendingTransactionState<T>(getStateAsLiveState()); } else { + if (useAutoRecovery) + { + storageRecoveryManager.removeCheckpoint(algorithm); + } rollback(); registrationService.didRollbackTransaction(this, algorithm, ex, errorType); } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java index cc818aca3031e39c816d398887e3397abab936e1..60d395a918420b76a83114038f04d1682915c984 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v2/JythonTopLevelDataSetHandlerV2.java @@ -96,4 +96,15 @@ public class JythonTopLevelDataSetHandlerV2<T extends DataSetInformation> extend { return false; } + + /** + * V2 registration framework -- do not put files that are scheduled for recovery into the faulty + * paths. + */ + @Override + public boolean shouldNotAddToFaultyPathsOrNull(File file) + { + // If there is a recovery marker file, do not add the file to faulty paths. + return hasRecoveryMarkerFile(file); + } } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRollbackerTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRollbackerTest.java index 7470373e040ceb8d17642301ccc8cd264804e64b..d832d8840cd2374a11c33e0e7c6ab59044695cf9 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRollbackerTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageRollbackerTest.java @@ -150,6 +150,14 @@ public class DataSetStorageRollbackerTest extends AbstractFileSystemTestCase { } + + /** + * V1 Rollbacker test -- any file can go into faulty paths. + */ + public boolean shouldNotAddToFaultyPathsOrNull(File storeItem) + { + return false; + } } private void setUpHomeDataBaseExpectations() diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java index c40a05c6547da5fe411b76367e75793cad9cb985..f890bb52604172559fdf1649c42976c53b0ceaf9 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonDropboxRecoveryTest.java @@ -29,6 +29,8 @@ import org.jmock.Expectations; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.test.RecordingMatcher; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment; @@ -57,7 +59,11 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest LinkedList<RecoveryTestCase> testCases = new LinkedList<RecoveryTestCase>(); RecoveryTestCase testCase; - testCase = new RecoveryTestCase("Basic recovery testcase"); + testCase = new RecoveryTestCase("basic recovery succeeded"); + testCases.add(testCase); + + testCase = new RecoveryTestCase("basic unrecoverable"); + testCase.canRecoverFromError = false; testCases.add(testCase); // result value @@ -100,15 +106,7 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest * If true than this registration has been succesfull. Which means that the recovery should * continue registration rather rollback. */ - protected boolean registrationSuccesfull = true; - - /** - * True if the registration should throw exception to the top level. With this setting the - * handler is said to throw all exception to the top level, so that we can catch them. To - * check how the system reacts to error's itself (like rollback mechanism) this should be - * set to false. - */ - protected boolean shouldThrowExceptionDuringRegistration = true; + protected boolean registrationSuccessful = true; private RecoveryTestCase(String title) { @@ -147,13 +145,32 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest // run the actual code handler.handle(markerFile); + if (testCase.canRecoverFromError) { - File recoveryMarkerFile = getCreatedRecoveryMarkerFile(); + File recoveryMarkerFile = assertRecoveryMarkerFile(); + assertOriginalMarkerFileExists(); handler.handle(recoveryMarkerFile); + + //if failure happened here then don't expect recovery / marker files to be deleted + + if (testCase.registrationSuccessful ) + { + //assert the item is in store and everything + } + else + { + //nothing is is store, all is cleared + } + + assertNoOriginalMarkerFileExists(); + assertNoRecoveryMarkerFile(); } else { + assertNoOriginalMarkerFileExists(); + assertNoRecoveryMarkerFile(); + // assert there is no recovery file // rolllback requirementes } @@ -166,6 +183,33 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest } + private void assertOriginalMarkerFileExists() + { + assertTrue( + "The original registration marker file should not be deleted when entering recovery mode", + markerFile.exists()); + } + + private void assertNoOriginalMarkerFileExists() + { + assertFalse( + "The original registration marker file should be deleted", + markerFile.exists()); + } + + private File assertRecoveryMarkerFile() + { + File file = getCreatedRecoveryMarkerFile(); + assertTrue("The recovery marker file does not exist! " + file, file.exists()); + return file; + } + + private void assertNoRecoveryMarkerFile() + { + File file = getCreatedRecoveryMarkerFile(); + assertTrue("The recovery marker file should not exist! " + file, false == file.exists()); + } + private File getCreatedRecoveryMarkerFile() { File originalIncoming = @@ -173,8 +217,6 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest File recoveryMarkerFile = new File(originalIncoming.getAbsolutePath() + IDataSetStorageRecoveryManager.PROCESSING_MARKER); - assertTrue("The recovery marker file does not exist! " + recoveryMarkerFile, - recoveryMarkerFile.exists()); return recoveryMarkerFile; } @@ -210,7 +252,7 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest { checkRegistrationSucceeded(); - if (testCase.registrationSuccesfull) + if (testCase.registrationSuccessful) { setStorageConfirmed(); } @@ -241,15 +283,24 @@ public class JythonDropboxRecoveryTest extends AbstractJythonDataSetHandlerTest { one(openBisService).performEntityOperations(with(atomicatOperationDetails)); - Exception e = new IllegalArgumentException("Failure in atomicOperationDetails"); + Exception e; + if (testCase.canRecoverFromError) + { + e = new EnvironmentFailureException("Potentially recoverable failure in registration"); + } else + { + e = new UserFailureException("Unrecoverable failure in registration"); + } + will(throwException(e)); } + @SuppressWarnings({ "rawtypes", "unchecked" }) protected void checkRegistrationSucceeded() { one(openBisService).listDataSetsByCode(Arrays.asList(DATA_SET_CODE)); - if (testCase.registrationSuccesfull) + if (testCase.registrationSuccessful) { // with the current implemntation returning the non-empty list should be enough List<ExternalData> externalDatas = (List) Arrays.asList(new Object()); diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java index ba2f614b48a6c6d21e97882e55e349838db0f7a8..42be78c44e3a72ed3bce2caff09baddf1c77e1f1 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java @@ -319,8 +319,8 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH return resultsList; } - //INFO: testCase parameters - + // INFO: testCase parameters + /** * Parameters for the single run of the testSimpleTransaction * @@ -428,7 +428,7 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH } } - //INFO: test simple transaction + // INFO: test simple transaction @Test(dataProvider = "simpleTransactionTestCaseProvider") public void testSimpleTransaction(final TestCaseParameters testCase) { @@ -515,11 +515,11 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH context.assertIsSatisfied(); } - public Expectations getSimpleTransactionExpectations( - final TestCaseParameters testCase, + public Expectations getSimpleTransactionExpectations(final TestCaseParameters testCase, final RecordingMatcher<AtomicEntityOperationDetails> atomicatOperationDetails) { - final Experiment experiment = new ExperimentBuilder().identifier(EXPERIMENT_IDENTIFIER).getExperiment(); + final Experiment experiment = + new ExperimentBuilder().identifier(EXPERIMENT_IDENTIFIER).getExperiment(); return new Expectations() { { @@ -530,6 +530,13 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH { checkIfRecoveryFile(); + if (testCase.failurePoint != null + && testCase.failurePoint + .compareTo(TestCaseParameters.FailurePoint.DURING_OPENBIS_REGISTRATION) < 0) + { + cleanRecoveryCheckpoint(false); + } + if (testCase.failurePoint == TestCaseParameters.FailurePoint.AT_THE_BEGINNING) { return; @@ -567,6 +574,7 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH if (testCase.failurePoint == TestCaseParameters.FailurePoint.DURING_OPENBIS_REGISTRATION) { + cleanRecoveryCheckpoint(true); return; } @@ -584,6 +592,23 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH will(returnValue(false)); } + @SuppressWarnings("unchecked") + private void cleanRecoveryCheckpoint(boolean required) + { + if (testCase.shouldUseAutoRecovery) + { + if (required) + { + one(storageRecoveryManager).removeCheckpoint( + with(any(DataSetStorageAlgorithmRunner.class))); + } else + { + allowing(storageRecoveryManager).removeCheckpoint( + with(any(DataSetStorageAlgorithmRunner.class))); + } + } + } + protected void setStorageConfirmed() { one(openBisService).setStorageConfirmed(DATA_SET_CODE); @@ -817,7 +842,6 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractJythonDataSetH } } - @Test public void testTwoSimpleDataSets() { diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java index 8122858083726463a4b5d0ab0f238292d560c54e..311fe1f79fefb2626310a7f29a16df6ce10fede7 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java @@ -710,6 +710,14 @@ public class DataSetRegistrationTransactionTest extends AbstractFileSystemTestCa { return new DataSet<DataSetInformation>(registrationDetails, stagingFile, openBisService); } + + /** + * V1 test -- any file can go into faulty paths. + */ + public boolean shouldNotAddToFaultyPathsOrNull(File storeItem) + { + return false; + } } private void checkContentsOfFile(File dst)