diff options
Diffstat (limited to 'documentapi')
4 files changed, 103 insertions, 13 deletions
diff --git a/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlHandler.java b/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlHandler.java index b46308e0daf..4d05125f417 100644 --- a/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlHandler.java +++ b/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlHandler.java @@ -3,13 +3,15 @@ package com.yahoo.documentapi; import com.yahoo.vdslib.VisitorStatistics; +import java.time.Duration; + /** * A class for controlling a visitor supplied through visitor parameters when * creating the visitor session. The class defines callbacks for reporting * progress and that the visitor is done. If you want to reimplement the * default behavior of those callbacks, you can write your own subclass. * - * @author <a href="mailto:humbe@yahoo-inc.com">Håkon Humberset</a> + * @author Håkon Humberset */ public class VisitorControlHandler { /** Possible completion codes for visiting. */ @@ -46,6 +48,14 @@ public class VisitorControlHandler { return "Unknown error"; } + + public CompletionCode getCode() { + return code; + } + + public String getMessage() { + return message; + } }; private VisitorControlSession session; @@ -94,6 +104,17 @@ public class VisitorControlHandler { } /** + * Returns true iff the statistics reported by the visiting session indicates at least one + * bucket has been completely visited. + * + * Not thread safe, so should only be called on a quiescent session after waitUntilDone + * has completed successfully. + */ + public boolean hasVisitedAnyBuckets() { + return ((currentStatistics != null) && (currentStatistics.getBucketsVisited() > 0)); + } + + /** * Callback called when the visitor is done. * * @param code the completion code @@ -130,25 +151,52 @@ public class VisitorControlHandler { * Waits until visiting is done, or the given timeout (in ms) expires. * Will wait forever if timeout is 0. * - * @param timeoutMs The maximum amount of milliseconds to wait. - * @return True if visiting is done (either by error or success). - * @throws InterruptedException If an interrupt signal was received while waiting. + * @param timeout Maximum time duration to wait before returning. + * @return True if visiting is done (either by error or success), false if session has timed out. + * @throws InterruptedException If an interrupt signal was received while waiting. */ - public boolean waitUntilDone(long timeoutMs) throws InterruptedException { + public boolean waitUntilDone(Duration timeout) throws InterruptedException { synchronized (this) { - if (completed) return true; - if (timeoutMs == 0) { + if (completed) { + return true; + } + if (timeout.isZero()) { while (!completed) { wait(); } } else { - wait(timeoutMs); + wait(timeout.toMillis()); } return completed; } } /** + * Waits until visiting is done, or the given timeout (in ms) expires. + * Will wait forever if timeout is 0. + * + * @param timeoutMs The maximum amount of milliseconds to wait. + * @return True if visiting is done (either by error or success), false if session has timed out. + * @throws InterruptedException If an interrupt signal was received while waiting. + * + * TODO deprecate this in favor of waitUntilDone(Duration) + */ + public boolean waitUntilDone(long timeoutMs) throws InterruptedException { + return waitUntilDone(Duration.ofMillis(timeoutMs)); + } + + /** + * Waits until visiting is done. Session timeout implicitly completes + * the visitor session, but will set an unsuccessful result code. + * + * @throws InterruptedException If an interrupt signal was received while waiting. + */ + public void waitUntilDone() throws InterruptedException { + final boolean done = waitUntilDone(Duration.ZERO); + assert done : "Infinite waitUntilDone timeout should always complete"; + } + + /** * Abort this visitor */ public void abort() { session.abort(); } diff --git a/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlSession.java b/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlSession.java index 4296407d633..4218417437c 100644 --- a/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlSession.java +++ b/documentapi/src/main/java/com/yahoo/documentapi/VisitorControlSession.java @@ -10,7 +10,7 @@ package com.yahoo.documentapi; * kinds of visitor sessions, such as acking visitor data and aborting the * session. * - * @author <a href="mailto:humbe@yahoo-inc.com">Håkon Humberset</a> + * @author Håkon Humberset */ public interface VisitorControlSession { /** diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java index 306103f2912..56edc7eb42a 100755 --- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java +++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java @@ -883,8 +883,7 @@ public class MessageBusVisitorSession implements VisitorSession { if (isFatalError(reply)) { if (params.skipBucketsOnFatalErrors()) { - progress.getToken().addFailedBucket(bucket, subProgress, message); - progress.getIterator().update(bucket, ProgressToken.FINISHED_BUCKET); + markBucketProgressAsFailed(bucket, subProgress, message); } else { reportVisitorError(message); transitionTo(new StateDescription(State.FAILED, message)); @@ -903,6 +902,11 @@ public class MessageBusVisitorSession implements VisitorSession { } } + private void markBucketProgressAsFailed(BucketId bucket, BucketId subProgress, String message) { + progress.getToken().addFailedBucket(bucket, subProgress, message); + progress.getIterator().update(bucket, ProgressToken.FINISHED_BUCKET); + } + private boolean enoughHitsReceived() { if (params.getMaxFirstPassHits() != -1 && statistics.getDocumentsReturned() >= params.getMaxFirstPassHits()) @@ -1024,7 +1028,6 @@ public class MessageBusVisitorSession implements VisitorSession { private void handleWrongDistributionReply(WrongDistributionReply reply) { try { - // Classnames clash with documentapi classes, so be explicit ClusterState newState = new ClusterState(reply.getSystemState()); int stateBits = newState.getDistributionBitCount(); if (stateBits != progress.getIterator().getDistributionBitCount()) { @@ -1123,7 +1126,7 @@ public class MessageBusVisitorSession implements VisitorSession { synchronized (completionMonitor) { // If we are destroying the session before it has completed (e.g. because // waitUntilDone timed out or an interactive visiting was interrupted) - // set us to aborted state so that we'll seize + // set us to aborted state so that we'll seize sending new visitors. if (!done) { transitionTo(new StateDescription(State.ABORTED, "Session explicitly destroyed before completion")); } diff --git a/documentapi/src/test/java/com/yahoo/documentapi/messagebus/test/VisitorControlHandlerTest.java b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/test/VisitorControlHandlerTest.java new file mode 100644 index 00000000000..d8340e6a3f6 --- /dev/null +++ b/documentapi/src/test/java/com/yahoo/documentapi/messagebus/test/VisitorControlHandlerTest.java @@ -0,0 +1,39 @@ +// Copyright 2017 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.documentapi.messagebus.test; + +import com.yahoo.documentapi.VisitorControlHandler; +import com.yahoo.vdslib.VisitorStatistics; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class VisitorControlHandlerTest { + + @Test + public void has_visited_any_buckets_is_false_if_no_bucket_stats_recorded() { + VisitorControlHandler handler = new VisitorControlHandler(); + assertFalse(handler.hasVisitedAnyBuckets()); + } + + @Test + public void has_visited_any_buckets_is_false_if_zero_buckets_visited() { + VisitorControlHandler handler = new VisitorControlHandler(); + VisitorStatistics stats = new VisitorStatistics(); + stats.setBucketsVisited(0); + handler.onVisitorStatistics(stats); + + assertFalse(handler.hasVisitedAnyBuckets()); + } + + @Test + public void has_visited_any_buckets_is_true_if_more_than_zero_buckets_visited() { + VisitorControlHandler handler = new VisitorControlHandler(); + VisitorStatistics stats = new VisitorStatistics(); + stats.setBucketsVisited(1); + handler.onVisitorStatistics(stats); + + assertTrue(handler.hasVisitedAnyBuckets()); + } + +} |