Skip to content

Commit

Permalink
TreeNodeDynamicSize impl part 8 - Cleanup 1
Browse files Browse the repository at this point in the history
  • Loading branch information
burqen committed Jan 16, 2018
1 parent 0deacb9 commit cadc8ff
Showing 1 changed file with 51 additions and 107 deletions.
Expand Up @@ -51,6 +51,11 @@ public class TreeNodeDynamicSize<KEY, VALUE> extends TreeNode<KEY,VALUE>
private static final int LEAST_NUMBER_OF_ENTRIES_PER_PAGE = 2;
private static final int MINIMUM_ENTRY_SIZE_CAP = Long.SIZE;
private final int keyValueSizeCap;
private final PrimitiveIntStack deadKeysOffset = new PrimitiveIntStack();
private final PrimitiveIntStack aliveKeysOffset = new PrimitiveIntStack();
private final int maxKeyCount = pageSize / bytesKeyOffset() + bytesKeySize() + bytesValueSize();
private final int[] oldOffset = new int[maxKeyCount];
private final int[] newOffset = new int[maxKeyCount];

TreeNodeDynamicSize( int pageSize, Layout<KEY,VALUE> layout )
{
Expand Down Expand Up @@ -303,114 +308,42 @@ Overflow leafOverflow( PageCursor cursor, int currentKeyCount, KEY newKey, VALUE
@Override
void defragmentLeaf( PageCursor cursor )
{
// Mark all offsets
PrimitiveIntStack deadKeysOffset = new PrimitiveIntStack();
PrimitiveIntStack aliveKeysOffset = new PrimitiveIntStack();
recordDeadAndAliveLeaf( cursor, deadKeysOffset, aliveKeysOffset );

/*
BEFORE MOVE
v aliveRangeOffset
[X][_][_][X][_][X][_][_]
^ ^ deadRangeOffset
|_____________ moveRangeOffset
AFTER MOVE
v aliveRangeOffset
[X][_][_][X][X][_][_][_]
^ deadRangeOffset
*/
int maxKeyCount = pageSize / (bytesKeySize() + bytesKeyOffset() + bytesValueSize());
int[] oldOffset = new int[maxKeyCount];
int[] newOffset = new int[maxKeyCount];
int oldOffsetCursor = 0;
int newOffsetCursor = 0;
int aliveRangeOffset = pageSize; // Everything after this point is alive
int deadRangeOffset; // Everything between this point and aliveRangeOffset is dead space

// Rightmost alive keys does not need to move
while ( deadKeysOffset.peek() < aliveKeysOffset.peek() )
{
aliveRangeOffset = aliveKeysOffset.poll();
}

do
{
// Locate next range of dead keys
deadRangeOffset = aliveRangeOffset;
while ( aliveKeysOffset.peek() < deadKeysOffset.peek() )
{
deadRangeOffset = deadKeysOffset.poll();
}
int minSizeOfOneKey = bytesKeySize() + bytesKeyOffset() + bytesValueSize();
doDefragment( cursor, LEAF );
}

// Locate next range of alive keys
int moveOffset = deadRangeOffset;
while ( deadKeysOffset.peek() < aliveKeysOffset.peek() )
{
int moveKey = aliveKeysOffset.poll();
oldOffset[oldOffsetCursor++] = moveKey;
moveOffset = moveKey;
}
private void defragmentInternal( PageCursor cursor )
{
int minSizeOfOneKey = bytesKeySize() + bytesKeyOffset() + childSize();
doDefragment( cursor, INTERNAL );
}

// Update offset mapping
int deadRangeSize = aliveRangeOffset - deadRangeOffset;
while ( oldOffsetCursor > newOffsetCursor )
{
newOffset[newOffsetCursor] = oldOffset[newOffsetCursor] + deadRangeSize;
newOffsetCursor++;
}
private void doDefragment( PageCursor cursor, Type type )
{
/*
The goal is to compact all alive keys in the node
by reusing the space occupied by dead keys.
// Do move
while ( moveOffset < (deadRangeOffset - deadRangeSize) )
{
// Move one block
deadRangeOffset -= deadRangeSize;
aliveRangeOffset -= deadRangeSize;
cursor.copyTo( deadRangeOffset, cursor, aliveRangeOffset, deadRangeSize );
}
// Move the last piece
int lastBlockSize = deadRangeOffset - moveOffset;
deadRangeOffset -= lastBlockSize;
aliveRangeOffset -= lastBlockSize;
cursor.copyTo( deadRangeOffset, cursor, aliveRangeOffset, lastBlockSize );
}
while ( !aliveKeysOffset.isEmpty() );
// Update allocOffset
setAllocOffset( cursor, aliveRangeOffset );
BEFORE
[8][X][1][3][X][2][X][7][5]
// Update offset array
int keyCount = keyCount( cursor );
keyPos:
for ( int pos = 0; pos < keyCount; pos++ )
{
int keyPosOffset = keyPosOffsetLeaf( pos );
cursor.setOffset( keyPosOffset );
int keyOffset = readKeyOffset( cursor );
for ( int index = 0; index < oldOffsetCursor; index++ )
{
if ( keyOffset == oldOffset[index] )
{
// Overwrite with new offset
cursor.setOffset( keyPosOffset );
putKeyOffset( cursor, newOffset[index] );
continue keyPos;
}
}
}
AFTER
.........[8][1][3][2][7][5]
^ Reclaimed space
// Update dead space
setDeadSpace( cursor, 0 );
}
It works like this:
Work from right to left.
For each dead space of size X (can be multiple consecutive dead keys)
Move all neighbouring alive keys to the left of that dead space X bytes to the right.
Can only move in blocks of size X at the time.
private void defragmentInternal( PageCursor cursor )
{
// Mark all offsets
PrimitiveIntStack deadKeysOffset = new PrimitiveIntStack();
PrimitiveIntStack aliveKeysOffset = new PrimitiveIntStack();
recordDeadAndAliveInternal( cursor, deadKeysOffset, aliveKeysOffset );
Step by step:
[8][X][1][3][X][2][X][7][5]
[8][X][1][3][X][X][2][7][5]
[8][X][X][X][1][3][2][7][5]
[X][X][X][8][1][3][2][7][5]
/*
Here is how the offsets work
BEFORE MOVE
v aliveRangeOffset
[X][_][_][X][_][X][_][_]
Expand All @@ -421,13 +354,24 @@ private void defragmentInternal( PageCursor cursor )
v aliveRangeOffset
[X][_][_][X][X][_][_][_]
^ deadRangeOffset
*/

*/
int maxKeyCount = pageSize / (bytesKeySize() + bytesKeyOffset() + childSize());
int[] oldOffset = new int[maxKeyCount];
int[] newOffset = new int[maxKeyCount];
// Mark all offsets
deadKeysOffset.clear();
aliveKeysOffset.clear();
if ( type == INTERNAL )
{
recordDeadAndAliveInternal( cursor, deadKeysOffset, aliveKeysOffset );
}
else
{
recordDeadAndAliveLeaf( cursor, deadKeysOffset, aliveKeysOffset );
}

// Cursors into field byte arrays
int oldOffsetCursor = 0;
int newOffsetCursor = 0;

int aliveRangeOffset = pageSize; // Everything after this point is alive
int deadRangeOffset; // Everything between this point and aliveRangeOffset is dead space

Expand Down Expand Up @@ -486,7 +430,7 @@ private void defragmentInternal( PageCursor cursor )
keyPos:
for ( int pos = 0; pos < keyCount; pos++ )
{
int keyPosOffset = keyPosOffsetInternal( pos );
int keyPosOffset = keyPosOffset( pos, type );
cursor.setOffset( keyPosOffset );
int keyOffset = readKeyOffset( cursor );
for ( int index = 0; index < oldOffsetCursor; index++ )
Expand Down Expand Up @@ -1043,7 +987,7 @@ public String toString()
return "TreeNodeDynamicSize[pageSize:" + pageSize + ", keyValueSizeCap:" + keyValueSizeCap + "]";
}

String asString( PageCursor cursor, boolean includeValue, long stableGeneration, long unstableGeneration )
private String asString( PageCursor cursor, boolean includeValue, long stableGeneration, long unstableGeneration )
{
int currentOffset = cursor.getOffset();
// [header] <- dont care
Expand Down

0 comments on commit cadc8ff

Please sign in to comment.