Skip to content

Commit

Permalink
Merge TreeNode operations on key and value
Browse files Browse the repository at this point in the history
  • Loading branch information
burqen committed Jan 16, 2018
1 parent ab9602d commit fb65368
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 53 deletions.
Expand Up @@ -631,8 +631,7 @@ private void insertInLeaf( PageCursor cursor, StructurePropagation<KEY> structur
if ( keyCount < bTreeNode.leafMaxKeyCount() ) if ( keyCount < bTreeNode.leafMaxKeyCount() )
{ {
// No overflow, insert key and value // No overflow, insert key and value
bTreeNode.insertKeyAt( cursor, key, pos, keyCount, LEAF ); bTreeNode.insertKeyValueAt( cursor, key, value, pos, keyCount );
bTreeNode.insertValueAt( cursor, value, pos, keyCount );
TreeNode.setKeyCount( cursor, keyCount + 1 ); TreeNode.setKeyCount( cursor, keyCount + 1 );


return; // No split has occurred return; // No split has occurred
Expand Down Expand Up @@ -770,8 +769,7 @@ private void splitLeaf( PageCursor cursor, StructurePropagation<KEY> structurePr
// first copy // first copy
copyKeysAndValues( cursor, middlePos, rightCursor, 0, countBeforePos ); copyKeysAndValues( cursor, middlePos, rightCursor, 0, countBeforePos );
} }
bTreeNode.insertKeyAt( rightCursor, newKey, countBeforePos, countBeforePos, LEAF ); bTreeNode.insertKeyValueAt( rightCursor, newKey, newValue, countBeforePos, countBeforePos );
bTreeNode.insertValueAt( rightCursor, newValue, countBeforePos, countBeforePos );
int countAfterPos = keyCount - pos; int countAfterPos = keyCount - pos;
if ( countAfterPos > 0 ) if ( countAfterPos > 0 )
{ {
Expand All @@ -796,8 +794,7 @@ private void splitLeaf( PageCursor cursor, StructurePropagation<KEY> structurePr
// If pos < middle. Write shifted values to left node. Else, don't write anything. // If pos < middle. Write shifted values to left node. Else, don't write anything.
if ( pos < middlePos ) if ( pos < middlePos )
{ {
bTreeNode.insertKeyAt( cursor, newKey, pos, middlePos - 1, LEAF ); bTreeNode.insertKeyValueAt( cursor, newKey, newValue, pos, middlePos - 1 );
bTreeNode.insertValueAt( cursor, newValue, pos, middlePos - 1 );
} }
TreeNode.setKeyCount( cursor, middlePos ); TreeNode.setKeyCount( cursor, middlePos );
TreeNode.setRightSibling( cursor, newRight, stableGeneration, unstableGeneration ); TreeNode.setRightSibling( cursor, newRight, stableGeneration, unstableGeneration );
Expand Down Expand Up @@ -1263,9 +1260,8 @@ private void mergeFromLeftSiblingLeaf( PageCursor cursor, PageCursor leftSibling
private void merge( PageCursor leftSiblingCursor, int leftSiblingKeyCount, PageCursor rightSiblingCursor, private void merge( PageCursor leftSiblingCursor, int leftSiblingKeyCount, PageCursor rightSiblingCursor,
int rightSiblingKeyCount, long stableGeneration, long unstableGeneration ) throws IOException int rightSiblingKeyCount, long stableGeneration, long unstableGeneration ) throws IOException
{ {
// Push keys in right sibling to the right // Push keys and values in right sibling to the right
bTreeNode.insertKeySlotsAt( rightSiblingCursor, 0, leftSiblingKeyCount, rightSiblingKeyCount ); bTreeNode.insertKeyValueSlotsAt( rightSiblingCursor, 0, leftSiblingKeyCount, rightSiblingKeyCount );
bTreeNode.insertValueSlotsAt( rightSiblingCursor, 0, leftSiblingKeyCount, rightSiblingKeyCount );


// Move keys and values from left sibling to right sibling // Move keys and values from left sibling to right sibling
copyKeysAndValues( leftSiblingCursor, 0, rightSiblingCursor, 0, leftSiblingKeyCount ); copyKeysAndValues( leftSiblingCursor, 0, rightSiblingCursor, 0, leftSiblingKeyCount );
Expand All @@ -1287,9 +1283,8 @@ private void rebalanceLeaf( PageCursor cursor, PageCursor leftSiblingCursor,
int keyCountInLeftSiblingAfterRebalance = totalKeyCount / 2; int keyCountInLeftSiblingAfterRebalance = totalKeyCount / 2;
int numberOfKeysToMove = leftSiblingKeyCount - keyCountInLeftSiblingAfterRebalance; int numberOfKeysToMove = leftSiblingKeyCount - keyCountInLeftSiblingAfterRebalance;


// Push keys in right sibling to the right // Push keys and values in right sibling to the right
bTreeNode.insertKeySlotsAt( cursor, 0, numberOfKeysToMove, keyCount ); bTreeNode.insertKeyValueSlotsAt( cursor, 0, numberOfKeysToMove, keyCount );
bTreeNode.insertValueSlotsAt( cursor, 0, numberOfKeysToMove, keyCount );


// Move keys and values from left sibling to right sibling // Move keys and values from left sibling to right sibling
copyKeysAndValues( leftSiblingCursor, keyCountInLeftSiblingAfterRebalance, cursor, 0, numberOfKeysToMove ); copyKeysAndValues( leftSiblingCursor, keyCountInLeftSiblingAfterRebalance, cursor, 0, numberOfKeysToMove );
Expand All @@ -1314,10 +1309,10 @@ private void rebalanceLeaf( PageCursor cursor, PageCursor leftSiblingCursor,
*/ */
private int simplyRemoveFromLeaf( PageCursor cursor, VALUE into, int keyCount, int pos ) private int simplyRemoveFromLeaf( PageCursor cursor, VALUE into, int keyCount, int pos )
{ {
// Remove key/value // Save value to remove
bTreeNode.removeKeyAt( cursor, pos, keyCount, LEAF );
bTreeNode.valueAt( cursor, into, pos ); bTreeNode.valueAt( cursor, into, pos );
bTreeNode.removeValueAt( cursor, pos, keyCount ); // Remove key/value
bTreeNode.removeKeyValueAt( cursor, pos, keyCount );


// Decrease key count // Decrease key count
int newKeyCount = keyCount - 1; int newKeyCount = keyCount - 1;
Expand Down
Expand Up @@ -247,18 +247,34 @@ KEY keyAt( PageCursor cursor, KEY into, int pos, Type type )
return into; return into;
} }


// Insert key without associated value.
// Useful for internal nodes and testing.
void insertKeyAt( PageCursor cursor, KEY key, int pos, int keyCount, Type type ) void insertKeyAt( PageCursor cursor, KEY key, int pos, int keyCount, Type type )
{ {
insertKeySlotsAt( cursor, pos, 1, keyCount ); insertKeySlotsAt( cursor, pos, 1, keyCount );
cursor.setOffset( keyOffset( pos ) ); cursor.setOffset( keyOffset( pos ) );
layout.writeKey( cursor, key ); layout.writeKey( cursor, key );
} }


void insertKeyValueAt( PageCursor cursor, KEY key, VALUE value, int pos, int keyCount )
{
insertKeyAt( cursor, key, pos, keyCount, Type.LEAF );
insertValueAt( cursor, value, pos, keyCount );
}

// Remove key without removing associated value.
// Useful for internal nodes and testing.
void removeKeyAt( PageCursor cursor, int pos, int keyCount, Type type ) void removeKeyAt( PageCursor cursor, int pos, int keyCount, Type type )
{ {
removeSlotAt( cursor, pos, keyCount, keyOffset( 0 ), keySize ); removeSlotAt( cursor, pos, keyCount, keyOffset( 0 ), keySize );
} }


void removeKeyValueAt( PageCursor cursor, int pos, int keyCount )
{
removeKeyAt( cursor, pos, keyCount, Type.LEAF );
removeValueAt( cursor, pos, keyCount );
}

private static void removeSlotAt( PageCursor cursor, int pos, int itemCount, int baseOffset, int itemSize ) private static void removeSlotAt( PageCursor cursor, int pos, int itemCount, int baseOffset, int itemSize )
{ {
for ( int posToMoveLeft = pos + 1, offset = baseOffset + posToMoveLeft * itemSize; for ( int posToMoveLeft = pos + 1, offset = baseOffset + posToMoveLeft * itemSize;
Expand All @@ -281,13 +297,15 @@ VALUE valueAt( PageCursor cursor, VALUE value, int pos )
return value; return value;
} }


void insertValueAt( PageCursor cursor, VALUE value, int pos, int keyCount ) // Always insert together with key. Use insertKeyValueAt
private void insertValueAt( PageCursor cursor, VALUE value, int pos, int keyCount )
{ {
insertValueSlotsAt( cursor, pos, 1, keyCount ); insertValueSlotsAt( cursor, pos, 1, keyCount );
setValueAt( cursor, value, pos ); setValueAt( cursor, value, pos );
} }


void removeValueAt( PageCursor cursor, int pos, int keyCount ) // Always insert together with key. Use removeKeyValueAt
private void removeValueAt( PageCursor cursor, int pos, int keyCount )
{ {
removeSlotAt( cursor, pos, keyCount, valueOffset( 0 ), valueSize ); removeSlotAt( cursor, pos, keyCount, valueOffset( 0 ), valueSize );
} }
Expand Down Expand Up @@ -342,17 +360,23 @@ private static void insertSlotsAt( PageCursor cursor, int pos, int numberOfSlots
} }
} }


void insertKeySlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount ) void insertKeyValueSlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount )
{
insertKeySlotsAt( cursor, pos, numberOfSlots, keyCount );
insertValueSlotsAt( cursor, pos, numberOfSlots, keyCount );
}

private void insertKeySlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount )
{ {
insertSlotsAt( cursor, pos, numberOfSlots, keyCount, keyOffset( 0 ), keySize ); insertSlotsAt( cursor, pos, numberOfSlots, keyCount, keyOffset( 0 ), keySize );
} }


void insertValueSlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount ) private void insertValueSlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount )
{ {
insertSlotsAt( cursor, pos, numberOfSlots, keyCount, valueOffset( 0 ), valueSize ); insertSlotsAt( cursor, pos, numberOfSlots, keyCount, valueOffset( 0 ), valueSize );
} }


void insertChildSlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount ) private void insertChildSlotsAt( PageCursor cursor, int pos, int numberOfSlots, int keyCount )
{ {
insertSlotsAt( cursor, pos, numberOfSlots, keyCount + 1, childOffset( 0 ), childSize() ); insertSlotsAt( cursor, pos, numberOfSlots, keyCount + 1, childOffset( 0 ), childSize() );
} }
Expand Down
Expand Up @@ -1019,7 +1019,7 @@ public void mustNotFindKeyRemovedInFrontOfSeeker() throws Exception


// Seeker pauses and writer remove rightmost key // Seeker pauses and writer remove rightmost key
// [0 1 ... maxKeyCount-2] // [0 1 ... maxKeyCount-2]
removeAtPos( maxKeyCount - 1, LEAF ); removeAtPos( maxKeyCount - 1 );
this.cursor.forceRetry(); this.cursor.forceRetry();


while ( cursor.next() ) while ( cursor.next() )
Expand Down Expand Up @@ -1101,7 +1101,7 @@ public void mustFindKeyMovedPassedSeekerBecauseOfRemove() throws Exception


// Seeker pauses and writer remove rightmost key // Seeker pauses and writer remove rightmost key
// [1 ... maxKeyCount-1] // [1 ... maxKeyCount-1]
removeAtPos( 0, LEAF ); removeAtPos( 0 );
seekCursor.forceRetry(); seekCursor.forceRetry();


while ( cursor.next() ) while ( cursor.next() )
Expand Down Expand Up @@ -2284,8 +2284,7 @@ private void append( long k )
int keyCount = TreeNode.keyCount( cursor ); int keyCount = TreeNode.keyCount( cursor );
insertKey.setValue( k ); insertKey.setValue( k );
insertValue.setValue( valueForKey( k ) ); insertValue.setValue( valueForKey( k ) );
node.insertKeyAt( cursor, insertKey, keyCount, keyCount, type ); node.insertKeyValueAt( cursor, insertKey, insertValue, keyCount, keyCount );
node.insertValueAt( cursor, insertValue, keyCount, keyCount );
TreeNode.setKeyCount( cursor, keyCount + 1 ); TreeNode.setKeyCount( cursor, keyCount + 1 );
} }


Expand All @@ -2299,16 +2298,14 @@ private void insertIn( int pos, long k )
insertKey.setValue( k ); insertKey.setValue( k );
insertValue.setValue( valueForKey( k ) ); insertValue.setValue( valueForKey( k ) );
TreeNode.Type type = TreeNode.isInternal( cursor ) ? INTERNAL : LEAF; TreeNode.Type type = TreeNode.isInternal( cursor ) ? INTERNAL : LEAF;
node.insertKeyAt( cursor, insertKey, pos, keyCount, type ); node.insertKeyValueAt( cursor, insertKey, insertValue, pos, keyCount );
node.insertValueAt( cursor, insertValue, pos, keyCount );
TreeNode.setKeyCount( cursor, keyCount + 1 ); TreeNode.setKeyCount( cursor, keyCount + 1 );
} }


private void removeAtPos( int pos, TreeNode.Type type ) private void removeAtPos( int pos )
{ {
int keyCount = TreeNode.keyCount( cursor ); int keyCount = TreeNode.keyCount( cursor );
node.removeKeyAt( cursor, pos, keyCount, type ); node.removeKeyValueAt( cursor, pos, keyCount );
node.removeValueAt( cursor, pos, keyCount );
TreeNode.setKeyCount( cursor, keyCount - 1 ); TreeNode.setKeyCount( cursor, keyCount - 1 );
} }


Expand Down
Expand Up @@ -226,22 +226,29 @@ public void shouldRemoveKeyInInternal() throws Exception
} }


@Test @Test
public void shouldSetAndGetValue() throws Exception public void shouldSetAndGetKeyValue() throws Exception
{ {
// GIVEN // GIVEN
TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION ); TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION );
MutableLong value = layout.newKey(); MutableLong key = layout.newKey();
MutableLong value = layout.newValue();


// WHEN // WHEN
long firstKey = 24680;
key.setValue( firstKey );
long firstValue = 123456789; long firstValue = 123456789;
value.setValue( firstValue ); value.setValue( firstValue );
node.insertValueAt( cursor, value, 0, 0 ); node.insertKeyValueAt( cursor, key , value, 0, 0 );


