📄 bpage.java
字号:
/**
* JDBM LICENSE v1.00
*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "JDBM" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Cees de Groot. For written permission,
* please contact cg@cdegroot.com.
*
* 4. Products derived from this Software may not be called "JDBM"
* nor may "JDBM" appear in their names without prior written
* permission of Cees de Groot.
*
* 5. Due credit should be given to the JDBM Project
* (http://jdbm.sourceforge.net/).
*
* THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001 (C) Alex Boisvert. All Rights Reserved.
* Contributions are Copyright (C) 2001 by their associated contributors.
*
*/
package jdbm.btree;
import jdbm.helper.Serializer;
import jdbm.helper.Tuple;
import jdbm.helper.TupleBrowser;
import java.io.IOException;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Page of a Btree.
* <p>
* The page contains a number of key-value pairs. Keys are ordered to allow
* dichotomic search.
* <p>
* If the page is a leaf page, the keys and values are user-defined and
* represent entries inserted by the user.
* <p>
* If the page is non-leaf, each key represents the greatest key in the
* underlying BPages and the values are recids pointing to the children BPages.
* The only exception is the rightmost BPage, which is considered to have an
* "infinite" key value, meaning that any insert will be to the left of this
* pseudo-key
*
* @author <a href="mailto:boisvert@intalio.com">Alex Boisvert</a>
* @version $Id: BPage.java,v 1.6 2003/09/21 15:46:59 boisvert Exp $
*/
public final class BPage
implements Serializer
{
private static final boolean DEBUG = false;
/**
* Version id for serialization.
*/
final static long serialVersionUID = 1L;
/**
* Parent B+Tree.
*/
transient BTree _btree;
/**
* This BPage's record ID in the PageManager.
*/
protected transient long _recid;
/**
* Flag indicating if this is a leaf BPage.
*/
protected boolean _isLeaf;
/**
* Keys of children nodes
*/
protected Object[] _keys;
/**
* Values associated with keys. (Only valid if leaf BPage)
*/
protected Object[] _values;
/**
* Children pages (recids) associated with keys. (Only valid if non-leaf BPage)
*/
protected long[] _children;
/**
* Index of first used item at the page
*/
protected int _first;
/**
* Previous leaf BPage (only if this BPage is a leaf)
*/
protected long _previous;
/**
* Next leaf BPage (only if this BPage is a leaf)
*/
protected long _next;
/**
* No-argument constructor used by serialization.
*/
public BPage()
{
// empty
}
/**
* Root page overflow constructor
*/
BPage( BTree btree, BPage root, BPage overflow )
throws IOException
{
_btree = btree;
_isLeaf = false;
_first = _btree._pageSize-2;
_keys = new Object[ _btree._pageSize ];
_keys[ _btree._pageSize-2 ] = overflow.getLargestKey();
_keys[ _btree._pageSize-1 ] = root.getLargestKey();
_children = new long[ _btree._pageSize ];
_children[ _btree._pageSize-2 ] = overflow._recid;
_children[ _btree._pageSize-1 ] = root._recid;
_recid = _btree._recman.insert( this, this );
}
/**
* Root page (first insert) constructor.
*/
BPage( BTree btree, Object key, Object value )
throws IOException
{
_btree = btree;
_isLeaf = true;
_first = btree._pageSize-2;
_keys = new Object[ _btree._pageSize ];
_keys[ _btree._pageSize-2 ] = key;
_keys[ _btree._pageSize-1 ] = null; // I am the root BPage for now
_values = new Object[ _btree._pageSize ];
_values[ _btree._pageSize-2 ] = value;
_values[ _btree._pageSize-1 ] = null; // I am the root BPage for now
_recid = _btree._recman.insert( this, this );
}
/**
* Overflow page constructor. Creates an empty BPage.
*/
BPage( BTree btree, boolean isLeaf )
throws IOException
{
_btree = btree;
_isLeaf = isLeaf;
// page will initially be half-full
_first = _btree._pageSize/2;
_keys = new Object[ _btree._pageSize ];
if ( isLeaf ) {
_values = new Object[ _btree._pageSize ];
} else {
_children = new long[ _btree._pageSize ];
}
_recid = _btree._recman.insert( this, this );
}
/**
* Get largest key under this BPage. Null is considered to be the
* greatest possible key.
*/
Object getLargestKey()
{
return _keys[ _btree._pageSize-1 ];
}
/**
* Return true if BPage is empty.
*/
boolean isEmpty()
{
if ( _isLeaf ) {
return ( _first == _values.length-1 );
} else {
return ( _first == _children.length-1 );
}
}
/**
* Return true if BPage is full.
*/
boolean isFull() {
return ( _first == 0 );
}
/**
* Find the object associated with the given key.
*
* @param height Height of the current BPage (zero is leaf page)
* @param key The key
* @return TupleBrowser positionned just before the given key, or before
* next greater key if key isn't found.
*/
TupleBrowser find( int height, Object key )
throws IOException
{
int index = findChildren( key );
/*
if ( DEBUG ) {
System.out.println( "BPage.find() current: " + this
+ " height: " + height);
}
*/
height -= 1;
if ( height == 0 ) {
// leaf BPage
return new Browser( this, index );
} else {
// non-leaf BPage
BPage child = childBPage( index );
return child.find( height, key );
}
}
/**
* Find first entry and return a browser positioned before it.
*
* @return TupleBrowser positionned just before the first entry.
*/
TupleBrowser findFirst()
throws IOException
{
if ( _isLeaf ) {
return new Browser( this, _first );
} else {
BPage child = childBPage( _first );
return child.findFirst();
}
}
/**
* Insert the given key and value.
* <p>
* Since the Btree does not support duplicate entries, the caller must
* specify whether to replace the existing value.
*
* @param height Height of the current BPage (zero is leaf page)
* @param key Insert key
* @param value Insert value
* @param replace Set to true to replace the existing value, if one exists.
* @return Insertion result containing existing value OR a BPage if the key
* was inserted and provoked a BPage overflow.
*/
InsertResult insert( int height, Object key, Object value, boolean replace )
throws IOException
{
InsertResult result;
long overflow;
int index = findChildren( key );
height -= 1;
if ( height == 0 ) {
result = new InsertResult();
// inserting on a leaf BPage
overflow = -1;
if ( DEBUG ) {
System.out.println( "Bpage.insert() Insert on leaf Bpage key=" + key
+ " value=" + value + " index="+index);
}
if ( compare( key, _keys[ index ] ) == 0 ) {
// key already exists
if ( DEBUG ) {
System.out.println( "Bpage.insert() Key already exists." ) ;
}
result._existing = _values[ index ];
if ( replace ) {
_values [ index ] = value;
_btree._recman.update( _recid, this, this );
}
// return the existing key
return result;
}
} else {
// non-leaf BPage
BPage child = childBPage( index );
result = child.insert( height, key, value, replace );
if ( result._existing != null ) {
// return existing key, if any.
return result;
}
if ( result._overflow == null ) {
// no overflow means we're done with insertion
return result;
}
// there was an overflow, we need to insert the overflow page
// on this BPage
if ( DEBUG ) {
System.out.println( "BPage.insert() Overflow page: " + result._overflow._recid );
}
key = result._overflow.getLargestKey();
overflow = result._overflow._recid;
// update child's largest key
_keys[ index ] = child.getLargestKey();
// clean result so we can reuse it
result._overflow = null;
}
// if we get here, we need to insert a new entry on the BPage
// before _children[ index ]
if ( !isFull() ) {
if ( height == 0 ) {
insertEntry( this, index-1, key, value );
} else {
insertChild( this, index-1, key, overflow );
}
_btree._recman.update( _recid, this, this );
return result;
}
// page is full, we must divide the page
int half = _btree._pageSize >> 1;
BPage newPage = new BPage( _btree, _isLeaf );
if ( index < half ) {
// move lower-half of entries to overflow BPage,
// including new entry
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -