diff --git a/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java b/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java index 211d15ab87cf2..0cc7d7f03dd74 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/NeoStoreDataSource.java @@ -88,6 +88,7 @@ import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; import org.neo4j.kernel.impl.store.MetaDataStore; import org.neo4j.kernel.impl.store.StoreId; import org.neo4j.kernel.impl.store.format.RecordFormatPropertyConfigurator; @@ -276,6 +277,7 @@ boolean applicable( DiagnosticsPhase phase ) private LabelScanStoreProvider labelScanStoreProvider; private File storeDir; private boolean readOnly; + private final IdController idController; private final RecoveryCleanupWorkCollector recoveryCleanupWorkCollector; private final AccessCapability accessCapability; @@ -325,7 +327,8 @@ public NeoStoreDataSource( SystemNanoClock clock, AccessCapability accessCapability, StoreCopyCheckPointMutex storeCopyCheckPointMutex, - RecoveryCleanupWorkCollector recoveryCleanupWorkCollector ) + RecoveryCleanupWorkCollector recoveryCleanupWorkCollector, + IdController idController ) { this.storeDir = storeDir; this.config = config; @@ -364,6 +367,7 @@ public NeoStoreDataSource( this.recoveryCleanupWorkCollector = recoveryCleanupWorkCollector; readOnly = config.get( Configuration.read_only ); + this.idController = idController; msgLog = logProvider.getLog( getClass() ); this.lockService = new ReentrantLockService(); this.legacyIndexProviderLookup = new LegacyIndexProviderLookup() @@ -479,6 +483,9 @@ public void start() throws IOException clock, propertyAccessor ); + Supplier transactionsSnapshotSupplier = () -> kernelModule.kernelTransactions().get(); + idController.initialize( transactionsSnapshotSupplier ); + kernelModule.satisfyDependencies( dependencies ); // Do these assignments last so that we can ensure no cyclical dependencies exist @@ -577,17 +584,12 @@ private StorageEngine buildStorageEngine( LegacyIndexProviderLookup legacyIndexProviderLookup, IndexConfigStore indexConfigStore, SchemaState schemaState, SynchronizedArrayIdOrderingQueue legacyIndexTransactionOrdering ) { - // TODO we should break this dependency on the kernelModule (which has not yet been created at this point in - // TODO the code) and instead let information about generations of transactions flow through the StorageEngine - // TODO API - Supplier transactionSnapshotSupplier = - () -> kernelModule.kernelTransactions().get(); - RecordStorageEngine storageEngine = new RecordStorageEngine( storeDir, config, idGeneratorFactory, - eligibleForReuse, idTypeConfigurationProvider, pageCache, fs, logProvider, propertyKeyTokenHolder, - labelTokens, relationshipTypeTokens, schemaState, constraintSemantics, scheduler, - tokenNameLookup, lockService, schemaIndexProvider, indexingServiceMonitor, databaseHealth, - labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering, - transactionSnapshotSupplier ); + RecordStorageEngine storageEngine = + new RecordStorageEngine( storeDir, config, pageCache, fs, logProvider, propertyKeyTokenHolder, + labelTokens, relationshipTypeTokens, schemaState, constraintSemantics, scheduler, + tokenNameLookup, lockService, schemaIndexProvider, indexingServiceMonitor, databaseHealth, + labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, + legacyIndexTransactionOrdering, idGeneratorFactory, idController ); // We pretend that the storage engine abstract hides all details within it. Whereas that's mostly // true it's not entirely true for the time being. As long as we need this call below, which diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java index a64651bec9d21..570a291f51bfd 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/CommunityEditionModule.java @@ -106,7 +106,10 @@ public CommunityEditionModule( PlatformModule platformModule ) statementLocksFactory = createStatementLocksFactory( lockManager, config, logging ); idTypeConfigurationProvider = createIdTypeConfigurationProvider( config ); + eligibleForIdReuse = IdReuseEligibility.ALWAYS; + idGeneratorFactory = dependencies.satisfyDependency( createIdGeneratorFactory( fileSystem, idTypeConfigurationProvider ) ); + idController = createIdController( platformModule ); propertyKeyTokenHolder = life.add( dependencies.satisfyDependency( new DelegatingPropertyKeyTokenHolder( createPropertyKeyCreator( config, dataSourceManager, idGeneratorFactory ) ) ) ); @@ -132,8 +135,6 @@ public CommunityEditionModule( PlatformModule platformModule ) ioLimiter = IOLimiter.unlimited(); - eligibleForIdReuse = IdReuseEligibility.ALWAYS; - registerRecovery( platformModule.databaseInfo, life, dependencies ); publishEditionInfo( dependencies.resolveDependency( UsageData.class ), platformModule.databaseInfo, config ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java index 2421068a08fa1..886ac9756ffff 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/DataSourceModule.java @@ -63,9 +63,9 @@ import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.impl.core.TokenNotFoundException; import org.neo4j.kernel.impl.logging.LogService; -import org.neo4j.kernel.impl.proc.ProcedureTransactionProvider; import org.neo4j.kernel.impl.proc.ProcedureConfig; import org.neo4j.kernel.impl.proc.ProcedureGDSFactory; +import org.neo4j.kernel.impl.proc.ProcedureTransactionProvider; import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.kernel.impl.proc.TerminationGuardProvider; import org.neo4j.kernel.impl.proc.TypeMappers.SimpleConverter; @@ -220,7 +220,8 @@ public DataSourceModule( final PlatformModule platformModule, EditionModule edit platformModule.availabilityGuard, platformModule.clock, editionModule.accessCapability, platformModule.storeCopyCheckPointMutex, - platformModule.recoveryCleanupWorkCollector ) ); + platformModule.recoveryCleanupWorkCollector, + editionModule.idController ) ); dataSourceManager.register( neoStoreDataSource ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java index 04a2ac2f58e83..f6374019516b3 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/factory/EditionModule.java @@ -44,12 +44,16 @@ import org.neo4j.kernel.impl.locking.StatementLocksFactory; import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.proc.Procedures; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.BufferedIdController; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.DefaultIdController; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; +import org.neo4j.kernel.impl.store.id.BufferingIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.util.DependencySatisfier; -import org.neo4j.scheduler.JobScheduler; import org.neo4j.kernel.impl.util.watcher.DefaultFileDeletionEventListener; import org.neo4j.kernel.impl.util.watcher.DefaultFileSystemWatcherService; import org.neo4j.kernel.impl.util.watcher.FileSystemWatcherService; @@ -57,8 +61,10 @@ import org.neo4j.kernel.internal.KernelDiagnostics; import org.neo4j.kernel.lifecycle.LifeSupport; import org.neo4j.logging.Log; +import org.neo4j.scheduler.JobScheduler; import org.neo4j.udc.UsageData; import org.neo4j.udc.UsageDataKeys; +import org.neo4j.unsafe.impl.internal.dragons.FeatureToggles; import static java.util.Collections.singletonMap; @@ -68,6 +74,9 @@ */ public abstract class EditionModule { + protected static final boolean safeIdBuffering = FeatureToggles.flag( + RecordStorageEngine.class, "safeIdBuffering", true ); // TODO: fix this! + void registerProcedures( Procedures procedures ) throws KernelException { procedures.registerProcedure( org.neo4j.kernel.builtinprocs.BuiltInProcedures.class ); @@ -112,6 +121,8 @@ void registerProcedures( Procedures procedures ) throws KernelException public FileSystemWatcherService watcherService; + public IdController idController; + protected FileSystemWatcherService createFileSystemWatcherService( FileSystemAbstraction fileSystem, File storeDir, LogService logging, JobScheduler jobScheduler, Predicate fileNameFilter ) { @@ -225,4 +236,24 @@ protected BoltConnectionTracker createSessionTracker() { return BoltConnectionTracker.NOOP; } + + protected IdController createIdController( PlatformModule platformModule ) + { + return safeIdBuffering ? createBufferedIdController( idGeneratorFactory, platformModule.jobScheduler, + eligibleForIdReuse, idTypeConfigurationProvider ) : createDefaultIdController(); + } + + protected BufferedIdController createBufferedIdController( IdGeneratorFactory idGeneratorFactory, + JobScheduler scheduler, IdReuseEligibility eligibleForIdReuse, + IdTypeConfigurationProvider idTypeConfigurationProvider ) + { + BufferingIdGeneratorFactory bufferingIdGeneratorFactory = + new BufferingIdGeneratorFactory( idGeneratorFactory, eligibleForIdReuse, idTypeConfigurationProvider ); + return new BufferedIdController( bufferingIdGeneratorFactory, scheduler ); + } + + protected DefaultIdController createDefaultIdController() + { + return new DefaultIdController(); + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java index a8c26f344f895..dc23ef616a107 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/RecordStorageEngine.java @@ -47,7 +47,6 @@ import org.neo4j.kernel.impl.api.CountsRecordState; import org.neo4j.kernel.impl.api.CountsStoreBatchTransactionApplier; import org.neo4j.kernel.impl.api.IndexReaderFactory; -import org.neo4j.kernel.impl.api.KernelTransactionsSnapshot; import org.neo4j.kernel.impl.api.LegacyBatchIndexApplier; import org.neo4j.kernel.impl.api.LegacyIndexApplierLookup; import org.neo4j.kernel.impl.api.LegacyIndexProviderLookup; @@ -71,8 +70,6 @@ import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.locking.LockGroup; import org.neo4j.kernel.impl.locking.LockService; -import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.BufferedIdController; -import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.DefaultIdController; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; import org.neo4j.kernel.impl.store.NeoStores; import org.neo4j.kernel.impl.store.RecordStore; @@ -81,8 +78,6 @@ import org.neo4j.kernel.impl.store.StoreType; import org.neo4j.kernel.impl.store.format.RecordFormat; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; -import org.neo4j.kernel.impl.store.id.IdReuseEligibility; -import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; import org.neo4j.kernel.impl.store.record.AbstractBaseRecord; import org.neo4j.kernel.impl.transaction.command.CacheInvalidationBatchTransactionApplier; import org.neo4j.kernel.impl.transaction.command.HighIdBatchTransactionApplier; @@ -131,8 +126,6 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle { private static final boolean takePropertyReadLocks = FeatureToggles.flag( RecordStorageEngine.class, "propertyReadLocks", false ); - private static final boolean safeIdBuffering = FeatureToggles.flag( - RecordStorageEngine.class, "safeIdBuffering", true ); private final StoreReadLayer storeLayer; private final IndexingService indexingService; @@ -152,7 +145,6 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle private final SchemaStorage schemaStorage; private final ConstraintSemantics constraintSemantics; private final IdOrderingQueue legacyIndexTransactionOrdering; - private final JobScheduler scheduler; private final LockService lockService; private final WorkSync,LabelUpdateWork> labelScanStoreSync; private final CommandReaderFactory commandReaderFactory; @@ -173,9 +165,6 @@ public class RecordStorageEngine implements StorageEngine, Lifecycle public RecordStorageEngine( File storeDir, Config config, - IdGeneratorFactory idGeneratorFactory, - IdReuseEligibility eligibleForReuse, - IdTypeConfigurationProvider idTypeConfigurationProvider, PageCache pageCache, FileSystemAbstraction fs, LogProvider logProvider, @@ -194,13 +183,13 @@ public RecordStorageEngine( LegacyIndexProviderLookup legacyIndexProviderLookup, IndexConfigStore indexConfigStore, IdOrderingQueue legacyIndexTransactionOrdering, - Supplier transactionsSnapshotSupplier ) + IdGeneratorFactory idGeneratorFactory, + IdController idController ) { this.propertyKeyTokenHolder = propertyKeyTokenHolder; this.relationshipTypeTokenHolder = relationshipTypeTokens; this.labelTokenHolder = labelTokens; this.schemaState = schemaState; - this.scheduler = scheduler; this.lockService = lockService; this.databaseHealth = databaseHealth; this.legacyIndexProviderLookup = legacyIndexProviderLookup; @@ -208,9 +197,8 @@ public RecordStorageEngine( this.constraintSemantics = constraintSemantics; this.legacyIndexTransactionOrdering = legacyIndexTransactionOrdering; - this.idController = createStorageIdController( idGeneratorFactory, eligibleForReuse, - idTypeConfigurationProvider, transactionsSnapshotSupplier ); - StoreFactory factory = new StoreFactory( storeDir, config, idController.getIdGeneratorFactory(), pageCache, fs, logProvider ); + this.idController = idController; + StoreFactory factory = new StoreFactory( storeDir, config, idGeneratorFactory, pageCache, fs, logProvider ); neoStores = factory.openAllNeoStores( true ); try @@ -263,17 +251,6 @@ public RecordStorageEngine( } } - private IdController createStorageIdController( IdGeneratorFactory idGeneratorFactory, - IdReuseEligibility eligibleForReuse, - IdTypeConfigurationProvider idTypeConfigurationProvider, - Supplier transactionsSnapshotSupplier ) - { - return safeIdBuffering ? - new BufferedIdController( idGeneratorFactory, transactionsSnapshotSupplier, - eligibleForReuse, idTypeConfigurationProvider, scheduler ) : - new DefaultIdController( idGeneratorFactory ); - } - private Supplier storeStatementSupplier( NeoStores neoStores ) { Supplier indexReaderFactory = () -> new IndexReaderFactory.Caching( indexingService ); diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/BufferedIdController.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/BufferedIdController.java index 63570f3f3d906..41cb7a9d964a8 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/BufferedIdController.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/BufferedIdController.java @@ -24,11 +24,8 @@ import org.neo4j.kernel.impl.api.KernelTransactionsSnapshot; import org.neo4j.kernel.impl.store.id.BufferingIdGeneratorFactory; -import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; -import org.neo4j.kernel.impl.store.id.IdReuseEligibility; -import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; -import org.neo4j.scheduler.JobScheduler; import org.neo4j.kernel.lifecycle.LifecycleAdapter; +import org.neo4j.scheduler.JobScheduler; /** * Storage id controller that provide buffering possibilities to be able so safely free and reuse ids. @@ -37,23 +34,14 @@ */ public class BufferedIdController extends LifecycleAdapter implements IdController { - private final BufferingIdGeneratorFactory bufferingIdGeneratorFactory; private final JobScheduler scheduler; private JobScheduler.JobHandle jobHandle; - public BufferedIdController( IdGeneratorFactory idGeneratorFactory, - Supplier transactionsSnapshotSupplier, IdReuseEligibility eligibleForReuse, - IdTypeConfigurationProvider idTypeConfigurationProvider, JobScheduler scheduler ) + public BufferedIdController( BufferingIdGeneratorFactory bufferingIdGeneratorFactory, JobScheduler scheduler ) { + this.bufferingIdGeneratorFactory = bufferingIdGeneratorFactory; this.scheduler = scheduler; - bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( - idGeneratorFactory, transactionsSnapshotSupplier, eligibleForReuse, idTypeConfigurationProvider ); - } - - public IdGeneratorFactory getIdGeneratorFactory() - { - return bufferingIdGeneratorFactory; } @Override @@ -80,4 +68,10 @@ public void maintenance() { bufferingIdGeneratorFactory.maintenance(); } + + @Override + public void initialize( Supplier transactionsSnapshotSupplier ) + { + bufferingIdGeneratorFactory.initialize( transactionsSnapshotSupplier ); + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/DefaultIdController.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/DefaultIdController.java index f9e76d776327a..88313b302a9b3 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/DefaultIdController.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/DefaultIdController.java @@ -20,6 +20,9 @@ package org.neo4j.kernel.impl.storageengine.impl.recordstorage.id; +import java.util.function.Supplier; + +import org.neo4j.kernel.impl.api.KernelTransactionsSnapshot; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.lifecycle.LifecycleAdapter; @@ -29,26 +32,22 @@ */ public class DefaultIdController extends LifecycleAdapter implements IdController { - - private IdGeneratorFactory idGeneratorFactory; - - public DefaultIdController( IdGeneratorFactory idGeneratorFactory ) + public DefaultIdController() { - this.idGeneratorFactory = idGeneratorFactory; } - public IdGeneratorFactory getIdGeneratorFactory() + @Override + public void clear() { - return idGeneratorFactory; } @Override - public void clear() + public void maintenance() { } @Override - public void maintenance() + public void initialize( Supplier transactionsSnapshotSupplier ) { } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/IdController.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/IdController.java index 4264039b7a068..d21a7a9074aec 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/IdController.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/storageengine/impl/recordstorage/id/IdController.java @@ -20,7 +20,9 @@ package org.neo4j.kernel.impl.storageengine.impl.recordstorage.id; -import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; +import java.util.function.Supplier; + +import org.neo4j.kernel.impl.api.KernelTransactionsSnapshot; import org.neo4j.kernel.lifecycle.Lifecycle; /** @@ -29,11 +31,6 @@ */ public interface IdController extends Lifecycle { - /** - * Retrieve id generation factory for current storage engine - * @return id generation factory - */ - IdGeneratorFactory getIdGeneratorFactory(); /** * Clear underlying id generation infrastructure (clear buffer of ids to reuse, reset buffers, etc.) @@ -44,4 +41,6 @@ public interface IdController extends Lifecycle * Perform ids related maintenance. */ void maintenance(); + + void initialize( Supplier transactionsSnapshotSupplier ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactory.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactory.java index 5e69690c5d160..8526838817ed9 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactory.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactory.java @@ -41,25 +41,17 @@ public class BufferingIdGeneratorFactory implements IdGeneratorFactory private final IdGeneratorFactory delegate; private final IdTypeConfigurationProvider idTypeConfigurationProvider; - public BufferingIdGeneratorFactory( IdGeneratorFactory delegate, Supplier boundaries, + public BufferingIdGeneratorFactory( IdGeneratorFactory delegate, IdReuseEligibility eligibleForReuse, IdTypeConfigurationProvider idTypeConfigurationProvider ) { this.delegate = delegate; this.idTypeConfigurationProvider = idTypeConfigurationProvider; - initialize( boundaries, eligibleForReuse ); + this.safeThreshold = snapshot -> snapshot.allClosed() && eligibleForReuse.isEligible( snapshot ); } - private void initialize( Supplier boundaries, IdReuseEligibility eligibleForReuse ) + public void initialize( Supplier transactionsSnapshotSupplier ) { - this.boundaries = boundaries; - this.safeThreshold = snapshot -> snapshot.allClosed() && eligibleForReuse.isEligible( snapshot ); - for ( BufferingIdGenerator generator : overriddenIdGenerators ) - { - if ( generator != null ) - { - generator.initialize( boundaries, safeThreshold ); - } - } + boundaries = transactionsSnapshotSupplier; } @Override @@ -72,32 +64,14 @@ public IdGenerator open( File filename, IdType idType, long highId, long maxId ) @Override public IdGenerator open( File filename, int grabSize, IdType idType, long highId, long maxId ) { + assert boundaries != null : "Factory needs to be initialized before usage"; + IdGenerator generator = delegate.open( filename, grabSize, idType, highId, maxId ); IdTypeConfiguration typeConfiguration = getIdTypeConfiguration(idType); if ( typeConfiguration.allowAggressiveReuse() ) { BufferingIdGenerator bufferingGenerator = new BufferingIdGenerator( generator ); - - // If shutdown was CLEAN - // BufferingIdGeneratorFactory has lifecycle: - // - Construct - // - open (all store files) - // - initialize - // - // If Shutdown was UNCLEAN - // BufferingIdGeneratorFactory has lifecycle: - // - Construct - // - open (all store files) will fail - // - initialize (with all generators being null) - // - recovery is performed - // - open (all store files) again - // - initialize will NOT be called again so... - // - call initialize on generators after open - // = that is why this if-statement is here - if ( boundaries != null ) - { - bufferingGenerator.initialize( boundaries, safeThreshold ); - } + bufferingGenerator.initialize( boundaries, safeThreshold ); overriddenIdGenerators[idType.ordinal()] = bufferingGenerator; generator = bufferingGenerator; } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactoryTest.java b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactoryTest.java index df76b06b68b32..8cb570e2b6a7c 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactoryTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/impl/store/id/BufferingIdGeneratorFactoryTest.java @@ -50,7 +50,8 @@ public void shouldDelayFreeingOfAggressivelyReusedIds() throws Exception MockedIdGeneratorFactory actual = new MockedIdGeneratorFactory(); ControllableSnapshotSupplier boundaries = new ControllableSnapshotSupplier(); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( - actual, boundaries, IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider() ); + actual, IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider() ); + bufferingIdGeneratorFactory.initialize( boundaries ); IdGenerator idGenerator = bufferingIdGeneratorFactory.open( new File( "doesnt-matter" ), 10, IdType.STRING_BLOCK, 0, Integer.MAX_VALUE ); @@ -79,8 +80,9 @@ public void shouldDelayFreeingOfAggressivelyReusedIdsConsideringTimeAsWell() thr final long safeZone = MINUTES.toMillis( 1 ); ControllableSnapshotSupplier boundaries = new ControllableSnapshotSupplier(); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( actual, - boundaries, t -> clock.millis() - t.snapshotTime() >= safeZone, + t -> clock.millis() - t.snapshotTime() >= safeZone, new CommunityIdTypeConfigurationProvider() ); + bufferingIdGeneratorFactory.initialize( boundaries ); IdGenerator idGenerator = bufferingIdGeneratorFactory.open( new File( "doesnt-matter" ), 10, IdType.STRING_BLOCK, 0, Integer.MAX_VALUE ); diff --git a/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java b/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java index fc90cc5bc265d..83bd6a73aff44 100644 --- a/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java +++ b/community/kernel/src/test/java/org/neo4j/test/rule/NeoStoreDataSourceRule.java @@ -56,6 +56,8 @@ import org.neo4j.kernel.impl.proc.Procedures; import org.neo4j.kernel.impl.spi.KernelContext; import org.neo4j.kernel.impl.spi.SimpleKernelContext; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.BufferedIdController; +import org.neo4j.kernel.impl.store.id.BufferingIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.DefaultIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; @@ -145,9 +147,10 @@ logService, mock( JobScheduler.class, RETURNS_MOCKS ), mock( TokenNameLookup.cla IOLimiter.unlimited(), availabilityGuard, clock, new CanWrite(), new StoreCopyCheckPointMutex(), - RecoveryCleanupWorkCollector.IMMEDIATE ); - -//>>>>>>> upstream/3.2 + RecoveryCleanupWorkCollector.IMMEDIATE, + new BufferedIdController( + new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, + idConfigurationProvider ), jobScheduler )); return dataSource; } diff --git a/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java b/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java index bd4855039c7c9..0cc3386c32a70 100644 --- a/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java +++ b/community/kernel/src/test/java/org/neo4j/test/rule/RecordStorageEngineRule.java @@ -20,9 +20,7 @@ package org.neo4j.test.rule; import java.io.File; -import java.util.Collections; import java.util.function.Function; -import java.util.function.Supplier; import org.neo4j.concurrent.Runnables; import org.neo4j.helpers.collection.Iterables; @@ -32,7 +30,6 @@ import org.neo4j.kernel.api.index.SchemaIndexProvider; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.api.BatchTransactionApplierFacade; -import org.neo4j.kernel.impl.api.KernelTransactionsSnapshot; import org.neo4j.kernel.impl.api.LegacyIndexProviderLookup; import org.neo4j.kernel.impl.api.SchemaState; import org.neo4j.kernel.impl.api.index.IndexingService; @@ -47,10 +44,12 @@ import org.neo4j.kernel.impl.locking.LockService; import org.neo4j.kernel.impl.locking.ReentrantLockService; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.RecordStorageEngine; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.BufferedIdController; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; +import org.neo4j.kernel.impl.store.id.BufferingIdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; import org.neo4j.kernel.impl.store.id.configuration.CommunityIdTypeConfigurationProvider; -import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; import org.neo4j.kernel.impl.util.IdOrderingQueue; import org.neo4j.kernel.impl.util.Neo4jJobScheduler; import org.neo4j.kernel.impl.util.SynchronizedArrayIdOrderingQueue; @@ -111,17 +110,18 @@ private RecordStorageEngine get( FileSystemAbstraction fs, PageCache pageCache, IndexConfigStore indexConfigStore = new IndexConfigStore( storeDirectory, fs ); JobScheduler scheduler = life.add( new Neo4jJobScheduler() ); Config config = Config.defaults(); - Supplier txSnapshotSupplier = - () -> new KernelTransactionsSnapshot( Collections.emptySet(), 0 ); - return life.add( new ExtendedRecordStorageEngine( storeDirectory, config, idGeneratorFactory, - IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider(), pageCache, fs, - NullLogProvider.getInstance(), - mock( PropertyKeyTokenHolder.class ), mock( LabelTokenHolder.class ), + + BufferingIdGeneratorFactory bufferingIdGeneratorFactory = + new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, + new CommunityIdTypeConfigurationProvider() ); + return life.add( new ExtendedRecordStorageEngine( storeDirectory, config, pageCache, fs, + NullLogProvider.getInstance(), mock( PropertyKeyTokenHolder.class ), mock( LabelTokenHolder.class ), mock( RelationshipTypeTokenHolder.class ), mock( SchemaState.class ), new StandardConstraintSemantics(), scheduler, mock( TokenNameLookup.class ), new ReentrantLockService(), schemaIndexProvider, IndexingService.NO_MONITOR, databaseHealth, labelScanStoreProvider, legacyIndexProviderLookup, indexConfigStore, - new SynchronizedArrayIdOrderingQueue( 20 ), txSnapshotSupplier, transactionApplierTransformer ) ); + new SynchronizedArrayIdOrderingQueue( 20 ), idGeneratorFactory, + new BufferedIdController( bufferingIdGeneratorFactory, scheduler ), transactionApplierTransformer ) ); } @Override @@ -192,34 +192,25 @@ public RecordStorageEngine build() private class ExtendedRecordStorageEngine extends RecordStorageEngine { - private final Function transactionApplierTransformer; - ExtendedRecordStorageEngine( File storeDir, Config config, - IdGeneratorFactory idGeneratorFactory, IdReuseEligibility eligibleForReuse, - IdTypeConfigurationProvider idTypeConfigurationProvider, - PageCache pageCache, FileSystemAbstraction fs, LogProvider logProvider, - PropertyKeyTokenHolder propertyKeyTokenHolder, LabelTokenHolder labelTokens, + ExtendedRecordStorageEngine( File storeDir, Config config, PageCache pageCache, FileSystemAbstraction fs, + LogProvider logProvider, PropertyKeyTokenHolder propertyKeyTokenHolder, LabelTokenHolder labelTokens, RelationshipTypeTokenHolder relationshipTypeTokens, SchemaState schemaState, - ConstraintSemantics constraintSemantics, JobScheduler scheduler, - TokenNameLookup tokenNameLookup, LockService lockService, - SchemaIndexProvider indexProvider, + ConstraintSemantics constraintSemantics, JobScheduler scheduler, TokenNameLookup tokenNameLookup, + LockService lockService, SchemaIndexProvider indexProvider, IndexingService.Monitor indexingServiceMonitor, DatabaseHealth databaseHealth, - LabelScanStoreProvider labelScanStoreProvider, - LegacyIndexProviderLookup legacyIndexProviderLookup, + LabelScanStoreProvider labelScanStoreProvider, LegacyIndexProviderLookup legacyIndexProviderLookup, IndexConfigStore indexConfigStore, IdOrderingQueue legacyIndexTransactionOrdering, - Supplier transactionsSnapshotSupplier, - Function - transactionApplierTransformer ) + IdGeneratorFactory idGeneratorFactory, IdController idController, + Function transactionApplierTransformer ) { - super( storeDir, config, idGeneratorFactory, eligibleForReuse, idTypeConfigurationProvider, - pageCache, fs, logProvider, propertyKeyTokenHolder, - labelTokens, relationshipTypeTokens, schemaState, constraintSemantics, scheduler, - tokenNameLookup, lockService, indexProvider, indexingServiceMonitor, databaseHealth, - labelScanStoreProvider, - legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering, - transactionsSnapshotSupplier ); + super( storeDir, config, pageCache, fs, logProvider, propertyKeyTokenHolder, labelTokens, + relationshipTypeTokens, schemaState, constraintSemantics, scheduler, tokenNameLookup, + lockService, indexProvider, indexingServiceMonitor, databaseHealth, labelScanStoreProvider, + legacyIndexProviderLookup, indexConfigStore, legacyIndexTransactionOrdering, idGeneratorFactory, + idController ); this.transactionApplierTransformer = transactionApplierTransformer; } diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java index 2aaf163d83f71..c1e25903c0352 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/EnterpriseCoreEditionModule.java @@ -37,6 +37,7 @@ import org.neo4j.causalclustering.core.state.ClusterStateException; import org.neo4j.causalclustering.core.state.ClusteringModule; import org.neo4j.causalclustering.core.state.machines.CoreStateMachinesModule; +import org.neo4j.causalclustering.core.state.machines.id.FreeIdFilteredIdGeneratorFactory; import org.neo4j.causalclustering.discovery.CoreTopologyService; import org.neo4j.causalclustering.discovery.DiscoveryServiceFactory; import org.neo4j.causalclustering.discovery.procedures.ClusterOverviewProcedure; @@ -83,7 +84,11 @@ import org.neo4j.kernel.impl.index.IndexConfigStore; import org.neo4j.kernel.impl.logging.LogService; import org.neo4j.kernel.impl.proc.Procedures; +import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.BufferedIdController; +import org.neo4j.kernel.impl.store.id.BufferingIdGeneratorFactory; +import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdReuseEligibility; +import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; import org.neo4j.kernel.impl.transaction.TransactionHeaderInformationFactory; import org.neo4j.kernel.impl.transaction.log.PhysicalLogFile; import org.neo4j.kernel.impl.util.Dependencies; @@ -96,6 +101,7 @@ import org.neo4j.kernel.monitoring.Monitors; import org.neo4j.logging.LogProvider; import org.neo4j.ssl.SslPolicy; +import org.neo4j.scheduler.JobScheduler; import org.neo4j.udc.UsageData; import static org.neo4j.causalclustering.core.CausalClusteringSettings.raft_messages_log_path; @@ -225,8 +231,14 @@ public void registerEditionSpecificProcedures( Procedures procedures ) throws Ke platformModule, clusterStateDirectory.get(), config, replicationModule.getReplicator(), consensusModule.raftMachine(), dependencies, localDatabase ); - this.idGeneratorFactory = coreStateMachinesModule.idGeneratorFactory; this.idTypeConfigurationProvider = coreStateMachinesModule.idTypeConfigurationProvider; + this.idGeneratorFactory = + safeIdBuffering ? new BufferingIdGeneratorFactory( coreStateMachinesModule.idGeneratorFactory, eligibleForIdReuse, + idTypeConfigurationProvider ) : coreStateMachinesModule.idGeneratorFactory; + this.idController = createIdController( platformModule ); + this.idGeneratorFactory = new FreeIdFilteredIdGeneratorFactory( coreStateMachinesModule.idGeneratorFactory, + coreStateMachinesModule.freeIdCondition ); + this.labelTokenHolder = coreStateMachinesModule.labelTokenHolder; this.propertyKeyTokenHolder = coreStateMachinesModule.propertyKeyTokenHolder; this.relationshipTypeTokenHolder = coreStateMachinesModule.relationshipTypeTokenHolder; @@ -246,6 +258,14 @@ public void registerEditionSpecificProcedures( Procedures procedures ) throws Ke life.add( coreServerModule.membershipWaiterLifecycle ); } + @Override + protected BufferedIdController createBufferedIdController( IdGeneratorFactory idGeneratorFactory, + JobScheduler scheduler, IdReuseEligibility eligibleForIdReuse, + IdTypeConfigurationProvider idTypeConfigurationProvider ) + { + return new BufferedIdController( (BufferingIdGeneratorFactory) idGeneratorFactory, scheduler ); + } + static Predicate fileWatcherFileNameFilter() { return Predicates.any( diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/CoreStateMachinesModule.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/CoreStateMachinesModule.java index 85e0a7383d9f3..7b4e002e95efd 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/CoreStateMachinesModule.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/CoreStateMachinesModule.java @@ -62,6 +62,7 @@ import org.neo4j.kernel.impl.factory.PlatformModule; import org.neo4j.kernel.impl.locking.Locks; import org.neo4j.kernel.impl.logging.LogService; +import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdType; import org.neo4j.kernel.impl.store.id.configuration.IdTypeConfigurationProvider; import org.neo4j.kernel.impl.store.stats.IdBasedStoreEntityCounters; @@ -94,7 +95,7 @@ public class CoreStateMachinesModule public static final String ID_ALLOCATION_NAME = "id-allocation"; public static final String LOCK_TOKEN_NAME = "lock-token"; - public final ReplicatedIdGeneratorFactory idGeneratorFactory; + public final IdGeneratorFactory idGeneratorFactory; public final IdTypeConfigurationProvider idTypeConfigurationProvider; public final LabelTokenHolder labelTokenHolder; public final PropertyKeyTokenHolder propertyKeyTokenHolder; @@ -103,6 +104,7 @@ public class CoreStateMachinesModule public final CommitProcessFactory commitProcessFactory; public final CoreStateMachines coreStateMachines; + public final BooleanSupplier freeIdCondition; public CoreStateMachinesModule( MemberId myself, PlatformModule platformModule, File clusterStateDirectory, Config config, RaftReplicator replicator, RaftMachine raftMachine, Dependencies dependencies, @@ -136,10 +138,10 @@ public CoreStateMachinesModule( MemberId myself, PlatformModule platformModule, idTypeConfigurationProvider = new EnterpriseIdTypeConfigurationProvider( config ); CommandIndexTracker commandIndexTracker = new CommandIndexTracker(); - BooleanSupplier freeIdCondition = new IdReusabilityCondition( commandIndexTracker, raftMachine, myself ); + freeIdCondition = new IdReusabilityCondition( commandIndexTracker, raftMachine, myself ); this.idGeneratorFactory = dependencies.satisfyDependency( createIdGeneratorFactory( fileSystem, idRangeAcquirer, logProvider, - idTypeConfigurationProvider, freeIdCondition ) ); + idTypeConfigurationProvider ) ); dependencies.satisfyDependency( new IdBasedStoreEntityCounters( this.idGeneratorFactory ) ); @@ -217,12 +219,12 @@ private Map getIdTypeAllocationSizeFromConfig( Config config ) return allocationSizes; } - private ReplicatedIdGeneratorFactory createIdGeneratorFactory( FileSystemAbstraction fileSystem, + private IdGeneratorFactory createIdGeneratorFactory( FileSystemAbstraction fileSystem, final ReplicatedIdRangeAcquirer idRangeAcquirer, final LogProvider logProvider, - IdTypeConfigurationProvider idTypeConfigurationProvider, BooleanSupplier freeIdCondition ) + IdTypeConfigurationProvider idTypeConfigurationProvider ) { - return new ReplicatedIdGeneratorFactory( fileSystem, idRangeAcquirer, logProvider, - idTypeConfigurationProvider, freeIdCondition ); + return new ReplicatedIdGeneratorFactory( fileSystem, idRangeAcquirer, + logProvider, idTypeConfigurationProvider ); } private Locks createLockManager( final Config config, Clock clock, final LogService logging, diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGenerator.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGenerator.java new file mode 100644 index 0000000000000..61c019e7d04ea --- /dev/null +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGenerator.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.core.state.machines.id; + +import java.util.function.BooleanSupplier; + +import org.neo4j.kernel.impl.store.id.IdGenerator; + +public class FreeIdFilteredIdGenerator extends IdGenerator.Delegate +{ + private final BooleanSupplier freeIdCondition; + + public FreeIdFilteredIdGenerator( IdGenerator delegate, BooleanSupplier freeIdCondition ) + { + super( delegate ); + this.freeIdCondition = freeIdCondition; + } + + @Override + public void freeId( long id ) + { + if ( freeIdCondition.getAsBoolean() ) + { + super.freeId( id ); + } + } +} diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGeneratorFactory.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGeneratorFactory.java new file mode 100644 index 0000000000000..07305fccaa05e --- /dev/null +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/FreeIdFilteredIdGeneratorFactory.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.causalclustering.core.state.machines.id; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BooleanSupplier; + +import org.neo4j.kernel.impl.store.id.IdGenerator; +import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; +import org.neo4j.kernel.impl.store.id.IdType; + + +public class FreeIdFilteredIdGeneratorFactory implements IdGeneratorFactory +{ + Map delegatedGenerator = new HashMap<>(); + private final IdGeneratorFactory delegate; + private final BooleanSupplier freeIdCondition; + + public FreeIdFilteredIdGeneratorFactory( IdGeneratorFactory delegate, BooleanSupplier freeIdCondition ) + { + this.delegate = delegate; + this.freeIdCondition = freeIdCondition; + } + + @Override + public IdGenerator open( File filename, IdType idType, long highId, long maxId ) + { + FreeIdFilteredIdGenerator freeIdFilteredIdGenerator = + new FreeIdFilteredIdGenerator( delegate.open( filename, idType, highId, maxId ), freeIdCondition ); + delegatedGenerator.put( idType, freeIdFilteredIdGenerator ); + return freeIdFilteredIdGenerator; + } + + @Override + public IdGenerator open( File filename, int grabSize, IdType idType, long highId, long maxId ) + { + FreeIdFilteredIdGenerator freeIdFilteredIdGenerator = + new FreeIdFilteredIdGenerator( delegate.open( filename, grabSize, idType, highId, maxId ), + freeIdCondition ); + delegatedGenerator.put( idType, freeIdFilteredIdGenerator ); + return freeIdFilteredIdGenerator; + } + + @Override + public void create( File filename, long highId, boolean throwIfFileExists ) + { + delegate.create( filename, highId, throwIfFileExists ); + } + + @Override + public IdGenerator get( IdType idType ) + { + return delegatedGenerator.get( idType ); + } +} diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGenerator.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGenerator.java index 34417b2d1ef73..b955e52f2c595 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGenerator.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGenerator.java @@ -20,7 +20,6 @@ package org.neo4j.causalclustering.core.state.machines.id; import java.io.File; -import java.util.function.BooleanSupplier; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.impl.store.id.IdContainer; @@ -39,21 +38,18 @@ class ReplicatedIdGenerator implements IdGenerator private final IdType idType; private final Log log; private final ReplicatedIdRangeAcquirer acquirer; - private final BooleanSupplier freeIdCondition; private volatile long highId; private volatile IdRangeIterator idQueue = EMPTY_ID_RANGE_ITERATOR; private IdContainer idContainer; ReplicatedIdGenerator( FileSystemAbstraction fs, File file, IdType idType, long highId, - ReplicatedIdRangeAcquirer acquirer, LogProvider logProvider, int grabSize, boolean aggressiveReuse, - BooleanSupplier freeIdCondition ) + ReplicatedIdRangeAcquirer acquirer, LogProvider logProvider, int grabSize, boolean aggressiveReuse ) { this.idType = idType; this.highId = highId; this.acquirer = acquirer; this.log = logProvider.getLog( getClass() ); - this.freeIdCondition = freeIdCondition; idContainer = new IdContainer( fs, file, grabSize, aggressiveReuse ); idContainer.init(); } @@ -67,10 +63,7 @@ public void close() @Override public void freeId( long id ) { - if ( freeIdCondition.getAsBoolean() ) - { - idContainer.freeId( id ); - } + idContainer.freeId( id ); } @Override @@ -94,7 +87,7 @@ public long getHighestPossibleIdInUse() @Override public long getNumberOfIdsInUse() { - return highId - idContainer.getFreeIdCount(); + return highId - getDefragCount(); } @Override diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorFactory.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorFactory.java index ded8a351f9a39..525f4b0ce6a2e 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorFactory.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorFactory.java @@ -22,7 +22,6 @@ import java.io.File; import java.util.HashMap; import java.util.Map; -import java.util.function.BooleanSupplier; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.impl.store.id.IdGenerator; @@ -39,17 +38,14 @@ public class ReplicatedIdGeneratorFactory implements IdGeneratorFactory private final ReplicatedIdRangeAcquirer idRangeAcquirer; private final LogProvider logProvider; private IdTypeConfigurationProvider idTypeConfigurationProvider; - private final BooleanSupplier freeIdCondition; public ReplicatedIdGeneratorFactory( FileSystemAbstraction fs, ReplicatedIdRangeAcquirer idRangeAcquirer, - LogProvider logProvider, IdTypeConfigurationProvider idTypeConfigurationProvider, - BooleanSupplier freeIdCondition ) + LogProvider logProvider, IdTypeConfigurationProvider idTypeConfigurationProvider ) { this.fs = fs; this.idRangeAcquirer = idRangeAcquirer; this.logProvider = logProvider; this.idTypeConfigurationProvider = idTypeConfigurationProvider; - this.freeIdCondition = freeIdCondition; } @Override @@ -77,7 +73,7 @@ private IdGenerator openGenerator( File file, int grabSize, IdType idType, long } ReplicatedIdGenerator replicatedIdGenerator = new ReplicatedIdGenerator( fs, file, idType, highId, idRangeAcquirer, logProvider, grabSize, - aggressiveReuse, freeIdCondition ); + aggressiveReuse ); generators.put( idType, replicatedIdGenerator); return replicatedIdGenerator; diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorTest.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorTest.java index c017954bd2644..46fd96866351e 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorTest.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdGeneratorTest.java @@ -55,9 +55,6 @@ public class ReplicatedIdGeneratorTest extends IdGeneratorContractTest { - private static final BooleanSupplier NO_REUSE = () -> false; - private static final BooleanSupplier ALWAYS_REUSE = () -> true; - private NullLogProvider logProvider = NullLogProvider.getInstance(); @Rule @@ -70,6 +67,7 @@ public class ReplicatedIdGeneratorTest extends IdGeneratorContractTest private RaftMachine raftMachine = Mockito.mock( RaftMachine.class ); private ExposedRaftState state = mock( ExposedRaftState.class ); private final CommandIndexTracker commandIndexTracker = mock( CommandIndexTracker.class ); + private IdReusabilityCondition idReusabilityCondition; @Before public void setUp() throws Exception @@ -77,6 +75,7 @@ public void setUp() throws Exception file = testDirectory.file( "idgen" ); fs = fileSystemRule.get(); when( raftMachine.state() ).thenReturn( state ); + idReusabilityCondition = getIdReusabilityCondition(); } @Override @@ -88,8 +87,9 @@ protected IdGenerator createIdGenerator( int grabSize ) @Override protected IdGenerator openIdGenerator( int grabSize ) { - return new ReplicatedIdGenerator( fs, file, IdType.NODE, 0, stubAcquirer(), logProvider, grabSize, - true, NO_REUSE ); + ReplicatedIdGenerator replicatedIdGenerator = + new ReplicatedIdGenerator( fs, file, IdType.NODE, 0, stubAcquirer(), logProvider, grabSize, true ); + return new FreeIdFilteredIdGenerator( replicatedIdGenerator, idReusabilityCondition ); } @Test @@ -98,7 +98,7 @@ public void shouldCreateIdFileForPersistence() throws Exception ReplicatedIdRangeAcquirer rangeAcquirer = simpleRangeAcquirer( IdType.NODE, 0, 1024 ); ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, 0, rangeAcquirer, logProvider, - 10, true, NO_REUSE ); + 10, true ); assertTrue( fs.fileExists( file ) ); } @@ -109,7 +109,7 @@ public void shouldNotStepBeyondAllocationBoundaryWithoutBurnedId() throws Except ReplicatedIdRangeAcquirer rangeAcquirer = simpleRangeAcquirer( IdType.NODE, 0, 1024 ); ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, 0, rangeAcquirer, logProvider, - 10, true, NO_REUSE ); + 10, true ); Set idsGenerated = collectGeneratedIds( idGenerator, 1024 ); @@ -127,7 +127,7 @@ public void shouldNotStepBeyondAllocationBoundaryWithBurnedId() throws Exception int burnedIds = 23; ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, - 10, true, NO_REUSE ); + 10, true ); Set idsGenerated = collectGeneratedIds( idGenerator, 1024 - burnedIds ); @@ -145,7 +145,7 @@ public void shouldThrowIfAdjustmentFailsDueToInconsistentValues() throws Excepti when( rangeAcquirer.acquireIds( IdType.NODE ) ).thenReturn( allocation( 3, 21, 21 ) ); ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, 42, rangeAcquirer, logProvider, 10, - true, NO_REUSE ); + true ); idGenerator.nextId(); } @@ -155,11 +155,10 @@ public void shouldReuseIdOnlyWhenLeader() throws Exception { ReplicatedIdRangeAcquirer rangeAcquirer = simpleRangeAcquirer( IdType.NODE, 0, 1024 ); - IdReusabilityCondition idReusabilityCondition = getIdReusabilityCondition(); - int burnedIds = 23; - ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, - 10, true, idReusabilityCondition ); + IdGenerator idGenerator = new FreeIdFilteredIdGenerator( + new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, 10, true ), + idReusabilityCondition ); idGenerator.freeId( 10 ); assertEquals( 0, idGenerator.getDefragCount() ); @@ -182,7 +181,7 @@ public void shouldReuseIdBeforeHighId() throws Exception int burnedIds = 23; ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, - 10, true, ALWAYS_REUSE ); + 10, true ); assertEquals( 23, idGenerator.nextId() ); @@ -202,8 +201,9 @@ public void freeIdOnlyWhenReusabilityConditionAllows() throws Exception IdReusabilityCondition idReusabilityCondition = getIdReusabilityCondition(); int burnedIds = 23; - ReplicatedIdGenerator idGenerator = new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, - 10, true, idReusabilityCondition ); + FreeIdFilteredIdGenerator idGenerator = new FreeIdFilteredIdGenerator( + new ReplicatedIdGenerator( fs, file, IdType.NODE, burnedIds, rangeAcquirer, logProvider, 10, true ), + idReusabilityCondition ); idGenerator.freeId( 10 ); assertEquals( 0, idGenerator.getDefragCount() ); diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdRangeAcquirerTest.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdRangeAcquirerTest.java index 5ed55ab3beb94..a05bfb69c5bc5 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdRangeAcquirerTest.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/core/state/machines/id/ReplicatedIdRangeAcquirerTest.java @@ -120,6 +120,6 @@ private ReplicatedIdGenerator createForMemberWithInitialIdAndRangeLength( Member LeaderLocator leaderLocator = Mockito.mock( LeaderLocator.class ); return new ReplicatedIdGenerator( fs, file, IdType.ARRAY_BLOCK, initialHighId, acquirer, - NullLogProvider.getInstance(), 10, true, () -> false ); + NullLogProvider.getInstance(), 10, true ); } } diff --git a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/scenarios/ClusterIdReuseIT.java b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/scenarios/ClusterIdReuseIT.java index ca039b62192b4..cf7a0b405357c 100644 --- a/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/scenarios/ClusterIdReuseIT.java +++ b/enterprise/causal-clustering/src/test/java/org/neo4j/causalclustering/scenarios/ClusterIdReuseIT.java @@ -32,6 +32,7 @@ import org.neo4j.graphdb.Node; import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; import org.neo4j.kernel.impl.store.id.IdGenerator; +import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdType; import org.neo4j.test.causalclustering.ClusterRule; @@ -65,9 +66,9 @@ public void shouldReuseIdsInCluster() throws Exception assumeTrue( leader1 != null && leader1.equals( leader2 ) ); // Force maintenance on leader - IdController idController = idMaintenanceOnLeader( leader1 ); - - final IdGenerator idGenerator = idController.getIdGeneratorFactory().get( IdType.NODE ); + idMaintenanceOnLeader( leader1 ); + IdGeneratorFactory idGeneratorFactory = resolveDependency( leader1, IdGeneratorFactory.class ); + final IdGenerator idGenerator = idGeneratorFactory.get( IdType.NODE ); assertEquals( 2, idGenerator.getDefragCount() ); final MutableLong node1id = new MutableLong(); @@ -105,7 +106,9 @@ public void newLeaderShouldNotReuseIds() throws Exception assumeTrue( creationLeader != null && creationLeader.equals( deletionLeader ) ); - IdGenerator creationLeaderIdGenerator = idMaintenanceOnLeader( creationLeader ).getIdGeneratorFactory().get( IdType.NODE ); + idMaintenanceOnLeader( creationLeader ); + IdGeneratorFactory idGeneratorFactory = resolveDependency( creationLeader, IdGeneratorFactory.class ); + IdGenerator creationLeaderIdGenerator = idGeneratorFactory.get( IdType.NODE ); assertEquals( 2, creationLeaderIdGenerator.getDefragCount() ); // Force leader switch @@ -114,9 +117,10 @@ public void newLeaderShouldNotReuseIds() throws Exception // waiting for new leader CoreClusterMember newLeader = cluster.awaitLeader(); assertNotSame( creationLeader.serverId(), newLeader.serverId() ); - IdController idController = idMaintenanceOnLeader( newLeader ); + idMaintenanceOnLeader( newLeader ); - final IdGenerator idGenerator = idController.getIdGeneratorFactory().get( IdType.NODE ); + IdGeneratorFactory newLeaderIdGeneratorFactory = resolveDependency( newLeader, IdGeneratorFactory.class ); + final IdGenerator idGenerator = newLeaderIdGeneratorFactory.get( IdType.NODE ); assertEquals( 0, idGenerator.getDefragCount() ); CoreClusterMember newCreationLeader = cluster.coreTx( ( db, tx ) -> @@ -139,11 +143,10 @@ public void reusePreviouslyFreedIds() throws Exception CoreClusterMember deletionLeader = removeTwoNodes( cluster, first, second ); assumeTrue( creationLeader != null && creationLeader.equals( deletionLeader ) ); - - IdGenerator creationLeaderIdGenerator = idMaintenanceOnLeader( creationLeader ).getIdGeneratorFactory().get( IdType.NODE ); + IdGeneratorFactory idGeneratorFactory = resolveDependency( creationLeader, IdGeneratorFactory.class ); + IdGenerator creationLeaderIdGenerator = idGeneratorFactory.get( IdType.NODE ); assertEquals( 2, creationLeaderIdGenerator.getDefragCount() ); - // Restart and re-elect first leader cluster.removeCoreMemberWithMemberId( creationLeader.serverId() ); cluster.addCoreMemberWithId( creationLeader.serverId() ).start(); @@ -156,7 +159,9 @@ public void reusePreviouslyFreedIds() throws Exception leader = cluster.awaitLeader(); } - creationLeaderIdGenerator = idMaintenanceOnLeader( leader ).getIdGeneratorFactory().get( IdType.NODE ); + idMaintenanceOnLeader( leader ); + IdGeneratorFactory leaderIdGeneratorFactory = resolveDependency( leader, IdGeneratorFactory.class ); + creationLeaderIdGenerator = leaderIdGeneratorFactory.get( IdType.NODE ); assertEquals( 2, creationLeaderIdGenerator.getDefragCount() ); final MutableLong node1id = new MutableLong(); @@ -177,11 +182,15 @@ public void reusePreviouslyFreedIds() throws Exception assertEquals( second.longValue(), node2id.longValue() ); } - private IdController idMaintenanceOnLeader( CoreClusterMember leader ) throws TimeoutException + private void idMaintenanceOnLeader( CoreClusterMember leader ) throws TimeoutException { - IdController idController = leader.database().getDependencyResolver().resolveDependency( IdController.class ); + IdController idController = resolveDependency( leader, IdController.class ); idController.maintenance(); - return idController; + } + + private T resolveDependency( CoreClusterMember leader, Class clazz ) + { + return leader.database().getDependencyResolver().resolveDependency( clazz ); } private CoreClusterMember removeTwoNodes( Cluster cluster, MutableLong first, MutableLong second ) throws Exception diff --git a/enterprise/kernel/src/test/java/org/neo4j/graphdb/store/id/RelationshipIdReuseStressIT.java b/enterprise/kernel/src/test/java/org/neo4j/graphdb/store/id/RelationshipIdReuseStressIT.java index e3c5973ac2fc9..2820e5a3a99ac 100644 --- a/enterprise/kernel/src/test/java/org/neo4j/graphdb/store/id/RelationshipIdReuseStressIT.java +++ b/enterprise/kernel/src/test/java/org/neo4j/graphdb/store/id/RelationshipIdReuseStressIT.java @@ -48,7 +48,7 @@ import org.neo4j.helpers.collection.Iterators; import org.neo4j.kernel.DeadlockDetectedException; import org.neo4j.kernel.impl.enterprise.configuration.EnterpriseEditionSettings; -import org.neo4j.kernel.impl.storageengine.impl.recordstorage.id.IdController; +import org.neo4j.kernel.impl.store.id.IdGeneratorFactory; import org.neo4j.kernel.impl.store.id.IdType; import org.neo4j.test.rule.DatabaseRule; import org.neo4j.test.rule.EnterpriseDatabaseRule; @@ -105,8 +105,8 @@ public void relationshipIdReused() throws Exception private long getHighestUsedIdForRelationships() { - IdController idController = embeddedDatabase.getDependencyResolver().resolveDependency( IdController.class ); - return idController.getIdGeneratorFactory().get( IdType.RELATIONSHIP ).getHighestPossibleIdInUse(); + IdGeneratorFactory idGeneratorFactory = embeddedDatabase.getDependencyResolver().resolveDependency( IdGeneratorFactory.class ); + return idGeneratorFactory.get( IdType.RELATIONSHIP ).getHighestPossibleIdInUse(); } private void completeFutures( List futures )