📄 bpage.java
字号:
if ( DEBUG ) {
System.out.println( "Bpage.insert() move lower-half of entries to overflow BPage, including new entry." ) ;
}
if ( height == 0 ) {
copyEntries( this, 0, newPage, half, index );
setEntry( newPage, half+index, key, value );
copyEntries( this, index, newPage, half+index+1, half-index-1 );
} else {
copyChildren( this, 0, newPage, half, index );
setChild( newPage, half+index, key, overflow );
copyChildren( this, index, newPage, half+index+1, half-index-1 );
}
} else {
// move lower-half of entries to overflow BPage,
// new entry stays on this BPage
if ( DEBUG ) {
System.out.println( "Bpage.insert() move lower-half of entries to overflow BPage. New entry stays" ) ;
}
if ( height == 0 ) {
copyEntries( this, 0, newPage, half, half );
copyEntries( this, half, this, half-1, index-half );
setEntry( this, index-1, key, value );
} else {
copyChildren( this, 0, newPage, half, half );
copyChildren( this, half, this, half-1, index-half );
setChild( this, index-1, key, overflow );
}
}
_first = half-1;
// nullify lower half of entries
for ( int i=0; i<_first; i++ ) {
if ( height == 0 ) {
setEntry( this, i, null, null );
} else {
setChild( this, i, null, -1 );
}
}
if ( _isLeaf ) {
// link newly created BPage
newPage._previous = _previous;
newPage._next = _recid;
if ( _previous != 0 ) {
BPage previous = loadBPage( _previous );
previous._next = newPage._recid;
_btree._recman.update( _previous, previous, this );
}
_previous = newPage._recid;
}
_btree._recman.update( _recid, this, this );
_btree._recman.update( newPage._recid, newPage, this );
result._overflow = newPage;
return result;
}
/**
* Remove the entry associated with the given key.
*
* @param height Height of the current BPage (zero is leaf page)
* @param key Removal key
* @return Remove result object
*/
RemoveResult remove( int height, Object key )
throws IOException
{
RemoveResult result;
int half = _btree._pageSize / 2;
int index = findChildren( key );
height -= 1;
if ( height == 0 ) {
// remove leaf entry
if ( compare( _keys[ index ], key ) != 0 ) {
throw new IllegalArgumentException( "Key not found: " + key );
}
result = new RemoveResult();
result._value = _values[ index ];
removeEntry( this, index );
// update this BPage
_btree._recman.update( _recid, this, this );
} else {
// recurse into Btree to remove entry on a children page
BPage child = childBPage( index );
result = child.remove( height, key );
// update children
_keys[ index ] = child.getLargestKey();
_btree._recman.update( _recid, this, this );
if ( result._underflow ) {
// underflow occured
if ( child._first != half+1 ) {
throw new IllegalStateException( "Error during underflow [1]" );
}
if ( index < _children.length-1 ) {
// exists greater brother page
BPage brother = childBPage( index+1 );
int bfirst = brother._first;
if ( bfirst < half ) {
// steal entries from "brother" page
int steal = ( half - bfirst + 1 ) / 2;
brother._first += steal;
child._first -= steal;
if ( child._isLeaf ) {
copyEntries( child, half+1, child, half+1-steal, half-1 );
copyEntries( brother, bfirst, child, 2*half-steal, steal );
} else {
copyChildren( child, half+1, child, half+1-steal, half-1 );
copyChildren( brother, bfirst, child, 2*half-steal, steal );
}
for ( int i=bfirst; i<bfirst+steal; i++ ) {
if ( brother._isLeaf ) {
setEntry( brother, i, null, null );
} else {
setChild( brother, i, null, -1 );
}
}
// update child's largest key
_keys[ index ] = child.getLargestKey();
// no change in previous/next BPage
// update BPages
_btree._recman.update( _recid, this, this );
_btree._recman.update( brother._recid, brother, this );
_btree._recman.update( child._recid, child, this );
} else {
// move all entries from page "child" to "brother"
if ( brother._first != half ) {
throw new IllegalStateException( "Error during underflow [2]" );
}
brother._first = 1;
if ( child._isLeaf ) {
copyEntries( child, half+1, brother, 1, half-1 );
} else {
copyChildren( child, half+1, brother, 1, half-1 );
}
_btree._recman.update( brother._recid, brother, this );
// remove "child" from current BPage
if ( _isLeaf ) {
copyEntries( this, _first, this, _first+1, index-_first );
setEntry( this, _first, null, null );
} else {
copyChildren( this, _first, this, _first+1, index-_first );
setChild( this, _first, null, -1 );
}
_first += 1;
_btree._recman.update( _recid, this, this );
// re-link previous and next BPages
if ( child._previous != 0 ) {
BPage prev = loadBPage( child._previous );
prev._next = child._next;
_btree._recman.update( prev._recid, prev, this );
}
if ( child._next != 0 ) {
BPage next = loadBPage( child._next );
next._previous = child._previous;
_btree._recman.update( next._recid, next, this );
}
// delete "child" BPage
_btree._recman.delete( child._recid );
}
} else {
// page "brother" is before "child"
BPage brother = childBPage( index-1 );
int bfirst = brother._first;
if ( bfirst < half ) {
// steal entries from "brother" page
int steal = ( half - bfirst + 1 ) / 2;
brother._first += steal;
child._first -= steal;
if ( child._isLeaf ) {
copyEntries( brother, 2*half-steal, child,
half+1-steal, steal );
copyEntries( brother, bfirst, brother,
bfirst+steal, 2*half-bfirst-steal );
} else {
copyChildren( brother, 2*half-steal, child,
half+1-steal, steal );
copyChildren( brother, bfirst, brother,
bfirst+steal, 2*half-bfirst-steal );
}
for ( int i=bfirst; i<bfirst+steal; i++ ) {
if ( brother._isLeaf ) {
setEntry( brother, i, null, null );
} else {
setChild( brother, i, null, -1 );
}
}
// update brother's largest key
_keys[ index-1 ] = brother.getLargestKey();
// no change in previous/next BPage
// update BPages
_btree._recman.update( _recid, this, this );
_btree._recman.update( brother._recid, brother, this );
_btree._recman.update( child._recid, child, this );
} else {
// move all entries from page "brother" to "child"
if ( brother._first != half ) {
throw new IllegalStateException( "Error during underflow [3]" );
}
child._first = 1;
if ( child._isLeaf ) {
copyEntries( brother, half, child, 1, half );
} else {
copyChildren( brother, half, child, 1, half );
}
_btree._recman.update( child._recid, child, this );
// remove "brother" from current BPage
if ( _isLeaf ) {
copyEntries( this, _first, this, _first+1, index-1-_first );
setEntry( this, _first, null, null );
} else {
copyChildren( this, _first, this, _first+1, index-1-_first );
setChild( this, _first, null, -1 );
}
_first += 1;
_btree._recman.update( _recid, this, this );
// re-link previous and next BPages
if ( brother._previous != 0 ) {
BPage prev = loadBPage( brother._previous );
prev._next = brother._next;
_btree._recman.update( prev._recid, prev, this );
}
if ( brother._next != 0 ) {
BPage next = loadBPage( brother._next );
next._previous = brother._previous;
_btree._recman.update( next._recid, next, this );
}
// delete "brother" BPage
_btree._recman.delete( brother._recid );
}
}
}
}
// underflow if page is more than half-empty
result._underflow = _first > half;
return result;
}
/**
* Find the first children node with a key equal or greater than the given
* key.
*
* @return index of first children with equal or greater key.
*/
private int findChildren( Object key )
{
int left = _first;
int right = _btree._pageSize-1;
// binary search
while ( left < right ) {
int middle = ( left + right ) / 2;
if ( compare( _keys[ middle ], key ) < 0 ) {
left = middle+1;
} else {
right = middle;
}
}
return right;
}
/**
* Insert entry at given position.
*/
private static void insertEntry( BPage page, int index,
Object key, Object value )
{
Object[] keys = page._keys;
Object[] values = page._values;
int start = page._first;
int count = index-page._first+1;
// shift entries to the left
System.arraycopy( keys, start, keys, start-1, count );
System.arraycopy( values, start, values, start-1, count );
page._first -= 1;
keys[ index ] = key;
values[ index ] = value;
}
/**
* Insert child at given position.
*/
private static void insertChild( BPage page, int index,
Object key, long child )
{
Object[] keys = page._keys;
long[] children = page._children;
int start = page._first;
int count = index-page._first+1;
// shift entries to the left
System.arraycopy( keys, start, keys, start-1, count );
System.arraycopy( children, start, children, start-1, count );
page._first -= 1;
keys[ index ] = key;
children[ index ] = child;
}
/**
* Remove entry at given position.
*/
private static void removeEntry( BPage page, int index )
{
Object[] keys = page._keys;
Object[] values = page._values;
int start = page._first;
int count = index-page._first;
System.arraycopy( keys, start, keys, start+1, count );
keys[ start ] = null;
System.arraycopy( values, start, values, start+1, count );
values[ start ] = null;
page._first++;
}
/**
* Remove child at given position.
*/
/*
private static void removeChild( BPage page, int index )
{
Object[] keys = page._keys;
long[] children = page._children;
int start = page._first;
int count = index-page._first;
System.arraycopy( keys, start, keys, start+1, count );
keys[ start ] = null;
System.arraycopy( children, start, children, start+1, count );
children[ start ] = (long) -1;
page._first++;
}
*/
/**
* Set the entry at the given index.
*/
private static void setEntry( BPage page, int index, Object key, Object value )
{
page._keys[ index ] = key;
page._values[ index ] = value;
}
/**
* Set the child BPage recid at the given index.
*/
private static void setChild( BPage page, int index, Object key, long recid )
{
page._keys[ index ] = key;
page._children[ index ] = recid;
}
/**
* Copy entries between two BPages
*/
private static void copyEntries( BPage source, int indexSource,
BPage dest, int indexDest, int count )
{
System.arraycopy( source._keys, indexSource, dest._keys, indexDest, count);
System.arraycopy( source._values, indexSource, dest._values, indexDest, count);
}
/**
* Copy child BPage recids between two BPages
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -