Skip to content

Commit

Permalink
Implement getAllEntriesReader for CombinedIndexAccessor
Browse files Browse the repository at this point in the history
  • Loading branch information
burqen authored and tinwelint committed Aug 4, 2017
1 parent 917dc5a commit e9aeb33
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 13 deletions.
Expand Up @@ -21,5 +21,7 @@

public interface BoundedIterable<RECORD> extends Iterable<RECORD>, AutoCloseable
{
long UNKNOWN_MAX_COUNT = -1;

long maxCount();
}
Expand Up @@ -30,7 +30,7 @@
import org.neo4j.index.internal.gbptree.Hit;
import org.neo4j.index.internal.gbptree.Layout;

class NumberAllEntriesReader<KEY extends SchemaNumberKey,VALUE extends SchemaNumberValue> implements BoundedIterable<Long>
public class NumberAllEntriesReader<KEY extends SchemaNumberKey,VALUE extends SchemaNumberValue> implements BoundedIterable<Long>
{
private final GBPTree<KEY,VALUE> tree;
private final Layout<KEY,VALUE> layout;
Expand Down Expand Up @@ -93,6 +93,6 @@ public void close() throws Exception
@Override
public long maxCount()
{
return -1;
return UNKNOWN_MAX_COUNT;
}
}
Expand Up @@ -21,9 +21,11 @@

import java.io.File;
import java.io.IOException;
import java.util.Iterator;

import org.neo4j.graphdb.ResourceIterator;
import org.neo4j.helpers.collection.BoundedIterable;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.kernel.api.exceptions.index.IndexEntryConflictException;
import org.neo4j.kernel.api.index.IndexAccessor;
import org.neo4j.kernel.api.index.IndexUpdater;
Expand Down Expand Up @@ -93,7 +95,38 @@ public IndexReader newReader()
@Override
public BoundedIterable<Long> newAllEntriesReader()
{
return null;
BoundedIterable<Long> boostAllEntries = boostAccessor.newAllEntriesReader();
BoundedIterable<Long> fallbackAllEntries = fallbackAccessor.newAllEntriesReader();
return new BoundedIterable<Long>()
{
@Override
public long maxCount()
{
long boostMaxCount = boostAllEntries.maxCount();
long fallbackMaxCount = fallbackAllEntries.maxCount();
return boostMaxCount == UNKNOWN_MAX_COUNT || fallbackMaxCount == UNKNOWN_MAX_COUNT ?
UNKNOWN_MAX_COUNT : boostMaxCount + fallbackMaxCount;
}

@Override
public void close() throws Exception
{
try
{
boostAllEntries.close();
}
finally
{
fallbackAllEntries.close();
}
}

@Override
public Iterator<Long> iterator()
{
return Iterables.concat( boostAllEntries, fallbackAllEntries ).iterator();
}
};
}

@Override
Expand Down
Expand Up @@ -23,20 +23,27 @@
import org.junit.Test;

import java.io.IOException;
import java.util.Set;

import org.neo4j.helpers.collection.BoundedIterable;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.helpers.collection.Iterators;
import org.neo4j.kernel.api.index.IndexAccessor;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.sameInstance;
import static org.hamcrest.core.AnyOf.anyOf;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;
import static org.neo4j.kernel.impl.index.schema.combined.CombinedIndexTestHelp.verifyCombinedThrowIfBothThrow;
import static org.neo4j.kernel.impl.index.schema.combined.CombinedIndexTestHelp.verifyFailOnSingleCloseFailure;
import static org.neo4j.kernel.impl.index.schema.combined.CombinedIndexTestHelp.verifyCombinedCloseThrowIfBothThrow;
import static org.neo4j.kernel.impl.index.schema.combined.CombinedIndexTestHelp.verifyCombinedCloseThrowOnSingleCloseThrow;
import static org.neo4j.kernel.impl.index.schema.combined.CombinedIndexTestHelp.verifyOtherIsClosedOnSingleThrow;

public class CombinedIndexAccessorTest
Expand Down Expand Up @@ -135,13 +142,13 @@ public void closeMustCloseBoostAndFallback() throws Exception
@Test
public void closeMustThrowIfFallbackThrow() throws Exception
{
verifyFailOnSingleCloseFailure( fallbackAccessor, combinedIndexAccessor );
verifyCombinedCloseThrowOnSingleCloseThrow( fallbackAccessor, combinedIndexAccessor );
}

@Test
public void closeMustThrowIfBoostThrow() throws Exception
{
verifyFailOnSingleCloseFailure( boostAccessor, combinedIndexAccessor );
verifyCombinedCloseThrowOnSingleCloseThrow( boostAccessor, combinedIndexAccessor );
}

@Test
Expand All @@ -159,6 +166,218 @@ public void closeMustCloseFallbackIfBoostThrow() throws Exception
@Test
public void closeMustThrowIfBothFail() throws Exception
{
verifyCombinedThrowIfBothThrow( boostAccessor, fallbackAccessor, combinedIndexAccessor );
verifyCombinedCloseThrowIfBothThrow( boostAccessor, fallbackAccessor, combinedIndexAccessor );
}

