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 md...@apache.org on 2016/08/22 16:01:44 UTC

svn commit: r1757217 - in /jackrabbit/oak/branches/1.2/oak-core/src: main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java

Author: mduerig
Date: Mon Aug 22 16:01:44 2016
New Revision: 1757217

URL: http://svn.apache.org/viewvc?rev=1757217&view=rev
Log:
OAK-4675: SNFE thrown while testing FileStore.cleanup() running concurrently with writes (fix for oak-segment)
* Synchronise FileAccess.Random.length as RandomAccessFile.length() is not thread safe
* Test case

Modified:
    jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java
    jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java

Modified: jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java?rev=1757217&r1=1757216&r2=1757217&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileAccess.java Mon Aug 22 16:01:44 2016
@@ -92,7 +92,7 @@ abstract class FileAccess {
         }
 
         @Override
-        public int length() throws IOException {
+        public synchronized int length() throws IOException {
             long length = file.length();
             checkState(length < Integer.MAX_VALUE);
             return (int) length;

Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java?rev=1757217&r1=1757216&r2=1757217&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/CompactionAndCleanupTest.java Mon Aug 22 16:01:44 2016
@@ -20,6 +20,8 @@
 package org.apache.jackrabbit.oak.plugins.segment;
 
 import static com.google.common.collect.Lists.newArrayList;
+import static java.util.concurrent.Executors.newFixedThreadPool;
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
 import static org.apache.commons.io.FileUtils.deleteDirectory;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
@@ -28,6 +30,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CleanupType.CLEAN_OLD;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -40,7 +43,10 @@ import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.annotation.Nonnull;
@@ -50,6 +56,7 @@ import org.apache.jackrabbit.oak.api.Blo
 import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.blob.ReferenceCollector;
 import org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy;
 import org.apache.jackrabbit.oak.plugins.segment.file.FileStore;
 import org.apache.jackrabbit.oak.plugins.segment.file.NonCachingFileStore;
@@ -356,4 +363,78 @@ public class CompactionAndCleanupTest {
             builder.setProperty(UUID.randomUUID().toString(), UUID.randomUUID().toString());
         }
     }
+
+    @Test
+    public void randomAccessFileConcurrentReadAndLength() throws Exception {
+        final FileStore fileStore = FileStore.newFileStore(directory)
+                .withMaxFileSize(1)
+                .withMemoryMapping(false)
+                .create();
+
+        final SegmentNodeStore nodeStore = new SegmentNodeStore(fileStore);
+        fileStore.setCompactionStrategy(new CompactionStrategy(false, false, CLEAN_NONE, 0, (byte) 0) {
+            @Override
+            public boolean compacted(@Nonnull Callable<Boolean> setHead)
+            throws Exception {
+                return nodeStore.locked(setHead);
+            }
+        });
+
+        ExecutorService executorService = newFixedThreadPool(300);
+        final AtomicInteger counter = new AtomicInteger();
+        final ReferenceCollector dummyCollector = new ReferenceCollector() {
+
+            @Override
+            public void addReference(String reference, String nodeId) {
+                // do nothing
+            }
+        };
+
+        try {
+            Callable<Void> concurrentWriteTask = new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    NodeBuilder builder = nodeStore.getRoot().builder();
+                    builder.setProperty("blob-" + counter.getAndIncrement(), createBlob(nodeStore, 25 * 25));
+                    nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+                    fileStore.flush();
+                    return null;
+                }
+            };
+
+            Callable<Void> concurrentCleanupTask = new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    fileStore.cleanup();
+                    return null;
+                }
+            };
+
+            Callable<Void> concurrentReferenceCollector = new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    fileStore.getTracker().collectBlobReferences(dummyCollector);
+                    return null;
+                }
+            };
+
+            List<Future<?>> results = newArrayList();
+            results.add(executorService.submit(concurrentCleanupTask));
+
+            for (int i = 0; i < 100; i++) {
+                results.add(executorService.submit(concurrentWriteTask));
+                results.add(executorService.submit(concurrentReferenceCollector));
+            }
+
+            for (Future<?> result : results) {
+                assertNull(result.get());
+            }
+
+        } finally {
+            executorService.shutdown();
+            executorService.awaitTermination(10, SECONDS);
+            fileStore.close();
+        }
+    }
+
 }