///
/// 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).
///
#include "DBIndex.h"
#include "Enumerator.h"
#define HEADER_SIZE 1024
using namespace System::Diagnostics;
using namespace JetBrains::Omea::Containers;
namespace DBIndex
{
OmniaMeaBTree::OmniaMeaBTree( String* filename, IFixedLengthKey* factoryKey )
{
Trace::Write( "OmeaBTree(" );
Trace::Write( System::IO::Path::GetFileName( filename ) );
Trace::WriteLine( "): Creating..." );
DBIndexHeapObject::CreateHeap();
_filename = filename;
_factoryKey = factoryKey->FactoryMethod();
_pagesCache = BTreePagesCache::Create( 16 );
_searchForRangeEnumerable = new SearchForRangeEnumerable( this );
_freeOffsets = new IntArrayList();
_oneItemList = new ArrayList( 1 );
_keysInIndex = 0;
_keyType = unknown_Key;
_page = 0;
_freePage = 0;
_firstKey = 0;
_lastKey = 0;
_headerKey = 0;
_btreeHeader = 0;
_btreeHeaderIterator = 0;
_keyComparer = 0;
_numberOfPages = 0;
_loadedPages = 0;
Object* key = factoryKey->Key;
Type* keyType = key->GetType();
if( keyType->Equals( __typeof( Int32 ) ) )
{
_keyType = int_Key;
}
else if( keyType->Equals( __typeof( Int64 ) ) )
{
_keyType = long_Key;
}
else if( keyType->Equals( __typeof( DateTime ) ) )
{
_keyType = datetime_Key;
}
else if( keyType->Equals( __typeof( Double ) ) )
{
_keyType = double_Key;
}
else if( keyType->Equals( __typeof( Compound ) ) )
{
Compound* compound = dynamic_cast< Compound* >( key );
Type* type1 = compound->_key1->GetType();
Type* type2 = compound->_key2->GetType();
if( type1->Equals( __typeof( Int32 ) ) )
{
if( type2->Equals( __typeof( Int32 ) ) )
{
_keyType = int_int_Key;
}
else if( type2->Equals( __typeof( DateTime ) ) )
{
_keyType = int_datetime_Key;
}
else if( type2->Equals( __typeof( Int64 ) ) )
{
_keyType = int_long_Key;
}
}
else if( type1->Equals( __typeof( Int64 ) ) )
{
if( type2->Equals( __typeof( Int32 ) ) )
{
_keyType = long_int_Key;
}
else if( type2->Equals( __typeof( Int64 ) ) )
{
_keyType = long_long_Key;
}
}
}
else if( keyType->Equals( __typeof( CompoundAndValue ) ) )
{
CompoundAndValue* compound = dynamic_cast< CompoundAndValue* >( key );
Type* type1 = compound->_key1->GetType();
Type* type2 = compound->_key2->GetType();
Type* valueType = compound->_value->GetType();
if( type1->Equals( __typeof( Int32 ) ) )
{
if( type2->Equals( __typeof( Int32 ) ) )
{
if( valueType->Equals( __typeof( Int32 ) ) )
{
_keyType = int_int_int_Key;
}
else if( valueType->Equals( __typeof( DateTime ) ) )
{
_keyType = int_int_datetime_Key;
}
}
else if( type2->Equals( __typeof( DateTime ) ) )
{
if( valueType->Equals( __typeof( Int32 ) ) )
{
_keyType = int_datetime_int_Key;
}
}
}
}
}
void OmniaMeaBTree::Dispose()
{
Trace::Write( "OmeaBTree(" );
Trace::Write( System::IO::Path::GetFileName( _filename ) );
Trace::WriteLine( "): Disposing..." );
if( _page )
{
TypeFactory::DeletePage( _page );
_page = 0;
}
if( _freePage )
{
TypeFactory::DeletePage( _freePage );
_freePage = 0;
}
if( !_firstKey )
{
TypeFactory::DeleteKey( _firstKey );
_firstKey = 0;
}
if( !_lastKey )
{
TypeFactory::DeleteKey( _lastKey );
_lastKey = 0;
}
if( !_headerKey )
{
TypeFactory::DeleteKey( _headerKey );
_headerKey = 0;
}
if( !_btreeHeader )
{
TypeFactory::DeleteHeader( _btreeHeader );
_btreeHeader = 0;
}
if( !_btreeHeaderIterator )
{
TypeFactory::DeleteHeaderIterator( _btreeHeaderIterator );
_btreeHeaderIterator = 0;
}
if( !_keyComparer )
{
TypeFactory::DeleteKeyComparer( _keyComparer );
_keyComparer = 0;
}
BTreePagesCache::Delete( _pagesCache );
_pagesCache = 0;
}
bool OmniaMeaBTree::Open()
{
InstantiateTypes();
_btreeFile = new FileStream( _filename, FileMode::OpenOrCreate, FileAccess::ReadWrite, FileShare::Read, 8 );
int fileHandle = _btreeFile->Handle.ToInt32();
_page->SetFileHandle( fileHandle );
if( _freePage )
{
_freePage->SetFileHandle( fileHandle );
}
_keysInIndex = 0;
/**
* check whether the btree was successfully closed, and load header if it was
*/
byte closed = ( _btreeFile->Length < HEADER_SIZE ) ? 0 : _btreeFile->ReadByte();
_btreeFile->Position = 0;
_btreeFile->WriteByte( 0 );
if( !closed )
{
for( int i = 1; i < HEADER_SIZE; ++i )
{
_btreeFile->WriteByte( 0 );
}
}
else
{
BinaryReader* reader = new BinaryReader( _btreeFile );
_keysInIndex = reader->ReadInt32();
int size = reader->ReadInt32();
_btreeFile->Position = size;
if( !_btreeHeader->Load( fileHandle ) )
{
throw new System::IO::IOException( "Failed to load BTree header" );
}
else
{
_btreeFile->SetLength( size );
_numberOfPages = _btreeHeader->Size();
}
}
_btreeFile->Flush();
return closed != 0;
}
void OmniaMeaBTree::Close()
{
Flush();
CloseFile();
/**
* save header and mark as closed
*/
try
{
_btreeFile = new FileStream( _filename, FileMode::OpenOrCreate, FileAccess::ReadWrite, FileShare::None, 8 );
if( _btreeFile->get_CanRead() && _btreeFile->get_CanWrite() )
{
BinaryWriter* writer = new BinaryWriter( _btreeFile );
_btreeFile->WriteByte( 0 );
writer->Write( _keysInIndex );
writer->Write( (int) _btreeFile->Length );
_btreeFile->Position = _btreeFile->Length;
if( _btreeHeader->Save( _btreeFile->Handle.ToInt32() ) )
{
_btreeFile->Position = 0;
_btreeFile->WriteByte( 1 );
}
CloseFile();
}
}
catch(...) {}
_btreeHeader->Clear();
_freeOffsets->Clear();
_keysInIndex = 0;
_numberOfPages = 0;
}
void OmniaMeaBTree::CloseFile()
{
if( _btreeFile != 0 )
{
_btreeFile->Close();
}
}
void OmniaMeaBTree::Clear()
{
// if btree is opened and was not disposed
if( _page )
{
_btreeHeader->Clear();
_freeOffsets->Clear();
_pagesCache->ClearWithoutSaving();
_keysInIndex = 0;
_btreeFile->SetLength( HEADER_SIZE );
_btreeFile->Position = 0;
for( int i = 0; i < HEADER_SIZE; ++i )
{
_btreeFile->WriteByte( 0 );
}
_numberOfPages = 0;
}
}
void OmniaMeaBTree::Flush()
{
// if btree was opened and not disposed
if( _page )
{
_pagesCache->Clear( *_btreeHeader );
}
}
void OmniaMeaBTree::GetAllKeys( IntArrayList* offsets )
{
const BTreeKeyBase* temp_keys[ MAX_KEYS_IN_PAGE ];
_btreeHeader->GetMinimumPage( *_btreeHeaderIterator );
while( !_btreeHeaderIterator->Exhausted() )
{
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
unsigned keyCount = page->GetAllKeys( temp_keys );
if( keyCount > MAX_KEYS_IN_PAGE )
{
throw new BadIndexesException( "BTree contains cycles. Possible memory corruption." );
}
CopyOffsets( temp_keys, keyCount, offsets );
_btreeHeaderIterator->MoveNextPage();
}
}
void OmniaMeaBTree::GetAllKeys( ArrayList* keys_offsets )
{
const BTreeKeyBase* temp_keys[ MAX_KEYS_IN_PAGE ];
_btreeHeader->GetMinimumPage( *_btreeHeaderIterator );
while( !_btreeHeaderIterator->Exhausted() )
{
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
unsigned keyCount = page->GetAllKeys( temp_keys );
if( keyCount > MAX_KEYS_IN_PAGE )
{
throw new BadIndexesException( "BTree contains cycles. Possible memory corruption." );
}
CopyKeys( temp_keys, keyCount, keys_offsets );
_btreeHeaderIterator->MoveNextPage();
}
}
IEnumerable* OmniaMeaBTree::GetAllKeys()
{
return new GetAllKeysEnumerable( this );
}
KeyPair* OmniaMeaBTree::GetMinimum()
{
_btreeHeader->GetMinimumPage( *_btreeHeaderIterator );
if( _btreeHeaderIterator->Exhausted() )
{
return 0;
}
_oneItemList->Clear();
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
const BTreeKeyBase* oneKey[ 1 ];
oneKey[ 0 ] = &page->GetMinimum();
CopyKeys( oneKey, 1, _oneItemList );
return dynamic_cast( _oneItemList->get_Item( 0 ) );
}
KeyPair* OmniaMeaBTree::GetMaximum()
{
_btreeHeader->GetMaximumPage( *_btreeHeaderIterator );
if( _btreeHeaderIterator->Exhausted() )
{
return 0;
}
_oneItemList->Clear();
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
const BTreeKeyBase* oneKey[ 1 ];
oneKey[ 0 ] = &page->GetMaximum();
CopyKeys( oneKey, 1, _oneItemList );
return dynamic_cast( _oneItemList->get_Item( 0 ) );
}
void OmniaMeaBTree::SearchForRange( IFixedLengthKey* beginKey, IFixedLengthKey* endKey, IntArrayList* offsets )
{
SetFirstAndLastKeys( beginKey, endKey );
const BTreeKeyBase& firstKey = *_firstKey;
const BTreeKeyBase& lastKey = *_lastKey;
const BTreeKeyBase* temp_keys[ MAX_KEYS_IN_PAGE ];
_btreeHeader->GetPage( firstKey, *_btreeHeaderIterator );
while( !_btreeHeaderIterator->Exhausted() )
{
_btreeHeaderIterator->GetCurrentKey( *_headerKey );
if( _keyComparer->Less( lastKey, *_headerKey ) )
{
break;
}
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
unsigned keyCount = page->SearchForRange( firstKey, lastKey, temp_keys );
if( keyCount > MAX_KEYS_IN_PAGE )
{
throw new BadIndexesException( "BTree contains cycles. Possible memory corruption." );
}
CopyOffsets( temp_keys, keyCount, offsets );
_btreeHeaderIterator->MoveNextPage();
}
}
void OmniaMeaBTree::SearchForRange( IFixedLengthKey* beginKey, IFixedLengthKey* endKey, ArrayList* keys_offsets )
{
SetFirstAndLastKeys( beginKey, endKey );
const BTreeKeyBase& firstKey = *_firstKey;
const BTreeKeyBase& lastKey = *_lastKey;
const BTreeKeyBase* temp_keys[ MAX_KEYS_IN_PAGE ];
_btreeHeader->GetPage( firstKey, *_btreeHeaderIterator );
while( !_btreeHeaderIterator->Exhausted() )
{
_btreeHeaderIterator->GetCurrentKey( *_headerKey );
if( _keyComparer->Less( lastKey, *_headerKey ) )
{
break;
}
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
unsigned keyCount = page->SearchForRange( firstKey, lastKey, temp_keys );
if( keyCount > MAX_KEYS_IN_PAGE )
{
throw new BadIndexesException( "BTree contains cycles. Possible memory corruption." );
}
CopyKeys( temp_keys, keyCount, keys_offsets );
_btreeHeaderIterator->MoveNextPage();
}
}
IEnumerable* OmniaMeaBTree::SearchForRange( IFixedLengthKey* beginKey, IFixedLengthKey* endKey )
{
dynamic_cast( _searchForRangeEnumerable )->Init( beginKey, endKey );
return _searchForRangeEnumerable;
}
void OmniaMeaBTree::DeleteKey( IFixedLengthKey* akey, int offset )
{
SetFirstKey( akey );
_firstKey->SetOffset( offset );
const BTreeKeyBase& firstKey = *_firstKey;
_btreeHeader->GetPage( firstKey, *_btreeHeaderIterator );
if( !_btreeHeaderIterator->Exhausted() )
{
BTreePageBase* page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
if( page->Delete( firstKey ) )
{
--_keysInIndex;
_btreeHeaderIterator->GetCurrentKey( *_headerKey );
offset = page->GetOffset();
if( page->GetCount() == 0 )
{
_freeOffsets->Add( offset );
_pagesCache->RemovePage( offset );
_btreeHeader->DeletePageOffset( *_headerKey );
--_numberOfPages;
}
else
{
const BTreeKeyBase& minKey = page->GetMinimum();
if( _keyComparer->Less( firstKey, minKey ) )
{
_btreeHeader->DeletePageOffset( firstKey );
_btreeHeader->SetPageOffset( minKey, offset );
}
}
}
}
}
void OmniaMeaBTree::InsertKey( IFixedLengthKey* akey, int offset )
{
SetFirstKey( akey );
_firstKey->SetOffset( offset );
++_keysInIndex;
const BTreeKeyBase& firstKey = *_firstKey;
BTreePageBase* page;
_btreeHeader->GetPage( firstKey, *_btreeHeaderIterator );
if( _btreeHeaderIterator->Exhausted() )
{
page = AllocPage();
page->Insert( firstKey );
_btreeHeader->SetPageOffset( firstKey, page->GetOffset() );
}
else
{
page = GetPageByOffset( _btreeHeaderIterator->GetCurrentOffset() );
if( !page->IsFull() )
{
if( page->IsAlmostFull() )
{
if( _keyComparer->Less( page->GetMaximum(), firstKey ) ||
_keyComparer->Less( firstKey, page->GetMinimum() ) )
{
BTreePageBase* newPage = AllocPage();
newPage->Insert( firstKey );
_btreeHeader->SetPageOffset( firstKey, newPage->GetOffset() );
return;
}
}
page->Insert( firstKey );
}
else
{
BTreePageBase* rightPage = AllocPage();
page->Split( *rightPage );
const BTreeKeyBase& minKey = rightPage->GetMinimum();
_btreeHeader->SetPageOffset( minKey, rightPage->GetOffset() );
if( _keyComparer->Less( firstKey, minKey ) )
{
page->Insert( firstKey );
}
else
{
rightPage->Insert( firstKey );
return;
}
}
_btreeHeaderIterator->GetCurrentKey( *_headerKey );
if( _keyComparer->Less( firstKey, *_headerKey ) )
{
_btreeHeader->DeletePageOffset( *_headerKey );
_btreeHeader->SetPageOffset( firstKey, page->GetOffset() );
}
}
}
int OmniaMeaBTree::get_MaxCount()
{
return MAX_KEYS_IN_PAGE;
}
int OmniaMeaBTree::get_Count()
{
return _keysInIndex;
}
void OmniaMeaBTree::SetCacheSize( int numberOfPages )
{
if( numberOfPages < 2 ) // cache size can't be less than 2
{
numberOfPages = 2;
}
_pagesCache->SetSize( (unsigned) numberOfPages );
}
int OmniaMeaBTree::GetCacheSize()
{
return _pagesCache->GetSize();
}
int OmniaMeaBTree::GetObjectsCount()
{
return DBIndexHeapObject::ObjectsCount();
}
int OmniaMeaBTree::GetUsedMemory()
{
return DBIndexHeapObject::HeapSize();
}
///////////////////////////////////////////////////////////////////////////
// implementation details (private members)
///////////////////////////////////////////////////////////////////////////
void OmniaMeaBTree::InstantiateTypes()
{
int type = _keyType;
if( type == unknown_Key )
{
throw new System::Exception( "Key type is not supported!" );
}
if( !_page )
{
_page = TypeFactory::NewPage( type );
}
if( !_firstKey )
{
_firstKey = TypeFactory::NewKey( type );
}
if( !_lastKey )
{
_lastKey = TypeFactory::NewKey( type );
}
if( !_headerKey )
{
_headerKey = TypeFactory::NewKey( type );
}
if( !_btreeHeader )
{
_btreeHeader = TypeFactory::NewHeader( type );
}
if( !_btreeHeaderIterator )
{
_btreeHeaderIterator = TypeFactory::NewHeaderIterator( type );
}
if( !_keyComparer )
{
_keyComparer = TypeFactory::NewKeyComparer( type );
}
}
void OmniaMeaBTree::SetFirstKey( IFixedLengthKey* akey )
{
switch( _keyType )
{
case int_Key:
{
int theKey = *dynamic_cast( akey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( theKey );
break;
}
case int_int_Key:
{
Compound* compound = dynamic_cast( akey->Key );
CompoundKey theKey;
theKey._first = *dynamic_cast( compound->_key1 );
theKey._second = *dynamic_cast( compound->_key2 );
static_cast< BTreeKey< CompoundKey >* >( _firstKey )->SetKey( theKey );
break;
}
case int_datetime_Key:
{
Compound* compound = dynamic_cast( akey->Key );
CompoundKey theKey;
theKey._first = *dynamic_cast( compound->_key1 );
theKey._second = dynamic_cast<__box DateTime*>( compound->_key2 )->Ticks;
static_cast< BTreeKey< CompoundKey >* >( _firstKey )->SetKey( theKey );
break;
}
case int_int_int_Key:
{
CompoundAndValue* compound = dynamic_cast( akey->Key );
CompoundKeyWithValue theKey;
theKey._first = *dynamic_cast( compound->_key1 );
theKey._second = *dynamic_cast( compound->_key2 );
int value = *dynamic_cast( compound->_value );
theKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( theKey );
break;
}
case int_int_datetime_Key:
{
CompoundAndValue* compound = dynamic_cast( akey->Key );
CompoundKeyWithValue theKey;
theKey._first = *dynamic_cast( compound->_key1 );
theKey._second = *dynamic_cast( compound->_key2 );
long value = dynamic_cast<__box DateTime*>( compound->_value )->Ticks;
theKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( theKey );
break;
}
case int_datetime_int_Key:
{
CompoundAndValue* compound = dynamic_cast( akey->Key );
CompoundKeyWithValue theKey;
theKey._first = *dynamic_cast( compound->_key1 );
theKey._second = dynamic_cast<__box DateTime*>( compound->_key2 )->Ticks;
int value = *dynamic_cast( compound->_value );
theKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( theKey );
break;
}
case long_Key:
{
long theKey = *dynamic_cast( akey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( theKey );
break;
}
case datetime_Key:
{
long theKey = dynamic_cast<__box DateTime*>( akey->Key )->Ticks;
static_cast< BTreeKey* >( _firstKey )->SetKey( theKey );
break;
}
case double_Key:
{
double theKey = *dynamic_cast( akey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( theKey );
break;
}
default: throw new System::Exception( "Key type is not supported!" );
}
}
void OmniaMeaBTree::SetFirstAndLastKeys( IFixedLengthKey* beginKey, IFixedLengthKey* endKey )
{
switch( _keyType )
{
case int_Key:
{
int firstKey = *dynamic_cast( beginKey->Key );
int lastKey = *dynamic_cast( endKey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey* >( _lastKey )->SetKey( lastKey );
break;
}
case int_int_Key:
{
Compound* compound1 = dynamic_cast( beginKey->Key );
Compound* compound2 = dynamic_cast( endKey->Key );
CompoundKey firstKey;
CompoundKey lastKey;
firstKey._first = *dynamic_cast( compound1->_key1 );
firstKey._second = *dynamic_cast( compound1->_key2 );
lastKey._first = *dynamic_cast( compound2->_key1 );
lastKey._second = *dynamic_cast( compound2->_key2 );
static_cast< BTreeKey< CompoundKey >* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey< CompoundKey >* >( _lastKey )->SetKey( lastKey );
break;
}
case int_datetime_Key:
{
Compound* compound1 = dynamic_cast( beginKey->Key );
Compound* compound2 = dynamic_cast( endKey->Key );
CompoundKey firstKey;
CompoundKey lastKey;
firstKey._first = *dynamic_cast( compound1->_key1 );
firstKey._second = dynamic_cast<__box DateTime*>( compound1->_key2 )->Ticks;
lastKey._first = *dynamic_cast( compound2->_key1 );
lastKey._second = dynamic_cast<__box DateTime*>( compound2->_key2 )->Ticks;
static_cast< BTreeKey< CompoundKey >* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey< CompoundKey >* >( _lastKey )->SetKey( lastKey );
break;
}
case int_int_int_Key:
{
CompoundAndValue* compound1 = dynamic_cast( beginKey->Key );
CompoundAndValue* compound2 = dynamic_cast( endKey->Key );
CompoundKeyWithValue firstKey;
CompoundKeyWithValue lastKey;
firstKey._first = *dynamic_cast( compound1->_key1 );
firstKey._second = *dynamic_cast( compound1->_key2 );
int value = *dynamic_cast( compound1->_value );
firstKey.SetValue( value );
lastKey._first = *dynamic_cast( compound2->_key1 );
lastKey._second = *dynamic_cast( compound2->_key2 );
value = *dynamic_cast( compound2->_value );
lastKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _lastKey )->SetKey( lastKey );
break;
}
case int_int_datetime_Key:
{
CompoundAndValue* compound1 = dynamic_cast( beginKey->Key );
CompoundAndValue* compound2 = dynamic_cast( endKey->Key );
CompoundKeyWithValue firstKey;
CompoundKeyWithValue lastKey;
firstKey._first = *dynamic_cast( compound1->_key1 );
firstKey._second = *dynamic_cast( compound1->_key2 );
long value = dynamic_cast<__box DateTime*>( compound1->_value )->Ticks;
firstKey.SetValue( value );
lastKey._first = *dynamic_cast( compound2->_key1 );
lastKey._second = *dynamic_cast( compound2->_key2 );
value = dynamic_cast<__box DateTime*>( compound2->_value )->Ticks;
lastKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _lastKey )->SetKey( lastKey );
break;
}
case int_datetime_int_Key:
{
CompoundAndValue* compound1 = dynamic_cast( beginKey->Key );
CompoundAndValue* compound2 = dynamic_cast( endKey->Key );
CompoundKeyWithValue firstKey;
CompoundKeyWithValue lastKey;
firstKey._first = *dynamic_cast( compound1->_key1 );
firstKey._second = dynamic_cast<__box DateTime*>( compound1->_key2 )->Ticks;
int value = *dynamic_cast( compound1->_value );
firstKey.SetValue( value );
lastKey._first = *dynamic_cast( compound2->_key1 );
lastKey._second = dynamic_cast<__box DateTime*>( compound2->_key2 )->Ticks;
value = *dynamic_cast( compound2->_value );
lastKey.SetValue( value );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey< CompoundKeyWithValue >* >( _lastKey )->SetKey( lastKey );
break;
}
case long_Key:
{
long firstKey = *dynamic_cast( beginKey->Key );
long lastKey = *dynamic_cast( endKey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey* >( _lastKey )->SetKey( lastKey );
break;
}
case datetime_Key:
{
long firstKey = dynamic_cast<__box DateTime*>( beginKey->Key )->Ticks;
long lastKey = dynamic_cast<__box DateTime*>( endKey->Key )->Ticks;
static_cast< BTreeKey* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey* >( _lastKey )->SetKey( lastKey );
break;
}
case double_Key:
{
double firstKey = *dynamic_cast( beginKey->Key );
double lastKey = *dynamic_cast( endKey->Key );
static_cast< BTreeKey* >( _firstKey )->SetKey( firstKey );
static_cast< BTreeKey* >( _lastKey )->SetKey( lastKey );
break;
}
default: throw new System::Exception( "Key type is not supported!" );
}
_firstKey->SetOffset( 0 );
_lastKey->SetOffset( MAX_OFFSET );
}
BTreePageBase* OmniaMeaBTree::GetPageByOffset( int offset )
{
BTreePageBase* page = _pagesCache->TryOffset( offset );
if( page == 0 )
{
page = PrepareNewPage( offset );
LoadPage( page );
}
return page;
}
BTreePageBase* OmniaMeaBTree::AllocPage()
{
++_numberOfPages;
int newOffset;
BTreePageBase* page;
int freeOffsetsCount = _freeOffsets->Count;
if( freeOffsetsCount == 0 )
{
newOffset = (int) _btreeFile->Length;
page = PrepareNewPage( newOffset );
page->Clear();
SavePage( page );
}
else
{
newOffset = _freeOffsets->get_Item( freeOffsetsCount - 1 );
_freeOffsets->RemoveAt( freeOffsetsCount - 1 );
page = PrepareNewPage( newOffset );
page->Clear();
}
return page;
}
BTreePageBase* OmniaMeaBTree::PrepareNewPage( int offset )
{
BTreePageBase* page = _freePage;
if( !page )
{
page = _page->Clone();
}
page->SetOffset( offset );
_freePage = _pagesCache->CachePage( page );
return page;
}
void OmniaMeaBTree::CopyOffsets( const BTreeKeyBase** temp_keys, unsigned count, IntArrayList* offsets )
{
for( unsigned i = 0; i < count; ++i )
{
offsets->Add( temp_keys[ i ]->GetOffset() );
}
}
static void CopyLongKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets, IFixedLengthKey* factoryKey )
{
for( int i = 0; i < count; ++i )
{
const BTreeKeyBase* key = temp_keys[ i ];
KeyPair* keyPair = new KeyPair();
keyPair->_offset = key->GetOffset();
keyPair->_key = factoryKey->FactoryMethod();
const BTreeKey< long >* cKey = static_cast< const BTreeKey< long >* >( key );
Int64 theKey( cKey->GetKey() );
keyPair->_key->Key = dynamic_cast< System::IComparable* >( __box( theKey ) );
keys_offsets->Add( keyPair );
}
}
static void CopyIntKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets, IFixedLengthKey* factoryKey )
{
for( int i = 0; i < count; ++i )
{
const BTreeKeyBase* key = temp_keys[ i ];
KeyPair* keyPair = new KeyPair();
keyPair->_offset = key->GetOffset();
keyPair->_key = factoryKey->FactoryMethod();
const BTreeKey< int >* cKey = static_cast< const BTreeKey< int >* >( key );
Int32 theKey( cKey->GetKey() );
keyPair->_key->Key = dynamic_cast< System::IComparable* >( __box( theKey ) );
keys_offsets->Add( keyPair );
}
}
static void CopyIntIntIntKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets, IFixedLengthKey* factoryKey )
{
for( int i = 0; i < count; ++i )
{
const BTreeKeyBase* key = temp_keys[ i ];
KeyPair* keyPair = new KeyPair();
keyPair->_offset = key->GetOffset();
keyPair->_key = factoryKey->FactoryMethod();
const BTreeKey< CompoundKeyWithValue >* cKey =
static_cast< const BTreeKey< CompoundKeyWithValue >* >( key );
Int32 key1( cKey->GetKey()._first );
Int32 key2( cKey->GetKey()._second );
Int32 value( cKey->GetKey().GetValue() );
CompoundAndValue* theKey = dynamic_cast< CompoundAndValue* >( keyPair->_key->Key );
theKey->_key1 = __box( key1 );
theKey->_key2 = __box( key2 );
theKey->_value = __box( value );
keyPair->_key->Key = dynamic_cast< System::IComparable* >( theKey );
keys_offsets->Add( keyPair );
}
}
static void CopyIntIntDateTimeKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets, IFixedLengthKey* factoryKey )
{
for( int i = 0; i < count; ++i )
{
const BTreeKeyBase* key = temp_keys[ i ];
KeyPair* keyPair = new KeyPair();
keyPair->_offset = key->GetOffset();
keyPair->_key = factoryKey->FactoryMethod();
const BTreeKey< CompoundKeyWithValue >* cKey =
static_cast< const BTreeKey< CompoundKeyWithValue >* >( key );
Int32 key1( cKey->GetKey()._first );
Int32 key2( cKey->GetKey()._second );
DateTime value( cKey->GetKey().GetValue() );
CompoundAndValue* theKey = dynamic_cast< CompoundAndValue* >( keyPair->_key->Key );
theKey->_key1 = __box( key1 );
theKey->_key2 = __box( key2 );
theKey->_value = __box( value );
keyPair->_key->Key = dynamic_cast< System::IComparable* >( theKey );
keys_offsets->Add( keyPair );
}
}
static void CopyIntDateTimeIntKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets, IFixedLengthKey* factoryKey )
{
for( int i = 0; i < count; ++i )
{
const BTreeKeyBase* key = temp_keys[ i ];
KeyPair* keyPair = new KeyPair();
keyPair->_offset = key->GetOffset();
keyPair->_key = factoryKey->FactoryMethod();
const BTreeKey< CompoundKeyWithValue >* cKey =
static_cast< const BTreeKey< CompoundKeyWithValue >* >( key );
Int32 key1( cKey->GetKey()._first );
DateTime key2( cKey->GetKey()._second );
Int32 value( cKey->GetKey().GetValue() );
CompoundAndValue* theKey = dynamic_cast< CompoundAndValue* >( keyPair->_key->Key );
theKey->_key1 = __box( key1 );
theKey->_key2 = __box( key2 );
theKey->_value = __box( value );
keyPair->_key->Key = dynamic_cast< System::IComparable* >( theKey );
keys_offsets->Add( keyPair );
}
}
void OmniaMeaBTree::CopyKeys( const BTreeKeyBase** temp_keys, int count, ArrayList* keys_offsets )
{
switch( _keyType )
{
case long_Key:
{
CopyLongKeys( temp_keys, count, keys_offsets, _factoryKey );
break;
}
case int_Key:
{
CopyIntKeys( temp_keys, count, keys_offsets, _factoryKey );
break;
}
case int_int_int_Key:
{
CopyIntIntIntKeys( temp_keys, count, keys_offsets, _factoryKey );
break;
}
case int_int_datetime_Key:
{
CopyIntIntDateTimeKeys( temp_keys, count, keys_offsets, _factoryKey );
break;
}
case int_datetime_int_Key:
{
CopyIntDateTimeIntKeys( temp_keys, count, keys_offsets, _factoryKey );
break;
}
}
}
void OmniaMeaBTree::LoadPage( BTreePageBase* page )
{
int pageHandle = page->GetFileHandle();
int fileHandle = _btreeFile->Handle.ToInt32();
if( pageHandle != fileHandle )
{
char s[ 100 ];
sprintf( s, "Page handle(%d) is not equal to btree file handle(%d).", pageHandle, fileHandle );
throw new System::IO::IOException( s );
}
int loadedBytes = page->Load();
int pageSize = page->GetSize();
if( loadedBytes != pageSize )
{
char s[ 200 ];
sprintf( s, "BTreePageBase.Load() returned %d, pageSize = %d, last error = %d.", loadedBytes, pageSize, ::GetLastError() );
throw new System::IO::IOException( s );
}
_loadedPages++;
}
void OmniaMeaBTree::SavePage( BTreePageBase* page )
{
int pageHandle = page->GetFileHandle();
int fileHandle = _btreeFile->Handle.ToInt32();
if( pageHandle != fileHandle )
{
char s[ 100 ];
sprintf( s, "Page handle(%d) is not equal to btree file handle(%d).", pageHandle, fileHandle );
throw new System::IO::IOException( s );
}
int savedBytes = page->Save();
int pageSize = page->GetSize();
if( savedBytes != pageSize )
{
char s[ 200 ];
sprintf( s, "BTreePageBase.Save() returned %d, pageSize = %d, last error = %d.", savedBytes, pageSize, ::GetLastError() );
throw new System::IO::IOException( s );
}
}
int OmniaMeaBTree::GetLoadedPages()
{
return _loadedPages;
}
int OmniaMeaBTree::GetPageSize()
{
return _page->GetSize();
}
}