///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
#ifndef _OMEA_BTREEPAGE_H
#define _OMEA_BTREEPAGE_H
#include
#ifdef _MSC_VER
#include
#else
#include
#endif
#include "DBIndexHeapObject.h"
#include "BTreeKey.h"
///////////////////////////////////////////////////////////////////////////////
// maximum number of keys in a page is equal to 2^10 - 2
// page size is actually greater on two keys: the first (zero-based) is null
// object necessary for red-black tree fixup operations, and the second used
// for storing extra info, such as count of keys and free list first index
///////////////////////////////////////////////////////////////////////////////
#define MAX_KEYS_IN_PAGE 1022
///////////////////////////////////////////////////////////////////////////////
// if a page is of size not less than defined below, then we consider it as
// "almost full page"
// attempt of insertion to an almost full page of a key which is greater or
// equal to page's maximum leads to allocation a new page where the key
// actually will be inserted
// this feature allows to minimize splitting when key data is partially ordered
///////////////////////////////////////////////////////////////////////////////
#define ALMOST_FULL_PAGE_SIZE ( MAX_KEYS_IN_PAGE - 64 )
///////////////////////////////////////////////////////////////////////////////
// magic number used for checking pages integrity
// hex digits of the pi number
///////////////////////////////////////////////////////////////////////////////
#define BTREE_PAGE_MAGIC_NUMBER 0xbb40e609
namespace DBIndex
{
///////////////////////////////////////////////////////////////////////////
// base abstract class for all BTree pages
///////////////////////////////////////////////////////////////////////////
class BTreePageBase : public DBIndexHeapObject
{
public:
virtual BTreePageBase* Clone() const = 0;
virtual int Load() = 0;
virtual int Save() = 0;
virtual void Clear() = 0;
virtual int GetSize() const = 0;
__forceinline void SetFileHandle( int fh ) { _fileHandle = fh; }
__forceinline int GetFileHandle() const { return _fileHandle; }
__forceinline int GetOffset() const { return _fileOffset; }
__forceinline void SetOffset( int offset )
{
if( _fileOffset != offset )
{
_fileOffset = offset;
_dirty = true;
}
}
virtual bool operator<( BTreePageBase& page ) = 0;
virtual unsigned SearchForRange( const BTreeKeyBase& first, const BTreeKeyBase& last, const BTreeKeyBase* keys[] ) const = 0;
virtual unsigned GetAllKeys( const BTreeKeyBase* keys[] ) const = 0;
virtual void Insert( const BTreeKeyBase& ) = 0;
virtual bool Delete( const BTreeKeyBase& ) = 0;
virtual const BTreeKeyBase& GetMinimum() = 0;
virtual const BTreeKeyBase& GetMaximum() = 0;
virtual const BTreeKeyBase& GetSuccessor( const BTreeKeyBase& ) const = 0;
virtual void Split( BTreePageBase& ) = 0;
virtual void Merge( const BTreePageBase& ) = 0;
virtual int GetCount() const = 0;
virtual void SetCount( int count ) = 0;
virtual int IncCount() = 0;
virtual int DecCount() = 0;
__forceinline bool IsFull() const { return GetCount() == MAX_KEYS_IN_PAGE; }
__forceinline bool IsAlmostFull() const { return GetCount() >= ALMOST_FULL_PAGE_SIZE; }
protected:
BTreePageBase( int fileHandle, int offset )
: _magickNumber( BTREE_PAGE_MAGIC_NUMBER ), _fileHandle( fileHandle ), _fileOffset( offset ), _dirty( true ) {}
unsigned _magickNumber;
int _fileHandle;
int _fileOffset;
bool _dirty;
};
///////////////////////////////////////////////////////////////////////////
// template class for pages with specified key
///////////////////////////////////////////////////////////////////////////
template< class Key > class BTreePage : public BTreePageBase
{
public:
BTreePage( int fileHandle, int offset )
: BTreePageBase( fileHandle, offset )
{
ClearImpl();
}
virtual BTreePageBase* Clone() const
{
return new BTreePage< Key >( _fileHandle, _fileOffset );
}
virtual int Load()
{
DWORD read;
#ifdef _MSC_VER
DWORD pageSize = (DWORD) GetSize();
::SetFilePointer( (HANDLE) _fileHandle, (LONG) _fileOffset, NULL, FILE_BEGIN );
::ReadFile( (HANDLE) _fileHandle, (LPVOID) &_tree, pageSize, &read, NULL );
_dirty = ( pageSize != read );
#else
_lseek( _fileHandle, _fileOffset, SEEK_SET );
int pageSize = GetSize();
read = _read( _fileHandle, (void*)&_tree, pageSize );
_dirty = read != pageSize;
#endif
_minimumIndex = _maximumIndex = 0;
// check page integrity
if( !_dirty )
{
unsigned rootIndex = GetRootIndex();
_dirty = ( rootIndex >> 10 ) != ( BTREE_PAGE_MAGIC_NUMBER >> 10 );
if( !_dirty )
{
// clear integrity marker
SetRootIndex( rootIndex ^ BTREE_PAGE_MAGIC_NUMBER );
}
}
return read;
}
virtual int Save()
{
DWORD pageSize = (DWORD) GetSize();
if( _dirty )
{
// set integrity marker
unsigned rootIndex = GetRootIndex();
SetRootIndex( rootIndex ^ BTREE_PAGE_MAGIC_NUMBER );
DWORD written;
#ifdef _MSC_VER
::SetFilePointer( (HANDLE) _fileHandle, (LONG) _fileOffset, NULL, FILE_BEGIN );
::WriteFile( (HANDLE) _fileHandle, (LPCVOID) &_tree, pageSize, &written, NULL );
_dirty = written != pageSize;
#else
_lseek( _fileHandle, _fileOffset, SEEK_SET );
written = _write( _fileHandle, (const void*) &_tree, pageSize );
_dirty = false;
#endif
// clear integrity marker
SetRootIndex( rootIndex );
return written;
}
return pageSize;
}
virtual void Clear()
{
ClearImpl();
}
virtual int GetSize() const
{
return sizeof( _tree );
}
virtual bool operator<( BTreePageBase& page )
{
const KeyType& rightKey = static_cast< const KeyType& >( page.GetMinimum() );
const KeyType& thisKey = static_cast< const KeyType& >( GetMinimum() );
return thisKey < rightKey;
}
virtual unsigned SearchForRange( const BTreeKeyBase& first, const BTreeKeyBase& last, const BTreeKeyBase* keys[] ) const
{
const KeyType& realFirst = static_cast< const KeyType& >( first );
const KeyType& realLast = static_cast< const KeyType& >( last );
unsigned next = 0;
unsigned index = GetRootIndex();
while( index )
{
const KeyType& key = _tree[ index ];
if( key < realFirst )
{
index = key.GetRight();
}
else
{
next = index;
index = key.GetLeft();
}
}
unsigned count = 0;
unsigned totalCount = GetCount();
while( next )
{
const KeyType& key = _tree[ next ];
if( realLast < key )
{
break;
}
if( count == totalCount )
{
return MAX_KEYS_IN_PAGE + 1;
}
keys[ count++ ] = &key;
next = GetSuccessor( key, next );
}
return count;
}
virtual unsigned GetAllKeys( const BTreeKeyBase* keys[] ) const
{
unsigned index = ( _minimumIndex > 0 ) ? _minimumIndex : GetMinimum( GetRootIndex() );
unsigned count = 0;
unsigned totalCount = GetCount();
while( index )
{
if( count == totalCount )
{
return MAX_KEYS_IN_PAGE + 1;
}
const KeyType& key = _tree[ index ];
keys[ count++ ] = &key;
index = GetSuccessor( key, index );
}
return count;
}
virtual void Insert( const BTreeKeyBase& key )
{
const KeyType& realKey = static_cast< const KeyType& >( key );
unsigned index = GetFirstFree(); // at first check free list
if( index )
{
SetFirstFree( _tree[ index ].GetRight() );
}
else
{
index = GetCount() + 2;
}
KeyType& allocatedKey = _tree[ index ];
allocatedKey = realKey;
allocatedKey.SetRight( 0 );
allocatedKey.SetLeft( 0 );
if( GetCount() == 0 )
{
allocatedKey.SetColor( BLACK );
allocatedKey.SetParent( 0 );
SetRootIndex( index );
}
else
{
unsigned pIndex = GetRootIndex();
for( ; ; )
{
KeyType& current = _tree[ pIndex ];
bool isLess = realKey < current;
unsigned childIndex = isLess ? current.GetLeft() : current.GetRight();
if( !childIndex )
{
allocatedKey.SetParent( pIndex );
if( isLess )
{
current.SetLeft( index );
}
else
{
current.SetRight( index );
}
break;
}
pIndex = childIndex;
}
allocatedKey.SetColor( RED );
while( index != GetRootIndex() )
{
pIndex = _tree[ index ].GetParent();
KeyType& parent = _tree[ pIndex ];
if( parent.GetColor() == BLACK )
{
break;
}
unsigned ppIndex = parent.GetParent();
KeyType& parentParent = _tree[ ppIndex ];
unsigned ppLeftIndex = parentParent.GetLeft();
unsigned ppRightIndex = parentParent.GetRight();
if( ppLeftIndex == pIndex )
{
KeyType& y = _tree[ ppRightIndex ];
if( y.GetColor() == RED )
{
parent.SetColor( BLACK );
y.SetColor( BLACK );
parentParent.SetColor( RED );
index = ppIndex;
}
else if( parent.GetRight() == index )
{
index = pIndex;
LeftRotate( index );
}
else
{
parent.SetColor( BLACK );
parentParent.SetColor( RED );
RightRotate( ppIndex );
}
}
else
{
KeyType& y = _tree[ ppLeftIndex ];
if( y.GetColor() == RED )
{
parent.SetColor( BLACK );
y.SetColor( BLACK );
parentParent.SetColor( RED );
index = ppIndex;
}
else if( parent.GetLeft() == index )
{
index = pIndex;
RightRotate( index );
}
else
{
parent.SetColor( BLACK );
parentParent.SetColor( RED );
LeftRotate( ppIndex );
}
}
}
_tree[ GetRootIndex() ].SetColor( BLACK ); // root's color is always Black
}
IncCount();
_dirty = true;
_minimumIndex = _maximumIndex = 0;
}
virtual bool Delete( const BTreeKeyBase& key )
{
if( GetCount() > 0 )
{
const KeyType& realKey = static_cast< const KeyType& >( key );
unsigned index = GetRootIndex();
do
{
KeyType& current = _tree[ index ];
if( realKey < current )
{
index = current.GetLeft();
}
else if( current < realKey )
{
index = current.GetRight();
}
else
{
break;
}
}
while( index );
if( index )
{
Delete( index );
_dirty = true;
_minimumIndex = _maximumIndex = 0;
return true;
}
}
return false;
}
virtual const BTreeKeyBase& GetMinimum()
{
if( _minimumIndex == 0 )
{
_minimumIndex = GetMinimum( GetRootIndex() );
}
return _tree[ _minimumIndex ];
}
virtual const BTreeKeyBase& GetMaximum()
{
if( _maximumIndex == 0 )
{
_maximumIndex = GetMaximum( GetRootIndex() );
}
return _tree[ _maximumIndex ];
}
virtual const BTreeKeyBase& GetSuccessor( const BTreeKeyBase& key ) const
{
const KeyType* realKey = static_cast< const KeyType* >( &key );
unsigned index = ( (char*)realKey - (char*)&_tree ) / sizeof( KeyType );
return _tree[ GetSuccessor( *realKey, index ) ];
}
// !!! Only full page can be splitted !!!
virtual void Split( BTreePageBase& rightPage )
{
KeyType root = _tree[ GetRootIndex() ];
// copy keys
KeyType treeCopy[ MAX_KEYS_IN_PAGE ];
memcpy( &treeCopy, &_tree[ 2 ], sizeof( treeCopy ) );
Clear();
for( int i = 0; i < MAX_KEYS_IN_PAGE; ++i )
{
const KeyType& current = treeCopy[ i ];
if( root < current )
{
rightPage.Insert( current );
}
else
{
Insert( current );
}
}
}
virtual void Merge( const BTreePageBase& rightPage )
{
if( rightPage.GetCount() > 0 )
{
const thisType& page = static_cast< const thisType& >( rightPage );
unsigned index = page.GetMinimum( page.GetRootIndex() );
while( index )
{
const KeyType& key = page._tree[ index ];
Insert( key );
index = page.GetSuccessor( key, index );
}
}
}
///////////////////////////////////////////////////////////////////////
// first key (with index 1) doesn't actually stores a key, but is
// used for saving extra info, such as count of keys in the page and
// the index of the first free key
// freed keys are represented with linked list of indexes
///////////////////////////////////////////////////////////////////////
virtual int GetCount() const { return _tree[ 1 ].GetParent(); }
virtual void SetCount( int count ) { _tree[ 1 ].SetParent( count ); }
virtual int IncCount()
{
int result = _tree[ 1 ].GetParent() + 1;
_tree[ 1 ].SetParent( result );
return result;
}
virtual int DecCount()
{
int result = _tree[ 1 ].GetParent() - 1;
_tree[ 1 ].SetParent( result );
return result;
}
private:
typedef BTreeKey< Key > KeyType;
typedef BTreePage< Key > thisType;
void ClearImpl()
{
// it is enough to clear only 2 header keys
memset( (char*) &_tree, 0, 2 * sizeof( KeyType ) );
_dirty = true;
_minimumIndex = _maximumIndex = 0;
}
// subtree minimum
unsigned GetMinimum( unsigned index ) const
{
unsigned left;
while( ( left = _tree[ index ].GetLeft() ) )
{
index = left;
}
return index;
}
// subtree maximum
unsigned GetMaximum( unsigned index ) const
{
unsigned right;
while( ( right = _tree[ index ].GetRight() ) )
{
index = right;
}
return index;
}
unsigned GetSuccessor( const KeyType& key, unsigned index ) const
{
unsigned right = key.GetRight();
if( right )
{
return GetMinimum( right );
}
unsigned parent = key.GetParent();
while( parent )
{
const KeyType& parentKey = _tree[ parent ];
if( parentKey.GetRight() != index )
{
break;
}
index = parent;
parent = parentKey.GetParent();
}
return parent;
}
void Delete( unsigned index )
{
KeyType& z = _tree[ index ];
unsigned i = ( !z.GetRight() || !z.GetLeft() ) ? index : GetSuccessor( z, index );
KeyType& y = _tree[ i ];
unsigned j = y.GetLeft();
j = ( j ) ? j : y.GetRight();
KeyType& x = _tree[ j ];
unsigned parent = y.GetParent();
x.SetParent( parent );
if( !parent )
{
SetRootIndex( j );
}
else
{
_tree[ parent ].SetLeftOrRight( j, i );
}
if( i != index )
{
z = y;
}
if( y.GetColor() == BLACK )
{
DeleteFixup( j );
}
FreeIndex( i );
if( DecCount() == 0 )
{
SetRootIndex( 0 );
}
}
void LeftRotate( unsigned index )
{
KeyType& x = _tree[ index ];
unsigned right = x.GetRight();
KeyType& y = _tree[ right ];
unsigned left = y.GetLeft();
x.SetRight( left );
if( left )
{
_tree[ left ].SetParent( index );
}
unsigned parent = x.GetParent();
y.SetParent( parent );
if( !parent )
{
SetRootIndex( right );
}
else
{
_tree[ parent ].SetLeftOrRight( right, index );
}
y.SetLeft( index );
x.SetParent( right );
}
void RightRotate( unsigned index )
{
KeyType& x = _tree[ index ];
unsigned left = x.GetLeft();
KeyType& y = _tree[ left ];
unsigned right = y.GetRight();
x.SetLeft( right );
if( right )
{
_tree[ right ].SetParent( index );
}
unsigned parent = x.GetParent();
y.SetParent( parent );
if( !parent )
{
SetRootIndex( left );
}
else
{
_tree[ parent ].SetRightOrLeft( left, index );
}
y.SetRight( index );
x.SetParent( left );
}
void DeleteFixup( unsigned index )
{
unsigned parent, w, left, right;
while( index != GetRootIndex() )
{
KeyType& x = _tree[ index ];
if( x.GetColor() == RED )
{
break;
}
parent = x.GetParent();
KeyType& p = _tree[ parent ];
if( p.GetLeft() == index )
{
w = p.GetRight();
if( _tree[ w ].GetColor() == RED )
{
_tree[ w ].SetColor( BLACK );
p.SetColor( RED );
LeftRotate( parent );
w = p.GetRight();
}
left = _tree[ w ].GetLeft();
right = _tree[ w ].GetRight();
if( _tree[ left ].GetColor() == BLACK && _tree[ right ].GetColor() == BLACK )
{
_tree[ w ].SetColor( RED );
index = parent;
}
else if( _tree[ right ].GetColor() == BLACK )
{
_tree[ left ].SetColor( BLACK );
_tree[ w ].SetColor( RED );
RightRotate( w );
w = p.GetRight();
}
else
{
_tree[ w ].SetColor( p.GetColor() );
p.SetColor( BLACK );
_tree[ right ].SetColor( BLACK );
LeftRotate( parent );
index = GetRootIndex();
break;
}
}
else
{
w = p.GetLeft();
if( _tree[ w ].GetColor() == RED )
{
_tree[ w ].SetColor( BLACK );
p.SetColor( RED );
RightRotate( parent );
w = p.GetLeft();
}
left = _tree[ w ].GetLeft();
right = _tree[ w ].GetRight();
if( _tree[ left ].GetColor() == BLACK && _tree[ right ].GetColor() == BLACK )
{
_tree[ w ].SetColor( RED );
index = parent;
}
else if( _tree[ left ].GetColor() == BLACK )
{
_tree[ right ].SetColor( BLACK );
_tree[ w ].SetColor( RED );
LeftRotate( w );
w = p.GetLeft();
}
else
{
_tree[ w ].SetColor( p.GetColor() );
p.SetColor( BLACK );
_tree[ left ].SetColor( BLACK );
RightRotate( parent );
index = GetRootIndex();
break;
}
}
}
_tree[ index ].SetColor( BLACK );
}
__forceinline unsigned GetRootIndex() const { return _tree[ 1 ].GetOffset(); }
__forceinline void SetRootIndex( unsigned index ) { _tree[ 1 ].SetOffset( index ); }
__forceinline unsigned GetFirstFree() const { return _tree[ 1 ].GetRight(); }
__forceinline void SetFirstFree( unsigned index ) { _tree[ 1 ].SetRight( index ); }
void FreeIndex( unsigned index )
{
unsigned fEmpty = GetFirstFree();
SetFirstFree( index );
_tree[ index ].SetRight( fEmpty );
}
KeyType _tree[ MAX_KEYS_IN_PAGE + 2 ];
unsigned _minimumIndex;
unsigned _maximumIndex;
};
}
#endif