From 955c18714a33a4c2b811933049a87c7957708a00 Mon Sep 17 00:00:00 2001 From: brinn <brinn> Date: Sat, 5 Jul 2008 15:31:23 +0000 Subject: [PATCH] [LMS-466, LMS-472] refactor: Status and RemoteStoreCopyActivitySensor, replace DateStatus with StatusWithResult add: AbstractCopyActivitySensor, StatusWithResult SVN: 7065 --- .../compression/file/FailureRecord.java | 2 +- .../file/InPlaceCompressionMethod.java | 3 +- .../compression/tiff/TiffCompressor.java | 2 +- .../cisd/common/exceptions/Status.java | 88 +++++++++-- .../cisd/common/exceptions/StatusFlag.java | 6 +- .../common/exceptions/StatusWithResult.java | 149 ++++++++++++++++++ .../common/filesystem/rsync/RsyncCopier.java | 23 +-- .../rsync/RsyncExitValueTranslator.java | 2 +- .../utilities/AbstractCopyActivitySensor.java | 138 ++++++++++++++++ .../file/CompressionWorkerTest.java | 16 +- .../filesystem/rsync/RsyncCopierTest.java | 4 +- .../filesystem/RetryingPathRemover.java | 3 +- .../datamover/filesystem/intf/DateStatus.java | 92 ----------- .../datamover/filesystem/intf/IFileStore.java | 5 +- .../filesystem/remote/RemotePathMover.java | 2 +- .../remote/RemoteStoreCopyActivitySensor.java | 105 ++---------- .../filesystem/store/FileStoreLocal.java | 14 +- .../filesystem/store/FileStoreRemote.java | 19 ++- .../store/FileStoreRemoteMounted.java | 18 +-- .../utils/QuietPeriodFileFilter.java | 10 +- .../RemoteStoreCopyActivitySensorTest.java | 28 ++-- .../utils/QuietPeriodFileFilterTest.java | 21 +-- 22 files changed, 466 insertions(+), 284 deletions(-) create mode 100644 common/source/java/ch/systemsx/cisd/common/exceptions/StatusWithResult.java create mode 100644 common/source/java/ch/systemsx/cisd/common/utilities/AbstractCopyActivitySensor.java delete mode 100644 datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/DateStatus.java diff --git a/common/source/java/ch/systemsx/cisd/common/compression/file/FailureRecord.java b/common/source/java/ch/systemsx/cisd/common/compression/file/FailureRecord.java index 243df7ec808..c6ffb27b9a0 100644 --- a/common/source/java/ch/systemsx/cisd/common/compression/file/FailureRecord.java +++ b/common/source/java/ch/systemsx/cisd/common/compression/file/FailureRecord.java @@ -45,7 +45,7 @@ public class FailureRecord { this.failedFile = failedFile; this.failureStatus = - new Status(StatusFlag.FATAL_ERROR, "Exceptional condition: " + Status.createError("Exceptional condition: " + throwableOrNull.getClass().getSimpleName()); this.throwableOrNull = throwableOrNull; } diff --git a/common/source/java/ch/systemsx/cisd/common/compression/file/InPlaceCompressionMethod.java b/common/source/java/ch/systemsx/cisd/common/compression/file/InPlaceCompressionMethod.java index 3d56e2260ca..14b706f1815 100644 --- a/common/source/java/ch/systemsx/cisd/common/compression/file/InPlaceCompressionMethod.java +++ b/common/source/java/ch/systemsx/cisd/common/compression/file/InPlaceCompressionMethod.java @@ -24,7 +24,6 @@ import org.apache.log4j.Logger; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.Status; -import ch.systemsx.cisd.common.exceptions.StatusFlag; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.process.ProcessExecutionHelper; @@ -94,7 +93,7 @@ public abstract class InPlaceCompressionMethod implements ICompressionMethod, IS { final String msg = String.format(msgTemplate, params); operationLog.error(msg); - return new Status(StatusFlag.FATAL_ERROR, msg); + return Status.createError(msg); } /** diff --git a/common/source/java/ch/systemsx/cisd/common/compression/tiff/TiffCompressor.java b/common/source/java/ch/systemsx/cisd/common/compression/tiff/TiffCompressor.java index ad6e60609ed..5892fe58186 100644 --- a/common/source/java/ch/systemsx/cisd/common/compression/tiff/TiffCompressor.java +++ b/common/source/java/ch/systemsx/cisd/common/compression/tiff/TiffCompressor.java @@ -44,7 +44,7 @@ public class TiffCompressor extends Compressor for (FailureRecord r : failed) { System.err.printf("%s (%s)\n", r.getFailedFile().getName(), r.getFailureStatus() - .getMessage()); + .tryGetErrorMessage()); } } diff --git a/common/source/java/ch/systemsx/cisd/common/exceptions/Status.java b/common/source/java/ch/systemsx/cisd/common/exceptions/Status.java index 6e4e057ef40..42809e39829 100644 --- a/common/source/java/ch/systemsx/cisd/common/exceptions/Status.java +++ b/common/source/java/ch/systemsx/cisd/common/exceptions/Status.java @@ -15,29 +15,78 @@ */ package ch.systemsx.cisd.common.exceptions; +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; + /** * A class that holds the information about the status of an operation. To be used whenever a * failure of an operation is signalled back via a return value rather than an exception. * * @author Bernd Rinn */ -public final class Status +public class Status { private final StatusFlag flag; - private final String message; + private final String errorMessageOrNull; /** The status indicating that the operation went fine. */ public static final Status OK = new Status(StatusFlag.OK, null); - public Status(StatusFlag flag, String message) + /** + * Create an error. + * + * @param retriable If <code>true</code>, the error will be marked 'retriable'. + */ + public static Status createError(boolean retriable) + { + return new Status(getErrorFlag(retriable), ""); + } + + public static Status createError(boolean retriable, String message) + { + assert message != null; + + return new Status(getErrorFlag(retriable), message); + } + + public static Status createError() + { + return new Status(StatusFlag.ERROR, ""); + } + + public static Status createError(String message) + { + assert message != null; + + return new Status(StatusFlag.ERROR, message); + } + + public static Status createRetriableError() + { + return new Status(StatusFlag.RETRIABLE_ERROR, ""); + } + + public static Status createRetriableError(String message) + { + assert message != null; + + return new Status(StatusFlag.RETRIABLE_ERROR, message); + } + + protected static StatusFlag getErrorFlag(boolean retriable) + { + return retriable ? StatusFlag.RETRIABLE_ERROR : StatusFlag.ERROR; + } + + protected Status(StatusFlag flag, String message) { assert flag != null; assert StatusFlag.OK.equals(flag) || message != null; this.flag = flag; - this.message = message; + this.errorMessageOrNull = message; } /** @@ -49,14 +98,26 @@ public final class Status } /** - * @return The message of the operation if <code>getFlag() != OK</code>, or <code>null</code> - * otherwise. + * @return <code>true</code> if this status represents an error. */ - public String getMessage() + public final boolean isError() { - return message; + return flag != StatusFlag.OK; } + /** + * @return The error message of the operation if <code>getFlag() != OK</code> (can be empty), or + * <code>null</code> otherwise. + */ + public String tryGetErrorMessage() + { + return errorMessageOrNull; + } + + // + // Object + // + @Override public boolean equals(Object obj) { @@ -68,22 +129,23 @@ public final class Status { return false; } - final Status status = (Status) obj; - return flag.equals(status.flag); + final Status that = (Status) obj; + return getFlag() == that.getFlag() + && ObjectUtils.equals(this.tryGetErrorMessage(), that.tryGetErrorMessage()); } @Override public int hashCode() { - return flag.hashCode(); + return (17 + flag.hashCode()) * 37 + ObjectUtils.hashCode(tryGetErrorMessage()); } @Override public String toString() { - if (message != null) + if (StringUtils.isNotBlank(errorMessageOrNull)) { - return flag.toString() + ": \"" + message + "\""; + return flag.toString() + ": \"" + errorMessageOrNull + "\""; } else { return flag.toString(); diff --git a/common/source/java/ch/systemsx/cisd/common/exceptions/StatusFlag.java b/common/source/java/ch/systemsx/cisd/common/exceptions/StatusFlag.java index f88bcd87baa..bcf0888fe36 100644 --- a/common/source/java/ch/systemsx/cisd/common/exceptions/StatusFlag.java +++ b/common/source/java/ch/systemsx/cisd/common/exceptions/StatusFlag.java @@ -27,9 +27,9 @@ public enum StatusFlag /** The operation has been successful. */ OK, - /** An error has occurred. Retrying the operation might remedy the problem. */ + /** An error has occurred. Retrying the operation might remove the problem. */ RETRIABLE_ERROR, - /** A fatal error has occurred. */ - FATAL_ERROR + /** An error has occurred. */ + ERROR } \ No newline at end of file diff --git a/common/source/java/ch/systemsx/cisd/common/exceptions/StatusWithResult.java b/common/source/java/ch/systemsx/cisd/common/exceptions/StatusWithResult.java new file mode 100644 index 00000000000..b7413607edd --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/exceptions/StatusWithResult.java @@ -0,0 +1,149 @@ +/* + * Copyright 2008 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.common.exceptions; + +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.builder.HashCodeBuilder; + +/** + * A {@link Status} that can also hold a result. + * + * @author Bernd Rinn + */ +public class StatusWithResult<T> extends Status +{ + + private final T resultOrNull; + + /** + * Creates a new result with status {@link StatusFlag#OK} and <var>resultOrNull</var>. + */ + public static <T> StatusWithResult<T> create(T resultOrNull) + { + return new StatusWithResult<T>(StatusFlag.OK, null, resultOrNull); + } + + /** + * Create an error. + * + * @param retriable If <code>true</code>, the error will be marked 'retriable'. + */ + public static <T> StatusWithResult<T> createError(boolean retriable) + { + return new StatusWithResult<T>(getErrorFlag(retriable), "", null); + } + + public static <T> StatusWithResult<T> createError(boolean retriable, String message) + { + assert message != null; + + return new StatusWithResult<T>(getErrorFlag(retriable), message, null); + } + + public static <T> StatusWithResult<T> createError() + { + return new StatusWithResult<T>(StatusFlag.ERROR, "", null); + } + + public static <T> StatusWithResult<T> createError(String message) + { + assert message != null; + + return new StatusWithResult<T>(StatusFlag.ERROR, message, null); + } + + public static <T> StatusWithResult<T> createRetriableError() + { + return new StatusWithResult<T>(StatusFlag.RETRIABLE_ERROR, "", null); + } + + public static <T> StatusWithResult<T> createRetriableError(String message) + { + assert message != null; + + return new StatusWithResult<T>(StatusFlag.RETRIABLE_ERROR, message, null); + } + + protected StatusWithResult(StatusFlag flag, String messageOrNull, T resultOrNull) + { + super(flag, messageOrNull); + this.resultOrNull = resultOrNull; + } + + /** + * Returns the result of the operation (may be <code>null</code>). + */ + public final T tryGetResult() + { + return resultOrNull; + } + + // + // Object + // + + @SuppressWarnings("unchecked") + private StatusWithResult<T> toStatusWithResult(Object obj) + { + return (StatusWithResult) obj; + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj == null || obj instanceof StatusWithResult == false) + { + return false; + } + final StatusWithResult<T> that = toStatusWithResult(obj); + return getFlag() == that.getFlag() + && ObjectUtils.equals(this.tryGetErrorMessage(), that.tryGetErrorMessage()) + && ObjectUtils.equals(this.tryGetResult(), that.tryGetResult()); + } + + @Override + public int hashCode() + { + final HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(getFlag()); + builder.append(tryGetErrorMessage()); + builder.append(tryGetResult()); + return builder.toHashCode(); + } + + @Override + public String toString() + { + final String messageOrNull = tryGetErrorMessage(); + if (StringUtils.isNotBlank(messageOrNull)) + { + return getFlag().toString() + ": \"" + messageOrNull + "\""; + } else if (resultOrNull != null) + { + return getFlag().toString() + ": result is \"" + resultOrNull + "\""; + } else + { + return getFlag().toString(); + } + } + +} diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java index a11886e473f..5be3ffde79d 100644 --- a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java +++ b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopier.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; +import ch.rinn.restrictions.Private; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.Status; import ch.systemsx.cisd.common.exceptions.StatusFlag; @@ -45,23 +46,24 @@ import ch.systemsx.cisd.common.utilities.OSUtilities; */ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier { - /** - * The {@link Status} returned if the process was terminated by {@link Process#destroy()}. - */ - protected static final Status TERMINATED_STATUS = - new Status(StatusFlag.RETRIABLE_ERROR, "Process was terminated."); - private static final Logger machineLog = LogFactory.getLogger(LogCategory.MACHINE, RsyncCopier.class); private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, RsyncCopier.class); + /** + * The {@link Status} returned if the process was terminated by {@link Process#destroy()}. + */ + @Private + static final Status TERMINATED_STATUS = + Status.createRetriableError("Process was terminated."); + private static final Status INTERRUPTED_STATUS = - new Status(StatusFlag.RETRIABLE_ERROR, "Process was interrupted."); + Status.createRetriableError("Process was interrupted."); private static final Status TIMEOUT_STATUS = - new Status(StatusFlag.RETRIABLE_ERROR, "Process has stopped because of timeout."); + Status.createRetriableError("Process has stopped because of timeout."); private final String rsyncExecutable; @@ -421,11 +423,12 @@ public final class RsyncCopier implements IPathCopier, IDirectoryImmutableCopier } int exitValue = processResult.getExitValue(); final StatusFlag flag = RsyncExitValueTranslator.getStatus(exitValue); - if (StatusFlag.OK.equals(flag)) + if (flag == StatusFlag.OK) { return Status.OK; } - return new Status(flag, RsyncExitValueTranslator.getMessage(exitValue)); + final boolean retriableError = (flag == StatusFlag.RETRIABLE_ERROR); + return Status.createError(retriableError, RsyncExitValueTranslator.getMessage(exitValue)); } } diff --git a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncExitValueTranslator.java b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncExitValueTranslator.java index af4cf1e5618..748860de314 100644 --- a/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncExitValueTranslator.java +++ b/common/source/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncExitValueTranslator.java @@ -125,7 +125,7 @@ final class RsyncExitValueTranslator case 125: return StatusFlag.RETRIABLE_ERROR; default: - return StatusFlag.FATAL_ERROR; + return StatusFlag.ERROR; } } diff --git a/common/source/java/ch/systemsx/cisd/common/utilities/AbstractCopyActivitySensor.java b/common/source/java/ch/systemsx/cisd/common/utilities/AbstractCopyActivitySensor.java new file mode 100644 index 00000000000..7dcc6025895 --- /dev/null +++ b/common/source/java/ch/systemsx/cisd/common/utilities/AbstractCopyActivitySensor.java @@ -0,0 +1,138 @@ +/* + * Copyright 2008 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.common.utilities; + +import org.apache.commons.lang.time.DurationFormatUtils; +import org.apache.log4j.Logger; + +import ch.systemsx.cisd.common.concurrent.InactivityMonitor.IActivitySensor; +import ch.systemsx.cisd.common.exceptions.StatusFlag; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; + +/** + * A super class for {@link IActivitySensor}s that sense changes in some sort of copy operation to + * a "target". + * + * @author Bernd Rinn + */ +public abstract class AbstractCopyActivitySensor implements IActivitySensor +{ + protected static final Logger machineLog = + LogFactory.getLogger(LogCategory.MACHINE, AbstractCopyActivitySensor.class); + + protected static final int DEFAULT_MAX_ERRORS_TO_IGNORE = 3; + + protected final int maxErrorsToIgnore; + + protected final long timeOfCreation = System.currentTimeMillis(); + + protected long timeOfLastConfirmedActivity = timeOfCreation; + + protected long timeOfLastReportedActivity = timeOfCreation; + + protected long lastNonErrorResult = -1L; + + protected StatusWithResult<Long> currentResult; + + protected int errorCount = 0; + + protected AbstractCopyActivitySensor() + { + this(DEFAULT_MAX_ERRORS_TO_IGNORE); + } + + protected AbstractCopyActivitySensor(int maxErrorsToIgnore) + { + this.maxErrorsToIgnore = maxErrorsToIgnore; + this.currentResult = null; + } + + /** + * Returns the result of obtaining the last activity of the target that is more recent than + * <var>thresholdMillis</var> (relative to the current point in time). + * <p> + * If the status of the result is {@link StatusFlag#OK}, the result must be the time of last + * activity in milli-seconds (and <i>must not</i> be <code>null</code>). + */ + protected abstract StatusWithResult<Long> getTargetTimeOfLastActivityMoreRecentThan( + long thresholdMillis); + + /** + * Returns a textual description of the target. + */ + protected abstract String getTargetDescription(); + + // + // IActivitySensor + // + + public long getTimeOfLastActivityMoreRecentThan(long thresholdMillis) + { + currentResult = getTargetTimeOfLastActivityMoreRecentThan(thresholdMillis); + final long now = System.currentTimeMillis(); + if (currentResult.isError()) + { + ++errorCount; + if (errorCount <= maxErrorsToIgnore) + { + timeOfLastReportedActivity = now; + machineLog.error(describeInactivity(now) + + String.format(" (error count: %d <= %d, goes unreported)", errorCount, + maxErrorsToIgnore)); + } else + { + machineLog.error(describeInactivity(now) + + " (error count: %s, reported to monitor)"); + } + } else + { + if (currentResult.tryGetResult() != lastNonErrorResult) + { + timeOfLastConfirmedActivity = now; + lastNonErrorResult = currentResult.tryGetResult(); + if (machineLog.isDebugEnabled()) + { + machineLog.debug("Observing write activity on " + getTargetDescription()); + } + } + // Implementation note: This means we can report an older time of activity than what we + // reported the last time if the last time we had an error. This is on purpose as it + // helps avoiding a situation where error and non-error situations do "flip-flop" and we + // could report progress where there is no progress. + timeOfLastReportedActivity = timeOfLastConfirmedActivity; + errorCount = 0; + } + + return timeOfLastReportedActivity; + } + + public String describeInactivity(long now) + { + if (currentResult.isError()) + { + return "Error: Unable to determine the time of write activity on " + + getTargetDescription(); + } else + { + final String inactivityPeriod = + DurationFormatUtils.formatDurationHMS(now - timeOfLastConfirmedActivity); + return "No write activity on " + getTargetDescription() + " for " + inactivityPeriod; + } + } +} diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/compression/file/CompressionWorkerTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/compression/file/CompressionWorkerTest.java index 39ad51041ae..db4d906f391 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/compression/file/CompressionWorkerTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/compression/file/CompressionWorkerTest.java @@ -125,7 +125,7 @@ public class CompressionWorkerTest public void testCompressionWorkerWithRetriableFailure() { final String faultyFile = "b"; - final Status faultyStatus = new Status(StatusFlag.RETRIABLE_ERROR, "some problem"); + final Status faultyStatus = Status.createRetriableError("some problem"); final File[] files = new File[] { new File("a"), new File(faultyFile), new File("c") }; context.checking(new Expectations() @@ -159,7 +159,7 @@ public class CompressionWorkerTest public void testCompressionWorkerWithRetriableFailureFinallyFailed() { final String faultyFile = "b"; - final Status faultyStatus = new Status(StatusFlag.RETRIABLE_ERROR, "some problem"); + final Status faultyStatus = Status.createRetriableError("some problem"); final File[] files = new File[] { new File("a"), new File(faultyFile), new File("c") }; context.checking(new Expectations() @@ -191,7 +191,7 @@ public class CompressionWorkerTest final FailureRecord record = failed.iterator().next(); assertEquals(faultyFile, record.getFailedFile().getName()); assertEquals(StatusFlag.RETRIABLE_ERROR, record.getFailureStatus().getFlag()); - assertEquals(faultyStatus.getMessage(), record.getFailureStatus().getMessage()); + assertEquals(faultyStatus.tryGetErrorMessage(), record.getFailureStatus().tryGetErrorMessage()); assertTrue(logRecorder.getLogContent().indexOf(CompressionWorker.EXITING_MSG) >= 0); } @@ -199,7 +199,7 @@ public class CompressionWorkerTest public void testCompressionWorkerWithFatalFailure() { final String faultyFile = "b"; - final Status fatalStatus = new Status(StatusFlag.FATAL_ERROR, "some problem"); + final Status fatalStatus = Status.createError("some problem"); final File[] files = new File[] { new File("a"), new File(faultyFile), new File("c") }; context.checking(new Expectations() @@ -226,8 +226,8 @@ public class CompressionWorkerTest assertEquals(1, failed.size()); final FailureRecord record = failed.iterator().next(); assertEquals(faultyFile, record.getFailedFile().getName()); - assertEquals(StatusFlag.FATAL_ERROR, record.getFailureStatus().getFlag()); - assertEquals(fatalStatus.getMessage(), record.getFailureStatus().getMessage()); + assertEquals(StatusFlag.ERROR, record.getFailureStatus().getFlag()); + assertEquals(fatalStatus.tryGetErrorMessage(), record.getFailureStatus().tryGetErrorMessage()); assertTrue(logRecorder.getLogContent().indexOf(CompressionWorker.EXITING_MSG) >= 0); } @@ -308,9 +308,9 @@ public class CompressionWorkerTest assertEquals(1, failed.size()); final FailureRecord record = failed.iterator().next(); assertEquals(faultyFile, record.getFailedFile().getName()); - assertEquals(StatusFlag.FATAL_ERROR, record.getFailureStatus().getFlag()); + assertEquals(StatusFlag.ERROR, record.getFailureStatus().getFlag()); assertEquals("Exceptional condition: " + FakedException.class.getSimpleName(), record - .getFailureStatus().getMessage()); + .getFailureStatus().tryGetErrorMessage()); assertEquals(ex, record.tryGetThrowable()); assertTrue(logRecorder.getLogContent().indexOf( String.format(CompressionWorker.EXCEPTION_COMPRESSING_MSG_TEMPLATE, faultyFile)) >= 0); diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java index 514bbc17422..d22a93d2246 100644 --- a/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java +++ b/common/sourceTest/java/ch/systemsx/cisd/common/filesystem/rsync/RsyncCopierTest.java @@ -179,7 +179,7 @@ public final class RsyncCopierTest public void testRsyncFatalFailure() throws IOException, InterruptedException { final int exitValue = 1; - StatusFlag expectedStatus = StatusFlag.FATAL_ERROR; + StatusFlag expectedStatus = StatusFlag.ERROR; testRsyncFailure(exitValue, expectedStatus); } @@ -191,7 +191,7 @@ public final class RsyncCopierTest final RsyncCopier copier = new RsyncCopier(buggyRsyncBinary, null, false, false); final Status status = copier.copy(sourceFile, destinationDirectory); assertEquals(expectedStatus, status.getFlag()); - assertEquals(RsyncExitValueTranslator.getMessage(exitValue), status.getMessage()); + assertEquals(RsyncExitValueTranslator.getMessage(exitValue), status.tryGetErrorMessage()); } @Test(groups = diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/RetryingPathRemover.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/RetryingPathRemover.java index e3ae9b46dea..9e216548ea3 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/RetryingPathRemover.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/RetryingPathRemover.java @@ -21,7 +21,6 @@ import java.io.File; import org.apache.log4j.Logger; import ch.systemsx.cisd.common.exceptions.Status; -import ch.systemsx.cisd.common.exceptions.StatusFlag; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.utilities.FileUtilities; @@ -53,7 +52,7 @@ final class RetryingPathRemover implements IPathRemover } private final static Status STATUS_FAILED_DELETION = - new Status(StatusFlag.FATAL_ERROR, "Failed to remove path."); + Status.createError("Failed to remove path."); public Status remove(File path) { diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/DateStatus.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/DateStatus.java deleted file mode 100644 index dd5fd15b63a..00000000000 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/DateStatus.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2008 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.datamover.filesystem.intf; - -import org.apache.commons.lang.builder.ToStringBuilder; - -import ch.systemsx.cisd.common.utilities.ModifiedShortPrefixToStringStyle; - -/** - * A class that holds the information about the result of an operation which is a number. There is a - * way to find out if an error occurred during operation execution, the result is unavailable then. - * - * @author Tomasz Pylak - */ -public final class DateStatus -{ - private final ResultStatus<Long> result; - - private DateStatus(final Long result, final boolean errorOccurred, final String messageOrNull) - { - this.result = new ResultStatus<Long>(result, errorOccurred, messageOrNull); - } - - public static final DateStatus create(final long result) - { - return new DateStatus(result, false, null); - } - - public static final DateStatus createError(final String message) - { - return new DateStatus(null, true, message); - } - - public static final DateStatus createError() - { - return new DateStatus(null, true, null); - } - - /** - * can be called only if no error occurred, otherwise it fails. - */ - public final long getResult() - { - return result.getResult(); - } - - /** has operation finished with an error? */ - public final boolean isError() - { - return result.isError(); - } - - public final String tryGetMessage() - { - return result.tryGetMessage(); - } - - // - // Object - // - - @Override - public final String toString() - { - final ToStringBuilder builder = - new ToStringBuilder(this, - ModifiedShortPrefixToStringStyle.MODIFIED_SHORT_PREFIX_STYLE); - if (isError()) - { - builder.append("[DateStatus, error: ", tryGetMessage() + "]"); - } else - { - final Long thisResult = result.getResult(); - builder.append("[DateStatus, result: ", String.format("%1$tF %1$tT", thisResult) + "]"); - } - return builder.toString(); - } -} diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileStore.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileStore.java index 9dca9a01215..15d6525622b 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileStore.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/intf/IFileStore.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.datamover.filesystem.intf; import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher; import ch.systemsx.cisd.common.logging.ISimpleLogger; import ch.systemsx.cisd.common.utilities.ISelfTestable; @@ -71,7 +72,7 @@ public interface IFileStore extends ISelfTestable * @return The time (in milliseconds since the start of the epoch) when <var>resource</var> was * last changed or error status if checking failed. */ - public DateStatus lastChanged(StoreItem item, long stopWhenFindYounger); + public StatusWithResult<Long> lastChanged(StoreItem item, long stopWhenFindYounger); /** * Returns the last time when there was a write access to <var>item</var>. @@ -83,7 +84,7 @@ public interface IFileStore extends ISelfTestable * @return The time (in milliseconds since the start of the epoch) when <var>resource</var> was * last changed or error status if checking failed. */ - public DateStatus lastChangedRelative(StoreItem item, long stopWhenFindYoungerRelative); + public StatusWithResult<Long> lastChangedRelative(StoreItem item, long stopWhenFindYoungerRelative); /** * List files in the scanned store. Sort in order of "oldest first". diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemotePathMover.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemotePathMover.java index 54c71efe40d..5447963bbff 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemotePathMover.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemotePathMover.java @@ -368,7 +368,7 @@ public final class RemotePathMover implements IStoreHandler { operationLog.warn(String.format(COPYING_PATH_TO_REMOTE_FAILED, getSrcPath(item), destinationDirectory, copyStatus)); - if (StatusFlag.FATAL_ERROR.equals(copyStatus.getFlag())) + if (StatusFlag.ERROR.equals(copyStatus.getFlag())) { break; } diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensor.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensor.java index a65c768d18e..9945474900f 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensor.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensor.java @@ -16,15 +16,10 @@ package ch.systemsx.cisd.datamover.filesystem.remote; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.time.DurationFormatUtils; -import org.apache.log4j.Logger; - import ch.systemsx.cisd.common.concurrent.InactivityMonitor.IActivitySensor; -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; +import ch.systemsx.cisd.common.utilities.AbstractCopyActivitySensor; import ch.systemsx.cisd.common.utilities.StoreItem; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; /** @@ -33,111 +28,37 @@ import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; * * @author Bernd Rinn */ -public class RemoteStoreCopyActivitySensor implements IActivitySensor +public class RemoteStoreCopyActivitySensor extends AbstractCopyActivitySensor { - private static final Logger machineLog = - LogFactory.getLogger(LogCategory.MACHINE, RemoteStoreCopyActivitySensor.class); - - private static final int MAX_ERROR_COUNT = 1; - - private final int maxErrorsToIgnore; - private final IFileStore destinationStore; private final StoreItem copyItem; - private final long timeOfCreation = System.currentTimeMillis(); - - private long timeOfLastConfirmedActivity = timeOfCreation; - - private long timeOfLastReportedActivity = timeOfCreation; - - private long lastNonErrorResult = -1L; - - private DateStatus currentResult; - - private int errorCount = 0; - public RemoteStoreCopyActivitySensor(IFileStore destinationStore, StoreItem copyItem) { - this(destinationStore, copyItem, MAX_ERROR_COUNT); + super(); + this.destinationStore = destinationStore; + this.copyItem = copyItem; } public RemoteStoreCopyActivitySensor(IFileStore destinationStore, StoreItem copyItem, int maxErrorsToIgnore) { + super(maxErrorsToIgnore); this.destinationStore = destinationStore; this.copyItem = copyItem; - this.maxErrorsToIgnore = maxErrorsToIgnore; - this.currentResult = - DateStatus.createError(String.format( - "Last activity on item '%s' of store '%s' never checked", copyItem, - destinationStore)); } - public long getTimeOfLastActivityMoreRecentThan(long thresholdMillis) + @Override + protected StatusWithResult<Long> getTargetTimeOfLastActivityMoreRecentThan(long thresholdMillis) { - currentResult = destinationStore.lastChangedRelative(copyItem, thresholdMillis); - final long now = System.currentTimeMillis(); - if (currentResult.isError()) - { - ++errorCount; - if (errorCount <= maxErrorsToIgnore) - { - timeOfLastReportedActivity = now; - machineLog.error(describeInactivity(now) - + String.format(" (error count: %d <= %d, goes unreported)", errorCount, - maxErrorsToIgnore)); - } else - { - machineLog.error(describeInactivity(now) - + " (error count: %s, reported to monitor)"); - } - } else - { - if (currentResult.getResult() != lastNonErrorResult) - { - timeOfLastConfirmedActivity = now; - lastNonErrorResult = currentResult.getResult(); - if (machineLog.isDebugEnabled()) - { - machineLog.debug(String.format( - "Observing write activity on item '%s' in store '%s'", copyItem, - destinationStore)); - } - } - // Implementation note: This means we can report an older time of activity than what we - // reported the last time if the last time we had an error. This is on purpose as it - // helps avoiding a situation where error and non-error situations do "flip-flop" and we - // could report progress where there is no progress. - timeOfLastReportedActivity = timeOfLastConfirmedActivity; - errorCount = 0; - } - - return timeOfLastReportedActivity; + return destinationStore.lastChangedRelative(copyItem, thresholdMillis); } - public String describeInactivity(long now) + @Override + protected String getTargetDescription() { - if (currentResult.isError()) - { - final String msg = currentResult.tryGetMessage(); - if (StringUtils.isBlank(msg)) - { - return String.format("Error: Unable to determine the time of write activity " - + "on item '%s' in store '%s'", copyItem, destinationStore); - } else - { - return String.format("Error [%s]: Unable to determine the time of write activity " - + "on item '%s' in store '%s'", msg, copyItem, destinationStore); - } - } else - { - final String inactivityPeriod = - DurationFormatUtils.formatDurationHMS(now - timeOfLastConfirmedActivity); - return String.format("No write activity on item '%s' in store '%s' for %s", copyItem, - destinationStore, inactivityPeriod); - } + return String.format("item '%s' in store '%s'", copyItem, destinationStore); } } diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreLocal.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreLocal.java index 24f78d224b2..f17cebee3a2 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreLocal.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreLocal.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.time.DateUtils; import org.apache.log4j.Logger; import ch.systemsx.cisd.common.exceptions.Status; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.exceptions.UnknownLastChangedException; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher; import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark; @@ -41,7 +42,6 @@ import ch.systemsx.cisd.datamover.filesystem.intf.IFileSysOperationsFactory; import ch.systemsx.cisd.datamover.filesystem.intf.IPathMover; import ch.systemsx.cisd.datamover.filesystem.intf.IPathRemover; import ch.systemsx.cisd.datamover.filesystem.intf.IStoreCopier; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; /** * An {@link IFileStore} implementation for local stores. @@ -88,20 +88,20 @@ public class FileStoreLocal extends AbstractFileStore implements IExtendedFileSt return BooleanStatus.createFromBoolean(exists); } - public final DateStatus lastChanged(final StoreItem item, final long stopWhenFindYounger) + public final StatusWithResult<Long> lastChanged(final StoreItem item, final long stopWhenFindYounger) { try { long lastChanged = FileUtilities.lastChanged(getChildFile(item), true, stopWhenFindYounger); - return DateStatus.create(lastChanged); + return StatusWithResult.<Long>create(lastChanged); } catch (UnknownLastChangedException ex) { return createLastChangedError(item, ex); } } - public final DateStatus lastChangedRelative(final StoreItem item, + public final StatusWithResult<Long> lastChangedRelative(final StoreItem item, final long stopWhenFindYoungerRelative) { try @@ -109,20 +109,20 @@ public class FileStoreLocal extends AbstractFileStore implements IExtendedFileSt long lastChanged = FileUtilities.lastChangedRelative(getChildFile(item), true, stopWhenFindYoungerRelative); - return DateStatus.create(lastChanged); + return StatusWithResult.<Long>create(lastChanged); } catch (UnknownLastChangedException ex) { return createLastChangedError(item, ex); } } - private static DateStatus createLastChangedError(final StoreItem item, + private static StatusWithResult<Long> createLastChangedError(final StoreItem item, UnknownLastChangedException ex) { String errorMsg = String.format("Could not determine \"last changed time\" of %s: %s", item, ex .getCause()); - return DateStatus.createError(errorMsg); + return StatusWithResult.<Long>createError(errorMsg); } public final BooleanStatus tryCheckDirectoryFullyAccessible(final long timeOutMillis) diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java index eccd25b7370..8991bad427c 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemote.java @@ -26,7 +26,7 @@ import org.apache.log4j.Logger; import ch.rinn.restrictions.Private; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.Status; -import ch.systemsx.cisd.common.exceptions.StatusFlag; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher; import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher.IFreeSpaceProvider; @@ -43,7 +43,6 @@ import ch.systemsx.cisd.datamover.filesystem.intf.IExtendedFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IFileSysOperationsFactory; import ch.systemsx.cisd.datamover.filesystem.intf.IStoreCopier; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; /** * @author Tomasz Pylak @@ -200,7 +199,7 @@ public class FileStoreRemote extends AbstractFileStore return Status.OK; } else { - return new Status(StatusFlag.RETRIABLE_ERROR, errMsg); + return Status.createRetriableError(errMsg); } } @@ -230,12 +229,12 @@ public class FileStoreRemote extends AbstractFileStore return constructStoreCopier(destinationDirectory, requiresDeletion); } - public final DateStatus lastChanged(final StoreItem item, final long stopWhenFindYounger) + public final StatusWithResult<Long> lastChanged(final StoreItem item, final long stopWhenFindYounger) { return lastChanged(item); } - private final DateStatus lastChanged(final StoreItem item) + private final StatusWithResult<Long> lastChanged(final StoreItem item) { final String itemPath = StoreItem.asFile(getPath(), item).getPath(); @@ -249,7 +248,7 @@ public class FileStoreRemote extends AbstractFileStore try { long lastChanged = Long.parseLong(resultLine) * 1000; - return DateStatus.create(lastChanged); + return StatusWithResult.<Long> create(lastChanged); } catch (final NumberFormatException e) { return createLastChangeError(item, "The result of " + cmd + " on remote host " @@ -261,10 +260,10 @@ public class FileStoreRemote extends AbstractFileStore } } - private static DateStatus createLastChangeError(StoreItem item, String errorMsg) + private static StatusWithResult<Long> createLastChangeError(StoreItem item, String errorMsg) { - return DateStatus.createError("Cannot obtain last change time of the item " + item - + ". Reason: " + errorMsg); + return StatusWithResult.<Long> createError("Cannot obtain last change time of the item " + + item + ". Reason: " + errorMsg); } private String getRemoteFindExecutableOrDie() @@ -282,7 +281,7 @@ public class FileStoreRemote extends AbstractFileStore } } - public final DateStatus lastChangedRelative(final StoreItem item, + public final StatusWithResult<Long> lastChangedRelative(final StoreItem item, final long stopWhenFindYoungerRelative) { return lastChanged(item); diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemoteMounted.java b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemoteMounted.java index 6d6f98c118b..2340c5da751 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemoteMounted.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/filesystem/store/FileStoreRemoteMounted.java @@ -20,7 +20,7 @@ import ch.systemsx.cisd.common.concurrent.MonitoringProxy; import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.Status; -import ch.systemsx.cisd.common.exceptions.StatusFlag; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.highwatermark.HighwaterMarkWatcher; import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark; import ch.systemsx.cisd.common.logging.ISimpleLogger; @@ -28,7 +28,6 @@ import ch.systemsx.cisd.common.logging.LogLevel; import ch.systemsx.cisd.common.utilities.StoreItem; import ch.systemsx.cisd.datamover.filesystem.intf.AbstractFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.BooleanStatus; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; import ch.systemsx.cisd.datamover.filesystem.intf.IExtendedFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; import ch.systemsx.cisd.datamover.filesystem.intf.IFileSysOperationsFactory; @@ -88,8 +87,7 @@ public final class FileStoreRemoteMounted extends AbstractFileStore final Status statusOrNull = localImplMonitored.delete(item); if (statusOrNull == null) { - return new Status(StatusFlag.RETRIABLE_ERROR, "Could not delete '" + item - + "': time out."); + return Status.createRetriableError("Could not delete '" + item + "': time out."); } return statusOrNull; } @@ -105,25 +103,25 @@ public final class FileStoreRemoteMounted extends AbstractFileStore return statusOrNull; } - public final DateStatus lastChanged(final StoreItem item, final long stopWhenFindYounger) + public final StatusWithResult<Long> lastChanged(final StoreItem item, final long stopWhenFindYounger) { - final DateStatus statusOrNull = localImplMonitored.lastChanged(item, stopWhenFindYounger); + final StatusWithResult<Long> statusOrNull = localImplMonitored.lastChanged(item, stopWhenFindYounger); if (statusOrNull == null) { - return DateStatus.createError(String.format( + return StatusWithResult.<Long>createError(String.format( "Could not determine \"last changed time\" of %s: time out.", item)); } return statusOrNull; } - public final DateStatus lastChangedRelative(final StoreItem item, + public final StatusWithResult<Long> lastChangedRelative(final StoreItem item, final long stopWhenFindYoungerRelative) { - final DateStatus statusOrNull = + final StatusWithResult<Long> statusOrNull = localImplMonitored.lastChangedRelative(item, stopWhenFindYoungerRelative); if (statusOrNull == null) { - return DateStatus.createError(String.format( + return StatusWithResult.<Long>createError(String.format( "Could not determine \"last changed time\" of %s: time out.", item)); } return statusOrNull; diff --git a/datamover/source/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilter.java b/datamover/source/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilter.java index bdca11f031b..d4b0c8909f2 100644 --- a/datamover/source/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilter.java +++ b/datamover/source/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilter.java @@ -25,13 +25,13 @@ import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import ch.rinn.restrictions.Private; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.common.utilities.ITimeProvider; import ch.systemsx.cisd.common.utilities.StoreItem; import ch.systemsx.cisd.common.utilities.SystemTimeProvider; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; import ch.systemsx.cisd.datamover.intf.ITimingParameters; /** @@ -159,12 +159,12 @@ public class QuietPeriodFileFilter implements IStoreItemFilter return false; } final long oldLastChanged = checkRecordOrNull.getTimeOfLastModification(); - DateStatus newStatus = fileStore.lastChanged(item, oldLastChanged); + final StatusWithResult<Long> newStatus = fileStore.lastChanged(item, oldLastChanged); if (newStatus.isError()) { return false; } - final long newLastChanged = newStatus.getResult(); + final long newLastChanged = newStatus.tryGetResult(); if (newLastChanged != oldLastChanged) { pathMap.put(item, new PathCheckRecord(now, newLastChanged)); @@ -198,10 +198,10 @@ public class QuietPeriodFileFilter implements IStoreItemFilter private void saveFirstModificationTime(final StoreItem item, final long now) { - DateStatus status = fileStore.lastChanged(item, 0L); + final StatusWithResult<Long> status = fileStore.lastChanged(item, 0L); if (status.isError() == false) { - pathMap.put(item, new PathCheckRecord(now, status.getResult())); + pathMap.put(item, new PathCheckRecord(now, status.tryGetResult())); } } diff --git a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensorTest.java b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensorTest.java index 102f48d3d9f..624bab75a16 100644 --- a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensorTest.java +++ b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/filesystem/remote/RemoteStoreCopyActivitySensorTest.java @@ -26,9 +26,9 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.logging.LogInitializer; import ch.systemsx.cisd.common.utilities.StoreItem; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; /** @@ -45,6 +45,8 @@ public class RemoteStoreCopyActivitySensorTest private static final long MAX_DELTA = 5L; + private static final int MAX_ERRORS_TO_IGNORE = 1; + private Mockery context; private IFileStore destinationStore; @@ -65,7 +67,8 @@ public class RemoteStoreCopyActivitySensorTest context = new Mockery(); destinationStore = context.mock(IFileStore.class); copyItem = new StoreItem(ITEM_NAME); - sensorUnderTest = new RemoteStoreCopyActivitySensor(destinationStore, copyItem); + sensorUnderTest = + new RemoteStoreCopyActivitySensor(destinationStore, copyItem, MAX_ERRORS_TO_IGNORE); } @AfterMethod @@ -84,7 +87,7 @@ public class RemoteStoreCopyActivitySensorTest { { one(destinationStore).lastChangedRelative(copyItem, THRESHOLD); - will(returnValue(DateStatus.create(lastChanged))); + will(returnValue(StatusWithResult.<Long> create(lastChanged))); } }); final long delta = @@ -106,13 +109,13 @@ public class RemoteStoreCopyActivitySensorTest { { one(destinationStore).lastChangedRelative(copyItem, THRESHOLD); - will(returnValue(DateStatus.createError(errorMsg))); + will(returnValue(StatusWithResult.<Long> createError(errorMsg))); } }); final long now = System.currentTimeMillis(); final long delta = now - sensorUnderTest.getTimeOfLastActivityMoreRecentThan(THRESHOLD); assertTrue("Delta is " + delta, delta < MAX_DELTA); - assertEquals("Error [ERROR message]: Unable to determine the time of write activity on " + assertEquals("Error: Unable to determine the time of write activity on " + "item 'I am probed' in store 'iFileStore'", sensorUnderTest .describeInactivity(now)); } @@ -125,19 +128,20 @@ public class RemoteStoreCopyActivitySensorTest { { exactly(3).of(destinationStore).lastChangedRelative(copyItem, THRESHOLD); - will(returnValue(DateStatus.createError(errorMsg))); + will(returnValue(StatusWithResult.<Long> createError(errorMsg))); } }); ConcurrencyUtilities.sleep(10L); final long now = System.currentTimeMillis(); final long lastActivity1 = sensorUnderTest.getTimeOfLastActivityMoreRecentThan(THRESHOLD); - assertEquals(now, lastActivity1); + final long delta = lastActivity1 - now; + assertTrue("Delta is " + delta, delta < MAX_DELTA); ConcurrencyUtilities.sleep(10L); final long lastActivity2 = sensorUnderTest.getTimeOfLastActivityMoreRecentThan(THRESHOLD); - assertEquals(now, lastActivity2); + assertEquals(lastActivity1, lastActivity2); ConcurrencyUtilities.sleep(10L); final long lastActivity3 = sensorUnderTest.getTimeOfLastActivityMoreRecentThan(THRESHOLD); - assertEquals(now, lastActivity3); + assertEquals(lastActivity1, lastActivity3); } @Test @@ -148,9 +152,9 @@ public class RemoteStoreCopyActivitySensorTest { { exactly(3).of(destinationStore).lastChangedRelative(copyItem, THRESHOLD); - will(onConsecutiveCalls(returnValue(DateStatus.create(17L)), - returnValue(DateStatus.createError(errorMsg)), returnValue(DateStatus - .create(17L)))); + will(onConsecutiveCalls(returnValue(StatusWithResult.<Long> create(17L)), + returnValue(StatusWithResult.<Long> createError(errorMsg)), + returnValue(StatusWithResult.<Long> create(17L)))); } }); ConcurrencyUtilities.sleep(10L); diff --git a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilterTest.java b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilterTest.java index 541650a17da..76420bb7f99 100644 --- a/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilterTest.java +++ b/datamover/sourceTest/java/ch/systemsx/cisd/datamover/utils/QuietPeriodFileFilterTest.java @@ -30,12 +30,12 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import ch.rinn.restrictions.Friend; +import ch.systemsx.cisd.common.exceptions.StatusWithResult; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.test.LogMonitoringAppender; import ch.systemsx.cisd.common.utilities.ITimeProvider; import ch.systemsx.cisd.common.utilities.StoreItem; import ch.systemsx.cisd.datamover.filesystem.intf.IFileStore; -import ch.systemsx.cisd.datamover.filesystem.intf.DateStatus; import ch.systemsx.cisd.datamover.intf.ITimingParameters; /** @@ -154,7 +154,7 @@ public class QuietPeriodFileFilterTest one(timeProvider).getTimeInMilliseconds(); will(returnValue(nowMillis)); one(fileStore).lastChanged(ITEM, 0L); - will(returnValue(DateStatus.create(pathLastChangedMillis))); + will(returnValue(StatusWithResult.<Long>create(pathLastChangedMillis))); for (int i = 1; i <= 100; ++i) { one(timeProvider).getTimeInMilliseconds(); @@ -163,7 +163,7 @@ public class QuietPeriodFileFilterTest // last call - will check only when last check is longer ago than the quiet // period one(fileStore).lastChanged(ITEM, pathLastChangedMillis); - will(returnValue(DateStatus.create(pathLastChangedMillis))); + will(returnValue(StatusWithResult.<Long>create(pathLastChangedMillis))); } }); for (int i = 0; i < 100; ++i) @@ -237,7 +237,7 @@ public class QuietPeriodFileFilterTest long now = 0; for (int i = 0; i < errorRepetitions; i++) { - prepareLastChanged(now, 0L, DateStatus.createError()); + prepareLastChanged(now, 0L, StatusWithResult.<Long>createError()); now += QUIET_PERIOD_MILLIS; } for (int i = 0; i < errorRepetitions; i++) @@ -245,12 +245,12 @@ public class QuietPeriodFileFilterTest assertNoAccept(); } // first time we acquire modification time - DateStatus lastChange = DateStatus.create(0); + final StatusWithResult<Long> lastChange = StatusWithResult.<Long>create(0L); prepareLastChanged(now, 0L, lastChange); now += QUIET_PERIOD_MILLIS; assertNoAccept(); // error again - prepareLastChanged(now, 0L, DateStatus.createError()); + prepareLastChanged(now, 0L, StatusWithResult.<Long>createError()); now += QUIET_PERIOD_MILLIS; assertNoAccept(); // second time we acquire modification time - and nothing change during the quite period, so @@ -274,11 +274,12 @@ public class QuietPeriodFileFilterTest private void prepareLastChanged(final long currentTime, final long stopWhenFindYounger, final long lastChanged) { - prepareLastChanged(currentTime, stopWhenFindYounger, DateStatus.create(lastChanged)); + prepareLastChanged(currentTime, stopWhenFindYounger, StatusWithResult + .<Long> create(lastChanged)); } private void prepareLastChanged(final long currentTime, final long stopWhenFindYounger, - final DateStatus lastChanged) + final StatusWithResult<Long> lastChanged) { context.checking(new Expectations() { @@ -307,13 +308,13 @@ public class QuietPeriodFileFilterTest one(timeProvider).getTimeInMilliseconds(); will(returnValue(nowMillis1)); allowing(fileStore).lastChanged(vanishingItem, 0L); - will(returnValue(DateStatus.create(pathLastChangedMillis1))); + will(returnValue(StatusWithResult.<Long>create(pathLastChangedMillis1))); // calls to get the required number of calls for clean up allowing(timeProvider).getTimeInMilliseconds(); will(returnValue(nowMillis2)); allowing(fileStore).lastChanged(with(same(ITEM)), with(greaterThanOrEqualTo(0L))); - will(returnValue(DateStatus.create(pathLastChangedMillis2))); + will(returnValue(StatusWithResult.<Long>create(pathLastChangedMillis2))); } }); final LogMonitoringAppender appender = -- GitLab