From d2b2ef8941d9faac7ed17498b9477edf619323a9 Mon Sep 17 00:00:00 2001 From: Mattias Persson Date: Wed, 18 Jan 2017 12:16:54 +0100 Subject: [PATCH] LuceneLabelScanStore gets told if it's read-only previously it was always writable, no matter what the neo4j config said. Integerestingly compliance testing tested the LuceneLabelScanStore directly and it asserted that a read-only label scan store shouldn't be able to create an initial store. When looking at the rest of the stores, they are actually created, even when read-only mode is set. Label scan store just happened to not fail when it was in read-only mode. So now lss aligns with stores in general in that they can be created even in read-only mode. --- .../checking/GraphStoreFixture.java | 2 +- .../impl/labelscan/LabelScanStoreTest.java | 10 ++++-- .../lucene/LuceneLabelScanStoreBuilder.java | 9 +++-- .../LuceneLabelScanIndexBuilder.java | 5 +++ .../impl/labelscan/LuceneLabelScanStore.java | 33 +++++++++++++++---- .../LuceneLabelScanStoreExtension.java | 16 +++++---- .../labelscan/LuceneLabelScanStoreTest.java | 7 ++-- 7 files changed, 56 insertions(+), 26 deletions(-) diff --git a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/GraphStoreFixture.java b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/GraphStoreFixture.java index 995adb0c2148c..d387ee7527683 100644 --- a/community/consistency-check/src/test/java/org/neo4j/consistency/checking/GraphStoreFixture.java +++ b/community/consistency-check/src/test/java/org/neo4j/consistency/checking/GraphStoreFixture.java @@ -188,7 +188,7 @@ public DirectStoreAccess directStoreAccess() Dependencies dependencies = new Dependencies(); dependencies.satisfyDependencies( Config.defaults(), fileSystem, new SimpleLogService( logProvider, logProvider ), indexStoreView, pageCache ); - KernelContext kernelContext = new SimpleKernelContext( fileSystem, directory, UNKNOWN, dependencies ); + KernelContext kernelContext = new SimpleKernelContext( directory, UNKNOWN, dependencies ); LabelScanStore labelScanStore = startLabelScanStore( config, dependencies, kernelContext ); directStoreAccess = new DirectStoreAccess( nativeStores, labelScanStore, createIndexes( fileSystem, config, operationalMode ) ); diff --git a/community/kernel/src/test/java/org/neo4j/kernel/api/impl/labelscan/LabelScanStoreTest.java b/community/kernel/src/test/java/org/neo4j/kernel/api/impl/labelscan/LabelScanStoreTest.java index b6f2fe95c79ef..1390fe420e44a 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/api/impl/labelscan/LabelScanStoreTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/api/impl/labelscan/LabelScanStoreTest.java @@ -20,7 +20,6 @@ package org.neo4j.kernel.api.impl.labelscan; import org.hamcrest.Matcher; -import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -123,10 +122,15 @@ public void forceShouldNotForceWriterOnReadOnlyScanStore() } @Test - public void failToStartIfLabelScanStoreIndexDoesNotExistInReadOnlyMode() + public void shouldStartIfLabelScanStoreIndexDoesNotExistInReadOnlyMode() throws IOException { - expectedException.expectCause( Matchers.instanceOf( UnsupportedOperationException.class ) ); + // WHEN start( false, true ); + + // THEN + + // no exception + assertTrue( store.isEmpty() ); } @Test diff --git a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneLabelScanStoreBuilder.java b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneLabelScanStoreBuilder.java index d756d7c9ebf48..141807b9b94cb 100644 --- a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneLabelScanStoreBuilder.java +++ b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneLabelScanStoreBuilder.java @@ -24,7 +24,6 @@ import java.util.function.Supplier; import org.neo4j.io.fs.FileSystemAbstraction; -import org.neo4j.kernel.api.impl.labelscan.LabelScanIndex; import org.neo4j.kernel.api.impl.labelscan.LuceneLabelScanIndexBuilder; import org.neo4j.kernel.api.impl.labelscan.LuceneLabelScanStore; import org.neo4j.kernel.api.labelscan.LabelScanStore; @@ -78,13 +77,13 @@ public LabelScanStore build() { // TODO: Replace with kernel extension based lookup LabelScanStore.Monitor monitor = new LoggingMonitor( logProvider.getLog( LuceneLabelScanStore.class ) ); - LabelScanIndex index = LuceneLabelScanIndexBuilder.create() + LuceneLabelScanIndexBuilder indexBuilder = LuceneLabelScanIndexBuilder.create() .withFileSystem( fileSystem ) .withIndexRootFolder( getStoreDirectory( storeDir ) ) .withConfig( config ) - .withOperationalMode( operationalMode ) - .build(); - labelScanStore = new LuceneLabelScanStore( index, new FullLabelStream( storeViewSupplier ), monitor ); + .withOperationalMode( operationalMode ); + labelScanStore = new LuceneLabelScanStore( indexBuilder, new FullLabelStream( storeViewSupplier ), + monitor ); try { diff --git a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanIndexBuilder.java b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanIndexBuilder.java index 27afde23c152e..8e317265e341a 100644 --- a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanIndexBuilder.java +++ b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanIndexBuilder.java @@ -71,4 +71,9 @@ public LabelScanIndex build() return isReadOnly() ? new ReadOnlyDatabaseLabelScanIndex( format, storageBuilder.build() ) : new WritableDatabaseLabelScanIndex( format, storageBuilder.build() ); } + + public LabelScanIndex buildWritable() + { + return new WritableDatabaseLabelScanIndex( format, storageBuilder.build() ); + } } diff --git a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStore.java b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStore.java index 07d4e039a574f..50141a12c7b1a 100644 --- a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStore.java +++ b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStore.java @@ -23,7 +23,6 @@ import java.io.File; import java.io.IOException; - import org.neo4j.graphdb.ResourceIterator; import org.neo4j.io.pagecache.IOLimiter; import org.neo4j.kernel.api.labelscan.AllEntriesLabelScanReader; @@ -36,16 +35,19 @@ public class LuceneLabelScanStore implements LabelScanStore { - private final LabelScanIndex luceneIndex; + private final LuceneLabelScanIndexBuilder indexBuilder; + private volatile LabelScanIndex luceneIndex; // We get in a full store stream here in case we need to fully rebuild the store if it's missing or corrupted. private final FullStoreChangeStream fullStoreStream; private final Monitor monitor; private boolean needsRebuild; + private boolean switchBackToReadOnly; - public LuceneLabelScanStore( LabelScanIndex luceneIndex, FullStoreChangeStream fullStoreStream, - Monitor monitor ) + public LuceneLabelScanStore( LuceneLabelScanIndexBuilder indexBuilder, + FullStoreChangeStream fullStoreStream, Monitor monitor ) { - this.luceneIndex = luceneIndex; + this.indexBuilder = indexBuilder; + this.luceneIndex = indexBuilder.build(); this.fullStoreStream = fullStoreStream; this.monitor = monitor; } @@ -94,7 +96,7 @@ public void init() throws IOException { monitor.noIndex(); - luceneIndex.create(); + create(); needsRebuild = true; } else if ( !luceneIndex.isValid() ) @@ -114,6 +116,18 @@ else if ( !luceneIndex.isValid() ) } } + private void create() throws IOException + { + if ( luceneIndex.isReadOnly() ) + { + luceneIndex.close(); + luceneIndex = indexBuilder.buildWritable(); + luceneIndex.create(); + switchBackToReadOnly = true; + // We'll switch back in start() later + } + } + @Override public void start() throws IOException { @@ -125,6 +139,13 @@ public void start() throws IOException monitor.rebuilt( numberOfNodes ); needsRebuild = false; } + + if ( switchBackToReadOnly ) + { + luceneIndex.close(); + luceneIndex = indexBuilder.build(); + luceneIndex.open(); + } } @Override diff --git a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreExtension.java b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreExtension.java index c29cdd5d5701f..dc527708c9eab 100644 --- a/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreExtension.java +++ b/community/lucene-index/src/main/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreExtension.java @@ -80,25 +80,27 @@ public LuceneLabelScanStoreExtension() @Override public LabelScanStoreProvider newInstance( KernelContext context, Dependencies dependencies ) throws Throwable { - boolean ephemeral = dependencies.getConfig().get( GraphDatabaseFacadeFactory.Configuration.ephemeral ); - DirectoryFactory directoryFactory = directoryFactory( ephemeral, dependencies.fileSystem() ); + Config config = dependencies.getConfig(); + boolean ephemeral = config.get( GraphDatabaseFacadeFactory.Configuration.ephemeral ); + FileSystemAbstraction fileSystem = dependencies.fileSystem(); + DirectoryFactory directoryFactory = directoryFactory( ephemeral, fileSystem ); - LabelScanIndex index = getLuceneIndex( context, directoryFactory, dependencies.fileSystem() ); + LuceneLabelScanIndexBuilder indexBuilder = getIndexBuilder( context, directoryFactory, fileSystem, config ); LogProvider logger = dependencies.getLogService().getInternalLogProvider(); Monitor loggingMonitor = new LoggingMonitor( logger.getLog( LuceneLabelScanStore.class ), monitor ); - LuceneLabelScanStore scanStore = new LuceneLabelScanStore( index, + LuceneLabelScanStore scanStore = new LuceneLabelScanStore( indexBuilder, new FullLabelStream( dependencies.indexStoreView() ), loggingMonitor ); return new LabelScanStoreProvider( LABEL_SCAN_STORE_NAME, scanStore, priority ); } - private LabelScanIndex getLuceneIndex( KernelContext context, DirectoryFactory directoryFactory, - FileSystemAbstraction fileSystem ) + private LuceneLabelScanIndexBuilder getIndexBuilder( KernelContext context, DirectoryFactory directoryFactory, + FileSystemAbstraction fileSystem, Config config ) { return LuceneLabelScanIndexBuilder.create() .withDirectoryFactory( directoryFactory ) .withFileSystem( fileSystem ) .withIndexRootFolder( LabelScanStoreProvider.getStoreDirectory( context.storeDir() ) ) - .build(); + .withConfig( config ); } } diff --git a/community/lucene-index/src/test/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreTest.java b/community/lucene-index/src/test/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreTest.java index 049db273b1337..47ca0c119fec4 100644 --- a/community/lucene-index/src/test/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreTest.java +++ b/community/lucene-index/src/test/java/org/neo4j/kernel/api/impl/labelscan/LuceneLabelScanStoreTest.java @@ -68,15 +68,14 @@ protected LabelScanStore createLabelScanStore( FileSystemAbstraction fs, File ro Config config = Config.defaults().with( MapUtil.stringMap( GraphDatabaseSettings.read_only.name(), String.valueOf( readOnly ) ) ); - LabelScanIndex index = LuceneLabelScanIndexBuilder.create() + LuceneLabelScanIndexBuilder indexBuilder = LuceneLabelScanIndexBuilder.create() .withDirectoryFactory( directoryFactory ) .withIndexStorage( indexStorage ) .withOperationalMode( OperationalMode.single ) .withConfig( config ) - .withDocumentFormat( documentFormat ) - .build(); + .withDocumentFormat( documentFormat ); - return new LuceneLabelScanStore( index, asStream( existingData ), monitor ); + return new LuceneLabelScanStore( indexBuilder, asStream( existingData ), monitor ); } @Override