long otherKey = 13579;
key.setValue( otherKey );
long otherValue = 987654321; long otherValue = 987654321;
value.setValue( otherValue ); value.setValue( otherValue );
node.insertValueAt( cursor, value, 1, 1 ); node.insertKeyValueAt( cursor, key, value, 1, 1 );


// THEN // THEN
assertEquals( firstKey, node.keyAt( cursor, key, 0, LEAF ).longValue() );
assertEquals( otherKey, node.keyAt( cursor, key, 1, LEAF ).longValue() );
assertEquals( firstValue, node.valueAt( cursor, value, 0 ).longValue() ); assertEquals( firstValue, node.valueAt( cursor, value, 0 ).longValue() );
assertEquals( otherValue, node.valueAt( cursor, value, 1 ).longValue() ); assertEquals( otherValue, node.valueAt( cursor, value, 1 ).longValue() );
} }
Expand All @@ -251,21 +258,30 @@ public void shouldRemoveValue() throws Exception
{ {
// GIVEN // GIVEN
TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION ); TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION );
MutableLong value = layout.newKey(); MutableLong key = layout.newKey();
MutableLong value = layout.newValue();
long firstKey = 24680;
key.setValue( firstKey );
long firstValue = 123456789; long firstValue = 123456789;
value.setValue( firstValue ); value.setValue( firstValue );
node.insertValueAt( cursor, value, 0, 0 ); node.insertKeyValueAt( cursor, key, value, 0, 0 );
long otherKey = 13579;
key.setValue( otherKey );
long otherValue = 987654321; long otherValue = 987654321;
value.setValue( otherValue ); value.setValue( otherValue );
node.insertValueAt( cursor, value, 1, 1 ); node.insertKeyValueAt( cursor, key, value, 1, 1 );
long thirdKey = 1029384756;
key.setValue( thirdKey );
long thirdValue = 49756; long thirdValue = 49756;
value.setValue( thirdValue ); value.setValue( thirdValue );
node.insertValueAt( cursor, value, 2, 2 ); node.insertKeyValueAt( cursor, key, value, 2, 2 );


// WHEN // WHEN
node.removeValueAt( cursor, 1, 3 ); node.removeKeyValueAt( cursor, 1, 3 );


// THEN // THEN
assertEquals( firstKey, node.keyAt( cursor, key, 0, LEAF ).longValue() );
assertEquals( thirdKey, node.keyAt( cursor, key, 1, LEAF ).longValue() );
assertEquals( firstValue, node.valueAt( cursor, value, 0 ).longValue() ); assertEquals( firstValue, node.valueAt( cursor, value, 0 ).longValue() );
assertEquals( thirdValue, node.valueAt( cursor, value, 1 ).longValue() ); assertEquals( thirdValue, node.valueAt( cursor, value, 1 ).longValue() );
} }
Expand All @@ -275,9 +291,11 @@ public void shouldOverwriteValue() throws Exception
{ {
// GIVEN // GIVEN
TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION ); TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION );
MutableLong key = layout.newKey();
MutableLong value = layout.newValue(); MutableLong value = layout.newValue();
key.setValue( 10 );
value.setValue( 1 ); value.setValue( 1 );
node.insertValueAt( cursor, value, 0, 0 ); node.insertKeyValueAt( cursor, key, value, 0, 0 );


// WHEN // WHEN
long overwrittenValue = 2; long overwrittenValue = 2;
Expand Down Expand Up @@ -387,21 +405,28 @@ public void shouldReadAndInsertKeys() throws Exception
} }


