From faaa61866ab41a05d0b41d0641e660c590ef00be Mon Sep 17 00:00:00 2001 From: MishaDemianenko Date: Thu, 20 Jul 2017 12:35:56 +0200 Subject: [PATCH] Open legacy index in writable mode for non single instance read only environments Open legacy indexes in writable mode for all read only environments except single instance. We need to allow indexes to be writable since they need to be updated during catch up updates. --- .../impl/lucene/legacy/LuceneDataSource.java | 13 ++++- .../legacy/LuceneIndexImplementation.java | 7 ++- .../index/lucene/LuceneKernelExtension.java | 7 ++- .../lucene/LuceneKernelExtensionFactory.java | 3 +- .../legacy/LuceneCommandApplierTest.java | 6 +-- .../lucene/legacy/LuceneDataSourceTest.java | 51 ++++++++++++++----- .../ReadOnlyIndexReferenceFactoryTest.java | 3 +- .../impl/lucene/legacy/RecoveryTest.java | 3 +- 8 files changed, 68 insertions(+), 25 deletions(-) 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(); }