You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by fr...@apache.org on 2018/06/19 11:26:23 UTC

svn commit: r1833822 - in /jackrabbit/oak/trunk/oak-segment-tar/src: main/java/org/apache/jackrabbit/oak/backup/impl/ main/java/org/apache/jackrabbit/oak/segment/ main/java/org/apache/jackrabbit/oak/segment/file/ main/java/org/apache/jackrabbit/oak/seg...

Author: frm
Date: Tue Jun 19 11:26:22 2018
New Revision: 1833822

URL: http://svn.apache.org/viewvc?rev=1833822&view=rev
Log:
OAK-7551 - Implement a stateless cancellation strategy

The cancellation strategy previously represented by `CancelCompactionSupplier`
has been replaced by `Canceller`. `Canceller` repesents a hierarchy of
cancellation conditions which can rely a cancellation request as soon as one of
the conditions is met. This allows the code to create more specific
cancellation conditions for specific parts of the codebase, withouth amassing
the cancellation state in a single entity.

Added:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java   (with props)
Removed:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CancelCompactionSupplier.java
Modified:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/CheckpointCompactor.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Compactor.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractCompactionStrategy.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractGarbageCollectionStrategy.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CompactionStrategy.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollectionStrategy.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollector.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CheckpointCompactorTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactorTest.java

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreBackupImpl.java Tue Jun 19 11:26:22 2018
@@ -27,7 +27,6 @@ import java.io.IOException;
 import javax.annotation.Nonnull;
 
 import com.google.common.base.Stopwatch;
-import com.google.common.base.Suppliers;
 import org.apache.jackrabbit.oak.backup.FileStoreBackup;
 import org.apache.jackrabbit.oak.segment.Compactor;
 import org.apache.jackrabbit.oak.segment.DefaultSegmentWriter;
@@ -42,6 +41,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.segment.file.tooling.BasicReadOnlyBlobStore;
 import org.slf4j.Logger;
@@ -90,11 +90,10 @@ public class FileStoreBackupImpl impleme
                     backup.getReader(),
                     writer,
                     backup.getBlobStore(),
-                    Suppliers.ofInstance(false),
                     GCNodeWriteMonitor.EMPTY
             );
             SegmentNodeState head = backup.getHead();
-            SegmentNodeState after = compactor.compact(head, current, head);
+            SegmentNodeState after = compactor.compact(head, current, head, Canceller.newCanceller());
             writer.flush();
 
             if (after != null) {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/backup/impl/FileStoreRestoreImpl.java Tue Jun 19 11:26:22 2018
@@ -39,6 +39,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
 import org.apache.jackrabbit.oak.segment.file.ReadOnlyFileStore;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -85,10 +86,9 @@ public class FileStoreRestoreImpl implem
                     store.getReader(),
                     writer,
                     store.getBlobStore(),
-                    Suppliers.ofInstance(false),
                     GCNodeWriteMonitor.EMPTY
             );
