diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/ConsistencyChecker.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/ConsistencyChecker.java index 48e98c0e78923..3cba8c698bad0 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/ConsistencyChecker.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/ConsistencyChecker.java @@ -27,6 +27,7 @@ import java.util.Comparator; import java.util.List; +import org.neo4j.index.internal.gbptree.GenerationSafePointerPair.GenerationTarget; import org.neo4j.io.pagecache.CursorException; import org.neo4j.io.pagecache.PageCursor; @@ -55,6 +56,7 @@ class ConsistencyChecker private final List rightmostPerLevel = new ArrayList<>(); private final long stableGeneration; private final long unstableGeneration; + private final GenerationKeeper generationTarget = new GenerationKeeper(); ConsistencyChecker( TreeNode node, Layout layout, long stableGeneration, long unstableGeneration ) { @@ -252,16 +254,16 @@ private boolean checkSubtree( PageCursor cursor, KeyRange range, long expec cursor, stableGeneration, unstableGeneration, "Successor", TreeNode.BYTE_POS_SUCCESSOR ); // for assertSiblings - leftSiblingPointer = TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration ); - rightSiblingPointer = TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration ); - leftSiblingPointerGeneration = node.pointerGeneration( cursor, leftSiblingPointer ); - rightSiblingPointerGeneration = node.pointerGeneration( cursor, rightSiblingPointer ); + leftSiblingPointer = TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration, generationTarget ); + leftSiblingPointerGeneration = generationTarget.generation; + rightSiblingPointer = TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration, generationTarget ); + rightSiblingPointerGeneration = generationTarget.generation; leftSiblingPointer = pointer( leftSiblingPointer ); rightSiblingPointer = pointer( rightSiblingPointer ); currentNodeGeneration = TreeNode.generation( cursor ); - successor = TreeNode.successor( cursor, stableGeneration, unstableGeneration ); - successorGeneration = node.pointerGeneration( cursor, successor ); + successor = TreeNode.successor( cursor, stableGeneration, unstableGeneration, generationTarget ); + successorGeneration = generationTarget.generation; keyCount = TreeNode.keyCount( cursor ); if ( !node.reasonableKeyCount( keyCount ) ) @@ -363,8 +365,8 @@ private void assertSubtrees( PageCursor cursor, KeyRange range, int keyCoun long childGeneration; do { - child = childAt( cursor, pos ); - childGeneration = node.pointerGeneration( cursor, child ); + child = childAt( cursor, pos, generationTarget ); + childGeneration = generationTarget.generation; node.keyAt( cursor, readKey, pos, INTERNAL ); } while ( cursor.shouldRetry() ); @@ -394,14 +396,8 @@ private void assertSubtrees( PageCursor cursor, KeyRange range, int keyCoun long childGeneration; do { - child = childAt( cursor, pos ); - } - while ( cursor.shouldRetry() ); - checkAfterShouldRetry( cursor ); - - do - { - childGeneration = node.pointerGeneration( cursor, child ); + child = childAt( cursor, pos, generationTarget ); + childGeneration = generationTarget.generation; } while ( cursor.shouldRetry() ); checkAfterShouldRetry( cursor ); @@ -418,11 +414,11 @@ private static void checkAfterShouldRetry( PageCursor cursor ) throws CursorExce cursor.checkAndClearCursorException(); } - private long childAt( PageCursor cursor, int pos ) + private long childAt( PageCursor cursor, int pos, GenerationTarget childGeneration ) { assertNoCrashOrBrokenPointerInGSPP( cursor, stableGeneration, unstableGeneration, "Child", node.childOffset( pos ) ); - return node.childAt( cursor, pos, stableGeneration, unstableGeneration ); + return node.childAt( cursor, pos, stableGeneration, unstableGeneration, childGeneration ); } private void assertKeyOrder( PageCursor cursor, KeyRange range, int keyCount, TreeNode.Type type ) diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationKeeper.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationKeeper.java new file mode 100644 index 0000000000000..3981753888397 --- /dev/null +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationKeeper.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.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 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.index.internal.gbptree; + +import org.neo4j.index.internal.gbptree.GenerationSafePointerPair.GenerationTarget; + +/** + * {@link GenerationTarget} which has its own generation field. + */ +class GenerationKeeper implements GenerationTarget +{ + long generation; + + @Override + public void accept( long generation ) + { + this.generation = generation; + } +} diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointer.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointer.java index 0973ec12f1d19..cb1ba72b2fe72 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointer.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointer.java @@ -48,7 +48,7 @@ class GenerationSafePointer { private static final int EMPTY_POINTER = 0; - private static final int EMPTY_GENERATION = 0; + static final int EMPTY_GENERATION = 0; static final long MIN_GENERATION = 1L; // unsigned int diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPair.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPair.java index 40212288f36c0..62a40ad35b1cb 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPair.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPair.java @@ -22,6 +22,7 @@ import org.neo4j.io.pagecache.PageCursor; import static java.lang.String.format; +import static org.neo4j.index.internal.gbptree.GenerationSafePointer.EMPTY_GENERATION; import static org.neo4j.index.internal.gbptree.GenerationSafePointer.MIN_GENERATION; import static org.neo4j.index.internal.gbptree.GenerationSafePointer.checksumOf; import static org.neo4j.index.internal.gbptree.GenerationSafePointer.readChecksum; @@ -77,19 +78,14 @@ * *
  *     READ success
- * [00__,____][____,____][ ... 6B pointer data ... ]
- *  ▲ ▲▲ ▲             ▲
- *  │ ││ └──────┬──────┘
- *  │ ││        └─────────────────────────────────────── GENERATION OFFSET or CHILD POS
- *  │ │└──────────────────────────────────────────────── 0:{@link #FLAG_ABS_OFFSET}/1:{@link #FLAG_LOGICAL_POS}
- *  │ └───────────────────────────────────────────────── 0:{@link #FLAG_SLOT_A}/1:{@link #FLAG_SLOT_B}
- *  └─────────────────────────────────────────────────── 0:{@link #FLAG_SUCCESS}/1:{@link #FLAG_FAIL}
+ * [00_ ,    ][    ,    ][ ... 6B pointer data ... ]
+ *    ▲
+ *    └───────────────────────────────────────────────── 0:{@link #FLAG_SLOT_A}/1:{@link #FLAG_SLOT_B}
  * 
*/ class GenerationSafePointerPair { static final int SIZE = GenerationSafePointer.SIZE * 2; - static final int NO_LOGICAL_POS = -1; static final String GENERATION_COMPARISON_NAME_B_BIG = "A < B"; static final String GENERATION_COMPARISON_NAME_A_BIG = "A > B"; static final String GENERATION_COMPARISON_NAME_EQUAL = "A == B"; @@ -111,11 +107,8 @@ class GenerationSafePointerPair static final long FLAG_GENERATION_B_BIG = 0x10000000_00000000L; static final long FLAG_SLOT_A = 0x00000000_00000000L; static final long FLAG_SLOT_B = 0x20000000_00000000L; - static final long FLAG_ABS_OFFSET = 0x00000000_00000000L; - static final long FLAG_LOGICAL_POS = 0x10000000_00000000L; static final int SHIFT_STATE_A = 56; static final int SHIFT_STATE_B = 53; - static final int SHIFT_GENERATION_OFFSET = 48; // Aggregations static final long SUCCESS_WRITE_TO_B = FLAG_SUCCESS | FLAG_WRITE | FLAG_SLOT_B; @@ -128,10 +121,6 @@ class GenerationSafePointerPair static final long STATE_MASK = 0x7; // After shift static final long GENERATION_COMPARISON_MASK = FLAG_GENERATION_EQUAL | FLAG_GENERATION_A_BIG | FLAG_GENERATION_B_BIG; static final long POINTER_MASK = 0x0000FFFF_FFFFFFFFL; - static final long GENERATION_OFFSET_MASK = 0x0FFF0000_00000000L; - static final long GENERATION_OFFSET_TYPE_MASK = FLAG_ABS_OFFSET | FLAG_LOGICAL_POS; - static final long HEADER_MASK = ~POINTER_MASK; - static final long MAX_GENERATION_OFFSET_MASK = 0xFFF; private GenerationSafePointerPair() { @@ -144,15 +133,11 @@ private GenerationSafePointerPair() * @param cursor {@link PageCursor} to read from, placed at the beginning of the GSPP. * @param stableGeneration stable index generation. * @param unstableGeneration unstable index generation. - * @param logicalPos logical position to use in header-part of the read result. If {@link #NO_LOGICAL_POS} - * then the {@link PageCursor#getOffset() cursor offset} is used. Header will also note whether or not - * this is a logical pos or the offset was used. This fact will be used in {@link #isLogicalPos(long)}. + * @param generationTarget target to write the generation of the selected pointer. * @return most recent readable pointer, or failure. Check result using {@link #isSuccess(long)}. */ - public static long read( PageCursor cursor, long stableGeneration, long unstableGeneration, int logicalPos ) + public static long read( PageCursor cursor, long stableGeneration, long unstableGeneration, GenerationTarget generationTarget ) { - int gsppOffset = cursor.getOffset(); - // Try A long generationA = readGeneration( cursor ); long pointerA = readPointer( cursor ); @@ -174,14 +159,14 @@ public static long read( PageCursor cursor, long stableGeneration, long unstable { if ( pointerStateB == STABLE || pointerStateB == EMPTY ) { - return buildSuccessfulReadResult( FLAG_SLOT_A, logicalPos, gsppOffset, pointerA ); + return buildSuccessfulReadResult( FLAG_SLOT_A, generationA, pointerA, generationTarget ); } } else if ( pointerStateB == UNSTABLE ) { if ( pointerStateA == STABLE || pointerStateA == EMPTY ) { - return buildSuccessfulReadResult( FLAG_SLOT_B, logicalPos, gsppOffset, pointerB ); + return buildSuccessfulReadResult( FLAG_SLOT_B, generationB, pointerB, generationTarget ); } } else if ( pointerStateA == STABLE && pointerStateB == STABLE ) @@ -189,37 +174,31 @@ else if ( pointerStateA == STABLE && pointerStateB == STABLE ) // compare generation if ( generationA > generationB ) { - return buildSuccessfulReadResult( FLAG_SLOT_A, logicalPos, gsppOffset, pointerA ); + return buildSuccessfulReadResult( FLAG_SLOT_A, generationA, pointerA, generationTarget ); } else if ( generationB > generationA ) { - return buildSuccessfulReadResult( FLAG_SLOT_B, logicalPos, gsppOffset, pointerB ); + return buildSuccessfulReadResult( FLAG_SLOT_B, generationB, pointerB, generationTarget ); } } else if ( pointerStateA == STABLE ) { - return buildSuccessfulReadResult( FLAG_SLOT_A, logicalPos, gsppOffset, pointerA ); + return buildSuccessfulReadResult( FLAG_SLOT_A, generationA, pointerA, generationTarget ); } else if ( pointerStateB == STABLE ) { - return buildSuccessfulReadResult( FLAG_SLOT_B, logicalPos, gsppOffset, pointerB ); + return buildSuccessfulReadResult( FLAG_SLOT_B, generationB, pointerB, generationTarget ); } + generationTarget.accept( EMPTY_GENERATION ); return FLAG_FAIL | FLAG_READ | generationState( generationA, generationB ) | ((long) pointerStateA) << SHIFT_STATE_A | ((long) pointerStateB) << SHIFT_STATE_B; } - private static long buildSuccessfulReadResult( long slot, int logicalPos, int gsppOffset, long pointer ) + private static long buildSuccessfulReadResult( long slot, long generation, long pointer, GenerationTarget generationTarget ) { - boolean isLogicalPos = logicalPos != NO_LOGICAL_POS; - long offsetType = isLogicalPos ? FLAG_LOGICAL_POS : FLAG_ABS_OFFSET; - long generationOffset = isLogicalPos ? logicalPos : gsppOffset; - if ( (generationOffset & ~MAX_GENERATION_OFFSET_MASK) != 0 ) - { - throw new IllegalArgumentException( "Illegal generationOffset:" + generationOffset + ", it would be too large, max is " + - MAX_GENERATION_OFFSET_MASK ); - } - return FLAG_SUCCESS | FLAG_READ | slot | offsetType | generationOffset << SHIFT_GENERATION_OFFSET | pointer; + generationTarget.accept( generation ); + return FLAG_SUCCESS | FLAG_READ | slot | pointer; } /** @@ -376,7 +355,7 @@ static byte pointerState( long stableGeneration, long unstableGeneration, * Checks to see if a result from read/write was successful. If not more failure information can be extracted * using {@link #failureDescription(long)}. * - * @param result result from {@link #read(PageCursor, long, long, int)} or {@link #write(PageCursor, long, long, long)}. + * @param result result from {@link #read(PageCursor, long, long, GenerationTarget)} or {@link #write(PageCursor, long, long, long)}. * @return {@code true} if successful read/write, otherwise {@code false}. */ static boolean isSuccess( long result ) @@ -385,7 +364,7 @@ static boolean isSuccess( long result ) } /** - * @param readResult whole read result from {@link #read(PageCursor, long, long, int)}, containing both + * @param readResult whole read result from {@link #read(PageCursor, long, long, GenerationTarget)}, containing both * pointer as well as header information about the pointer. * @return the pointer-part of {@code readResult}. */ @@ -395,7 +374,7 @@ static long pointer( long readResult ) } /** - * Calling {@link #read(PageCursor, long, long, int)} (potentially also {@link #write(PageCursor, long, long, long)}) + * Calling {@link #read(PageCursor, long, long, GenerationTarget)} (potentially also {@link #write(PageCursor, long, long, long)}) * can fail due to seeing an unexpected state of the two GSPs. Failing right there and then isn't an option * due to how the page cache works and that something read from a {@link PageCursor} must not be interpreted * until after passing a {@link PageCursor#shouldRetry()} returning {@code false}. This creates a need for @@ -403,7 +382,7 @@ static long pointer( long readResult ) * the caller which interprets the result fail in a proper place. That place can make use of this method * by getting a human-friendly description about the failure. * - * @param result result from {@link #read(PageCursor, long, long, int)} or + * @param result result from {@link #read(PageCursor, long, long, GenerationTarget)} or * {@link #write(PageCursor, long, long, long)}. * @return a human-friendly description of the failure. */ @@ -420,7 +399,7 @@ static String failureDescription( long result ) /** * Asserts that a result is {@link #isSuccess(long) successful}, otherwise throws {@link IllegalStateException}. * - * @param result result returned from {@link #read(PageCursor, long, long, int)} or + * @param result result returned from {@link #read(PageCursor, long, long, GenerationTarget)} or * {@link #write(PageCursor, long, long, long)} * @return {@code true} if {@link #isSuccess(long) successful}, for interoperability with {@code assert}. */ @@ -488,18 +467,10 @@ static boolean resultIsFromSlotA( long result ) return (result & SLOT_MASK) == FLAG_SLOT_A; } - static boolean isLogicalPos( long readResult ) + interface GenerationTarget { - return (readResult & GENERATION_OFFSET_TYPE_MASK) == FLAG_LOGICAL_POS; + void accept( long generation ); } - static int generationOffset( long readResult ) - { - if ( (readResult & HEADER_MASK) == 0 ) - { - throw new IllegalArgumentException( "Expected a header in read result, but read result was " + readResult ); - } - - return Math.toIntExact( (readResult & GENERATION_OFFSET_MASK) >>> SHIFT_GENERATION_OFFSET ); - } + static final GenerationTarget NO_GENERATION_TARGET = geneation -> {}; } diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/SeekCursor.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/SeekCursor.java index 988dc7959047e..c8521d2ab589a 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/SeekCursor.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/SeekCursor.java @@ -389,6 +389,11 @@ class SeekCursor implements RawCursor,IOException>, Hi */ private boolean forceReadHeader; + /** + * Place where read generations will be kept when reading child/sibling/successor pointers. + */ + private final GenerationKeeper generationKeeper = new GenerationKeeper(); + @SuppressWarnings( "unchecked" ) SeekCursor( PageCursor cursor, TreeNode bTreeNode, KEY fromInclusive, KEY toExclusive, Layout layout, long stableGeneration, long unstableGeneration, LongSupplier generationSupplier, @@ -465,8 +470,8 @@ private void traverseDownToFirstLeaf() throws IOException if ( isInternal ) { - pointerId = bTreeNode.childAt( cursor, pos, stableGeneration, unstableGeneration ); - pointerGeneration = readPointerGenerationOnSuccess( pointerId ); + pointerId = bTreeNode.childAt( cursor, pos, stableGeneration, unstableGeneration, generationKeeper ); + pointerGeneration = generationKeeper.generation; } } while ( cursor.shouldRetry() ); @@ -632,7 +637,7 @@ private boolean readAndValidateNextKeyValueBatch() throws IOException { // We may need to go to previous sibling to find correct place to start seeking from prevSiblingId = readPrevSibling(); - prevSiblingGeneration = readPointerGenerationOnSuccess( prevSiblingId ); + prevSiblingGeneration = generationKeeper.generation; } } @@ -641,7 +646,7 @@ private boolean readAndValidateNextKeyValueBatch() throws IOException { // Read right sibling pointerId = readNextSibling(); - pointerGeneration = readPointerGenerationOnSuccess( pointerId ); + pointerGeneration = generationKeeper.generation; } for ( int readPos = pos; cachedLength < mutableKeys.length && 0 <= readPos && readPos < keyCount; readPos += stride ) { @@ -808,18 +813,6 @@ private boolean goToSuccessor() throws IOException return goTo( successor, successorGeneration, "successor", true ); } - /** - * @return generation of {@code pointerId}, if the pointer id was successfully read. - */ - private long readPointerGenerationOnSuccess( long pointerId ) - { - if ( GenerationSafePointerPair.isSuccess( pointerId ) ) - { - return bTreeNode.pointerGeneration( cursor, pointerId ); - } - return -1; // this value doesn't matter - } - /** * @return {@code false} if there was a set expectancy on first key in tree node which weren't met, * otherwise {@code true}. Caller should @@ -842,8 +835,8 @@ private boolean verifyFirstKeyInNodeIsExpectedAfterGoTo() private long readPrevSibling() { return seekForward ? - TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration ) : - TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration ); + TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration, generationKeeper ) : + TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration, generationKeeper ); } /** @@ -852,8 +845,8 @@ private long readPrevSibling() private long readNextSibling() { return seekForward ? - TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration ) : - TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration ); + TreeNode.rightSibling( cursor, stableGeneration, unstableGeneration, generationKeeper ) : + TreeNode.leftSibling( cursor, stableGeneration, unstableGeneration, generationKeeper ); } /** @@ -894,11 +887,8 @@ private boolean readHeader() currentNodeGeneration = TreeNode.generation( cursor ); - successor = TreeNode.successor( cursor, stableGeneration, unstableGeneration ); - if ( GenerationSafePointerPair.isSuccess( successor ) ) - { - successorGeneration = bTreeNode.pointerGeneration( cursor, successor ); - } + successor = TreeNode.successor( cursor, stableGeneration, unstableGeneration, generationKeeper ); + successorGeneration = generationKeeper.generation; isInternal = TreeNode.isInternal( cursor ); // Find the left-most key within from-range keyCount = TreeNode.keyCount( cursor ); diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNode.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNode.java index f75840414ca9f..2b048370ab0e1 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNode.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNode.java @@ -22,9 +22,10 @@ import java.io.IOException; import java.util.Comparator; +import org.neo4j.index.internal.gbptree.GenerationSafePointerPair.GenerationTarget; import org.neo4j.io.pagecache.PageCursor; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.NO_LOGICAL_POS; +import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.NO_GENERATION_TARGET; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.read; /** @@ -132,21 +133,36 @@ static int keyCount( PageCursor cursor ) } static long rightSibling( PageCursor cursor, long stableGeneration, long unstableGeneration ) + { + return rightSibling( cursor, stableGeneration, unstableGeneration, NO_GENERATION_TARGET ); + } + + static long rightSibling( PageCursor cursor, long stableGeneration, long unstableGeneration, GenerationTarget generationTarget ) { cursor.setOffset( BYTE_POS_RIGHTSIBLING ); - return read( cursor, stableGeneration, unstableGeneration, NO_LOGICAL_POS ); + return read( cursor, stableGeneration, unstableGeneration, generationTarget ); } static long leftSibling( PageCursor cursor, long stableGeneration, long unstableGeneration ) + { + return leftSibling( cursor, stableGeneration, unstableGeneration, NO_GENERATION_TARGET ); + } + + static long leftSibling( PageCursor cursor, long stableGeneration, long unstableGeneration, GenerationTarget generationTarget ) { cursor.setOffset( BYTE_POS_LEFTSIBLING ); - return read( cursor, stableGeneration, unstableGeneration, NO_LOGICAL_POS ); + return read( cursor, stableGeneration, unstableGeneration, generationTarget ); } static long successor( PageCursor cursor, long stableGeneration, long unstableGeneration ) + { + return successor( cursor, stableGeneration, unstableGeneration, NO_GENERATION_TARGET ); + } + + static long successor( PageCursor cursor, long stableGeneration, long unstableGeneration, GenerationTarget generationTarget ) { cursor.setOffset( BYTE_POS_SUCCESSOR ); - return read( cursor, stableGeneration, unstableGeneration, NO_LOGICAL_POS ); + return read( cursor, stableGeneration, unstableGeneration, generationTarget ); } static void setGeneration( PageCursor cursor, long generation ) @@ -186,20 +202,6 @@ static void setSuccessor( PageCursor cursor, long successorId, long stableGenera GenerationSafePointerPair.assertSuccess( result ); } - long pointerGeneration( PageCursor cursor, long readResult ) - { - if ( !GenerationSafePointerPair.isRead( readResult ) ) - { - throw new IllegalArgumentException( "Expected read result, but got " + readResult ); - } - int offset = GenerationSafePointerPair.generationOffset( readResult ); - int gsppOffset = GenerationSafePointerPair.isLogicalPos( readResult ) ? childOffset( offset ) : offset; - int gspOffset = GenerationSafePointerPair.resultIsFromSlotA( readResult ) ? - gsppOffset : gsppOffset + GenerationSafePointer.SIZE; - cursor.setOffset( gspOffset ); - return GenerationSafePointer.readGeneration( cursor ); - } - // BODY METHODS /** @@ -263,7 +265,16 @@ abstract void insertKeyAndRightChildAt( PageCursor cursor, KEY key, long child, */ abstract boolean setValueAt( PageCursor cursor, VALUE value, int pos ); - abstract long childAt( PageCursor cursor, int pos, long stableGeneration, long unstableGeneration ); + long childAt( PageCursor cursor, int pos, long stableGeneration, long unstableGeneration ) + { + return childAt( cursor, pos, stableGeneration, unstableGeneration, NO_GENERATION_TARGET ); + } + + long childAt( PageCursor cursor, int pos, long stableGeneration, long unstableGeneration, GenerationTarget generationTarget ) + { + cursor.setOffset( childOffset( pos ) ); + return read( cursor, stableGeneration, unstableGeneration, generationTarget ); + } abstract void setChildAt( PageCursor cursor, long child, int pos, long stableGeneration, long unstableGeneration ); diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeDynamicSize.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeDynamicSize.java index d9f6c53ab299d..de7af8df219ab 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeDynamicSize.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeDynamicSize.java @@ -44,7 +44,6 @@ import static org.neo4j.index.internal.gbptree.DynamicSizeUtil.putTombstone; import static org.neo4j.index.internal.gbptree.DynamicSizeUtil.readKeyOffset; import static org.neo4j.index.internal.gbptree.DynamicSizeUtil.readKeyValueSize; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.read; import static org.neo4j.index.internal.gbptree.PageCursorUtil.putUnsignedShort; import static org.neo4j.index.internal.gbptree.TreeNode.Type.INTERNAL; import static org.neo4j.index.internal.gbptree.TreeNode.Type.LEAF; @@ -347,13 +346,6 @@ private void progressCursor( PageCursor cursor, int delta ) cursor.setOffset( cursor.getOffset() + delta ); } - @Override - long childAt( PageCursor cursor, int pos, long stableGeneration, long unstableGeneration ) - { - cursor.setOffset( childOffset( pos ) ); - return read( cursor, stableGeneration, unstableGeneration, pos ); - } - @Override void setChildAt( PageCursor cursor, long child, int pos, long stableGeneration, long unstableGeneration ) { diff --git a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeFixedSize.java b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeFixedSize.java index bde12f59a7f0f..2cc7ff2bc2fab 100644 --- a/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeFixedSize.java +++ b/community/index/src/main/java/org/neo4j/index/internal/gbptree/TreeNodeFixedSize.java @@ -21,7 +21,6 @@ import org.neo4j.io.pagecache.PageCursor; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.read; import static org.neo4j.index.internal.gbptree.Layout.FIXED_SIZE_KEY; import static org.neo4j.index.internal.gbptree.Layout.FIXED_SIZE_VALUE; import static org.neo4j.index.internal.gbptree.TreeNode.Type.INTERNAL; @@ -179,13 +178,6 @@ boolean setValueAt( PageCursor cursor, VALUE value, int pos ) return true; } - @Override - long childAt( PageCursor cursor, int pos, long stableGeneration, long unstableGeneration ) - { - cursor.setOffset( childOffset( pos ) ); - return read( cursor, stableGeneration, unstableGeneration, pos ); - } - @Override void setChildAt( PageCursor cursor, long child, int pos, long stableGeneration, long unstableGeneration ) { diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairAdditionalTest.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairAdditionalTest.java deleted file mode 100644 index 42644943d4fde..0000000000000 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairAdditionalTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2002-2018 "Neo4j," - * Neo4j Sweden AB [http://neo4j.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 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.index.internal.gbptree; - -import org.junit.jupiter.api.Test; - -import org.neo4j.io.pagecache.PageCache; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.neo4j.index.internal.gbptree.GenerationSafePointer.MIN_GENERATION; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.MAX_GENERATION_OFFSET_MASK; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.read; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.write; - -class GenerationSafePointerPairAdditionalTest -{ - @Test - void shouldFailFastOnTooLargeGenerationOffset() - { - // GIVEN - int pageSize = PageCache.PAGE_SIZE; - PageAwareByteArrayCursor cursor = new PageAwareByteArrayCursor( pageSize ); - cursor.next( 0 ); - long firstGeneration = MIN_GENERATION; - long secondGeneration = firstGeneration + 1; - long thirdGeneration = secondGeneration + 1; - int offset = 0; - cursor.setOffset( offset ); - write( cursor, 10, firstGeneration, secondGeneration ); - cursor.setOffset( offset ); - write( cursor, 11, secondGeneration, thirdGeneration ); - - assertThrows( IllegalArgumentException.class, () -> - { - cursor.setOffset( offset ); - read( cursor, secondGeneration, thirdGeneration, (int) (MAX_GENERATION_OFFSET_MASK + 1) ); - } ); - } -} diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairTest.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairTest.java index c326a5f8ff469..f39b9aaf2e053 100644 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairTest.java +++ b/community/index/src/test/java/org/neo4j/index/internal/gbptree/GenerationSafePointerPairTest.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Collection; +import org.neo4j.index.internal.gbptree.GenerationSafePointerPair.GenerationTarget; import org.neo4j.io.pagecache.ByteArrayPageCursor; import org.neo4j.io.pagecache.PageCursor; @@ -40,7 +41,6 @@ import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.FLAG_READ; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.FLAG_WRITE; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.GENERATION_COMPARISON_MASK; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.NO_LOGICAL_POS; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.READ_OR_WRITE_MASK; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.SHIFT_STATE_A; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.SHIFT_STATE_B; @@ -128,39 +128,21 @@ public static Collection data() private final PageCursor cursor = ByteArrayPageCursor.wrap( new byte[PAGE_SIZE] ); @Test - public void shouldReadWithLogicalPosition() + public void shouldRead() { // GIVEN cursor.setOffset( SLOT_A_OFFSET ); long preStatePointerA = stateA.materialize( cursor, POINTER_A ); cursor.setOffset( SLOT_B_OFFSET ); long preStatePointerB = stateB.materialize( cursor, POINTER_B ); - int pos = 1234; // WHEN cursor.setOffset( GSPP_OFFSET ); - long result = GenerationSafePointerPair.read( cursor, STABLE_GENERATION, UNSTABLE_GENERATION, pos ); + GenerationKeeper generationKeeper = new GenerationKeeper(); + long result = GenerationSafePointerPair.read( cursor, STABLE_GENERATION, UNSTABLE_GENERATION, generationKeeper ); // THEN - expectedReadOutcome.verifyRead( cursor, result, stateA, stateB, preStatePointerA, preStatePointerB, pos ); - } - - @Test - public void shouldReadWithNoLogicalPosition() - { - // GIVEN - cursor.setOffset( SLOT_A_OFFSET ); - long preStatePointerA = stateA.materialize( cursor, POINTER_A ); - cursor.setOffset( SLOT_B_OFFSET ); - long preStatePointerB = stateB.materialize( cursor, POINTER_B ); - - // WHEN - cursor.setOffset( GSPP_OFFSET ); - long result = GenerationSafePointerPair.read( cursor, STABLE_GENERATION, UNSTABLE_GENERATION, NO_LOGICAL_POS ); - - // THEN - expectedReadOutcome.verifyRead( cursor, result, stateA, stateB, preStatePointerA, preStatePointerB, - NO_LOGICAL_POS ); + expectedReadOutcome.verifyRead( cursor, result, stateA, stateB, preStatePointerA, preStatePointerB, generationKeeper.generation ); } @Test @@ -289,7 +271,7 @@ long materialize( PageCursor cursor, long pointer ) } @Override - void verify( PageCursor cursor, long expectedPointer, boolean slotA, int logicalPos ) + void verify( PageCursor cursor, long expectedPointer, boolean slotA ) { cursor.setOffset( slotA ? SLOT_A_OFFSET : SLOT_B_OFFSET ); @@ -371,25 +353,30 @@ long materialize( PageCursor cursor, long pointer ) * @param expectedPointer expected pointer, as received from {@link #materialize(PageCursor, long)}. * @param slotA whether or not this is for slot A, otherwise B. */ - void verify( PageCursor cursor, long expectedPointer, boolean slotA, int logicalPos ) + void verify( PageCursor cursor, long expectedPointer, boolean slotA ) { assertEquals( expectedPointer, slotA ? readSlotA( cursor ) : readSlotB( cursor ) ); } + + public static long readGeneration( PageCursor cursor, boolean slotA ) + { + cursor.setOffset( slotA ? SLOT_A_OFFSET : SLOT_B_OFFSET ); + return GenerationSafePointer.readGeneration( cursor ); + } } interface Slot { /** * @param cursor {@link PageCursor} to read actual result from. - * @param result read-result from {@link GenerationSafePointerPair#read(PageCursor, long, long, int)}. + * @param result read-result from {@link GenerationSafePointerPair#read(PageCursor, long, long, GenerationTarget)}. * @param stateA state of pointer A when read. * @param stateB state of pointer B when read. * @param preStatePointerA pointer A as it looked like in pre-state. * @param preStatePointerB pointer B as it looked like in pre-state. - * @param logicalPos expected logical pos. + * @param generation read generation. */ - void verifyRead( PageCursor cursor, long result, State stateA, State stateB, - long preStatePointerA, long preStatePointerB, int logicalPos ); + void verifyRead( PageCursor cursor, long result, State stateA, State stateB, long preStatePointerA, long preStatePointerB, long generation ); /** * @param cursor {@link PageCursor} to read actual result from. @@ -418,26 +405,15 @@ enum Success implements Slot } @Override - public void verifyRead( PageCursor cursor, long result, State stateA, State stateB, - long preStatePointerA, long preStatePointerB, int logicalPos ) + public void verifyRead( PageCursor cursor, long result, State stateA, State stateB, long preStatePointerA, long preStatePointerB, long generation ) { assertSuccess( result ); long pointer = GenerationSafePointerPair.pointer( result ); assertEquals( expectedPointer, pointer ); assertEquals( expectedSlot == SLOT_A, GenerationSafePointerPair.resultIsFromSlotA( result ) ); - if ( logicalPos == NO_LOGICAL_POS ) - { - assertFalse( GenerationSafePointerPair.isLogicalPos( result ) ); - assertEquals( GSPP_OFFSET, GenerationSafePointerPair.generationOffset( result ) ); - } - else - { - assertTrue( GenerationSafePointerPair.isLogicalPos( result ) ); - assertEquals( logicalPos, GenerationSafePointerPair.generationOffset( result ) ); - } - - stateA.verify( cursor, preStatePointerA, SLOT_A, logicalPos ); - stateB.verify( cursor, preStatePointerB, SLOT_B, logicalPos ); + stateA.verify( cursor, preStatePointerA, SLOT_A ); + stateB.verify( cursor, preStatePointerB, SLOT_B ); + assertEquals( State.readGeneration( cursor, expectedSlot ), generation ); } @Override @@ -484,12 +460,12 @@ enum Fail implements Slot } @Override - public void verifyRead( PageCursor cursor, long result, State stateA, State stateB, - long preStatePointerA, long preStatePointerB, int logicalPos ) + public void verifyRead( PageCursor cursor, long result, State stateA, State stateB, long preStatePointerA, long preStatePointerB, long generation ) { assertFailure( result, FLAG_READ, generationComparison, stateA.byteValue, stateB.byteValue ); - stateA.verify( cursor, preStatePointerA, SLOT_A, logicalPos ); - stateB.verify( cursor, preStatePointerB, SLOT_B, logicalPos ); + stateA.verify( cursor, preStatePointerA, SLOT_A ); + stateB.verify( cursor, preStatePointerB, SLOT_B ); + assertEquals( GenerationSafePointer.EMPTY_GENERATION, generation ); } @Override @@ -497,8 +473,8 @@ public void verifyWrite( PageCursor cursor, long result, State stateA, State sta long preStatePointerA, long preStatePointerB ) { assertFailure( result, FLAG_WRITE, generationComparison, stateA.byteValue, stateB.byteValue ); - stateA.verify( cursor, preStatePointerA, SLOT_A, NO_LOGICAL_POS /*Don't care*/ ); - stateB.verify( cursor, preStatePointerB, SLOT_B, NO_LOGICAL_POS /*Don't care*/ ); + stateA.verify( cursor, preStatePointerA, SLOT_A ); + stateB.verify( cursor, preStatePointerB, SLOT_B ); } } } diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/InternalTreeLogicTestBase.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/InternalTreeLogicTestBase.java index 3221cf612fe1c..8ba89104b5e0d 100644 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/InternalTreeLogicTestBase.java +++ b/community/index/src/test/java/org/neo4j/index/internal/gbptree/InternalTreeLogicTestBase.java @@ -1695,17 +1695,20 @@ private void assertSiblingOrderAndPointers( long... children ) throws IOExceptio { long currentPageId = readCursor.getCurrentPageId(); RightmostInChain rightmost = new RightmostInChain(); + GenerationKeeper generationTarget = new GenerationKeeper(); for ( long child : children ) { goTo( readCursor, child ); - long leftSibling = TreeNode.leftSibling( readCursor, stableGeneration, unstableGeneration ); - long rightSibling = TreeNode.rightSibling( readCursor, stableGeneration, unstableGeneration ); + long leftSibling = TreeNode.leftSibling( readCursor, stableGeneration, unstableGeneration, generationTarget ); + long leftSiblingGeneration = generationTarget.generation; + long rightSibling = TreeNode.rightSibling( readCursor, stableGeneration, unstableGeneration, generationTarget ); + long rightSiblingGeneration = generationTarget.generation; rightmost.assertNext( readCursor, TreeNode.generation( readCursor ), pointer( leftSibling ), - node.pointerGeneration( readCursor, leftSibling ), + leftSiblingGeneration, pointer( rightSibling ), - node.pointerGeneration( readCursor, rightSibling ) ); + rightSiblingGeneration ); } rightmost.assertLast(); goTo( readCursor, currentPageId ); diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/PointerCheckingTest.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/PointerCheckingTest.java index 9ea574fa567b5..ac2d81043376f 100644 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/PointerCheckingTest.java +++ b/community/index/src/test/java/org/neo4j/index/internal/gbptree/PointerCheckingTest.java @@ -25,7 +25,7 @@ import org.neo4j.io.pagecache.PageCursor; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.NO_LOGICAL_POS; +import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.NO_GENERATION_TARGET; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.read; import static org.neo4j.index.internal.gbptree.GenerationSafePointerPair.write; import static org.neo4j.index.internal.gbptree.PageCursorUtil.put6BLong; @@ -46,9 +46,9 @@ void checkChildShouldThrowOnNoNode() @Test void checkChildShouldThrowOnReadFailure() { - long result = GenerationSafePointerPair.read( cursor, 0, 1, 123 ); + long result = GenerationSafePointerPair.read( cursor, 0, 1, NO_GENERATION_TARGET ); - assertThrows(TreeInconsistencyException.class, () -> PointerChecking.checkPointer( result, false ) ); + assertThrows( TreeInconsistencyException.class, () -> PointerChecking.checkPointer( result, false ) ); } @Test @@ -74,7 +74,7 @@ void checkChildShouldPassOnReadSuccess() cursor.rewind(); // WHEN - long result = read( cursor, 0, firstGeneration, 456 ); + long result = read( cursor, 0, firstGeneration, NO_GENERATION_TARGET ); // THEN PointerChecking.checkPointer( result, false ); @@ -98,7 +98,7 @@ void checkSiblingShouldPassOnReadSuccessForNoNodePointer() cursor.rewind(); // WHEN - long result = read( cursor, firstGeneration, secondGeneration, NO_LOGICAL_POS ); + long result = read( cursor, firstGeneration, secondGeneration, NO_GENERATION_TARGET ); // THEN PointerChecking.checkPointer( result, true ); @@ -113,7 +113,7 @@ void checkSiblingShouldPassOnReadSuccessForNodePointer() cursor.rewind(); // WHEN - long result = read( cursor, firstGeneration, secondGeneration, NO_LOGICAL_POS ); + long result = read( cursor, firstGeneration, secondGeneration, NO_GENERATION_TARGET ); // THEN PointerChecking.checkPointer( result, true ); @@ -122,7 +122,7 @@ void checkSiblingShouldPassOnReadSuccessForNodePointer() @Test void checkSiblingShouldThrowOnReadFailure() { - long result = read( cursor, firstGeneration, secondGeneration, NO_LOGICAL_POS ); + long result = read( cursor, firstGeneration, secondGeneration, NO_GENERATION_TARGET ); assertThrows( TreeInconsistencyException.class, () -> PointerChecking.checkPointer( result, true ) ); } @@ -141,7 +141,7 @@ void checkSiblingShouldThrowOnReadIllegalPointer() cursor.rewind(); // WHEN - long result = read( cursor, firstGeneration, pointer, NO_LOGICAL_POS ); + long result = read( cursor, firstGeneration, pointer, NO_GENERATION_TARGET ); assertThrows(TreeInconsistencyException.class, () -> PointerChecking.checkPointer( result, true ) ); } diff --git a/community/index/src/test/java/org/neo4j/index/internal/gbptree/TreeNodeTestBase.java b/community/index/src/test/java/org/neo4j/index/internal/gbptree/TreeNodeTestBase.java index 3b4634898abb5..725802f7de364 100644 --- a/community/index/src/test/java/org/neo4j/index/internal/gbptree/TreeNodeTestBase.java +++ b/community/index/src/test/java/org/neo4j/index/internal/gbptree/TreeNodeTestBase.java @@ -58,6 +58,7 @@ public abstract class TreeNodeTestBase private TestLayout layout; private TreeNode node; + private final GenerationKeeper generationTarget = new GenerationKeeper(); @Inject private RandomRule random; @@ -602,8 +603,8 @@ void shouldReadPointerGenerationFromAbsoluteOffsetSlotA() TreeNode.setRightSibling( cursor, pointer, STABLE_GENERATION, generation ); // WHEN - long readResult = TreeNode.rightSibling( cursor, STABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = TreeNode.rightSibling( cursor, STABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -622,8 +623,8 @@ void shouldReadPointerGenerationFromAbsoluteOffsetSlotB() TreeNode.setRightSibling( cursor, pointer, UNSTABLE_GENERATION, generation ); // WHEN - long readResult = TreeNode.rightSibling( cursor, UNSTABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = TreeNode.rightSibling( cursor, UNSTABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -641,8 +642,8 @@ void shouldReadPointerGenerationFromLogicalPosSlotA() node.setChildAt( cursor, pointer, childPos, STABLE_GENERATION, generation ); // WHEN - long readResult = node.childAt( cursor, childPos, STABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = node.childAt( cursor, childPos, STABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -660,8 +661,8 @@ void shouldReadPointerGenerationFromLogicalPosZeroSlotA() node.setChildAt( cursor, pointer, childPos, STABLE_GENERATION, generation ); // WHEN - long readResult = node.childAt( cursor, childPos, STABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = node.childAt( cursor, childPos, STABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -681,8 +682,8 @@ void shouldReadPointerGenerationFromLogicalPosZeroSlotB() node.setChildAt( cursor, pointer, childPos, UNSTABLE_GENERATION, generation ); // WHEN - long readResult = node.childAt( cursor, childPos, UNSTABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = node.childAt( cursor, childPos, UNSTABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -702,8 +703,8 @@ void shouldReadPointerGenerationFromLogicalPosSlotB() node.setChildAt( cursor, pointer, childPos, UNSTABLE_GENERATION, generation ); // WHEN - long readResult = node.childAt( cursor, childPos, UNSTABLE_GENERATION, generation ); - long readGeneration = node.pointerGeneration( cursor, readResult ); + long readResult = node.childAt( cursor, childPos, UNSTABLE_GENERATION, generation, generationTarget ); + long readGeneration = generationTarget.generation; // THEN assertEquals( pointer, pointer( readResult ) ); @@ -711,37 +712,6 @@ void shouldReadPointerGenerationFromLogicalPosSlotB() assertFalse( resultIsFromSlotA( readResult ) ); } - @Test - void shouldThrowIfReadingPointerGenerationOnWriteResult() - { - // GIVEN - long writeResult = GenerationSafePointerPair.write( cursor, 123, STABLE_GENERATION, UNSTABLE_GENERATION ); - assertThrows( IllegalArgumentException.class, () -> node.pointerGeneration( cursor, writeResult ) ); - } - - @Test - void shouldThrowIfReadingPointerGenerationOnZeroReadResultHeader() - { - // GIVEN - long pointer = 123; - assertThrows( IllegalArgumentException.class, () -> node.pointerGeneration( cursor, pointer ) ); - } - - @Test - void shouldUseLogicalGenerationPosWhenReadingChild() - { - // GIVEN - long child = 101; - int pos = 3; - node.setChildAt( cursor, child, pos, STABLE_GENERATION, UNSTABLE_GENERATION ); - - // WHEN - long result = node.childAt( cursor, pos, STABLE_GENERATION, UNSTABLE_GENERATION ); - - // THEN - assertTrue( GenerationSafePointerPair.isLogicalPos( result ) ); - } - private void assertKeyEquals( KEY expectedKey, KEY actualKey ) { assertEquals( 0, layout.compare( expectedKey, actualKey ), String.format( "expectedKey=%s, actualKey=%s", expectedKey, actualKey ) );