// newAllEntriesReader

@Test
public void allEntriesReaderMustCombineResultFromBoostAndFallback() throws Exception
{
// given
long[] boostEntries = {0, 1, 2, 5, 6};
long[] fallbackEntries = {3, 4, 7, 8};
mockAllEntriesReaders( boostEntries, fallbackEntries );

// when
Set<Long> result = Iterables.asSet( combinedIndexAccessor.newAllEntriesReader() );

// then
assertResultContainsAll( result, boostEntries );
assertResultContainsAll( result, fallbackEntries );
}

@Test
public void allEntriesReaderMustCombineResultFromBoostAndFallbackWithEmptyBoost() throws Exception
{
// given
long[] boostEntries = new long[0];
long[] fallbackEntries = {3, 4, 7, 8};
mockAllEntriesReaders( boostEntries, fallbackEntries );

// when
Set<Long> result = Iterables.asSet( combinedIndexAccessor.newAllEntriesReader() );

// then
assertResultContainsAll( result, boostEntries );
assertResultContainsAll( result, fallbackEntries );
}

@Test
public void allEntriesReaderMustCombineResultFromBoostAndFallbackWithEmptyFallback() throws Exception
{
// given
long[] boostEntries = {0, 1, 2, 5, 6};
long[] fallbackEntries = new long[0];
mockAllEntriesReaders( boostEntries, fallbackEntries );

// when
Set<Long> result = Iterables.asSet( combinedIndexAccessor.newAllEntriesReader() );

// then
assertResultContainsAll( result, boostEntries );
assertResultContainsAll( result, fallbackEntries );
}

@Test
public void allEntriesReaderMustCombineResultFromBoostAndFallbackBothEmpty() throws Exception
{
// given
long[] boostEntries = new long[0];
long[] fallbackEntries = new long[0];
mockAllEntriesReaders( boostEntries, fallbackEntries );

// when
Set<Long> result = Iterables.asSet( combinedIndexAccessor.newAllEntriesReader() );

// then
assertResultContainsAll( result, boostEntries );
assertResultContainsAll( result, fallbackEntries );
assertTrue( result.isEmpty() );
}

@Test
public void allEntriesReaderMustCloseBothBoostAndFallback() throws Exception
{
// given
BoundedIterable<Long> boostAllEntriesReader = mockSingleAllEntriesReader( boostAccessor, new long[0] );
BoundedIterable<Long> fallbackAllEntriesReader = mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// when
combinedIndexAccessor.newAllEntriesReader().close();

// then
verify( boostAllEntriesReader, times( 1 ) ).close();
verify( fallbackAllEntriesReader, times( 1 ) ).close();
}

@Test
public void allEntriesReaderMustCloseBoostIfFallbackThrow() throws Exception
{
// given
BoundedIterable<Long> boostAllEntriesReader = mockSingleAllEntriesReader( boostAccessor, new long[0] );
BoundedIterable<Long> fallbackAllEntriesReader = mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
verifyOtherIsClosedOnSingleThrow( fallbackAllEntriesReader, boostAllEntriesReader, combinedAllEntriesReader );
}

@Test
public void allEntriesReaderMustCloseFallbackIfBoostThrow() throws Exception
{
// given
BoundedIterable<Long> boostAllEntriesReader = mockSingleAllEntriesReader( boostAccessor, new long[0] );
BoundedIterable<Long> fallbackAllEntriesReader = mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
verifyOtherIsClosedOnSingleThrow( boostAllEntriesReader, fallbackAllEntriesReader, combinedAllEntriesReader );
}

@Test
public void allEntriesReaderMustThrowIfFallbackThrow() throws Exception
{
// given
mockSingleAllEntriesReader( boostAccessor, new long[0] );
BoundedIterable<Long> fallbackAllEntriesReader = mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
CombinedIndexTestHelp.verifyCombinedCloseThrowOnSingleCloseThrow( fallbackAllEntriesReader, combinedAllEntriesReader );
}

@Test
public void allEntriesReaderMustThrowIfBoostThrow() throws Exception
{
// given
BoundedIterable<Long> boostAllEntriesReader = mockSingleAllEntriesReader( boostAccessor, new long[0] );
mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
CombinedIndexTestHelp.verifyCombinedCloseThrowOnSingleCloseThrow( boostAllEntriesReader, combinedAllEntriesReader );

}

