@Test public void shouldContinueThroughEmptyIdBatch() { // given IdSequence idSource = mock( IdSequence.class ); Iterator<IdRange> ranges = asList( new IdRange( EMPTY_LONG_ARRAY, 0, BATCH_SIZE ), new IdRange( EMPTY_LONG_ARRAY, BATCH_SIZE, 0 ), new IdRange( EMPTY_LONG_ARRAY, BATCH_SIZE, BATCH_SIZE ) ).iterator(); when( idSource.nextIdBatch( anyInt() ) ).thenAnswer( invocation -> ranges.next() ); RenewableBatchIdSequence ids = new RenewableBatchIdSequence( idSource, BATCH_SIZE, excessIds::add ); // when/then for ( long expectedId = 0; expectedId < BATCH_SIZE * 2; expectedId++ ) { assertEquals( expectedId, ids.nextId() ); } }
@Test public void shouldOnlyCloseOnce() { // given for ( int i = 0; i < BATCH_SIZE / 2; i++ ) { ids.nextId(); } // when ids.close(); // then for ( long i = BATCH_SIZE / 2; i < BATCH_SIZE; i++ ) { assertTrue( excessIds.remove( i ) ); } // and when closing one more time ids.close(); // then assertTrue( excessIds.isEmpty() ); }
@Override public void close() { for ( StoreType type : StoreType.values() ) { IdSequence generator = idGenerator( type ); if ( generator instanceof RenewableBatchIdSequence ) { ((RenewableBatchIdSequence)generator).close(); } } } }
public RenewableBatchIdSequences( NeoStores stores, int batchSize ) { for ( StoreType type : StoreType.values() ) { if ( type.isRecordStore() ) { RecordStore<AbstractBaseRecord> store = stores.getRecordStore( type ); if ( type.isLimitedIdStore() || batchSize == 1 ) { // This is a token store or otherwise meta-data store, so let's not add batching for it types[type.ordinal()] = store; } else { // This is a normal record store where id batching is beneficial types[type.ordinal()] = new RenewableBatchIdSequence( store, batchSize, store::freeId ); } } } }
@Test public void shouldRequestIdBatchFromSourceOnFirstCall() { // given assertEquals( 0, idSource.calls ); // when/then assertEquals( 0, ids.nextId() ); assertEquals( 1, idSource.calls ); for ( int i = 1; i < BATCH_SIZE; i++ ) { assertEquals( i, ids.nextId() ); assertEquals( 1, idSource.calls ); } }
@Test public void shouldHandleCloseWithNoCurrentBatch() { // when ids.close(); // then assertTrue( excessIds.isEmpty() ); }
public RenewableBatchIdSequences( NeoStores stores, int batchSize ) { for ( StoreType type : StoreType.values() ) { if ( type.isRecordStore() ) { RecordStore<AbstractBaseRecord> store = stores.getRecordStore( type ); if ( type.isLimitedIdStore() || batchSize == 1 ) { // This is a token store or otherwise meta-data store, so let's not add batching for it types[type.ordinal()] = store; } else { // This is a normal record store where id batching is beneficial types[type.ordinal()] = new RenewableBatchIdSequence( store, batchSize, store::freeId ); } } } }
@Test public void shouldRequestIdBatchFromSourceOnDepletingCurrent() { // given assertEquals( 0, idSource.calls ); for ( int i = 0; i < BATCH_SIZE; i++ ) { assertEquals( i, ids.nextId() ); } assertEquals( 1, idSource.calls ); // when long firstIdOfNextBatch = ids.nextId(); // then assertEquals( BATCH_SIZE, firstIdOfNextBatch ); assertEquals( 2, idSource.calls ); }
@Test public void shouldGiveBackExcessIdsOnClose() { // given for ( int i = 0; i < BATCH_SIZE / 2; i++ ) { ids.nextId(); } // when ids.close(); // then assertEquals( BATCH_SIZE - BATCH_SIZE / 2, excessIds.size() ); for ( long i = BATCH_SIZE / 2; i < BATCH_SIZE; i++ ) { assertTrue( excessIds.contains( i ) ); } }
@Override public void close() { for ( StoreType type : StoreType.values() ) { IdSequence generator = idGenerator( type ); if ( generator instanceof RenewableBatchIdSequence ) { ((RenewableBatchIdSequence)generator).close(); } } } }