Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnReadDirectory.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnReadDirectory.java (revision 1868860) +++ src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/CopyOnReadDirectory.java (working copy) @@ -263,6 +263,8 @@ } /** + * Close the files _after_ the method returns (asynchronously). + * * On close file which are not present in remote are removed from local. * CopyOnReadDir is opened at different revisions of the index state * @@ -274,8 +276,6 @@ * be ensured that any currently opened IndexSearcher does not get affected. * The way IndexSearchers get created in IndexTracker it ensures that new searcher * pinned to newer revision gets opened first and then existing ones are closed. - * - * */ @Override public void close() throws IOException { Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java (revision 1868860) +++ src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DefaultDirectoryFactory.java (working copy) @@ -66,7 +66,19 @@ // (copy from the remote directory to the local directory) // to avoid having to stream it when merging String indexPath = definition.getIndexPath(); - Directory d = indexCopier.wrapForRead(indexPath, definition, directory, dirName); + + // Here we create a new index directory, because + // re-using the existing directory (opened above) would + // mean that the directory returned by the method + // shares the same OakDirectory instance. + // That in turn could result in concurrently changing + // the NodeBuilder on close, as d.close() closes the directory + // _asynchronously_ (after the method returned). + // With newIndexDirectory, the internal OakDirectory is not shared + Directory readerDir = newIndexDirectory(definition, builder, dirName); + Directory d = indexCopier.wrapForRead(indexPath, definition, readerDir, dirName); + + // closing is done asynchronously d.close(); } directory = indexCopier.wrapForWrite(definition, directory, reindex, dirName, cowDirectoryTracker); Index: src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DirectoryFactory.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DirectoryFactory.java (revision 1868860) +++ src/main/java/org/apache/jackrabbit/oak/plugins/index/lucene/directory/DirectoryFactory.java (working copy) @@ -25,8 +25,24 @@ import org.apache.jackrabbit.oak.spi.state.NodeBuilder; import org.apache.lucene.store.Directory; +/** + * A builder for Lucene directories. + */ public interface DirectoryFactory { + /** + * Open a new directory. + * + * Internally, it read the data from the index definition. It writes to the + * builder, for example when closing the directory. + * + * @param definition the index definition + * @param builder the builder pointing to the index definition (see above + * for usage) + * @param dirName the name of the directory (in the file system) + * @param reindex whether reindex is needed + * @return the Lucene directory + */ Directory newInstance(LuceneIndexDefinition definition, NodeBuilder builder, String dirName, boolean reindex) throws IOException;