@Test
public void allEntriesReaderMustReportUnknownMaxCountIfBoostReportUnknownMaxCount() throws Exception
{
// given
mockSingleAllEntriesReaderWithUnknownMaxCount( boostAccessor, new long[0] );
mockSingleAllEntriesReader( fallbackAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
assertThat( combinedAllEntriesReader.maxCount(), is( BoundedIterable.UNKNOWN_MAX_COUNT ) );
}

@Test
public void allEntriesReaderMustReportUnknownMaxCountIfFallbackReportUnknownMaxCount() throws Exception
{
// given
mockSingleAllEntriesReaderWithUnknownMaxCount( fallbackAccessor, new long[0] );
mockSingleAllEntriesReader( boostAccessor, new long[0] );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
assertThat( combinedAllEntriesReader.maxCount(), is( BoundedIterable.UNKNOWN_MAX_COUNT ) );
}

@Test
public void allEntriesReaderMustReportCombinedMaxCountOfBoostAndFallback() throws Exception
{
mockSingleAllEntriesReader( boostAccessor, new long[]{1, 2} );
mockSingleAllEntriesReader( fallbackAccessor, new long[]{3, 4} );

// then
BoundedIterable<Long> combinedAllEntriesReader = combinedIndexAccessor.newAllEntriesReader();
assertThat( combinedAllEntriesReader.maxCount(), is( 4L ) );
}

private void assertResultContainsAll( Set<Long> result, long[] boostEntries )
{
for ( long boostEntry : boostEntries )
{
assertTrue( "Expected to contain " + boostEntry + ", but was " + result, result.contains( boostEntry ) );
}
}

private void mockAllEntriesReaders( long[] boostEntries, long[] fallbackEntries )
{
mockSingleAllEntriesReader( boostAccessor, boostEntries );
mockSingleAllEntriesReader( fallbackAccessor, fallbackEntries );
}

private BoundedIterable<Long> mockSingleAllEntriesReader( IndexAccessor targetAccessor, long[] entries )
{
BoundedIterable<Long> allEntriesReader = mockedAllEntriesReader( entries );
when( targetAccessor.newAllEntriesReader() ).thenReturn( allEntriesReader );
return allEntriesReader;
}

private BoundedIterable<Long> mockedAllEntriesReader( long... entries )
{
return mockedAllEntriesReader( true, entries );
}

private BoundedIterable<Long> mockSingleAllEntriesReaderWithUnknownMaxCount( IndexAccessor targetAccessor, long[] entries )
{
BoundedIterable<Long> allEntriesReader = mockedAllEntriesReaderUnknownMaxCount( entries );
when( targetAccessor.newAllEntriesReader() ).thenReturn( allEntriesReader );
return allEntriesReader;
}

private BoundedIterable<Long> mockedAllEntriesReaderUnknownMaxCount( long... entries )
{
return mockedAllEntriesReader( false, entries );
}

private BoundedIterable<Long> mockedAllEntriesReader( boolean knownMaxCount, long... entries )
{
BoundedIterable<Long> mockedAllEntriesReader = mock( BoundedIterable.class );
when( mockedAllEntriesReader.maxCount() ).thenReturn( knownMaxCount ? entries.length : BoundedIterable.UNKNOWN_MAX_COUNT );
when( mockedAllEntriesReader.iterator() ).thenReturn( Iterators.asIterator(entries ) );
return mockedAllEntriesReader;
}
}
Expand Up @@ -154,7 +154,7 @@ static void verifyOtherIsClosedOnSingleThrow( AutoCloseable failingCloseable, Au
verify( successfulCloseable, Mockito.times( 1 ) ).close();
}

static void verifyFailOnSingleCloseFailure( AutoCloseable failingCloseable, AutoCloseable combinedCloseable )
static void verifyCombinedCloseThrowOnSingleCloseThrow( AutoCloseable failingCloseable, AutoCloseable combinedCloseable )
throws Exception
{
IOException expectedFailure = new IOException( "fail" );
Expand All @@ -170,7 +170,7 @@ static void verifyFailOnSingleCloseFailure( AutoCloseable failingCloseable, Auto
}
}

static void verifyCombinedThrowIfBothThrow( AutoCloseable boostCloseable, AutoCloseable fallbackCloseable,
static void verifyCombinedCloseThrowIfBothThrow( AutoCloseable boostCloseable, AutoCloseable fallbackCloseable,
AutoCloseable combinedCloseable ) throws Exception
{
// given
Expand Down
Expand Up @@ -272,13 +272,13 @@ public void closeMustCloseBothBoostAndFallback() throws Exception
@Test
public void closeMustThrowIfFallbackThrow() throws Exception
{
CombinedIndexTestHelp.verifyFailOnSingleCloseFailure( fallbackUpdater, combinedIndexUpdater );
CombinedIndexTestHelp.verifyCombinedCloseThrowOnSingleCloseThrow( fallbackUpdater, combinedIndexUpdater );
}

@Test
public void closeMustThrowIfBoostThrow() throws Exception
{
CombinedIndexTestHelp.verifyFailOnSingleCloseFailure( boostUpdater, combinedIndexUpdater );
CombinedIndexTestHelp.verifyCombinedCloseThrowOnSingleCloseThrow( boostUpdater, combinedIndexUpdater );
}

@Test
Expand All @@ -296,6 +296,6 @@ public void closeMustCloseFallbackIfBoostThrow() throws Exception
@Test
public void closeMustThrowIfBothThrow() throws Exception
{
CombinedIndexTestHelp.verifyCombinedThrowIfBothThrow( boostUpdater, fallbackUpdater, combinedIndexUpdater );
CombinedIndexTestHelp.verifyCombinedCloseThrowIfBothThrow( boostUpdater, fallbackUpdater, combinedIndexUpdater );
}
}

0 comments on commit e9aeb33

Please sign in to comment.