diff --git a/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSource.java b/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSource.java index b791d224d9b45..ef5265850cd60 100644 --- a/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSource.java +++ b/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSource.java @@ -59,6 +59,7 @@ import org.neo4j.io.fs.FileUtils; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.index.IndexEntityType; import org.neo4j.kernel.lifecycle.LifecycleAdapter; @@ -100,6 +101,7 @@ public String toString() private final File storeDir; private final Config config; private final FileSystemAbstraction fileSystemAbstraction; + private final OperationalMode operationalMode; private IndexClockCache indexSearchers; private File baseStorePath; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); @@ -113,13 +115,15 @@ public String toString() /** * Constructs this data source. */ - public LuceneDataSource( File storeDir, Config config, IndexConfigStore indexStore, FileSystemAbstraction fileSystemAbstraction ) + public LuceneDataSource( File storeDir, Config config, IndexConfigStore indexStore, FileSystemAbstraction + fileSystemAbstraction, OperationalMode operationalMode ) { this.storeDir = storeDir; this.config = config; this.indexStore = indexStore; this.typeCache = new IndexTypeCache( indexStore ); this.fileSystemAbstraction = fileSystemAbstraction; + this.operationalMode = operationalMode; } @Override @@ -127,7 +131,7 @@ public void init() { this.filesystemFacade = config.get( Configuration.ephemeral ) ? LuceneFilesystemFacade.MEMORY : LuceneFilesystemFacade.FS; - readOnly = config.get( GraphDatabaseSettings.read_only ); + readOnly = isReadOnly( config, operationalMode ); indexSearchers = new IndexClockCache( config.get( Configuration.lucene_searcher_cache_size ) ); this.baseStorePath = this.filesystemFacade.ensureDirectoryExists( fileSystemAbstraction, getLuceneIndexStoreDirectory( storeDir ) ); @@ -473,6 +477,11 @@ private void makeSureAllIndexesAreInstantiated() } } + private boolean isReadOnly( Config config, OperationalMode operationalMode ) + { + return config.get( GraphDatabaseSettings.read_only ) && (OperationalMode.single == operationalMode); + } + enum LuceneFilesystemFacade { FS diff --git a/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneIndexImplementation.java b/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneIndexImplementation.java index d1d18b4898c99..32b41f5b24a0d 100644 --- a/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneIndexImplementation.java +++ b/community/lucene-index/src/main/java/org/neo4j/index/impl/lucene/legacy/LuceneIndexImplementation.java @@ -32,6 +32,7 @@ import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.TransactionApplier; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.lifecycle.LifecycleAdapter; import org.neo4j.kernel.spi.legacyindex.IndexCommandFactory; @@ -60,20 +61,22 @@ public class LuceneIndexImplementation extends LifecycleAdapter implements Index private final Config config; private final Supplier indexStore; private final FileSystemAbstraction fileSystemAbstraction; + private final OperationalMode operationalMode; public LuceneIndexImplementation( File storeDir, Config config, Supplier indexStore, - FileSystemAbstraction fileSystemAbstraction ) + FileSystemAbstraction fileSystemAbstraction, OperationalMode operationalMode ) { this.storeDir = storeDir; this.config = config; this.indexStore = indexStore; this.fileSystemAbstraction = fileSystemAbstraction; + this.operationalMode = operationalMode; } @Override public void init() throws Throwable { - this.dataSource = new LuceneDataSource( storeDir, config, indexStore.get(), fileSystemAbstraction ); + this.dataSource = new LuceneDataSource( storeDir, config, indexStore.get(), fileSystemAbstraction, operationalMode ); this.dataSource.init(); } diff --git a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtension.java b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtension.java index 0c731467ebc16..b9e8985a247c8 100644 --- a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtension.java +++ b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtension.java @@ -25,6 +25,7 @@ import org.neo4j.index.impl.lucene.legacy.LuceneIndexImplementation; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.lifecycle.LifecycleAdapter; import org.neo4j.kernel.spi.legacyindex.IndexProviders; @@ -36,15 +37,17 @@ public class LuceneKernelExtension extends LifecycleAdapter private final Supplier indexStore; private final FileSystemAbstraction fileSystemAbstraction; private final IndexProviders indexProviders; + private final OperationalMode operationalMode; public LuceneKernelExtension( File storeDir, Config config, Supplier indexStore, - FileSystemAbstraction fileSystemAbstraction, IndexProviders indexProviders ) + FileSystemAbstraction fileSystemAbstraction, IndexProviders indexProviders, OperationalMode operationalMode ) { this.storeDir = storeDir; this.config = config; this.indexStore = indexStore; this.fileSystemAbstraction = fileSystemAbstraction; this.indexProviders = indexProviders; + this.operationalMode = operationalMode; } @Override @@ -52,7 +55,7 @@ public void init() { LuceneIndexImplementation indexImplementation = - new LuceneIndexImplementation( storeDir, config, indexStore, fileSystemAbstraction ); + new LuceneIndexImplementation( storeDir, config, indexStore, fileSystemAbstraction, operationalMode ); indexProviders.registerIndexProvider( LuceneIndexImplementation.SERVICE_NAME, indexImplementation ); } diff --git a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtensionFactory.java b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtensionFactory.java index 577716a01f811..0ad5e1d484f46 100644 --- a/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtensionFactory.java +++ b/community/lucene-index/src/main/java/org/neo4j/index/lucene/LuceneKernelExtensionFactory.java @@ -51,6 +51,7 @@ public Lifecycle newInstance( KernelContext context, Dependencies dependencies ) dependencies.getConfig(), dependencies::getIndexStore, context.fileSystem(), - dependencies.getIndexProviders() ); + dependencies.getIndexProviders(), + context.databaseInfo().operationalMode ); } } diff --git a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneCommandApplierTest.java b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneCommandApplierTest.java index e2ab7f496ce19..3b253893cc6d3 100644 --- a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneCommandApplierTest.java +++ b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneCommandApplierTest.java @@ -26,9 +26,10 @@ import java.util.Map; import org.neo4j.graphdb.Node; -import org.neo4j.kernel.configuration.Settings; import org.neo4j.helpers.collection.MapUtil; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.configuration.Settings; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexCommand.AddNodeCommand; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.index.IndexDefineCommand; @@ -39,7 +40,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; - import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.index.impl.lucene.legacy.LuceneIndexImplementation.EXACT_CONFIG; @@ -61,7 +61,7 @@ public void shouldHandleMultipleIdSpaces() throws Exception configStore.set( Node.class, indexName, EXACT_CONFIG ); LuceneDataSource dataSource = life.add( spy( new LuceneDataSource( dir, new Config( stringMap( LuceneDataSource.Configuration.ephemeral.name(), Settings.TRUE ) ), - configStore, fs.get() ) ) ); + configStore, fs.get(), OperationalMode.single ) ) ); try ( LuceneCommandApplier applier = new LuceneCommandApplier( dataSource, false ) ) { diff --git a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSourceTest.java b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSourceTest.java index f56f834a18875..6c67f53019134 100644 --- a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSourceTest.java +++ b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/LuceneDataSourceTest.java @@ -35,6 +35,7 @@ import org.neo4j.helpers.collection.MapUtil; import org.neo4j.io.fs.DefaultFileSystemAbstraction; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.index.IndexEntityType; import org.neo4j.kernel.lifecycle.LifeRule; @@ -74,8 +75,7 @@ public void doNotTryToCommitWritersOnForceInReadOnlyMode() throws IOException stopDataSource(); Config readOnlyConfig = new Config( readOnlyConfig(), GraphDatabaseSettings.class ); - LuceneDataSource readOnlyDataSource = life.add( new LuceneDataSource( directory.graphDbDir(), readOnlyConfig, - indexStore, new DefaultFileSystemAbstraction() ) ); + LuceneDataSource readOnlyDataSource = life.add( getLuceneDataSource( readOnlyConfig ) ); assertNotNull( readOnlyDataSource.getIndexSearcher( indexIdentifier ) ); readOnlyDataSource.force(); @@ -89,27 +89,42 @@ public void notAllowIndexDeletionInReadOnlyMode() throws IOException stopDataSource(); Config readOnlyConfig = new Config( readOnlyConfig(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), readOnlyConfig, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( readOnlyConfig, OperationalMode.single ) ); expectedException.expect( IllegalStateException.class ); expectedException.expectMessage("Index deletion in read only mode is not supported."); dataSource.deleteIndex( indexIdentifier, false ); } @Test - public void useReadOnlyIndexSearcherInReadOnlyMode() throws IOException + public void useReadOnlyIndexSearcherInReadOnlyModeForSingleInstance() throws IOException { IndexIdentifier indexIdentifier = identifier( "foo" ); prepareIndexesByIdentifiers( indexIdentifier ); stopDataSource(); Config readOnlyConfig = new Config( readOnlyConfig(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), readOnlyConfig, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( readOnlyConfig, OperationalMode.single ) ); IndexReference indexSearcher = dataSource.getIndexSearcher( indexIdentifier ); assertTrue( "Read only index reference should be used in read only mode.", ReadOnlyIndexReference.class.isInstance( indexSearcher ) ); } + @Test + public void useWritableIndexSearcherInReadOnlyModeForNonSingleInstance() throws IOException + { + IndexIdentifier indexIdentifier = identifier( "foo" ); + prepareIndexesByIdentifiers( indexIdentifier ); + stopDataSource(); + + Config readOnlyConfig = new Config( readOnlyConfig(), GraphDatabaseSettings.class ); + dataSource = life.add( getLuceneDataSource( readOnlyConfig, OperationalMode.ha ) ); + + IndexReference indexSearcher = dataSource.getIndexSearcher( indexIdentifier ); + assertTrue( "Writable index reference should be used in read only mode in ha mode.", + WritableIndexReference.class.isInstance( indexSearcher ) ); + } + @Test public void refreshReadOnlyIndexSearcherInReadOnlyMode() throws IOException { @@ -118,7 +133,7 @@ public void refreshReadOnlyIndexSearcherInReadOnlyMode() throws IOException stopDataSource(); Config readOnlyConfig = new Config( readOnlyConfig(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), readOnlyConfig, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( readOnlyConfig ) ); IndexReference indexSearcher = dataSource.getIndexSearcher( indexIdentifier ); IndexReference indexSearcher2 = dataSource.getIndexSearcher( indexIdentifier ); @@ -133,7 +148,7 @@ public void refreshReadOnlyIndexSearcherInReadOnlyMode() throws IOException public void testShouldReturnIndexWriterFromLRUCache() throws Throwable { Config config = new Config( config(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier identifier = identifier( "foo" ); IndexWriter writer = dataSource.getIndexSearcher( identifier ).getWriter(); assertSame( writer, dataSource.getIndexSearcher( identifier ).getWriter() ); @@ -143,7 +158,7 @@ public void testShouldReturnIndexWriterFromLRUCache() throws Throwable public void testShouldReturnIndexSearcherFromLRUCache() throws Throwable { Config config = new Config( config(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier identifier = identifier( "foo" ); IndexReference searcher = dataSource.getIndexSearcher( identifier ); assertSame( searcher, dataSource.getIndexSearcher( identifier ) ); @@ -158,7 +173,7 @@ public void testClosesOldestIndexWriterWhenCacheSizeIsExceeded() throws Throwabl Map configMap = config(); configMap.put( GraphDatabaseSettings.lucene_searcher_cache_size.name(), "2" ); Config config = new Config( configMap, GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier fooIdentifier = identifier( "foo" ); IndexIdentifier barIdentifier = identifier( "bar" ); IndexIdentifier bazIdentifier = identifier( "baz" ); @@ -177,7 +192,7 @@ public void testClosesOldestIndexSearcherWhenCacheSizeIsExceeded() throws Throwa Map configMap = config(); configMap.put( GraphDatabaseSettings.lucene_searcher_cache_size.name(), "2" ); Config config = new Config( configMap, GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier fooIdentifier = identifier( "foo" ); IndexIdentifier barIdentifier = identifier( "bar" ); IndexIdentifier bazIdentifier = identifier( "baz" ); @@ -198,7 +213,7 @@ public void testRecreatesSearcherWhenRequestedAgain() throws Throwable Map configMap = config(); configMap.put( GraphDatabaseSettings.lucene_searcher_cache_size.name(), "2" ); Config config = new Config( configMap, GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier fooIdentifier = identifier( "foo" ); IndexIdentifier barIdentifier = identifier( "bar" ); IndexIdentifier bazIdentifier = identifier( "baz" ); @@ -222,7 +237,7 @@ public void testRecreatesWriterWhenRequestedAgainAfterCacheEviction() throws Thr Map configMap = config(); configMap.put( GraphDatabaseSettings.lucene_searcher_cache_size.name(), "2" ); Config config = new Config( configMap, GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); IndexIdentifier fooIdentifier = identifier( "foo" ); IndexIdentifier barIdentifier = identifier( "bar" ); IndexIdentifier bazIdentifier = identifier( "baz" ); @@ -247,7 +262,7 @@ private Map config() private void prepareIndexesByIdentifiers( IndexIdentifier indexIdentifier ) { Config config = new Config( config(), GraphDatabaseSettings.class ); - dataSource = life.add( new LuceneDataSource( directory.graphDbDir(), config, indexStore, new DefaultFileSystemAbstraction() ) ); + dataSource = life.add( getLuceneDataSource( config ) ); dataSource.getIndexSearcher( indexIdentifier ); dataSource.force(); } @@ -269,4 +284,14 @@ private IndexIdentifier identifier( String name ) return new IndexIdentifier( IndexEntityType.Node, name ); } + private LuceneDataSource getLuceneDataSource( Config config ) + { + return getLuceneDataSource( config, OperationalMode.unknown ); + } + + private LuceneDataSource getLuceneDataSource( Config config, OperationalMode operationalMode ) + { + return new LuceneDataSource( directory.graphDbDir(), config, indexStore, + new DefaultFileSystemAbstraction(), operationalMode ); + } } diff --git a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/ReadOnlyIndexReferenceFactoryTest.java b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/ReadOnlyIndexReferenceFactoryTest.java index f1a6435fbb9f7..98b8d7758700b 100644 --- a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/ReadOnlyIndexReferenceFactoryTest.java +++ b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/ReadOnlyIndexReferenceFactoryTest.java @@ -33,6 +33,7 @@ import org.neo4j.helpers.collection.MapUtil; import org.neo4j.io.fs.DefaultFileSystemAbstraction; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.index.IndexEntityType; import org.neo4j.test.CleanupRule; @@ -89,7 +90,7 @@ private void setupIndexInfrastructure() throws IOException indexStore = new IndexConfigStore( storeDir, fileSystemAbstraction ); indexStore.set( Node.class, INDEX_NAME, MapUtil.stringMap( IndexManager.PROVIDER, "lucene", "type", "fulltext" ) ); LuceneDataSource luceneDataSource = new LuceneDataSource( storeDir, new Config( MapUtil.stringMap() ), - indexStore, fileSystemAbstraction ); + indexStore, fileSystemAbstraction, OperationalMode.single ); try { luceneDataSource.init(); diff --git a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/RecoveryTest.java b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/RecoveryTest.java index 42ccce270d828..17841c0828b9c 100644 --- a/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/RecoveryTest.java +++ b/community/lucene-index/src/test/java/org/neo4j/index/impl/lucene/legacy/RecoveryTest.java @@ -38,6 +38,7 @@ import org.neo4j.io.fs.DefaultFileSystemAbstraction; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.OperationalMode; import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.test.DatabaseRule; import org.neo4j.test.EmbeddedDatabaseRule; @@ -166,7 +167,7 @@ public void recoveryForRelationshipCommandsOnly() throws Throwable FileSystemAbstraction fileSystem = new DefaultFileSystemAbstraction(); Config config = new Config( MapUtil.stringMap(), GraphDatabaseSettings.class ); LuceneDataSource ds = new LuceneDataSource( storeDir, config, new IndexConfigStore( storeDir, fileSystem ), - fileSystem ); + fileSystem, OperationalMode.single ); ds.start(); ds.stop(); }