-            SegmentNodeState after = compactor.compact(current, head, current);
+            SegmentNodeState after = compactor.compact(current, head, current, Canceller.newCanceller());
             writer.flush();
             store.getRevisions().setHead(current.getRecordId(), after.getRecordId());
         } finally {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/CheckpointCompactor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/CheckpointCompactor.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/CheckpointCompactor.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/CheckpointCompactor.java Tue Jun 19 11:26:22 2018
@@ -38,8 +38,8 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.base.Supplier;
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.gc.GCMonitor;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -80,7 +80,6 @@ public class CheckpointCompactor {
      * @param reader     segment reader used to read from the segments
      * @param writer     segment writer used to serialise to segments
      * @param blobStore  the blob store or {@code null} if none
-     * @param cancel     a flag that can be used to cancel the compaction process
      * @param compactionMonitor   notification call back for each compacted nodes,
      *                            properties, and binaries
      */
@@ -89,10 +88,9 @@ public class CheckpointCompactor {
             @Nonnull SegmentReader reader,
             @Nonnull SegmentWriter writer,
             @Nullable BlobStore blobStore,
-            @Nonnull Supplier<Boolean> cancel,
             @Nonnull GCNodeWriteMonitor compactionMonitor) {
         this.gcListener = gcListener;
-        this.compactor = new Compactor(reader, writer, blobStore, cancel, compactionMonitor);
+        this.compactor = new Compactor(reader, writer, blobStore, compactionMonitor);
         this.nodeWriter = (node, stableId) -> {
             RecordId nodeId = writer.writeNode(node, stableId);
             return new SegmentNodeState(reader, writer, blobStore, nodeId);
@@ -110,17 +108,23 @@ public class CheckpointCompactor {
      */
     @CheckForNull
     public SegmentNodeState compact(
-            @Nonnull NodeState base,
-            @Nonnull NodeState uncompacted,
-            @Nonnull NodeState onto)
-    throws IOException {
+        @Nonnull NodeState base,
+        @Nonnull NodeState uncompacted,
+        @Nonnull NodeState onto,
+        Canceller canceller
+    ) throws IOException {
         // Collect a chronologically ordered list of roots for the uncompacted
         // state. This list consists of all checkpoints followed by the root.
         LinkedHashMap<String, NodeState> uncompactedRoots = collectRoots(uncompacted);
 
         // Compact the list of uncompacted roots to a list of compacted roots.
         LinkedHashMap<String, NodeState> compactedRoots = compact(
-                getRoot(base), uncompactedRoots, getRoot(onto));
+            getRoot(base),
+            uncompactedRoots,
+            getRoot(onto),
+            canceller
+        );
+
         if (compactedRoots == null) {
             return null;
         }
@@ -158,15 +162,16 @@ public class CheckpointCompactor {
      */
     @CheckForNull
     private LinkedHashMap<String, NodeState> compact(
-            @Nonnull NodeState base,
-            @Nonnull LinkedHashMap<String, NodeState> uncompactedRoots,
-            @Nonnull NodeState onto)
-    throws IOException {
+        @Nonnull NodeState base,
+        @Nonnull LinkedHashMap<String, NodeState> uncompactedRoots,
+        @Nonnull NodeState onto,
+        Canceller canceller
+    ) throws IOException {
         LinkedHashMap<String, NodeState> compactedRoots = newLinkedHashMap();
         for (Entry<String, NodeState> uncompactedRoot : uncompactedRoots.entrySet()) {
             String path = uncompactedRoot.getKey();
             NodeState uncompacted = uncompactedRoot.getValue();
-            Result result = compactWithCache(base, uncompacted, onto, path);
+            Result result = compactWithCache(base, uncompacted, onto, path, canceller);
             if (result == null) {
                 return null;
             }
@@ -234,15 +239,16 @@ public class CheckpointCompactor {
      */
     @CheckForNull
     private Result compactWithCache(
-            @Nonnull NodeState before,
-            @Nonnull NodeState after,
-            @Nonnull NodeState onto,
-            @Nonnull String path)
-    throws IOException {
+        @Nonnull NodeState before,
+        @Nonnull NodeState after,
+        @Nonnull NodeState onto,
+        @Nonnull String path,
+        Canceller canceller
+    ) throws IOException {
         gcListener.info("compacting {}.", path);
         NodeState compacted = cpCache.get(after);
         if (compacted == null) {
-            compacted = compactor.compact(before, after, onto);
+            compacted = compactor.compact(before, after, onto, canceller);
             if (compacted == null) {
                 return null;
             } else {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Compactor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Compactor.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Compactor.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Compactor.java Tue Jun 19 11:26:22 2018
@@ -35,12 +35,12 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.base.Supplier;
 import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
@@ -72,9 +72,6 @@ public class Compactor {
     private final BlobStore blobStore;
 
     @Nonnull
-    private final Supplier<Boolean> cancel;
-
-    @Nonnull
     private final GCNodeWriteMonitor compactionMonitor;
 
     /**
@@ -82,7 +79,6 @@ public class Compactor {
      * @param reader     segment reader used to read from the segments
      * @param writer     segment writer used to serialise to segments
      * @param blobStore  the blob store or {@code null} if none
-     * @param cancel     a flag that can be used to cancel the compaction process
      * @param compactionMonitor   notification call back for each compacted nodes,
      *                            properties, and binaries
      */
@@ -90,12 +86,10 @@ public class Compactor {
             @Nonnull SegmentReader reader,
             @Nonnull SegmentWriter writer,
             @Nullable BlobStore blobStore,
-            @Nonnull Supplier<Boolean> cancel,
             @Nonnull GCNodeWriteMonitor compactionMonitor) {
         this.writer = checkNotNull(writer);
         this.reader = checkNotNull(reader);
         this.blobStore = blobStore;
-        this.cancel = checkNotNull(cancel);
         this.compactionMonitor = checkNotNull(compactionMonitor);
     }
 
@@ -106,8 +100,8 @@ public class Compactor {
      * @throws IOException
      */
     @CheckForNull
-    public SegmentNodeState compact(@Nonnull NodeState state) throws IOException {
-        return compact(EMPTY_NODE, state, EMPTY_NODE);
+    public SegmentNodeState compact(@Nonnull NodeState state, Canceller canceller) throws IOException {
+        return compact(EMPTY_NODE, state, EMPTY_NODE, canceller);
     }
 
     /**
@@ -120,14 +114,15 @@ public class Compactor {
      */
     @CheckForNull
     public SegmentNodeState compact(
-            @Nonnull NodeState before,
-            @Nonnull NodeState after,
-            @Nonnull NodeState onto)
-    throws IOException {
+        @Nonnull NodeState before,
+        @Nonnull NodeState after,
+        @Nonnull NodeState onto,
+        Canceller canceller
+    ) throws IOException {
         checkNotNull(before);
         checkNotNull(after);
         checkNotNull(onto);
-        return new CompactDiff(onto).diff(before, after);
+        return new CompactDiff(onto, canceller).diff(before, after);
     }
 
     @CheckForNull
@@ -146,6 +141,8 @@ public class Compactor {
         @Nonnull
         private final NodeState base;
 
+        private final Canceller canceller;
+
         @CheckForNull
         private IOException exception;
 
@@ -159,14 +156,15 @@ public class Compactor {
             }
         }
 
-        CompactDiff(@Nonnull NodeState base) {
+        CompactDiff(@Nonnull NodeState base, Canceller canceller) {
             this.builder = new MemoryNodeBuilder(checkNotNull(base));
+            this.canceller = canceller;
             this.base = base;
         }
 
         @CheckForNull
         SegmentNodeState diff(@Nonnull NodeState before, @Nonnull NodeState after) throws IOException {
-            boolean success = after.compareAgainstBaseState(before, new CancelableDiff(this, cancel));
+            boolean success = after.compareAgainstBaseState(before, new CancelableDiff(this, () -> canceller.check().isCancelled()));
             if (exception != null) {
                 throw new IOException(exception);
             } else if (success) {
@@ -201,7 +199,7 @@ public class Compactor {
         @Override
         public boolean childNodeAdded(@Nonnull String name, @Nonnull NodeState after) {
             try {
-                SegmentNodeState compacted = compact(after);
+                SegmentNodeState compacted = compact(after, canceller);
                 if (compacted != null) {
                     updated();
                     builder.setChildNode(name, compacted);
@@ -218,7 +216,7 @@ public class Compactor {
         @Override
         public boolean childNodeChanged(@Nonnull String name, @Nonnull NodeState before, @Nonnull NodeState after) {
             try {
-                SegmentNodeState compacted = compact(before, after, base.getChildNode(name));
+                SegmentNodeState compacted = compact(before, after, base.getChildNode(name), canceller);
                 if (compacted != null) {
                     updated();
                     builder.setChildNode(name, compacted);

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractCompactionStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractCompactionStrategy.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractCompactionStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractCompactionStrategy.java Tue Jun 19 11:26:22 2018
@@ -35,6 +35,8 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentNodeState;
 import org.apache.jackrabbit.oak.segment.SegmentWriter;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.GCType;
+import org.apache.jackrabbit.oak.segment.file.cancel.Cancellation;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
@@ -74,12 +76,13 @@ abstract class AbstractCompactionStrateg
         Context context,
         NodeState base,
         NodeState onto,
-        CheckpointCompactor compactor
+        CheckpointCompactor compactor,
+        Canceller canceller
     ) throws InterruptedException {
         RecordId compactedId = setHead(context, headId -> {
             try {
                 PrintableStopwatch t = PrintableStopwatch.createStarted();
-                SegmentNodeState after = compactor.compact(base, context.getSegmentReader().readNode(headId), onto);
+                SegmentNodeState after = compactor.compact(base, context.getSegmentReader().readNode(headId), onto, canceller);
                 if (after != null) {
                     return after.getRecordId();
                 }
@@ -133,19 +136,20 @@ abstract class AbstractCompactionStrateg
 
             context.getCompactionMonitor().init(gcEntry.getRepoSize(), gcEntry.getNodes(), initialSize);
 
+            Canceller compactionCanceller = context.getCanceller().withShortCircuit();
+
             CheckpointCompactor compactor = new CheckpointCompactor(
                 context.getGCListener(),
                 context.getSegmentReader(),
                 writer,
                 context.getBlobStore(),
-                context.getCanceller(),
                 context.getCompactionMonitor()
             );
 
             SegmentNodeState head = getHead(context);
-            SegmentNodeState compacted = compactor.compact(base, head, base);
+            SegmentNodeState compacted = compactor.compact(base, head, base, compactionCanceller);
             if (compacted == null) {
-                context.getGCListener().warn("compaction cancelled: {}.", context.getCanceller());
+                context.getGCListener().warn("compaction cancelled: {}.", compactionCanceller.check().getReason().orElse("unknown reason"));
                 return compactionAborted(context, nextGeneration);
             }
 
@@ -168,9 +172,9 @@ abstract class AbstractCompactionStrateg
                 PrintableStopwatch cycleWatch = PrintableStopwatch.createStarted();
 
                 head = getHead(context);
-                compacted = compactor.compact(previousHead, head, compacted);
+                compacted = compactor.compact(previousHead, head, compacted, compactionCanceller);
                 if (compacted == null) {
-                    context.getGCListener().warn("compaction cancelled: {}.", context.getCanceller());
+                    context.getGCListener().warn("compaction cancelled: {}.", compactionCanceller.check().getReason().orElse("unknown reason"));
                     return compactionAborted(context, nextGeneration);
                 }
 
@@ -190,16 +194,20 @@ abstract class AbstractCompactionStrateg
                     PrintableStopwatch forceWatch = PrintableStopwatch.createStarted();
 
                     cycles++;
-                    context.getCanceller().timeOutAfter(forceTimeout, SECONDS);
-                    compacted = forceCompact(context, previousHead, compacted, compactor);
+
+                    Canceller forcedCompactionCanceller = compactionCanceller
+                        .withTimeout("forced compaction timeout exceeded", forceTimeout, SECONDS)
+                        .withShortCircuit();
+                    compacted = forceCompact(context, previousHead, compacted, compactor, forcedCompactionCanceller);
                     success = compacted != null;
                     if (success) {
                         context.getGCListener().info("compaction succeeded to force compact remaining commits after {}.", forceWatch);
                     } else {
-                        if (context.getCanceller().get()) {
+                        Cancellation cancellation = forcedCompactionCanceller.check();
+                        if (cancellation.isCancelled()) {
                             context.getGCListener().warn("compaction failed to force compact remaining commits " +
                                     "after {}. Compaction was cancelled: {}.",
-                                forceWatch, context.getCanceller());
+                                forceWatch, cancellation.getReason().orElse("unknown reason"));
                         } else {
                             context.getGCListener().warn("compaction failed to force compact remaining commits. " +
                                     "after {}. Could not acquire exclusive access to the node store.",

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractGarbageCollectionStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractGarbageCollectionStrategy.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractGarbageCollectionStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/AbstractGarbageCollectionStrategy.java Tue Jun 19 11:26:22 2018
@@ -31,6 +31,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentReader;
 import org.apache.jackrabbit.oak.segment.SegmentTracker;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.segment.file.tar.TarFiles;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
@@ -229,7 +230,7 @@ abstract class AbstractGarbageCollection
             }
 
             @Override
-            public CancelCompactionSupplier getCanceller() {
+            public Canceller getCanceller() {
                 return context.getCanceller();
             }
 

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CompactionStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CompactionStrategy.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CompactionStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/CompactionStrategy.java Tue Jun 19 11:26:22 2018
@@ -25,6 +25,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentReader;
 import org.apache.jackrabbit.oak.segment.SegmentTracker;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.TarFiles;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 
@@ -50,7 +51,7 @@ interface CompactionStrategy {
 
         BlobStore getBlobStore();
 
-        CancelCompactionSupplier getCanceller();
+        Canceller getCanceller();
 
         int getGCCount();
 

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java Tue Jun 19 11:26:22 2018
@@ -48,6 +48,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentWriter;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
 import org.apache.jackrabbit.oak.segment.file.ShutDown.ShutDownCloser;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.segment.file.tar.TarFiles;
 import org.apache.jackrabbit.oak.segment.spi.persistence.RepositoryLock;
@@ -163,11 +164,10 @@ public class FileStore extends AbstractF
             segmentCache,
             segmentWriter,
             stats,
-            new CancelCompactionSupplier(
-                () -> !sufficientDiskSpace.get(),
-                () -> !sufficientMemory.get(),
-                shutDown::isShutDown
-            ),
+            Canceller.newCanceller()
+                .withCondition("not enough disk space", () -> !sufficientDiskSpace.get())
+                .withCondition("not enough memory", () -> !sufficientMemory.get())
+                .withCondition("FileStore is shutting down", shutDown::isShutDown),
             this::flush,
             generation ->
                 defaultSegmentWriterBuilder("c")

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollectionStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollectionStrategy.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollectionStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollectionStrategy.java Tue Jun 19 11:26:22 2018
@@ -28,6 +28,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentReader;
 import org.apache.jackrabbit.oak.segment.SegmentTracker;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.TarFiles;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 
@@ -57,7 +58,7 @@ interface GarbageCollectionStrategy {
 
         BlobStore getBlobStore();
 
-        CancelCompactionSupplier getCanceller();
+        Canceller getCanceller();
 
         long getLastSuccessfulGC();
 

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollector.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollector.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/GarbageCollector.java Tue Jun 19 11:26:22 2018
@@ -39,6 +39,7 @@ import org.apache.jackrabbit.oak.segment
 import org.apache.jackrabbit.oak.segment.SegmentWriter;
 import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions;
 import org.apache.jackrabbit.oak.segment.file.GarbageCollectionStrategy.SuccessfulGarbageCollectionListener;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.segment.file.tar.TarFiles;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
@@ -90,7 +91,7 @@ class GarbageCollector {
 
     private final FileStoreStats stats;
 
-    private final CancelCompactionSupplier cancel;
+    private final Canceller cancel;
 
     private final Flusher flusher;
 
@@ -98,6 +99,7 @@ class GarbageCollector {
 
     private final GCNodeWriteMonitor compactionMonitor;
 
+
     /**
      * Timestamp of the last time full or tail compaction was successfully
      * invoked. 0 if never.
@@ -112,6 +114,8 @@ class GarbageCollector {
      */
     private SegmentGCOptions.GCType lastCompactionType = FULL;
 
+    private volatile boolean cancelRequested;
+
     GarbageCollector(
         SegmentGCOptions gcOptions,
         GCListener gcListener,
@@ -126,7 +130,7 @@ class GarbageCollector {
         SegmentCache segmentCache,
         SegmentWriter segmentWriter,
         FileStoreStats stats,
-        CancelCompactionSupplier cancel,
+        Canceller canceller,
         Flusher flusher,
         SegmentWriterFactory segmentWriterFactory
     ) {
@@ -143,7 +147,7 @@ class GarbageCollector {
         this.segmentCache = segmentCache;
         this.segmentWriter = segmentWriter;
         this.stats = stats;
-        this.cancel = cancel;
+        this.cancel = canceller.withCondition("cancelled by user", () -> cancelRequested);
         this.flusher = flusher;
         this.segmentWriterFactory = segmentWriterFactory;
         this.compactionMonitor = new GCNodeWriteMonitor(gcOptions.getGcLogInterval(), gcListener);
@@ -201,7 +205,7 @@ class GarbageCollector {
             }
 
             @Override
-            public CancelCompactionSupplier getCanceller() {
+            public Canceller getCanceller() {
                 return cancel;
             }
 
@@ -274,26 +278,32 @@ class GarbageCollector {
     }
 
     synchronized void run(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         strategy.collectGarbage(newGarbageCollectionContext(GC_COUNT.incrementAndGet()));
     }
 
     synchronized void runFull(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         strategy.collectFullGarbage(newGarbageCollectionContext(GC_COUNT.incrementAndGet()));
     }
 
     synchronized void runTail(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         strategy.collectTailGarbage(newGarbageCollectionContext(GC_COUNT.incrementAndGet()));
     }
 
     synchronized CompactionResult compactFull(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         return strategy.compactFull(newGarbageCollectionContext(GC_COUNT.get()));
     }
 
     synchronized CompactionResult compactTail(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         return strategy.compactTail(newGarbageCollectionContext(GC_COUNT.get()));
     }
 
     synchronized List<String> cleanup(GarbageCollectionStrategy strategy) throws IOException {
+        cancelRequested = false;
         return strategy.cleanup(newGarbageCollectionContext(GC_COUNT.get()));
     }
 
@@ -317,7 +327,7 @@ class GarbageCollector {
     }
 
     void cancel() {
-        cancel.cancel();
+        cancelRequested = true;
     }
 
 }

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.Optional;
+
+/**
+ * The result of a check for a pending cancellation request.
+ */
+public class Cancellation {
+
+    private final boolean cancelled;
+
+    private final String reason;
+
+    Cancellation(boolean cancelled, String reason) {
+        this.cancelled = cancelled;
+        this.reason = reason;
+    }
+
+    /**
+     * Returns {@code true} if cancellation has been requested, {@code false}
+     * otherwise.
+     */
+    public boolean isCancelled() {
+        return cancelled;
+    }
+
+    /**
+     * If cancellation has been requested (i.e. if {@link #isCancelled()} is
+     * {@code true}), returns the reason of the cancellation as provided by the
+     * user. Otherwise, an empty {@link Optional} is returned.
+     */
+    public Optional<String> getReason() {
+        return Optional.ofNullable(reason);
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Cancellation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.BooleanSupplier;
+
+/**
+ * Represents a way to check for a cancellation request. Users of this class
+ * (possibly cancelable, long-running operations) should periodically check
+ * whether a cancellation request has been received.
+ */
+public class Canceller {
+
+    private static final Canceller ROOT = new Canceller();
+
+    private static final Cancellation NOPE = new Cancellation(false, null);
+
+    /**
+     * Create a new {@link Canceller} which is trivially empty. The returned
+     * {@link Canceller} will never relay a positive cancellation request.
+     *
+     * @return an instance of {@link Canceller}.
+     */
+    public static Canceller newCanceller() {
+        return ROOT;
+    }
+
+    Canceller() {
+        // Prevent instantiation outside of this package.
+    }
+
+    /**
+     * Check if cancellation has been requested. This method should be invoked
+     * periodically, and the returned {@link Cancellation} should be inspected
+     * and reacted upon.
+     *
+     * @return an instance of {@link Cancellation}.
+     */
+    public Cancellation check() {
+        return NOPE;
+    }
+
+    /**
+     * Return a new {@link Canceller} based on a boolean predicate. The returned
+     * instance will relay a positive cancellation request when either the
+     * supplied boolean predicate is {@code true} or this {@link Canceller} is
+     * cancelled.
+     *
+     * @param reason    The reason associated to the boolean condition.
+     * @param condition A boolean predicate.
+     * @return a new instance of {@link Canceller}.
+     */
+    public Canceller withCondition(String reason, BooleanSupplier condition) {
+        return new ConditionCanceller(this, reason, condition);
+    }
+
+    /**
+     * Return a new {@link Canceller} based on time duration. The returned
+     * instance will relay a positive cancellation request when either the
+     * duration expires or this {@link Canceller} is cancelled.
+     *
+     * @param reason   The reason associated to the boolean condition.
+     * @param duration The duration for the timeout.
+     * @param unit     The time unit for the duration.
+     * @return a new instance of {@link Canceller}.
+     */
+    public Canceller withTimeout(String reason, long duration, TimeUnit unit) {
+        return new TimeoutCanceller(this, reason, duration, unit);
+    }
+
+    /**
+     * Create a new {@link Canceller} based on this {@link Canceller}. The
+     * returned instance will be canceled when this instance is canceled, but
+     * will never transition back to an "uncanceled" state.
+     *
+     * @return an new instance of {@link Canceller}.
+     */
+    public Canceller withShortCircuit() {
+        return new ShortCircuitCanceller(this);
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/Canceller.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.BooleanSupplier;
+
+class ConditionCanceller extends Canceller {
+
+    private final Canceller parent;
+
+    private final String reason;
+
+    private final BooleanSupplier condition;
+
+    ConditionCanceller(Canceller parent, String reason, BooleanSupplier condition) {
+        this.parent = parent;
+        this.reason = reason;
+        this.condition = condition;
+    }
+
+    @Override
+    public Cancellation check() {
+        if (condition.getAsBoolean()) {
+            return new Cancellation(true, reason);
+        }
+        return parent.check();
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ConditionCanceller.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+class ShortCircuitCanceller extends Canceller {
+
+    private final AtomicReference<Cancellation> cancellation = new AtomicReference<>();
+
+    private final Canceller parent;
+
+    ShortCircuitCanceller(Canceller parent) {
+        this.parent = parent;
+    }
+
+    @Override
+    public Cancellation check() {
+        return cancellation.updateAndGet(prev -> prev != null && prev.isCancelled() ? prev : parent.check());
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/ShortCircuitCanceller.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.concurrent.TimeUnit;
+
+class TimeoutCanceller extends Canceller {
+
+    private final Canceller parent;
+
+    private final String reason;
+
+    private final long expiration;
+
+    TimeoutCanceller(Canceller parent, String reason, long duration, TimeUnit unit) {
+        this.parent = parent;
+        this.reason = reason;
+        this.expiration = System.currentTimeMillis() + unit.toMillis(duration);
+    }
+
+    @Override
+    public Cancellation check() {
+        if (System.currentTimeMillis() > expiration) {
+            return new Cancellation(true, reason);
+        }
+        return parent.check();
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/cancel/TimeoutCanceller.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CheckpointCompactorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CheckpointCompactorTest.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CheckpointCompactorTest.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CheckpointCompactorTest.java Tue Jun 19 11:26:22 2018
@@ -44,6 +44,7 @@ import org.apache.jackrabbit.oak.api.Com
 import org.apache.jackrabbit.oak.segment.file.FileStore;
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.segment.file.tar.GCGeneration;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
@@ -91,7 +92,7 @@ public class CheckpointCompactorTest {
         String cp2 = nodeStore.checkpoint(DAYS.toMillis(1));
 
         SegmentNodeState uncompacted1 = fileStore.getHead();
-        SegmentNodeState compacted1 = compactor.compact(EMPTY_NODE, uncompacted1, EMPTY_NODE);
+        SegmentNodeState compacted1 = compactor.compact(EMPTY_NODE, uncompacted1, EMPTY_NODE, Canceller.newCanceller());
         assertNotNull(compacted1);
         assertFalse(uncompacted1 == compacted1);
         checkGeneration(compacted1, compactedGeneration);
@@ -108,7 +109,7 @@ public class CheckpointCompactorTest {
         String cp4 = nodeStore.checkpoint(DAYS.toMillis(1));
 
         SegmentNodeState uncompacted2 = fileStore.getHead();
-        SegmentNodeState compacted2 = compactor.compact(uncompacted1, uncompacted2, compacted1);
+        SegmentNodeState compacted2 = compactor.compact(uncompacted1, uncompacted2, compacted1, Canceller.newCanceller());
         assertNotNull(compacted2);
         assertFalse(uncompacted2 == compacted2);
         checkGeneration(compacted2, compactedGeneration);
@@ -173,7 +174,6 @@ public class CheckpointCompactorTest {
                 fileStore.getReader(),
                 writer,
                 fileStore.getBlobStore(),
-                Suppliers.ofInstance(false),
                 GCNodeWriteMonitor.EMPTY);
     }
 

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactorTest.java?rev=1833822&r1=1833821&r2=1833822&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactorTest.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactorTest.java Tue Jun 19 11:26:22 2018
@@ -39,13 +39,12 @@ import java.util.Random;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
 import org.apache.jackrabbit.oak.api.Blob;
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.segment.file.FileStore;
 import org.apache.jackrabbit.oak.segment.file.GCNodeWriteMonitor;
 import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
+import org.apache.jackrabbit.oak.segment.file.cancel.Canceller;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -78,11 +77,11 @@ public class CompactorTest {
 
     @Test
     public void testCompact() throws Exception {
-        Compactor compactor = createCompactor(fileStore, Suppliers.ofInstance(false), null);
+        Compactor compactor = createCompactor(fileStore, null);
         addTestContent(nodeStore);
 
         SegmentNodeState uncompacted = (SegmentNodeState) nodeStore.getRoot();
-        SegmentNodeState compacted = compactor.compact(uncompacted);
+        SegmentNodeState compacted = compactor.compact(uncompacted, Canceller.newCanceller());
         assertNotNull(compacted);
         assertFalse(uncompacted == compacted);
         assertEquals(uncompacted, compacted);
@@ -90,7 +89,7 @@ public class CompactorTest {
 
         modifyTestContent(nodeStore);
         NodeState modified = nodeStore.getRoot();
-        compacted = compactor.compact(uncompacted, modified, compacted);
+        compacted = compactor.compact(uncompacted, modified, compacted, Canceller.newCanceller());
         assertNotNull(compacted);
         assertFalse(modified == compacted);
         assertEquals(modified, compacted);
@@ -99,11 +98,11 @@ public class CompactorTest {
 
     @Test
     public void testExceedUpdateLimit() throws Exception {
-        Compactor compactor = createCompactor(fileStore, Suppliers.ofInstance(false), null);
+        Compactor compactor = createCompactor(fileStore, null);
         addNodes(nodeStore, Compactor.UPDATE_LIMIT * 2 + 1);
 
         SegmentNodeState uncompacted = (SegmentNodeState) nodeStore.getRoot();
-        SegmentNodeState compacted = compactor.compact(uncompacted);
+        SegmentNodeState compacted = compactor.compact(uncompacted, Canceller.newCanceller());
         assertNotNull(compacted);
         assertFalse(uncompacted == compacted);
         assertEquals(uncompacted, compacted);
@@ -112,31 +111,31 @@ public class CompactorTest {
 
     @Test
     public void testCancel() throws IOException, CommitFailedException {
-        Compactor compactor = createCompactor(fileStore, Suppliers.ofInstance(true), null);
+        Compactor compactor = createCompactor(fileStore, null);
         addTestContent(nodeStore);
         NodeBuilder builder = nodeStore.getRoot().builder();
         builder.setChildNode("cancel").setProperty("cancel", "cancel");
         nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
 
-        assertNull(compactor.compact(nodeStore.getRoot()));
+        assertNull(compactor.compact(nodeStore.getRoot(), Canceller.newCanceller().withCondition("reason", () -> true)));
     }
 
     @Test(expected = IOException.class)
     public void testIOException() throws IOException, CommitFailedException {
-        Compactor compactor = createCompactor(fileStore, Suppliers.ofInstance(false), "IOException");
+        Compactor compactor = createCompactor(fileStore, "IOException");
         addTestContent(nodeStore);
-        compactor.compact(nodeStore.getRoot());
+        compactor.compact(nodeStore.getRoot(), Canceller.newCanceller());
     }
 
     @Nonnull
-    private static Compactor createCompactor(FileStore fileStore, Supplier<Boolean> cancel, String failOnName) {
+    private static Compactor createCompactor(FileStore fileStore, String failOnName) {
         SegmentWriter writer = defaultSegmentWriterBuilder("c")
                 .withGeneration(newGCGeneration(1, 1, true))
                 .build(fileStore);
         if (failOnName != null) {
             writer = new FailingSegmentWriter(writer, failOnName);
         }
-        return new Compactor(fileStore.getReader(), writer, fileStore.getBlobStore(), cancel, GCNodeWriteMonitor.EMPTY);
+        return new Compactor(fileStore.getReader(), writer, fileStore.getBlobStore(), GCNodeWriteMonitor.EMPTY);
     }
 
     private static void addNodes(SegmentNodeStore nodeStore, int count)

Added: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java?rev=1833822&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java Tue Jun 19 11:26:22 2018
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file.cancel;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.lang3.mutable.MutableBoolean;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CancellerTest {
+
+    private static void assertNotCancelled(Cancellation c) {
+        Assert.assertFalse(c.isCancelled());
+        Assert.assertFalse(c.getReason().isPresent());
+    }
+
+    private static void assertCancelled(Cancellation c, String reason) {
+        Assert.assertTrue(c.isCancelled());
+        Assert.assertEquals(c.getReason(), Optional.of(reason));
+    }
+
+    @Test
+    public void emptyCancellerShouldNotCancel() {
+        Cancellation c = Canceller.newCanceller().check();
+        assertNotCancelled(c);
+    }
+
+    @Test
+    public void trueConditionShouldCancel() {
+        Cancellation c = Canceller.newCanceller().withCondition("reason", () -> true).check();
+        assertCancelled(c, "reason");
+    }
+
+    @Test
+    public void falseConditionShouldNotCancel() {
+        Cancellation c = Canceller.newCanceller().withCondition("reason", () -> false).check();
+        assertNotCancelled(c);
+    }
+
+    @Test
+    public void falseConditionShouldCheckParent() {
+        Cancellation c = Canceller.newCanceller()
+            .withCondition("parent", () -> true)
+            .withCondition("child", () -> false)
+            .check();
+        assertCancelled(c, "parent");
+    }
+
+    @Test
+    public void expiredTimeoutShouldCancel() throws Exception {
+        Canceller canceller = Canceller.newCanceller().withTimeout("reason", 1, TimeUnit.MILLISECONDS);
+        Thread.sleep(10);
+        Cancellation c = canceller.check();
+        assertCancelled(c, "reason");
+    }
+
+    @Test
+    public void validTimeoutShouldNotCancel() {
+        Cancellation c = Canceller.newCanceller().withTimeout("reason", 1, TimeUnit.DAYS).check();
+        assertNotCancelled(c);
+    }
+
+    @Test
+    public void validTimeoutShouldCheckParent() {
+        Cancellation c = Canceller.newCanceller()
+            .withCondition("parent", () -> true)
+            .withTimeout("child", 1, TimeUnit.DAYS)
+            .check();
+        assertCancelled(c, "parent");
+    }
+
+    @Test
+    public void shortCircuitShouldCancelWhenParentCancel() {
+        Cancellation c = Canceller.newCanceller()
+            .withCondition("reason", () -> true)
+            .withShortCircuit()
+            .check();
+        assertCancelled(c, "reason");
+    }
+
+    @Test
+    public void shortCircuitShouldNotCancelWhenParentDoesNotCancel() {
+        Cancellation c = Canceller.newCanceller()
+            .withCondition("reason", () -> false)
+            .withShortCircuit()
+            .check();
+        assertNotCancelled(c);
+    }
+
+    @Test
+    public void shortCircuitShouldBreakCircuitWithParentOnFailure() {
+        MutableBoolean b = new MutableBoolean(false);
+        Canceller c = Canceller.newCanceller()
+            .withCondition("reason", b::booleanValue)
+            .withShortCircuit();
+        assertNotCancelled(c.check());
+        b.setValue(true);
+        assertCancelled(c.check(), "reason");
+        b.setValue(false);
+        assertCancelled(c.check(), "reason");
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/cancel/CancellerTest.java
------------------------------------------------------------------------------
    svn:eol-style = native