private DatabaseIdContext createBufferingIdContext( Function<String,? extends IdGeneratorFactory> idGeneratorFactoryProvider, JobScheduler jobScheduler, String databaseName ) { IdGeneratorFactory idGeneratorFactory = idGeneratorFactoryProvider.apply( databaseName ); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( idGeneratorFactory, eligibleForIdReuse, idTypeConfigurationProvider ); BufferedIdController bufferingController = createBufferedIdController( bufferingIdGeneratorFactory, jobScheduler ); return createIdContext( bufferingIdGeneratorFactory, bufferingController ); }
@Test public void shouldDelayFreeingOfAggressivelyReusedIds() { // GIVEN MockedIdGeneratorFactory actual = new MockedIdGeneratorFactory(); ControllableSnapshotSupplier boundaries = new ControllableSnapshotSupplier(); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( actual, IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider() ); bufferingIdGeneratorFactory.initialize( boundaries ); IdGenerator idGenerator = bufferingIdGeneratorFactory.open( new File( "doesnt-matter" ), 10, IdType.STRING_BLOCK, () -> 0L, Integer.MAX_VALUE ); // WHEN idGenerator.freeId( 7 ); verifyNoMoreInteractions( actual.get( IdType.STRING_BLOCK ) ); // after some maintenance and transaction still not closed bufferingIdGeneratorFactory.maintenance(); verifyNoMoreInteractions( actual.get( IdType.STRING_BLOCK ) ); // although after transactions have all closed boundaries.setMostRecentlyReturnedSnapshotToAllClosed(); bufferingIdGeneratorFactory.maintenance(); // THEN verify( actual.get( IdType.STRING_BLOCK ) ).freeId( 7 ); }
mock( Procedures.class ), IOLimiter.UNLIMITED, databaseAvailabilityGuard, clock, new CanWrite(), new StoreCopyCheckPointMutex(), RecoveryCleanupWorkCollector.immediate(), new BufferedIdController( new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, idConfigurationProvider ), jobScheduler ), DatabaseInfo.COMMUNITY, new TransactionVersionContextSupplier(), ON_HEAP, Collections.emptyList(), file -> EMPTY_WATCHER, new GraphDatabaseFacade(), Iterables.empty() ) );
@Test public void shouldDelayFreeingOfAggressivelyReusedIdsConsideringTimeAsWell() { // GIVEN MockedIdGeneratorFactory actual = new MockedIdGeneratorFactory(); final FakeClock clock = Clocks.fakeClock(); final long safeZone = MINUTES.toMillis( 1 ); ControllableSnapshotSupplier boundaries = new ControllableSnapshotSupplier(); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( actual, t -> clock.millis() - t.snapshotTime() >= safeZone, new CommunityIdTypeConfigurationProvider() ); bufferingIdGeneratorFactory.initialize( boundaries ); IdGenerator idGenerator = bufferingIdGeneratorFactory.open( new File( "doesnt-matter" ), 10, IdType.STRING_BLOCK, () -> 0L, Integer.MAX_VALUE ); // WHEN idGenerator.freeId( 7 ); verifyNoMoreInteractions( actual.get( IdType.STRING_BLOCK ) ); // after some maintenance and transaction still not closed bufferingIdGeneratorFactory.maintenance(); verifyNoMoreInteractions( actual.get( IdType.STRING_BLOCK ) ); // although after transactions have all closed boundaries.setMostRecentlyReturnedSnapshotToAllClosed(); bufferingIdGeneratorFactory.maintenance(); // ... the clock would still say "nope" so no interaction verifyNoMoreInteractions( actual.get( IdType.STRING_BLOCK ) ); // then finally after time has passed as well clock.forward( 70, SECONDS ); bufferingIdGeneratorFactory.maintenance(); // THEN verify( actual.get( IdType.STRING_BLOCK ) ).freeId( 7 ); }
private RecordStorageEngine get( FileSystemAbstraction fs, PageCache pageCache, IndexProvider indexProvider, DatabaseHealth databaseHealth, DatabaseLayout databaseLayout, Function<BatchTransactionApplierFacade, BatchTransactionApplierFacade> transactionApplierTransformer, Monitors monitors, LockService lockService ) { IdGeneratorFactory idGeneratorFactory = new EphemeralIdGenerator.Factory(); ExplicitIndexProvider explicitIndexProviderLookup = mock( ExplicitIndexProvider.class ); when( explicitIndexProviderLookup.allIndexProviders() ).thenReturn( Iterables.empty() ); IndexConfigStore indexConfigStore = new IndexConfigStore( databaseLayout, fs ); JobScheduler scheduler = life.add( createScheduler() ); Config config = Config.defaults( GraphDatabaseSettings.default_schema_provider, indexProvider.getProviderDescriptor().name() ); Dependencies dependencies = new Dependencies(); dependencies.satisfyDependency( indexProvider ); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( idGeneratorFactory, IdReuseEligibility.ALWAYS, new CommunityIdTypeConfigurationProvider() ); DefaultIndexProviderMap indexProviderMap = new DefaultIndexProviderMap( dependencies, config ); NullLogProvider nullLogProvider = NullLogProvider.getInstance(); life.add( indexProviderMap ); return life.add( new ExtendedRecordStorageEngine( databaseLayout, config, pageCache, fs, nullLogProvider, nullLogProvider, mockedTokenHolders(), mock( SchemaState.class ), new StandardConstraintSemantics(), scheduler, mock( TokenNameLookup.class ), lockService, indexProviderMap, IndexingService.NO_MONITOR, databaseHealth, explicitIndexProviderLookup, indexConfigStore, new SynchronizedArrayIdOrderingQueue(), idGeneratorFactory, new BufferedIdController( bufferingIdGeneratorFactory, scheduler ), transactionApplierTransformer, monitors, RecoveryCleanupWorkCollector.immediate(), OperationalMode.single ) ); }
private DatabaseIdContext createBufferingIdContext( Function<String,? extends IdGeneratorFactory> idGeneratorFactoryProvider, JobScheduler jobScheduler, String databaseName ) { IdGeneratorFactory idGeneratorFactory = idGeneratorFactoryProvider.apply( databaseName ); BufferingIdGeneratorFactory bufferingIdGeneratorFactory = new BufferingIdGeneratorFactory( idGeneratorFactory, eligibleForIdReuse, idTypeConfigurationProvider ); BufferedIdController bufferingController = createBufferedIdController( bufferingIdGeneratorFactory, jobScheduler ); return createIdContext( bufferingIdGeneratorFactory, bufferingController ); }