Author: catholicon
Date: Mon Apr 22 07:46:29 2019
New Revision: 1857937
URL: http://svn.apache.org/viewvc?rev=1857937&view=rev
Log:
OAK-7065: Remove orphan file from local directory in case indexing fails
Test to assert that local directory created due to reindexing get
cleaned up if indexing cycle fails
Added:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java
(with props)
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopier.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnWriteDirectory.java
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierCleanupTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneWritesOnSegmentStatsTest.java
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopier.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopier.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopier.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopier.java
Mon Apr 22 07:46:29 2019
@@ -56,6 +56,7 @@ import org.apache.lucene.store.Directory
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.FilterDirectory;
import org.apache.lucene.store.NoLockFactory;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -124,11 +125,17 @@ public class IndexCopier implements Copy
return new CopyOnReadDirectory(this, remote, local, prefetchEnabled,
indexPath, executor);
}
- public Directory wrapForWrite(LuceneIndexDefinition definition, Directory
remote, boolean reindexMode, String dirName) throws IOException {
- Directory local = createLocalDirForIndexWriter(definition, dirName);
+ public Directory wrapForWrite(LuceneIndexDefinition definition, Directory
remote,
+ boolean reindexMode, String dirName,
+ COWDirecetoryTracker cowDirecetoryTracker)
throws IOException {
+ Directory local = createLocalDirForIndexWriter(definition, dirName,
reindexMode, cowDirecetoryTracker);
String indexPath = definition.getIndexPath();
checkIntegrity(indexPath, local, remote);
- return new CopyOnWriteDirectory(this, remote, local, reindexMode,
indexPath, executor);
+
+ CopyOnWriteDirectory cowDirectory = new CopyOnWriteDirectory(this,
remote, local, reindexMode, indexPath, executor);
+ cowDirecetoryTracker.registerOpenedDirectory(cowDirectory);
+
+ return cowDirectory;
}
@Override
@@ -148,10 +155,16 @@ public class IndexCopier implements Copy
return indexRootDirectory;
}
- protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName) throws IOException {
+ protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName,
+ boolean reindexMode,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
String indexPath = definition.getIndexPath();
File indexWriterDir = getIndexDir(definition, indexPath, dirName);
+ if (reindexMode) {
+
cowDirecetoryTracker.registerReindexingLocalDirectory(indexWriterDir);
+ }
+
//By design indexing in Oak is single threaded so Lucene locking
//can be disabled
Directory dir = FSDirectory.open(indexWriterDir,
NoLockFactory.getNoLockFactory());
@@ -637,4 +650,17 @@ public class IndexCopier implements Copy
}
}
}
+
+ public interface COWDirecetoryTracker {
+ void registerOpenedDirectory(@NotNull CopyOnWriteDirectory directory);
+ void registerReindexingLocalDirectory(@NotNull File dir);
+
+ COWDirecetoryTracker NOOP = new COWDirecetoryTracker() {
+ @Override
+ public void registerOpenedDirectory(CopyOnWriteDirectory
directory) {}
+
+ @Override
+ public void registerReindexingLocalDirectory(File dir) {}
+ };
+ }
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProvider.java
Mon Apr 22 07:46:29 2019
@@ -16,11 +16,15 @@
*/
package org.apache.jackrabbit.oak.plugins.index.lucene;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.FileUtils;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.plugins.index.*;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier.COWDirecetoryTracker;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory.ActiveDeletedBlobCollector;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory.BlobDeletionCallback;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.CopyOnWriteDirectory;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.DefaultDirectoryFactory;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.DirectoryFactory;
import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.IndexingQueue;
@@ -50,8 +54,10 @@ import org.jetbrains.annotations.Nullabl
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
import java.util.Collection;
import java.util.LinkedList;
+import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -213,7 +219,12 @@ public class LuceneIndexEditorProvider i
}
if (writerFactory == null) {
- writerFactory = new
DefaultIndexWriterFactory(mountInfoProvider,
newDirectoryFactory(blobDeletionCallback), writerConfig);
+ COWDirectoryCleanupCallback cowDirectoryCleanupCallback = new
COWDirectoryCleanupCallback();
+
indexingContext.registerIndexCommitCallback(cowDirectoryCleanupCallback);
+
+ writerFactory = new
DefaultIndexWriterFactory(mountInfoProvider,
+ newDirectoryFactory(blobDeletionCallback,
cowDirectoryCleanupCallback),
+ writerConfig);
}
LuceneIndexEditorContext context = new
LuceneIndexEditorContext(root, definition, indexDefinition, callback,
@@ -251,8 +262,9 @@ public class LuceneIndexEditorProvider i
this.inMemoryDocsLimit = inMemoryDocsLimit;
}
- protected DirectoryFactory newDirectoryFactory(BlobDeletionCallback
blobDeletionCallback) {
- return new DefaultDirectoryFactory(indexCopier, blobStore,
blobDeletionCallback);
+ protected DirectoryFactory newDirectoryFactory(BlobDeletionCallback
blobDeletionCallback,
+ COWDirecetoryTracker
cowDirectoryTracker) {
+ return new DefaultDirectoryFactory(indexCopier, blobStore,
blobDeletionCallback, cowDirectoryTracker);
}
private LuceneDocumentHolder getDocumentHolder(CommitContext
commitContext){
@@ -288,4 +300,42 @@ public class LuceneIndexEditorProvider i
private static CommitContext getCommitContext(IndexingContext
indexingContext) {
return (CommitContext)
indexingContext.getCommitInfo().getInfo().get(CommitContext.NAME);
}
+
+ private static class COWDirectoryCleanupCallback implements
IndexCommitCallback, COWDirecetoryTracker {
+ private static final Logger LOG =
LoggerFactory.getLogger(COWDirectoryCleanupCallback.class);
+
+ private List<CopyOnWriteDirectory> openedCoWDirectories =
Lists.newArrayList();
+ private List<File> reindexingLocalDirectories = Lists.newArrayList();
+
+
+ @Override
+ public void commitProgress(IndexProgress indexProgress) {
+ // we only worry about failed indexing
+ if (indexProgress == IndexProgress.COMMIT_FAILED) {
+ for (CopyOnWriteDirectory d : openedCoWDirectories) {
+ try {
+ d.close();
+ } catch (Exception e) {
+ LOG.warn("Error occurred while closing {}", d, e);
+ }
+ }
+
+ for (File f : reindexingLocalDirectories) {
+ if ( ! FileUtils.deleteQuietly(f)) {
+ LOG.warn("Failed to delete {}", f);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void registerOpenedDirectory(@NotNull CopyOnWriteDirectory
directory) {
+ openedCoWDirectories.add(directory);
+ }
+
+ @Override
+ public void registerReindexingLocalDirectory(@NotNull File dir) {
+ reindexingLocalDirectories.add(dir);
+ }
+ }
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnWriteDirectory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnWriteDirectory.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnWriteDirectory.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnWriteDirectory.java
Mon Apr 22 07:46:29 2019
@@ -79,6 +79,7 @@ public class CopyOnWriteDirectory extend
private final CountDownLatch copyDone = new CountDownLatch(1);
private final boolean reindexMode;
private final String indexPath;
+ private boolean closed;
/**
* Current background task
@@ -203,8 +204,16 @@ public class CopyOnWriteDirectory extend
return ref.openInput(context);
}
+ public boolean isClosed() {
+ return closed;
+ }
+
@Override
public void close() throws IOException {
+ if (isClosed()) {
+ return;
+ }
+
int pendingCopies = queue.size();
addTask(STOP);
@@ -257,6 +266,8 @@ public class CopyOnWriteDirectory extend
local.close();
remote.close();
+
+ closed = true;
}
@Override
Modified:
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java
Mon Apr 22 07:46:29 2019
@@ -22,7 +22,9 @@ package org.apache.jackrabbit.oak.plugin
import java.io.File;
import java.io.IOException;
+import org.apache.jackrabbit.oak.plugins.index.IndexCommitCallback;
import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier.COWDirecetoryTracker;
import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.ActiveDeletedBlobCollectorFactory.BlobDeletionCallback;
import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
@@ -41,15 +43,18 @@ public class DefaultDirectoryFactory imp
private final IndexCopier indexCopier;
private final GarbageCollectableBlobStore blobStore;
private final BlobDeletionCallback blobDeletionCallback;
+ private final COWDirecetoryTracker cowDirecetoryTracker;
public DefaultDirectoryFactory(@Nullable IndexCopier indexCopier,
@Nullable GarbageCollectableBlobStore blobStore) {
- this(indexCopier, blobStore, BlobDeletionCallback.NOOP);
+ this(indexCopier, blobStore, BlobDeletionCallback.NOOP,
COWDirecetoryTracker.NOOP);
}
public DefaultDirectoryFactory(@Nullable IndexCopier indexCopier,
@Nullable GarbageCollectableBlobStore blobStore,
- @NotNull
ActiveDeletedBlobCollectorFactory.BlobDeletionCallback blobDeletionCallback) {
+ @NotNull
ActiveDeletedBlobCollectorFactory.BlobDeletionCallback blobDeletionCallback,
+ @NotNull COWDirecetoryTracker
cowDirectoryTracker) {
this.indexCopier = indexCopier;
this.blobStore = blobStore;
this.blobDeletionCallback = blobDeletionCallback;
+ this.cowDirecetoryTracker = cowDirectoryTracker;
}
@Override
@@ -65,7 +70,7 @@ public class DefaultDirectoryFactory imp
Directory d = indexCopier.wrapForRead(indexPath, definition,
directory, dirName);
d.close();
}
- directory = indexCopier.wrapForWrite(definition, directory,
reindex, dirName);
+ directory = indexCopier.wrapForWrite(definition, directory,
reindex, dirName, cowDirecetoryTracker);
}
return directory;
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierCleanupTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierCleanupTest.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierCleanupTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierCleanupTest.java
Mon Apr 22 07:46:29 2019
@@ -474,7 +474,9 @@ public class IndexCopierCleanupTest {
}
@Override
- protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName) throws IOException {
+ protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName,
+ boolean reindexMode,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
return new DelayCopyingSimpleFSDirectory(baseFSDir);
}
@@ -487,7 +489,7 @@ public class IndexCopierCleanupTest {
}
Directory getCoWDir() throws IOException {
- return wrapForWrite(defn, remote, false, INDEX_DATA_CHILD_NAME);
+ return wrapForWrite(defn, remote, false, INDEX_DATA_CHILD_NAME,
COWDirecetoryTracker.NOOP);
}
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierTest.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/IndexCopierTest.java
Mon Apr 22 07:46:29 2019
@@ -595,7 +595,8 @@ public class IndexCopierTest {
IndexCopier copier = new IndexCopier(sameThreadExecutor(),
getWorkDir());
LuceneIndexDefinition defn = new LuceneIndexDefinition(root,
builder.getNodeState(), "/foo");
- Directory dir = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ Directory dir = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
byte[] t1 = writeFile(dir, "t1");
@@ -613,7 +614,8 @@ public class IndexCopierTest {
IndexCopier copier = new IndexCopier(sameThreadExecutor(),
getWorkDir());
LuceneIndexDefinition defn = new LuceneIndexDefinition(root,
builder.getNodeState(), "/foo");
- Directory dir = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ Directory dir = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
byte[] t1 = writeFile(dir, "t1");
@@ -642,7 +644,8 @@ public class IndexCopierTest {
//State of remote directory should set before wrapping as later
//additions would not be picked up given COW assume remote directory
//to be read only
- Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
assertEquals(newHashSet("t1"), newHashSet(local.listAll()));
assertEquals(t1.length, local.fileLength("t1"));
@@ -699,7 +702,8 @@ public class IndexCopierTest {
Directory remote = new CloseSafeDir();
byte[] t1 = writeFile(remote, "t1");
byte[] t2 = writeFile(remote, "t2");
- Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
assertEquals(newHashSet("t1", "t2"), newHashSet(local.listAll()));
byte[] t3 = writeFile(local, "t3");
@@ -749,7 +753,8 @@ public class IndexCopierTest {
}
};
byte[] t1 = writeFile(remote, "t1");
- Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
//Read should be served from remote
readRemotes.clear();readLocal.clear();
@@ -779,7 +784,8 @@ public class IndexCopierTest {
Directory remote = new CloseSafeDir();
- final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
byte[] t1 = writeFile(local, "t1");
assertTrue(local.fileExists("t1"));
@@ -841,7 +847,8 @@ public class IndexCopierTest {
Directory remote = new CloseSafeDir();
- final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
byte[] t1 = writeFile(local, "t1");
assertTrue(local.fileExists("t1"));
@@ -909,7 +916,8 @@ public class IndexCopierTest {
}
};
- final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
toFail.add("t2");
byte[] t1 = writeFile(local, "t1");
byte[] t2 = writeFile(local, "t2");
@@ -947,7 +955,8 @@ public class IndexCopierTest {
}
};
- final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME);
+ final Directory local = copier.wrapForWrite(defn, remote, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
toPause.add("t2");
byte[] t1 = writeFile(local, "t1");
byte[] t2 = writeFile(local, "t2");
@@ -1018,7 +1027,8 @@ public class IndexCopierTest {
};
//Start copying a file to remote via COW
- Directory cow1 = copier.wrapForWrite(defn, remote2, false,
INDEX_DATA_CHILD_NAME);
+ Directory cow1 = copier.wrapForWrite(defn, remote2, false,
INDEX_DATA_CHILD_NAME,
+ IndexCopier.COWDirecetoryTracker.NOOP);
byte[] f2 = writeFile(cow1, "f2");
//Before copy is done to remote lets delete f1 from remote and
@@ -1145,7 +1155,9 @@ public class IndexCopierTest {
}
@Override
- protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName) throws IOException {
+ protected Directory createLocalDirForIndexWriter(LuceneIndexDefinition
definition, String dirName,
+ boolean reindexMode,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
return baseDir;
}
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
Mon Apr 22 07:46:29 2019
@@ -215,8 +215,9 @@ public class LucenePropertyIndexTest ext
@Override
public Directory wrapForWrite(LuceneIndexDefinition definition,
- Directory remote, boolean
reindexMode, String dirName) throws IOException {
- Directory ret = super.wrapForWrite(definition, remote,
reindexMode, dirName);
+ Directory remote, boolean
reindexMode, String dirName,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
+ Directory ret = super.wrapForWrite(definition, remote,
reindexMode, dirName, cowDirecetoryTracker);
cowDir = getFSDirPath(ret);
return ret;
}
Modified:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneWritesOnSegmentStatsTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneWritesOnSegmentStatsTest.java?rev=1857937&r1=1857936&r2=1857937&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneWritesOnSegmentStatsTest.java
(original)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneWritesOnSegmentStatsTest.java
Mon Apr 22 07:46:29 2019
@@ -235,8 +235,9 @@ public class LuceneWritesOnSegmentStatsT
@Override
public Directory wrapForWrite(LuceneIndexDefinition definition,
- Directory remote, boolean
reindexMode, String dirName) throws IOException {
- Directory ret = super.wrapForWrite(definition, remote,
reindexMode, dirName);
+ Directory remote, boolean
reindexMode, String dirName,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
+ Directory ret = super.wrapForWrite(definition, remote,
reindexMode, dirName, cowDirecetoryTracker);
cowDir = getFSDirPath(ret);
return ret;
}
Added:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java?rev=1857937&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java
(added)
+++
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java
Mon Apr 22 07:46:29 2019
@@ -0,0 +1,406 @@
+/*
+ * 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.plugins.index.lucene.writer;
+
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.io.Closer;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexUpdate;
+import org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import
org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.directory.CopyOnWriteDirectory;
+import
org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.commit.*;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.lucene.store.Directory;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static
org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INDEX_DATA_CHILD_NAME;
+import static org.junit.Assert.*;
+
+public class FailedIndexUpdateTest {
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder(new
File("target"));
+
+ private Closer closer;
+
+ private Root root;
+ private AsyncIndexUpdate asyncIndexUpdate;
+ private LocalDirectoryTrackingIndexCopier copier;
+ private FailOnDemandValidatorProvider failOnDemandValidatorProvider;
+
+ private static final String TEST_CONTENT_PATH = "/test";
+
+ @Before
+ public void setup() throws Exception {
+ closer = Closer.create();
+ createRepository();
+ }
+
+ private void createRepository() throws IOException {
+ ExecutorService executorService = Executors.newFixedThreadPool(2);
+ closer.register(new ExecutorCloser(executorService));
+ copier = new LocalDirectoryTrackingIndexCopier(executorService,
temporaryFolder.getRoot());
+ FailIfDefinedEditorProvider luceneEditorProvider = new
FailIfDefinedEditorProvider(copier);
+
+ IndexEditorProvider editorProvider = new
CompositeIndexEditorProvider(new NodeCounterEditorProvider(),
luceneEditorProvider);
+
+ NodeStore store = new MemoryNodeStore(INITIAL_CONTENT);
+
+ Oak oak = new Oak(store)
+ .with(new OpenSecurityProvider())
+ ;
+ root = oak.createRoot();
+
+ failOnDemandValidatorProvider = new FailOnDemandValidatorProvider();
+ asyncIndexUpdate = new AsyncIndexUpdate("async", store,
editorProvider);
+
asyncIndexUpdate.setValidatorProviders(Collections.singletonList(failOnDemandValidatorProvider));
+ }
+
+ @After
+ public void after() throws IOException {
+ closer.close();
+ }
+
+ @Test
+ public void workingReindexDirCleanUpOnFailureOfOtherIndex() throws
Exception {
+ createIndex("fails", "foo", true);
+ asyncIndexUpdate.run();
+ assertFalse("Indexing mustn't be failing",
asyncIndexUpdate.isFailing());
+ copier.clearStats();
+
+ createIndex("reindexing", "foo", false);
+
+ root.getTree("/").addChild("test")
+ .addChild("a").setProperty("foo", "bar");
+ root.commit();
+
+ asyncIndexUpdate.run();
+ assertTrue("Indexing must fail", asyncIndexUpdate.isFailing());
+
+ Set<File> reindexingDirPaths = copier.getReindexingDirPaths();
+ assertEquals(1, reindexingDirPaths.size());
+
+ File reindexingDir = reindexingDirPaths.iterator().next();
+ assertFalse("Reindexing directories must get cleaned up on failure",
reindexingDir.exists());
+
+ copier.getDirs().forEach((key, value) -> assertTrue("Writer for " +
key + " must be closed", value.isClosed()));
+ }
+
+ @Test
+ public void workingReindexDirCleanUpOnFailureOfMerge() throws Exception {
+ failOnDemandValidatorProvider.shouldFail = true;
+
+ createIndex("reindexing", "foo", false);
+
+ root.getTree("/").addChild("test")
+ .addChild("a").setProperty("foo", "bar");
+ root.commit();
+
+ asyncIndexUpdate.run();
+ assertTrue("Indexing must fail", asyncIndexUpdate.isFailing());
+
+ Set<File> reindexingDirPaths = copier.getReindexingDirPaths();
+ assertEquals(1, reindexingDirPaths.size());
+
+ File reindexingDir = reindexingDirPaths.iterator().next();
+ assertFalse("Reindexing directories must get cleaned up on failure",
reindexingDir.exists());
+
+ copier.getDirs().forEach((key, value) -> assertTrue("Writer for " +
key + " must be closed", value.isClosed()));
+ }
+
+ @Test
+ public void workingIndexDirDoesNotCleanUpOnFailureOfOtherIndex() throws
Exception {
+ createIndex("fails", "foo", true);
+ createIndex("working", "foo", false);
+ asyncIndexUpdate.run();
+
+ assertFalse("Indexing mustn't be failing",
asyncIndexUpdate.isFailing());
+
+ copier.clearStats();
+
+ root.getTree("/").addChild("test")
+ .addChild("a").setProperty("foo", "bar");
+ root.commit();
+
+ asyncIndexUpdate.run();
+ assertTrue("Indexing must fail", asyncIndexUpdate.isFailing());
+
+ Set<File> reindexingDirPaths = copier.getReindexingDirPaths();
+ assertEquals("No directories are reindexing", 0,
reindexingDirPaths.size());
+
+ assertEquals("Number of open directories aren't as expected", 2,
copier.getDirPaths().size());
+
+ copier.getDirPaths().forEach((key, value) -> assertTrue(key + " must
not get cleaned up on failure", value.exists()));
+
+ copier.getDirs().forEach((key, value) -> assertTrue("Writer for " +
key + " must be closed", value.isClosed()));
+ }
+
+ @Test
+ public void workingIndexDirDoesNotCleanUpOnFailureOfMerge() throws
Exception {
+ createIndex("working", "foo", false);
+ asyncIndexUpdate.run();
+ assertFalse("Indexing mustn't be failing",
asyncIndexUpdate.isFailing());
+ copier.clearStats();
+
+ failOnDemandValidatorProvider.shouldFail = true;
+
+ root.getTree("/").addChild("test")
+ .addChild("a").setProperty("foo", "bar");
+ root.commit();
+
+ asyncIndexUpdate.run();
+ assertTrue("Indexing must fail", asyncIndexUpdate.isFailing());
+
+
+ Set<File> reindexingDirPaths = copier.getReindexingDirPaths();
+ assertEquals("No directories are reindexing.", 0,
reindexingDirPaths.size());
+
+ assertEquals("Number of open directories aren't as expected", 1,
copier.getDirPaths().size());
+
+ copier.getDirPaths().forEach((key, value) -> assertTrue(key + " must
not get cleaned up on failure", value.exists()));
+
+ copier.getDirs().forEach((key, value) -> assertTrue("Writer for " +
key + " must be closed", value.isClosed()));
+ }
+
+ private void createIndex(String idxName, String propName, boolean
shouldFail) throws CommitFailedException {
+ IndexDefinitionBuilder idxBuilder = new IndexDefinitionBuilder();
+
+ idxBuilder
+ .includedPaths(TEST_CONTENT_PATH)
+ .indexRule("nt:base")
+ .property(propName).propertyIndex();
+ Tree idx =
idxBuilder.build(root.getTree("/oak:index").addChild(idxName));
+ idx.setProperty("shouldFail", shouldFail);
+
+ root.commit();
+ }
+
+ static class LocalDirectoryTrackingIndexCopier extends IndexCopier {
+
+ private final Map<String, CopyOnWriteDirectory> dirs =
Maps.newHashMap();
+ private final Map<String, File> dirPaths = Maps.newHashMap();
+ private final Set<File> reindexingDirPaths = Sets.newHashSet();
+
+ LocalDirectoryTrackingIndexCopier(Executor executor, File
indexRootDir) throws IOException {
+ super(executor, indexRootDir);
+ }
+
+ @Override
+ public Directory wrapForWrite(LuceneIndexDefinition definition,
+ Directory remote,
+ boolean reindexMode,
String dirName,
+ COWDirecetoryTracker
cowDirecetoryTracker) throws IOException {
+ CopyOnWriteDirectory dir = (CopyOnWriteDirectory)
+ super.wrapForWrite(definition, remote, reindexMode,
dirName, cowDirecetoryTracker);
+
+ String indexPath = definition.getIndexPath();
+ dirs.put(indexPath, dir);
+ File dirPath = getIndexDir(definition, indexPath, dirName);
+ dirPaths.put(indexPath, dirPath);
+ if (reindexMode) {
+ reindexingDirPaths.add(dirPath);
+ }
+
+ return dir;
+ }
+
+ void clearStats() {
+ dirs.clear();
+ dirPaths.clear();
+ reindexingDirPaths.clear();
+ }
+
+ Map<String, CopyOnWriteDirectory> getDirs() {
+ return dirs;
+ }
+
+ Map<String, File> getDirPaths() {
+ return dirPaths;
+ }
+
+ Set<File> getReindexingDirPaths() {
+ return reindexingDirPaths;
+ }
+ }
+
+ private static class FailIfDefinedEditorProvider extends
LuceneIndexEditorProvider {
+ FailIfDefinedEditorProvider(IndexCopier copier) {
+ super(copier);
+ }
+
+ @Override
+ public Editor getIndexEditor(@NotNull String type, @NotNull
NodeBuilder definition,
+ @NotNull NodeState root,
+ @NotNull IndexUpdateCallback callback)
throws CommitFailedException {
+ Editor editor = super.getIndexEditor(type, definition, root,
callback);
+ if (definition.getBoolean("shouldFail")) {
+ editor = new FailOnLeavePathEditor(editor, TEST_CONTENT_PATH);
+ }
+ return editor;
+ }
+ }
+
+ private static class FailOnLeavePathEditor implements Editor {
+ private final Editor delegate;
+ private final String failingPath;
+ final String currPath;
+
+ FailOnLeavePathEditor(Editor delegate, String failingPath) {
+ this(delegate, failingPath, "", "");
+ }
+
+ private FailOnLeavePathEditor(Editor delegate, String failingPath,
String parentPath, String name) {
+ this.delegate = delegate != null ? delegate : new DefaultEditor();
+ this.failingPath = failingPath;
+ this.currPath = ("/".equals(parentPath) ? parentPath : parentPath
+ "/") + name;
+ }
+
+ @Override
+ public void enter(NodeState before, NodeState after) throws
CommitFailedException {
+ delegate.enter(before, after);
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) throws
CommitFailedException {
+ delegate.leave(before, after); // delegate call before failing
+
+ if (failingPath.equals(currPath)) {
+ throw new CommitFailedException("index-fail", 1, null);
+ }
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after) throws
CommitFailedException {
+ delegate.propertyAdded(after);
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after)
throws CommitFailedException {
+ delegate.propertyChanged(before, after);
+ }
+
+ @Override
+ public void propertyDeleted(PropertyState before) throws
CommitFailedException {
+ delegate.propertyDeleted(before);
+ }
+
+ @Override
+ @Nullable
+ public Editor childNodeAdded(String name, NodeState after) throws
CommitFailedException {
+ return new FailOnLeavePathEditor(delegate.childNodeAdded(name,
after), failingPath, currPath, name);
+ }
+
+ @Override
+ @Nullable
+ public Editor childNodeChanged(String name, NodeState before,
NodeState after) throws CommitFailedException {
+ return new FailOnLeavePathEditor(delegate.childNodeChanged(name,
before, after), failingPath, currPath, name);
+ }
+
+ @Override
+ @Nullable
+ public Editor childNodeDeleted(String name, NodeState before) throws
CommitFailedException {
+ return new FailOnLeavePathEditor(delegate.childNodeDeleted(name,
before), failingPath, currPath, name);
+ }
+ }
+
+ static class FailOnDemandValidatorProvider extends ValidatorProvider {
+
+ boolean shouldFail;
+ static final String FAILING_PATH_FRAGMENT = INDEX_DATA_CHILD_NAME;
+
+ @Override
+ protected @Nullable Validator getRootValidator(NodeState before,
NodeState after, CommitInfo info) {
+ return new FailOnDemandValidator(new DefaultValidator());
+ }
+
+ class FailOnDemandValidator extends FailOnLeavePathEditor implements
Validator {
+ final Validator delegate;
+
+ FailOnDemandValidator(Validator delegate) {
+ super(delegate, "");
+ this.delegate = delegate;
+ }
+
+ private FailOnDemandValidator(Validator delegate, String
parentPath, String name) {
+ super(delegate, "", parentPath, name);
+ this.delegate = delegate != null ? delegate : new
DefaultValidator();
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after) throws
CommitFailedException {
+ super.leave(before, after);
+
+ if (shouldFail && currPath.contains(FAILING_PATH_FRAGMENT)) {
+ throw new CommitFailedException("validator-fail", 1, null);
+ }
+ }
+
+ @Override
+ @Nullable
+ public Validator childNodeAdded(String name, NodeState after)
throws CommitFailedException {
+ return new FailOnDemandValidator(delegate.childNodeAdded(name,
after), currPath, name);
+ }
+
+ @Override
+ @Nullable
+ public Validator childNodeChanged(String name, NodeState before,
NodeState after) throws CommitFailedException {
+ return new
FailOnDemandValidator(delegate.childNodeChanged(name, before, after), currPath,
name);
+ }
+
+ @Override
+ @Nullable
+ public Validator childNodeDeleted(String name, NodeState before)
throws CommitFailedException {
+ return new
FailOnDemandValidator(delegate.childNodeDeleted(name, before), currPath, name);
+ }
+ }
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/writer/FailedIndexUpdateTest.java
------------------------------------------------------------------------------
svn:eol-style = native