@Test @Test
public void shouldReadAndInsertValues() throws Exception public void shouldReadAndInsertKeyValues() throws Exception
{ {
// GIVEN // GIVEN
TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION ); TreeNode.initializeLeaf( cursor, STABLE_GENERATION, UNSTABLE_GENERATION );
MutableLong value = layout.newKey(); MutableLong key = layout.newKey();
MutableLong value = layout.newValue();
key.setValue( 1 );
value.setValue( 1 ); value.setValue( 1 );
node.insertValueAt( cursor, value, 0, 0 ); node.insertKeyValueAt( cursor, key, value, 0, 0 );
key.setValue( 3 );
value.setValue( 3 ); value.setValue( 3 );
node.insertValueAt( cursor, value, 1, 1 ); node.insertKeyValueAt( cursor, key, value, 1, 1 );


// WHEN // WHEN
key.setValue( 2 );
value.setValue( 2 ); value.setValue( 2 );
node.insertValueAt( cursor, value, 1, 2 ); node.insertKeyValueAt( cursor, key, value, 1, 2 );


// THEN // THEN
assertEquals( 1, node.keyAt( cursor, key, 0, LEAF ).longValue() );
assertEquals( 2, node.keyAt( cursor, key, 1, LEAF ).longValue() );
assertEquals( 3, node.keyAt( cursor, key, 2, LEAF ).longValue() );
assertEquals( 1, node.valueAt( cursor, value, 0 ).longValue() ); assertEquals( 1, node.valueAt( cursor, value, 0 ).longValue() );
assertEquals( 2, node.valueAt( cursor, value, 1 ).longValue() ); assertEquals( 2, node.valueAt( cursor, value, 1 ).longValue() );
assertEquals( 3, node.valueAt( cursor, value, 2 ).longValue() ); assertEquals( 3, node.valueAt( cursor, value, 2 ).longValue() );
Expand Down Expand Up @@ -457,11 +482,9 @@ public void shouldInsertAndRemoveRandomKeysAndValues() throws Exception
} }
while ( contains( expectedKeys, 0, expectedKeyCount, key.longValue() ) ); while ( contains( expectedKeys, 0, expectedKeyCount, key.longValue() ) );


node.insertKeyAt( cursor, key, position, expectedKeyCount, LEAF );
insert( expectedKeys, expectedKeyCount, key.longValue(), position );

value.setValue( random.nextLong() ); value.setValue( random.nextLong() );
node.insertValueAt( cursor, value, position, expectedKeyCount ); node.insertKeyValueAt( cursor, key, value, position, expectedKeyCount );
insert( expectedKeys, expectedKeyCount, key.longValue(), position );
insert( expectedValues, expectedKeyCount, value.longValue(), position ); insert( expectedValues, expectedKeyCount, value.longValue(), position );


TreeNode.setKeyCount( cursor, ++expectedKeyCount ); TreeNode.setKeyCount( cursor, ++expectedKeyCount );
Expand All @@ -473,13 +496,11 @@ public void shouldInsertAndRemoveRandomKeysAndValues() throws Exception
{ // there are things to remove { // there are things to remove
int position = random.nextInt( expectedKeyCount ); int position = random.nextInt( expectedKeyCount );
node.keyAt( cursor, key, position, LEAF ); node.keyAt( cursor, key, position, LEAF );
node.removeKeyAt( cursor, position, expectedKeyCount, LEAF );
long expectedKey = remove( expectedKeys, expectedKeyCount, position );
assertEquals( expectedKey, key.longValue() );

node.valueAt( cursor, value, position ); node.valueAt( cursor, value, position );
node.removeValueAt( cursor, position, expectedKeyCount ); node.removeKeyValueAt( cursor, position, expectedKeyCount );
long expectedKey = remove( expectedKeys, expectedKeyCount, position );
long expectedValue = remove( expectedValues, expectedKeyCount, position ); long expectedValue = remove( expectedValues, expectedKeyCount, position );
assertEquals( expectedKey, key.longValue() );
assertEquals( expectedValue, value.longValue() ); assertEquals( expectedValue, value.longValue() );


TreeNode.setKeyCount( cursor, --expectedKeyCount ); TreeNode.setKeyCount( cursor, --expectedKeyCount );
Expand Down

0 comments on commit fb65368

Please sign in to comment.