From e5e63ea6a9e17f14c38d6818ce9e7cc6f72c27c7 Mon Sep 17 00:00:00 2001 From: Anton Persson Date: Mon, 2 Jan 2017 16:08:23 +0100 Subject: [PATCH] Test backwards seek in SeekCursorTest --- .../gbptree/PageAwareByteArrayCursor.java | 2 +- .../neo4j/index/gbptree/SeekCursorTest.java | 542 ++++++++++++++++-- 2 files changed, 490 insertions(+), 54 deletions(-) diff --git a/community/index/src/test/java/org/neo4j/index/gbptree/PageAwareByteArrayCursor.java b/community/index/src/test/java/org/neo4j/index/gbptree/PageAwareByteArrayCursor.java index faaa283b8bca8..62d9f4540c340 100644 --- a/community/index/src/test/java/org/neo4j/index/gbptree/PageAwareByteArrayCursor.java +++ b/community/index/src/test/java/org/neo4j/index/gbptree/PageAwareByteArrayCursor.java @@ -66,7 +66,7 @@ private void initialize() PageAwareByteArrayCursor duplicate() { - return new PageAwareByteArrayCursor( pages, pageSize, nextPageId ); + return new PageAwareByteArrayCursor( pages, pageSize, currentPageId ); } PageAwareByteArrayCursor duplicate( long nextPageId ) diff --git a/community/index/src/test/java/org/neo4j/index/gbptree/SeekCursorTest.java b/community/index/src/test/java/org/neo4j/index/gbptree/SeekCursorTest.java index f3d977411e6c0..18b20c352df74 100644 --- a/community/index/src/test/java/org/neo4j/index/gbptree/SeekCursorTest.java +++ b/community/index/src/test/java/org/neo4j/index/gbptree/SeekCursorTest.java @@ -77,7 +77,6 @@ public long getAsLong() private static long unstableGen = stableGen + 1; private long rootId; - private long rootGen; private int numberOfRootSplits; @Before @@ -91,7 +90,6 @@ public void setUp() throws IOException private void updateRoot() { rootId = cursor.getCurrentPageId(); - rootGen = unstableGen; treeLogic.initialize( cursor ); } @@ -116,6 +114,25 @@ public void mustFindEntriesWithinRangeInBeginningOfSingleLeaf() throws Exception } } + @Test + public void mustFindEntriesWithinRangeInBeginningOfSingleLeafBackwards() throws Exception + { + // GIVEN + for ( int i = 0; i < maxKeyCount; i++ ) + { + append( i ); + } + int fromInclusive = maxKeyCount / 2; + int toExclusive = -1; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + // THEN + assertRangeInSingleLeaf( fromInclusive, toExclusive, cursor ); + } + } + @Test public void mustFindEntriesWithinRangeInEndOfSingleLeaf() throws Exception { @@ -135,6 +152,25 @@ public void mustFindEntriesWithinRangeInEndOfSingleLeaf() throws Exception } } + @Test + public void mustFindEntriesWithinRangeInEndOfSingleLeafBackwards() throws Exception + { + // GIVEN + for ( int i = 0; i < maxKeyCount; i++ ) + { + append( i ); + } + int fromInclusive = this.maxKeyCount - 1; + int toExclusive = maxKeyCount / 2; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + // THEN + assertRangeInSingleLeaf( fromInclusive, toExclusive, cursor ); + } + } + @Test public void mustFindEntriesWithinRangeInMiddleOfSingleLeaf() throws Exception { @@ -155,6 +191,26 @@ public void mustFindEntriesWithinRangeInMiddleOfSingleLeaf() throws Exception } } + @Test + public void mustFindEntriesWithinRangeInMiddleOfSingleLeafBackwards() throws Exception + { + // GIVEN + for ( int i = 0; i < maxKeyCount; i++ ) + { + append( i ); + } + int middle = maxKeyCount / 2; + int fromInclusive = (middle + maxKeyCount) / 2; + int toExclusive = middle / 2; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + // THEN + assertRangeInSingleLeaf( fromInclusive, toExclusive, cursor ); + } + } + @Test public void mustFindEntriesSpanningTwoLeaves() throws Exception { @@ -184,6 +240,34 @@ public void mustFindEntriesSpanningTwoLeaves() throws Exception } } + @Test + public void mustFindEntriesSpanningTwoLeavesBackwards() throws Exception + { + // GIVEN + int i = 0; + while ( i < maxKeyCount ) + { + append( i ); + i++; + } + createRightSibling( cursor ); + while ( i < maxKeyCount * 2 ) + { + append( i ); + i++; + } + + int fromInclusive = maxKeyCount * 2 - 1; + int toExclusive = -1; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + // THEN + assertRangeInSingleLeaf( fromInclusive, toExclusive, cursor ); + } + } + @Test public void mustFindEntriesOnSecondLeafWhenStartingFromFirstLeaf() throws Exception { @@ -212,6 +296,32 @@ public void mustFindEntriesOnSecondLeafWhenStartingFromFirstLeaf() throws Except } } + @Test + public void mustFindEntriesOnSecondLeafWhenStartingFromFirstLeafBackwards() throws Exception + { + // GIVEN + int i = 0; + while ( i < maxKeyCount * 2 ) + { + if ( i == maxKeyCount ) + { + createRightSibling( cursor ); + } + append( i ); + i++; + } + + int fromInclusive = maxKeyCount - 1; + int toExclusive = -1; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + // THEN + assertRangeInSingleLeaf( fromInclusive, toExclusive, cursor ); + } + } + @Test public void mustNotContinueToSecondLeafAfterFindingEndOfRangeInFirst() throws Exception { @@ -228,7 +338,6 @@ public boolean next( long pageId ) throws IOException // GIVEN int i = 0; - long left = cursor.getCurrentPageId(); while ( i < maxKeyCount * 2 ) { if ( i == maxKeyCount ) @@ -238,10 +347,9 @@ public boolean next( long pageId ) throws IOException append( i ); i++; } - pageCursorSpy.next( left ); - int fromInclusive = 0; - int toExclusive = maxKeyCount - 1; + int fromInclusive = maxKeyCount * 2 - 1; + int toExclusive = maxKeyCount; // Reset nextCalled.set( false ); @@ -258,7 +366,7 @@ public boolean next( long pageId ) throws IOException /* INSERT */ @Test - public void mustFindNewKeyInsertedRightOfSeekPoint() throws Exception + public void mustFindNewKeyInsertedAfterOfSeekPoint() throws Exception { // GIVEN int middle = maxKeyCount / 2; @@ -294,6 +402,43 @@ public void mustFindNewKeyInsertedRightOfSeekPoint() throws Exception } } + @Test + public void mustFindNewKeyInsertedAfterOfSeekPointBackwards() throws Exception + { + // GIVEN + int middle = maxKeyCount / 2; + for ( int i = 1; i <= middle; i++ ) + { + append( i ); + } + int fromInclusive = middle; + int toExclusive = 0; // Will insert 0 later + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + int stopPoint = middle / 2; + int readKeys = 0; + while ( readKeys < stopPoint && cursor.next() ) + { + assertKeyAndValue( cursor, middle - readKeys ); + readKeys++; + } + + // Seeker pauses and writer insert new key at the end of leaf + insertIn( 0, 0 ); + this.cursor.forceRetry(); + + // Seeker continue + while ( cursor.next() ) + { + assertKeyAndValue( cursor, middle - readKeys ); + readKeys++; + } + assertEquals( toExclusive, middle - readKeys ); + } + } + @Test public void mustFindKeyInsertedOnSeekPosition() throws Exception { @@ -322,9 +467,52 @@ public void mustFindKeyInsertedOnSeekPosition() throws Exception } // Seeker pauses and writer insert new key in position where seeker will read next - long midInsert = (stopPoint * 2) - 1; + long midInsert = expected.get( stopPoint ) - 1; insertIn( stopPoint, midInsert ); - expected.add( readKeys, midInsert ); + expected.add( stopPoint, midInsert ); + this.cursor.forceRetry(); + + while ( cursor.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; + } + assertEquals( expected.size(), readKeys ); + } + } + + @Test + public void mustFindKeyInsertedOnSeekPositionBackwards() throws Exception + { + // GIVEN + List expected = new ArrayList<>(); + int middle = maxKeyCount / 2; + for ( int i = middle; i > 0; i-- ) + { + long key = i * 2; + insert( key, valueForKey( key ) ); + expected.add( key ); + } + int fromInclusive = middle * 2; + long toExclusive = 0; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + int stopPoint = middle / 2; + int readKeys = 0; + while ( readKeys < stopPoint && cursor.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; + } + + // Seeker pauses and writer insert new key in position where seeker will read next + long midInsert = expected.get( stopPoint ) + 1; + insert( midInsert, valueForKey( midInsert ) ); + expected.add( stopPoint, midInsert ); this.cursor.forceRetry(); while ( cursor.next() ) @@ -338,7 +526,7 @@ public void mustFindKeyInsertedOnSeekPosition() throws Exception } @Test - public void mustNotFindKeyInsertedLeftOfSeekPoint() throws Exception + public void mustNotFindKeyInsertedBeforeOfSeekPoint() throws Exception { // GIVEN List expected = new ArrayList<>(); @@ -365,7 +553,7 @@ public void mustNotFindKeyInsertedLeftOfSeekPoint() throws Exception } // Seeker pauses and writer insert new key to the left of seekers next position - long midInsert = ((stopPoint - 1) * 2) - 1; + long midInsert = expected.get( readKeys - 1 ) - 1; insertIn( stopPoint - 1, midInsert ); this.cursor.forceRetry(); @@ -379,6 +567,48 @@ public void mustNotFindKeyInsertedLeftOfSeekPoint() throws Exception } } + @Test + public void mustNotFindKeyInsertedBeforeOfSeekPointBackwards() throws Exception + { + // GIVEN + List expected = new ArrayList<>(); + int middle = maxKeyCount / 2; + for ( int i = middle; i > 0; i-- ) + { + long key = i * 2; + insert( key, valueForKey( key ) ); + expected.add( key ); + } + int fromInclusive = middle * 2; + long toExclusive = 0; + + // WHEN + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + { + int stopPoint = middle / 2; + int readKeys = 0; + while ( readKeys < stopPoint && cursor.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; + } + + // Seeker pauses and writer insert new key to the left of seekers next position + long midInsert = expected.get( readKeys - 1 ) + 1; + insert( midInsert, valueForKey( midInsert ) ); + this.cursor.forceRetry(); + + while ( cursor.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; + } + assertEquals( expected.size(), readKeys ); + } + } + /* INSERT INTO SPLIT */ @Test @@ -396,7 +626,9 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToLeft() th long toExclusive = maxKeyCount + 1; // We will add maxKeyCount later // WHEN - try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) { int middle = maxKeyCount / 2; int stopPoint = middle / 2; @@ -410,18 +642,9 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToLeft() th // Seeker pauses and writer insert new key which causes a split expected.add( (long) maxKeyCount ); + insert( (long) maxKeyCount ); - // Add rightmost keys to right sibling - long left = createRightSibling( this.cursor ); - for ( int i = middle; i <= maxKeyCount; i++ ) - { - Long key = expected.get( i ); - append( key ); - } - // Update keycount in left sibling - this.cursor.next( left ); - node.setKeyCount( this.cursor, middle ); - this.cursor.forceRetry(); + seekCursor.forceRetry(); while ( cursor.next() ) { @@ -433,6 +656,51 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToLeft() th } } + @Test + public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToRightBackwards() throws Exception + { + // GIVEN + List expected = new ArrayList<>(); + for ( int i = maxKeyCount; i > 0; i-- ) + { + long key = i; + insert( key ); + expected.add( key ); + } + int fromInclusive = maxKeyCount; + long toExclusive = -1; // We will add 0 later + + // WHEN + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor seeker = seekCursor( fromInclusive, toExclusive, seekCursor ) ) + { + int middle = maxKeyCount / 2; + int stopPoint = middle / 2; + int readKeys = 0; + while ( readKeys < stopPoint && seeker.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( seeker, key ); + readKeys++; + } + + // Seeker pauses and writer insert new key which causes a split + expected.add( 0L ); + insert( 0L); + + seekCursor.forceRetry(); + + while ( seeker.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( seeker, key ); + readKeys++; + } + assertEquals( expected.size(), readKeys ); + } + } + @Test public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToRight() throws Exception { @@ -441,14 +709,16 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToRight() t for ( int i = 0; i < maxKeyCount; i++ ) { long key = i; - append( key ); + insert( key ); expected.add( key ); } int fromInclusive = 0; long toExclusive = maxKeyCount + 1; // We will add maxKeyCount later // WHEN - try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) { int middle = maxKeyCount / 2; int stopPoint = middle + (middle / 2); @@ -462,18 +732,52 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToRight() t // Seeker pauses and writer insert new key which causes a split expected.add( (long) maxKeyCount ); + insert( (long) maxKeyCount ); + seekCursor.forceRetry(); - // Add rightmost keys to right sibling - long left = createRightSibling( this.cursor ); - for ( int i = middle; i <= maxKeyCount; i++ ) + while ( cursor.next() ) { - Long key = expected.get( i ); - append( key ); + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; } - // Update keycount in left sibling - this.cursor.next( left ); - node.setKeyCount( this.cursor, middle ); - this.cursor.forceRetry(); + assertEquals( expected.size(), readKeys ); + } + } + + @Test + public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToLeftBackwards() throws Exception + { + // GIVEN + List expected = new ArrayList<>(); + for ( int i = maxKeyCount; i > 0; i-- ) + { + long key = i; + insert( key ); + expected.add( key ); + } + int fromInclusive = maxKeyCount; + long toExclusive = -1; // We will add 0 later + + // WHEN + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) + { + int middle = maxKeyCount / 2; + int stopPoint = middle + (middle / 2); + int readKeys = 0; + while ( readKeys < stopPoint && cursor.next() ) + { + long key = expected.get( readKeys ); + assertKeyAndValue( cursor, key ); + readKeys++; + } + + // Seeker pauses and writer insert new key which causes a split + expected.add( 0L ); + insert( 0L ); + seekCursor.forceRetry(); while ( cursor.next() ) { @@ -488,7 +792,7 @@ public void mustContinueToNextLeafWhenRangeIsSplitIntoRightLeafAndPosToRight() t /* REMOVE */ @Test - public void mustNotFindKeyRemovedRightOfSeekPoint() throws Exception + public void mustNotFindKeyRemovedInFrontOfSeeker() throws Exception { // GIVEN // [0 1 ... maxKeyCount-1] @@ -514,7 +818,7 @@ public void mustNotFindKeyRemovedRightOfSeekPoint() throws Exception // Seeker pauses and writer remove rightmost key // [0 1 ... maxKeyCount-2] - remove( maxKeyCount - 1 ); + removeAtPos( maxKeyCount - 1 ); this.cursor.forceRetry(); while ( cursor.next() ) @@ -528,19 +832,61 @@ public void mustNotFindKeyRemovedRightOfSeekPoint() throws Exception } @Test - public void mustFindKeyMovedToLeftOfSeekPointBecauseOfRemove() throws Exception + public void mustNotFindKeyRemovedInFrontOfSeekerBackwards() throws Exception + { + // GIVEN + // [1 2 ... maxKeyCount] + for ( int i = 1; i <= maxKeyCount; i++ ) + { + insert( i ); + } + int fromInclusive = maxKeyCount; + int toExclusive = 0; + + // WHEN + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor seeker = seekCursor( fromInclusive, toExclusive, seekCursor ) ) + { + // THEN + int middle = maxKeyCount / 2; + int readKeys = 0; + while ( readKeys < middle && seeker.next() ) + { + assertKeyAndValue( seeker, maxKeyCount - readKeys ); + readKeys++; + } + + // Seeker pauses and writer remove rightmost key + // [2 ... maxKeyCount] + remove( 1 ); + seekCursor.forceRetry(); + + while ( seeker.next() ) + { + assertKeyAndValue( seeker, maxKeyCount - readKeys ); + readKeys++; + } + assertEquals( maxKeyCount - 1, readKeys ); + } + } + + @Test + public void mustFindKeyMovedPassedSeekerBecauseOfRemove() throws Exception { // GIVEN // [0 1 ... maxKeyCount-1] for ( int i = 0; i < maxKeyCount; i++ ) { - append( i ); + insert( i ); } int fromInclusive = 0; int toExclusive = maxKeyCount; // WHEN - try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) { // THEN int middle = maxKeyCount / 2; @@ -554,8 +900,8 @@ public void mustFindKeyMovedToLeftOfSeekPointBecauseOfRemove() throws Exception // Seeker pauses and writer remove rightmost key // [1 ... maxKeyCount-1] - remove( 0 ); - this.cursor.forceRetry(); + removeAtPos( 0 ); + seekCursor.forceRetry(); while ( cursor.next() ) { @@ -568,37 +914,115 @@ public void mustFindKeyMovedToLeftOfSeekPointBecauseOfRemove() throws Exception } @Test - public void mustFindKeyMovedToLeftOfSeekPointBecauseOfRemoveOfPreviouslyReturnedKey() throws Exception + public void mustFindKeyMovedPassedSeekerBecauseOfRemoveBackwards() throws Exception + { + // GIVEN + // [1 2... maxKeyCount] + for ( int i = maxKeyCount; i > 0; i-- ) + { + insert( i ); + } + int fromInclusive = maxKeyCount; + int toExclusive = 0; + + // WHEN + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) + { + // THEN + int middle = maxKeyCount / 2; + int readKeys = 0; + while ( readKeys < middle && cursor.next() ) + { + assertKeyAndValue( cursor, maxKeyCount - readKeys ); + readKeys++; + } + + // Seeker pauses and writer remove rightmost key + // [1 ... maxKeyCount-1] + remove( maxKeyCount ); + seekCursor.forceRetry(); + + while ( cursor.next() ) + { + assertKeyAndValue( cursor, maxKeyCount - readKeys ); + readKeys++; + } + assertEquals( maxKeyCount, readKeys ); + } + } + + @Test + public void mustFindKeyMovedSeekerBecauseOfRemoveOfMostRecentReturnedKey() throws Exception { // GIVEN for ( int i = 0; i < maxKeyCount; i++ ) { - append( i ); + insert( i ); } int fromInclusive = 0; int toExclusive = maxKeyCount; // WHEN - try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive ) ) + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) { // THEN int middle = maxKeyCount / 2; int readKeys = 0; while ( readKeys < middle && cursor.next() ) { - long key = readKeys; - assertKeyAndValue( cursor, key ); + assertKeyAndValue( cursor, readKeys ); readKeys++; } // Seeker pauses and writer remove rightmost key - remove( middle - 1 ); - this.cursor.forceRetry(); + remove( readKeys - 1 ); + seekCursor.forceRetry(); while ( cursor.next() ) { - long key = readKeys; - assertKeyAndValue( cursor, key ); + assertKeyAndValue( cursor, readKeys ); + readKeys++; + } + assertEquals( maxKeyCount, readKeys ); + } + } + + @Test + public void mustFindKeyMovedSeekerBecauseOfRemoveOfMostRecentReturnedKeyBackwards() throws Exception + { + // GIVEN + for ( int i = maxKeyCount; i > 0; i-- ) + { + insert( i ); + } + int fromInclusive = maxKeyCount; + int toExclusive = 0; + + // WHEN + PageAwareByteArrayCursor seekCursor = cursor.duplicate(); + seekCursor.next(); + try ( SeekCursor cursor = seekCursor( fromInclusive, toExclusive, seekCursor ) ) + { + // THEN + int middle = maxKeyCount / 2; + int readKeys = 0; + while ( readKeys < middle && cursor.next() ) + { + assertKeyAndValue( cursor, maxKeyCount - readKeys ); + readKeys++; + } + + // Seeker pauses and writer remove rightmost key + remove( maxKeyCount - readKeys + 1 ); + seekCursor.forceRetry(); + + while ( cursor.next() ) + { + assertKeyAndValue( cursor, maxKeyCount - readKeys ); readKeys++; } assertEquals( maxKeyCount, readKeys ); @@ -692,7 +1116,6 @@ public void shouldRereadSiblingIfReadFailureCausedByConcurrentCheckpoint() throw public void shouldFailOnSiblingReadFailureIfNotCausedByConcurrentCheckpoint() throws Exception { // given - long newRoot; long i = 0L; while ( numberOfRootSplits == 0 ) { @@ -1150,6 +1573,11 @@ private void corruptGSPP( PageAwareByteArrayCursor duplicate, int offset ) duplicate.putInt( offset + GenSafePointer.SIZE, ~someBytes ); } + private void insert( long key ) throws IOException + { + insert( key, valueForKey( key ) ); + } + private void insert( long key, long value ) throws IOException { insert( key, value, cursor ); @@ -1163,6 +1591,13 @@ private void insert( long key, long value, PageCursor cursor ) throws IOExceptio handleAfterChange(); } + private void remove( long key ) throws IOException + { + insertKey.setValue( key ); + treeLogic.remove( cursor, structurePropagation, insertKey, insertValue, stableGen, unstableGen ); + handleAfterChange(); + } + private void handleAfterChange() throws IOException { if ( structurePropagation.hasSplit ) @@ -1215,11 +1650,12 @@ private long createRightSibling( PageCursor pageCursor ) throws IOException private static void assertRangeInSingleLeaf( int fromInclusive, int toExclusive, SeekCursor cursor ) throws IOException { + int stride = fromInclusive <= toExclusive ? 1 : -1; long expectedKey = fromInclusive; while ( cursor.next() ) { assertKeyAndValue( cursor, expectedKey ); - expectedKey++; + expectedKey += stride; } assertEquals( toExclusive, expectedKey ); } @@ -1277,7 +1713,7 @@ private void insertIn( int pos, long k ) node.setKeyCount( cursor, keyCount + 1 ); } - private void remove( int pos ) + private void removeAtPos( int pos ) { int keyCount = node.keyCount( cursor ); node.removeKeyAt( cursor, pos, keyCount );