Author: frm
Date: Wed Jun 29 13:42:50 2016
New Revision: 1750636
URL: http://svn.apache.org/viewvc?rev=1750636&view=rev
Log:
OAK-3468 - Replace BackgroundThread with Scheduler
BackgroundThread has been replaced with either PeriodicOperation or
TriggeredOperation, depending on the needed execution strategy. These classes
do not make use of threading directly, but rely on the Executor framework and
other concurrency utilities.
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java
(with props)
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java
(with props)
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java
(with props)
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java
(with props)
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java
(with props)
Removed:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/BackgroundThread.java
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
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=1750636&r1=1750635&r2=1750636&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
Wed Jun 29 13:42:50 2016
@@ -159,13 +159,13 @@ public class FileStore implements Segmen
* The background flush thread. Automatically flushes the TarMK state
* once every five seconds.
*/
- private final BackgroundThread flushThread;
+ private final PeriodicOperation flushOperation;
/**
* The background compaction thread. Compacts the TarMK contents whenever
* triggered by the {@link #gc()} method.
*/
- private final BackgroundThread compactionThread;
+ private final TriggeredOperation compactionOperation;
/**
* This background thread periodically asks the {@code SegmentGCOptions}
@@ -173,7 +173,7 @@ public class FileStore implements Segmen
* space. The result of this comparison is stored in the state of this
* {@code FileStore}.
*/
- private final BackgroundThread diskSpaceThread;
+ private final PeriodicOperation diskSpaceOperation;
private final SegmentGCOptions gcOptions;
@@ -228,7 +228,7 @@ public class FileStore implements Segmen
};
// FIXME OAK-4450: Properly split the FileStore into read-only and r/w
variants
- FileStore(FileStoreBuilder builder, boolean readOnly) throws IOException {
+ FileStore(FileStoreBuilder builder, final boolean readOnly) throws
IOException {
this.tracker = new SegmentTracker();
this.revisions = builder.getRevisions();
this.blobStore = builder.getBlobStore();
@@ -317,47 +317,46 @@ public class FileStore implements Segmen
lock = null;
}
- // FIXME OAK-3468 Replace BackgroundThread with Scheduler
- // Externalise these background operations
- if (!readOnly) {
- flushThread = BackgroundThread.run(
- "TarMK flush thread [" + directory + "]", 5000, // 5s
interval
- new Runnable() {
- @Override
- public void run() {
- try {
- flush();
- } catch (IOException e) {
- log.warn("Failed to flush the TarMK at {}",
directory, e);
- }
- }
- });
- compactionThread = BackgroundThread.run(
- "TarMK compaction thread [" + directory + "]", -1,
- new Runnable() {
- @Override
- public void run() {
- try {
- maybeCompact(true);
- } catch (IOException e) {
- log.error("Error running compaction", e);
- }
- }
- });
+ flushOperation = new PeriodicOperation(String.format("TarMK flush
thread [%s]", directory), 5, SECONDS, new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ flush();
+ } catch (IOException e) {
+ log.warn("Failed to flush the TarMK at {}", directory, e);
+ }
+ }
- diskSpaceThread = BackgroundThread.run(
- "TarMK disk space check [" + directory + "]",
MINUTES.toMillis(1), new Runnable() {
+ });
- @Override
- public void run() {
- checkDiskSpace();
+ compactionOperation = new TriggeredOperation(String.format("TarMK
compaction thread [%s]", directory), new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ maybeCompact(true);
+ } catch (IOException e) {
+ log.error("Error running compaction", e);
}
+ }
- });
- } else {
- flushThread = null;
- compactionThread = null;
- diskSpaceThread = null;
+ });
+
+ diskSpaceOperation = new PeriodicOperation(String.format("TarMK disk
space check [%s]", directory), 1, MINUTES, new Runnable() {
+
+ @Override
+ public void run() {
+ checkDiskSpace();
+ }
+
+ });
+
+ // FIXME OAK-3468 Replace BackgroundThread with Scheduler
+ // Externalise these background operations
+ if (!readOnly) {
+ flushOperation.start();
+ diskSpaceOperation.start();
}
sufficientDiskSpace = new AtomicBoolean(true);
@@ -1078,9 +1077,37 @@ public class FileStore implements Segmen
// avoid deadlocks by closing (and joining) the background
// threads before acquiring the synchronization lock
- closeAndLogOnFail(compactionThread);
- closeAndLogOnFail(flushThread);
- closeAndLogOnFail(diskSpaceThread);
+
+ try {
+ if (compactionOperation.stop(5, SECONDS)) {
+ log.debug("The compaction background thread was successfully
shut down");
+ } else {
+ log.warn("The compaction background thread takes too long to
shutdown");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ try {
+ if (flushOperation.stop(5, SECONDS)) {
+ log.debug("The flush background thread was successfully shut
down");
+ } else {
+ log.warn("The flush background thread takes too long to
shutdown");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
+ try {
+ if (diskSpaceOperation.stop(5, SECONDS)) {
+ log.debug("The disk space check background thread was
successfully shut down");
+ } else {
+ log.warn("The disk space check background thread takes too
long to shutdown");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+
try {
flush();
revisions.close();
@@ -1305,7 +1332,7 @@ public class FileStore implements Segmen
* Trigger a garbage collection cycle
*/
public void gc() {
- compactionThread.trigger();
+ compactionOperation.trigger();
}
public Map<String, Set<UUID>> getTarReaderIndex() {
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java?rev=1750636&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java
(added)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java
Wed Jun 29 13:42:50 2016
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * A {@link ThreadFactory} that configures threads used to execute background
+ * operations.
+ */
+class OperationThreadFactory implements ThreadFactory {
+
+ private final ThreadFactory wrapped;
+
+ private final String name;
+
+ /**
+ * Create a new instance of this class wrapping another {@link
+ * ThreadFactory}.
+ *
+ * @param wrapped the instance of {@link ThreadFactory} to wrap.
+ * @param name the name to assign to the created threads.
+ */
+ public OperationThreadFactory(ThreadFactory wrapped, String name) {
+ this.wrapped = wrapped;
+ this.name = name;
+ }
+
+ @Override
+ public Thread newThread(Runnable runnable) {
+ Thread thread = wrapped.newThread(runnable);
+ thread.setName(name);
+ thread.setDaemon(true);
+ return thread;
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/OperationThreadFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java?rev=1750636&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java
(added)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java
Wed Jun 29 13:42:50 2016
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+import static java.util.concurrent.Executors.defaultThreadFactory;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A background operation that run continuously. Executions of this operation
+ * are interleaved by a user-specified period of time.
+ */
+class PeriodicOperation {
+
+ private final ScheduledExecutorService scheduler;
+
+ private final long period;
+
+ private final TimeUnit timeUnit;
+
+ private final Runnable runnable;
+
+ /**
+ * Create a new background operation that runs at a specific time rate.
+ *
+ * @param name the name of the background operation.
+ * @param period the period between successive executions.
+ * @param timeUnit the time unit of the period.
+ * @param runnable the {@code Runnable} to execute.
+ */
+ public PeriodicOperation(String name, long period, TimeUnit timeUnit,
Runnable runnable) {
+ this.scheduler = newSingleThreadScheduledExecutor(new
OperationThreadFactory(defaultThreadFactory(), name));
+ this.period = period;
+ this.timeUnit = timeUnit;
+ this.runnable = runnable;
+ }
+
+ /**
+ * Start the operation.
+ */
+ public void start() {
+ scheduler.scheduleAtFixedRate(runnable, period, period, timeUnit);
+ }
+
+ /**
+ * Stop the operation and wait for its termination.
+ *
+ * @param timeout the amount of time to wait for the termination.
+ * @param timeUnit the time unit of the wait time.
+ * @return {@code true} if the operation was stopped in time, {@code false}
+ * if stopping the operation timed out.
+ * @throws InterruptedException if interrupted while waiting.
+ */
+ public boolean stop(long timeout, TimeUnit timeUnit) throws
InterruptedException {
+ scheduler.shutdown();
+ return scheduler.awaitTermination(timeout, timeUnit);
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperation.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java?rev=1750636&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java
(added)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java
Wed Jun 29 13:42:50 2016
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import static java.util.concurrent.Executors.defaultThreadFactory;
+import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A background operation running on a different thread that is executed upon
an
+ * external trigger. Only one instance of the same operation is guaranteed to
+ * run at any time.
+ */
+class TriggeredOperation {
+
+ private final ExecutorService scheduler;
+
+ private final Runnable runnable;
+
+ private Future<?> future;
+
+ /**
+ * Create a new triggered operation.
+ *
+ * @param name the name of the operation.
+ * @param runnable the code to run when the operation is triggered.
+ */
+ public TriggeredOperation(String name, Runnable runnable) {
+ this.scheduler = newSingleThreadScheduledExecutor(new
OperationThreadFactory(defaultThreadFactory(), name));
+ this.runnable = runnable;
+ }
+
+ /**
+ * Trigger the execution of the operation. If the operation is still
+ * running, calling this method doesn't have any effect. Otherwise, a new
+ * execution of the operation is started.
+ */
+ public void trigger() {
+ synchronized (this) {
+ if (future == null || future.isDone()) {
+ future = scheduler.submit(runnable);
+ }
+ }
+ }
+
+ /**
+ * Stop the operation and wait for its termination.
+ *
+ * @param timeout the amount of time to wait.
+ * @param timeUnit the time unit of the wait time.
+ * @return {@code true} if the operation was stopped in time, {@code false}
+ * if stopping the operation timed out.
+ * @throws InterruptedException if interrupted while waiting.
+ */
+ public boolean stop(long timeout, TimeUnit timeUnit) throws
InterruptedException {
+ scheduler.shutdown();
+ return scheduler.awaitTermination(timeout, timeUnit);
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperation.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java?rev=1750636&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java
(added)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java
Wed Jun 29 13:42:50 2016
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+
+public class PeriodicOperationTest {
+
+ @Test
+ public void periodicTrigger() {
+ final CountDownLatch executions = new CountDownLatch(5);
+
+ // Define an operation to be run ever 100ms.
+
+ PeriodicOperation operation = new PeriodicOperation("test", 100,
TimeUnit.MILLISECONDS, new Runnable() {
+
+ @Override
+ public void run() {
+ executions.countDown();
+ }
+
+ });
+
+ // Start running the operation.
+
+ operation.start();
+
+ // Wait for the first 5 executions of the operation. The amount of
+ // iterations to wait for is defined by the CountDownLatch above.
+
+ try {
+ executions.await();
+ } catch (InterruptedException e) {
+ fail("operation not triggered");
+ }
+
+ // Stop the operation. This shouldn't time out.
+
+ try {
+ assertTrue(operation.stop(500, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail("unable to stop the operation");
+ }
+ }
+
+ @Test
+ public void stopTimeOut() {
+ final CountDownLatch started = new CountDownLatch(1);
+ final CountDownLatch terminate = new CountDownLatch(1);
+
+ // Define an operation to be run every 100ms.
+
+ PeriodicOperation operation = new PeriodicOperation("test", 100,
TimeUnit.MILLISECONDS, new Runnable() {
+
+ @Override
+ public void run() {
+ started.countDown();
+
+ try {
+ terminate.await();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ });
+
+ // Start running the operation periodically.
+
+ operation.start();
+
+ // Wait until the first execution of the operation begins. At this
+ // point, the operation is being waiting for this thread to try and
stop
+ // it.
+
+ try {
+ started.await();
+ } catch (InterruptedException e) {
+ fail("operation not triggered");
+ }
+
+ // Try and stop the operation. Since the operation will keep running
+ // until we say otherwise, the stop() method will time out and return
+ // false.
+
+ try {
+ assertFalse(operation.stop(500, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail("unable to stop the operation");
+ }
+
+ // Tell the operation to terminate, so the background thread can be
+ // killed.
+
+ terminate.countDown();
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/PeriodicOperationTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java?rev=1750636&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java
(added)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java
Wed Jun 29 13:42:50 2016
@@ -0,0 +1,179 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+public class TriggeredOperationTest {
+
+ @Test
+ public void trigger() {
+ final CountDownLatch triggered = new CountDownLatch(1);
+
+ // Define a triggered operation.
+
+ final TriggeredOperation operation = new TriggeredOperation("test",
new Runnable() {
+
+ @Override
+ public void run() {
+ triggered.countDown();
+ }
+
+ });
+
+ // Trigger an execution of the operation.
+
+ operation.trigger();
+
+ // Wait until the operation is actually executed.
+
+ try {
+ triggered.await();
+ } catch (InterruptedException e) {
+ fail("operation not triggered");
+ }
+
+ // Stop the background operation. This shouldn't time out.
+
+ try {
+ assertTrue(operation.stop(10, TimeUnit.SECONDS));
+ } catch (InterruptedException e) {
+ fail("unable to stop the operation");
+ }
+ }
+
+ @Test
+ public void stopTimeOut() {
+ final CountDownLatch triggered = new CountDownLatch(1);
+ final CountDownLatch terminate = new CountDownLatch(1);
+
+ // Define a triggered operation.
+
+ TriggeredOperation operation = new TriggeredOperation("test", new
Runnable() {
+
+ @Override
+ public void run() {
+ triggered.countDown();
+
+ try {
+ terminate.await();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ });
+
+ // Trigger an execution of the operation.
+
+ operation.trigger();
+
+ // Wait for the execution of the operation.
+
+ try {
+ triggered.await();
+ } catch (InterruptedException e) {
+ fail("operation not triggered");
+ }
+
+ // At this point, the operation started its execution and is waiting
for
+ // this thread to send a signal. If we try to stop the operation, we
+ // will receive a timeout.
+
+ try {
+ assertFalse(operation.stop(500, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail("unable to stop the operation");
+ }
+
+ // Signal the operation to terminate so the background thread can be
+ // killed.
+
+ terminate.countDown();
+ }
+
+ @Test
+ public void overlappingTrigger() {
+ final AtomicInteger counter = new AtomicInteger();
+ final CountDownLatch triggered = new CountDownLatch(1);
+ final CountDownLatch terminate = new CountDownLatch(1);
+
+ // Define a triggered operation.
+
+ TriggeredOperation operation = new TriggeredOperation("test", new
Runnable() {
+
+ @Override
+ public void run() {
+ triggered.countDown();
+
+ counter.incrementAndGet();
+
+ try {
+ terminate.await();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ });
+
+ // Trigger the first execution of the operation.
+
+ operation.trigger();
+
+ // Wait for the operation to start.
+
+ try {
+ triggered.await();
+ } catch (InterruptedException e) {
+ fail("operation not triggered");
+ }
+
+ // At this point the operation is running, waiting for this thread to
+ // send a termination signal. Triggering the operation will not execute
+ // a new instance of the operation.
+
+ operation.trigger();
+
+ // Send a signal to the operation to terminate its execution.
+
+ terminate.countDown();
+
+ // Stop the operation. This shouldn't time out.
+
+ try {
+ assertTrue(operation.stop(500, TimeUnit.MILLISECONDS));
+ } catch (InterruptedException e) {
+ fail("unable to stop the operation");
+ }
+
+ // Check that the operation was only executed once.
+
+ assertEquals(1, counter.get());
+ }
+
+}
Propchange:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/TriggeredOperationTest.java
------------------------------------------------------------------------------
svn:eol-style = native