/// /// 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). /// using System; using System.IO; using System.Runtime.Serialization; using System.Collections; namespace JetBrains.Omea.Containers { internal class BTreeNode : IComparable { private IComparable _minKey; private int _minOffset; private int _count = 0; private long _pageOffset = 0; public BTreeNode( IComparable minKey ) { _minKey = minKey; } public BTreeNode( IComparable minKey, int minOffset, long pageOffset ) { _minKey = minKey; _minOffset = minOffset; _pageOffset = pageOffset; } public BTreeNode( IComparable minKey, int minOffset, long pageOffset, int count ) { _minKey = minKey; _minOffset = minOffset; _pageOffset = pageOffset; _count = count; } public void ChangeMinKey( IComparable minKey, int minOffset ) { _minKey = minKey; _minOffset = minOffset; } public int IncrementCount() { return ++_count; } public int DecrementCount() { return --_count; } public IComparable MinKey { get { return _minKey; } } public int MinOffset { get { return _minOffset; } } public void SetNewCount( int newCount ) { _count = newCount; } public int Count { get { return _count; } } public long PageOffset { get { return _pageOffset; } } #region IComparable Members public int CompareTo(object obj) { if ( _minKey != null ) { int result = _minKey.CompareTo( ((BTreeNode)obj)._minKey ); if ( result == 0 ) { result = _minOffset - ((BTreeNode)obj)._minOffset; } return result; } else { return -1; } } #endregion } public class KeyPair { public IFixedLengthKey _key; public int _offset; public KeyPair() {} public KeyPair( IFixedLengthKey key, int offset ) { _key = key; _offset = offset; } } internal class BTreePage { private int _maxCount = 0; private BTreeNode _treeNode = null; private FileStream _stream; private BinaryReader _reader; private BinaryWriter _writer; private MemoryStream _memoryStream; private BinaryReader _memoryReader; private BinaryWriter _memoryWriter; private IFixedLengthKey _factoryKey; private IFixedLengthKey _curKey; private byte[] _bytes = new byte[BTree.PAGE_SIZE]; private int _keySize; private bool _modified; private int _rightBound; private const int _deferredArrayStartCapacity = 4; private const int _deferredArrayMaximumSize = 256; private ArrayList _deferredDeletions = new ArrayList( _deferredArrayStartCapacity ); private ArrayList _deferredInsertions = new ArrayList( _deferredArrayStartCapacity ); private KeyPair _keyPair = new KeyPair(); private static KeyPairComparer _keyComparer = new KeyPairComparer(); private class KeyPairComparer : IComparer { public int Compare( object x, object y ) { KeyPair pair_x = (KeyPair) x; KeyPair pair_y = (KeyPair) y; int result = pair_x._key.CompareTo( pair_y._key ); if( result == 0 ) { result = pair_x._offset - pair_y._offset; } return result; } } public BTreePage( BTreeNode treeNode, int maxCount, FileStream stream, IFixedLengthKey factoryKey ) { SetPageData( treeNode, maxCount, factoryKey ); _stream = stream; _reader = new BinaryReader( stream ); _writer = new BinaryWriter( stream ); _memoryStream = new MemoryStream( _bytes, 0, BTree.PAGE_SIZE ); _memoryReader = new BinaryReader( _memoryStream ); _memoryWriter = new BinaryWriter( _memoryStream ); } public void SetPageData( BTreeNode treeNode, int maxCount, IFixedLengthKey factoryKey ) { _treeNode = treeNode; _rightBound = _treeNode.Count; _maxCount = maxCount; _factoryKey = factoryKey; _curKey = _factoryKey.FactoryMethod(); _keySize = _factoryKey.KeySize + 4; } private IFixedLengthKey MemoryRead( int index, out int offset ) { SetPosition( index ); return MemoryReadNext( out offset ); } private void SetPosition( int index ) { _memoryReader.BaseStream.Position = BTree.HEADER_SIZE + _keySize * index; } private IFixedLengthKey MemoryReadNext( out int offset ) { _curKey.Read( _memoryReader ); offset = _memoryReader.ReadInt32(); return _curKey; } private void MemoryWrite( IFixedLengthKey key, int offset, int index ) { _memoryWriter.BaseStream.Position = BTree.HEADER_SIZE + _keySize * index; key.Write( _memoryWriter ); _memoryWriter.Write( offset ); } public int GetAllKeys( IntArrayList offsets ) { int count = _treeNode.Count; if ( count > 0 ) { ProcessDeferredUpdates(); SetPosition( 0 ); for( int index = 0; index < count; index++ ) { int offset; MemoryReadNext( out offset ); offsets.Add( offset ); } } return count; } public int GetAllKeys( ArrayList keys_offsets ) { int count = _treeNode.Count; if ( count > 0 ) { ProcessDeferredUpdates(); SetPosition( 0 ); for( int index = 0; index < count; index++ ) { int offset; IFixedLengthKey key = MemoryReadNext( out offset ); keys_offsets.Add( new KeyPair( key.FactoryMethod(), offset ) ); } } return count; } public void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, IntArrayList offsets ) { if ( _treeNode.Count == 0 ) { return; } int index, offset; KeyPair pair; IFixedLengthKey deferredKey; int deferredInsertionsIndex = ~GetDeferredInsertionIndex( beginKey, -1 ); IFixedLengthKey foundKey = SearchL( 0, _rightBound, beginKey, -1, out index ); if ( foundKey != null && index != -1 && index < _rightBound ) { int deferredDeletionsIndex = ~GetDeferredDeletionIndex( beginKey, -1 ); SetPosition( index ); for ( ; index < _rightBound; ++index ) { IFixedLengthKey aKey = MemoryReadNext( out offset ); for( ; deferredInsertionsIndex < _deferredInsertions.Count; ++deferredInsertionsIndex ) { pair = (KeyPair)_deferredInsertions[ deferredInsertionsIndex ]; deferredKey = pair._key; if( deferredKey.CompareTo( aKey ) > 0 ) { break; } if( beginKey.CompareTo( deferredKey ) <= 0 ) { if( endKey.CompareTo( deferredKey ) < 0 ) { break; } offsets.Add( pair._offset ); } } if ( endKey.CompareTo( aKey ) < 0 ) { break; } bool deleted = false; while( deferredDeletionsIndex < _deferredDeletions.Count ) { pair = (KeyPair)_deferredDeletions[ deferredDeletionsIndex ]; int compareResult = pair._key.CompareTo( aKey ); if( compareResult == 0 ) { compareResult = pair._offset - offset; } if( compareResult > 0 ) { break; } ++deferredDeletionsIndex; if( compareResult == 0 ) { deleted = true; break; } } if( !deleted ) { offsets.Add( offset ); } } } for( ; deferredInsertionsIndex < _deferredInsertions.Count; ++deferredInsertionsIndex ) { pair = (KeyPair)_deferredInsertions[ deferredInsertionsIndex ]; deferredKey = pair._key; if( beginKey.CompareTo( deferredKey ) <= 0 ) { if( endKey.CompareTo( deferredKey ) < 0 ) { break; } offsets.Add( pair._offset ); } } } public void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, ArrayList keys_offsets ) { if ( _treeNode.Count == 0 ) { return; } int index, offset; KeyPair pair; IFixedLengthKey deferredKey; int deferredInsertionsIndex = ~GetDeferredInsertionIndex( beginKey, -1 ); IFixedLengthKey foundKey = SearchL( 0, _rightBound, beginKey, -1, out index ); if ( foundKey != null && index != -1 && index < _rightBound ) { int deferredDeletionsIndex = ~GetDeferredDeletionIndex( beginKey, -1 ); SetPosition( index ); for ( ; index < _rightBound; ++index ) { IFixedLengthKey aKey = MemoryReadNext( out offset ); for( ; deferredInsertionsIndex < _deferredInsertions.Count; ++deferredInsertionsIndex ) { pair = (KeyPair)_deferredInsertions[ deferredInsertionsIndex ]; deferredKey = pair._key; if( deferredKey.CompareTo( aKey ) > 0 ) { break; } if( beginKey.CompareTo( deferredKey ) <= 0 ) { if( endKey.CompareTo( deferredKey ) < 0 ) { break; } keys_offsets.Add( pair ); } } if ( endKey.CompareTo( aKey ) < 0 ) { break; } bool deleted = false; while( deferredDeletionsIndex < _deferredDeletions.Count ) { pair = (KeyPair)_deferredDeletions[ deferredDeletionsIndex ]; int compareResult = pair._key.CompareTo( aKey ); if( compareResult == 0 ) { compareResult = pair._offset - offset; } if( compareResult > 0 ) { break; } ++deferredDeletionsIndex; if( compareResult == 0 ) { deleted = true; break; } } if( !deleted ) { keys_offsets.Add( new KeyPair( aKey.FactoryMethod(), offset ) ); } } } for( ; deferredInsertionsIndex < _deferredInsertions.Count; ++deferredInsertionsIndex ) { pair = (KeyPair)_deferredInsertions[ deferredInsertionsIndex ]; deferredKey = pair._key; if( beginKey.CompareTo( deferredKey ) <= 0 ) { if( endKey.CompareTo( deferredKey ) < 0 ) { break; } keys_offsets.Add( pair ); } } } private IFixedLengthKey Search( int l, int r, IFixedLengthKey key, int offset, out int index ) { index = -1; if ( l > r ) { return null; } IFixedLengthKey mKey = null; while( l < r ) { int m = ( l + r ) >> 1; int off; mKey = MemoryRead( m, out off ); int compareResult = key.CompareTo( mKey ); if ( compareResult == 0 && offset != -1 ) { compareResult = offset - off; } index = m; if ( compareResult == 0 ) { return mKey; } if( compareResult > 0 ) { l = m + 1; } else { r = m; } } return null; } private IFixedLengthKey SearchL( int l, int r, IFixedLengthKey key, int offset, out int index ) { index = -1; if ( l > r ) { return null; } index = l; IFixedLengthKey mKey = null; while( l < r ) { int m = ( l + r ) >> 1; int off; mKey = MemoryRead( m, out off ); int compareResult = key.CompareTo( mKey ); if ( compareResult == 0 && offset != -1 ) { compareResult = offset - off; } if( compareResult > 0 ) { l = m + 1; index = l; } else { r = m; index = r; } } return mKey; } private IFixedLengthKey SearchR( int l, int r, IFixedLengthKey key, int offset, out int index ) { index = -1; if ( l > r ) { return null; } index = r; IFixedLengthKey mKey = null; while( l < r ) { int m = ( l + r ) >> 1; int off; mKey = MemoryRead( m, out off ); int compareResult = key.CompareTo( mKey ); if ( compareResult == 0 && offset != -1 ) { compareResult = offset - off; } if( compareResult >= 0 ) { l = m + 1; index = l; } else { r = m; index = m; } } return mKey; } private void CopyBytes( Array source, int sourceIndex, Array target, int targetIndex, int count ) { long sIndex = _keySize * sourceIndex + BTree.HEADER_SIZE; long dIndex = _keySize * targetIndex + BTree.HEADER_SIZE; long shiftCount = _keySize * count; Array.Copy( source, sIndex, target, dIndex, shiftCount ); } private void ProcessDeferredUpdates() { int count = _treeNode.Count; _rightBound = count; if( count == 0 ) { _deferredDeletions.Clear(); _deferredInsertions.Clear(); return; } int deleted = _deferredDeletions.Count; int inserted = _deferredInsertions.Count; if( deleted > 0 || inserted > 0 ) { int off; int rightBound = count + deleted - inserted; int i = _maxCount; bool isDeleted; KeyPair pair; while( rightBound > 0 ) { isDeleted = false; IFixedLengthKey key = MemoryRead( --rightBound, out off ); _keyPair._key = key; _keyPair._offset = off; // at first, look through deferred deletions while( deleted > 0 ) { pair = (KeyPair)_deferredDeletions[ deleted - 1 ]; int compareResult = _keyComparer.Compare( _keyPair, pair ); if( compareResult >= 0 ) { if( ( isDeleted = compareResult == 0 ) ) { --deleted; } break; } --deleted; } // if current key is not deleted, merge it with deferred insertions if( !isDeleted ) { while( inserted > 0 ) { pair = (KeyPair)_deferredInsertions[ inserted - 1 ]; if( _keyComparer.Compare( _keyPair, pair ) > 0 ) { MemoryWrite( key, off, --i ); break; } else { MemoryWrite( pair._key, pair._offset, --i ); --inserted; } } if( inserted == 0 ) { MemoryWrite( key, off, --i ); } } } // if some insertions remain, write it before all other key pairs while( inserted > 0 ) { pair = (KeyPair)_deferredInsertions[ --inserted ]; MemoryWrite( pair._key, pair._offset, --i ); } if( i > 0 ) { CopyBytes( _bytes, i, _bytes, 0, count ); } _deferredDeletions.Clear(); _deferredInsertions.Clear(); } } private bool DeferDeletion( IFixedLengthKey key, int offset ) { int index = GetDeferredInsertionIndex( key, offset ); if( index >= 0 ) { _deferredInsertions.RemoveAt( index ); return true; } else { if( _deferredDeletions.Count == _deferredArrayMaximumSize ) { ProcessDeferredUpdates(); } index = GetDeferredDeletionIndex( key, offset ); if( index < 0 ) { _deferredDeletions.Insert( ~index, new KeyPair( key.FactoryMethod(), offset ) ); return true; } } return false; } private int GetDeferredDeletionIndex( IFixedLengthKey key, int offset ) { _keyPair._key = key; _keyPair._offset = offset; return _deferredDeletions.BinarySearch( _keyPair, _keyComparer ); } private void DeferInsertion( IFixedLengthKey key, int offset ) { int index = GetDeferredDeletionIndex( key, offset ); if( index >= 0 ) { _deferredDeletions.RemoveAt( index ); } else { int insertedCount = _deferredInsertions.Count; if( insertedCount == _deferredArrayMaximumSize || _rightBound + insertedCount == _maxCount ) { ProcessDeferredUpdates(); } index = GetDeferredInsertionIndex( key, offset ); if( index < 0 ) { _deferredInsertions.Insert( ~index, new KeyPair( key.FactoryMethod(), offset ) ); } } } private int GetDeferredInsertionIndex( IFixedLengthKey key, int offset ) { _keyPair._key = key; _keyPair._offset = offset; return _deferredInsertions.BinarySearch( _keyPair, _keyComparer ); } private void UpdateMinKey( IFixedLengthKey key, int offset ) { int keyCompare = key.CompareTo( _treeNode.MinKey ); if ( keyCompare < 0 || ( keyCompare == 0 && offset < _treeNode.MinOffset ) ) { _treeNode.ChangeMinKey( key.FactoryMethod(), offset ); } } public void DeleteKey( IFixedLengthKey key, int offset ) { if( DeferDeletion( key, offset ) ) { _modified = true; _treeNode.DecrementCount(); } } public void InsertKey( IFixedLengthKey key, int offset ) { DeferInsertion( key, offset ); UpdateMinKey( key, offset ); _modified = true; _treeNode.IncrementCount(); } public void Read() { _reader.BaseStream.Position = _treeNode.PageOffset; _reader.Read( _bytes, 0, BTree.PAGE_SIZE ); _memoryReader.BaseStream.Position = BTree.HEADER_SIZE; _rightBound = _treeNode.Count; _modified = false; } public void Write() { if( _modified ) { _modified = false; ProcessDeferredUpdates(); _memoryWriter.BaseStream.Position = 0; _memoryWriter.Write( _treeNode.Count ); _writer.BaseStream.Position = _treeNode.PageOffset; _writer.Write( _bytes, 0, BTree.PAGE_SIZE ); _writer.Flush(); } } public BTreeNode BTreeNode { get { return _treeNode; } } public BTreePage Split( IFixedLengthKey key, int offset, long pageOffset, float splitFactor ) { ProcessDeferredUpdates(); if( splitFactor >= 1 || splitFactor < 0.1 ) { throw new Exception( "BTreePage.Split: splitFactor = " + splitFactor.ToString() + " is not applicable" ); } int mIndex = (int) (_maxCount * splitFactor); int off; IFixedLengthKey minKey = MemoryRead( mIndex, out off ).FactoryMethod(); BTreePage splittedPage = new BTreePage( new BTreeNode( minKey, off, pageOffset, _maxCount - mIndex ), _maxCount, _stream, _factoryKey ); CopyBytes( _bytes, mIndex, splittedPage._bytes, 0, _maxCount - mIndex ); _treeNode.SetNewCount( mIndex ); _rightBound = mIndex; _modified = splittedPage._modified = true; if ( key.CompareTo( minKey ) < 0 ) { InsertKey( key, offset ); } else { splittedPage.InsertKey( key, offset ); } return splittedPage; } public void Merge( BTreePage rightPage ) { int offset; ProcessDeferredUpdates(); rightPage.ProcessDeferredUpdates(); rightPage.SetPosition( 0 ); for( int i = 0; i < rightPage._rightBound; ++i ) { IFixedLengthKey key = rightPage.MemoryReadNext( out offset ); MemoryWrite( key, offset, _rightBound++ ); } _treeNode.SetNewCount( _rightBound ); rightPage._treeNode.SetNewCount( 0 ); _modified = rightPage._modified = true; } public bool Full() { return _treeNode.Count == _maxCount; } public bool Empty() { return _treeNode.Count == 0; } } public interface IFixedLengthKey : IComparable { IFixedLengthKey FactoryMethod( BinaryReader reader ); IFixedLengthKey FactoryMethod(); void Read( BinaryReader reader ); void Write( BinaryWriter writer ); IComparable Key { get; set; } int KeySize { get; } void SetIntKey( int key ); } /// /// classes for compound keys /// public class Compound : IComparable { public IComparable _key1; public IComparable _key2; public Compound( IComparable key1, IComparable key2 ) { _key1 = key1; _key2 = key2; } public Compound Clone() { return new Compound( _key1, _key2 ); } #region IComparable Members public int CompareTo(object obj) { int result = _key1.CompareTo( ((Compound)obj)._key1 ); if ( result == 0 ) { result = _key2.CompareTo( ((Compound)obj)._key2 ); } return result; } #endregion } public class CompoundAndValue : IComparable { public IComparable _key1; public IComparable _key2; public IComparable _value; public CompoundAndValue( IComparable key1, IComparable key2, IComparable value ) { _key1 = key1; _key2 = key2; _value = value; } public CompoundAndValue Clone() { return new CompoundAndValue( _key1, _key2, _value ); } #region IComparable Members public int CompareTo(object obj) { int result = _key1.CompareTo( ((CompoundAndValue)obj)._key1 ); if ( result == 0 ) { result = _key2.CompareTo( ((CompoundAndValue)obj)._key2 ); } /*if ( result == 0 ) { result = _value.CompareTo( ((CompoundAndValue)obj)._value ); }*/ return result; } #endregion } public class KeySizeException : Exception { public KeySizeException() : base( "KeySize should be positive integer" ) { } } /// /// interface to a BTree implementation /// is declared as abstract class in order to be able to define static flag /// which is used by factory methods of key classes ( IFixedLengthKey FactoryMethod ) /// also is used in managed C++ DBIndex implementation /// /// public abstract class IBTree : IDisposable { public abstract void Dispose(); public abstract bool Open(); public abstract void Close(); public abstract void Clear(); public abstract void GetAllKeys( IntArrayList offsets ); public abstract void GetAllKeys( ArrayList keys_offsets ); public abstract IEnumerable GetAllKeys(); public abstract void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, IntArrayList offsets ); public abstract void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, ArrayList keys_offsets ); public abstract IEnumerable SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey ); public abstract void DeleteKey( IFixedLengthKey key, int offset ); public abstract void InsertKey( IFixedLengthKey key, int offset ); public abstract int MaxCount { get; } public abstract int Count { get; } public abstract void SetCacheSize( int numberOfPages ); public abstract int GetCacheSize(); public abstract int GetLoadedPages(); public abstract int GetPageSize(); public static bool _bUseOldKeys = false; } [Serializable] public class BadIndexesException : Exception { public BadIndexesException() : base() { } public BadIndexesException( string message ) : base( message ) {} public BadIndexesException( string message, Exception innerException ) : base( message, innerException ) {} protected BadIndexesException( SerializationInfo info, StreamingContext context ) : base( info, context ) { } } public class BTree : IBTree { public const int PAGE_SIZE = 0x4000; public const int HEADER_SIZE = 1024; public const int CACHE_SIZE = 20; private string _fileName; private FileStream _stream; private BinaryReader _reader; private BinaryWriter _writer; private int _count = 0; private int _maxCount = 0; private RedBlackTree _rbTree = new RedBlackTree(); private BTreeNode _searchNode = new BTreeNode( null ); private IFixedLengthKey _factoryKey; private Stack freePages = new Stack(); private ObjectCache _cache; private BTreePage _freeNode; public BTree( string fileName, IFixedLengthKey factoryKey ) { _factoryKey = factoryKey; _fileName = fileName; if ( _factoryKey.KeySize <= 0 ) { throw new KeySizeException(); } _maxCount = (PAGE_SIZE - HEADER_SIZE) / ( _factoryKey.KeySize + 4 ); } #region IBTree implementation public override void Dispose() { } public override bool Open() { _stream = new FileStream( _fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 64 ); _rbTree = new RedBlackTree(); _reader = new BinaryReader( _stream ); _writer = new BinaryWriter( _stream ); _count = 0; _cache = new ObjectCache( CACHE_SIZE ); _cache.ObjectRemoved += new ObjectCacheEventHandler( _cache_ObjectRemoved ); freePages.Clear(); int numPages = (int)(_stream.Length / PAGE_SIZE); //Tracer._Trace( "####################### " + _fileName ); for ( int i = 0; i < numPages; i++ ) { long pageOffset = i * PAGE_SIZE; _stream.Position = pageOffset; int count = _reader.ReadInt32(); //Tracer._Trace( "####################### count = " + count.ToString() ); _stream.Position = pageOffset + HEADER_SIZE; IFixedLengthKey key = _factoryKey.FactoryMethod( _reader ); int offset = _reader.ReadInt32(); if ( count != 0 ) { _rbTree.RB_Insert( new BTreeNode( key, offset, pageOffset, count ) ); } else { freePages.Push( pageOffset ); } _count += count; } return true; } public override void Close() { _cache.RemoveAll(); _cache = null; _freeNode = null; _count = 0; _reader.Close(); _writer.Close(); _stream.Close(); } public override void Clear() { Close(); File.Delete( _fileName ); Open(); } public override void GetAllKeys( IntArrayList offsets ) { RBNodeBase rbNode = _rbTree.GetMinimumNode(); while ( rbNode != null ) { BTreePage page = PreparePage( (BTreeNode)rbNode.Key ); if ( page.GetAllKeys( offsets ) == 0 ) { break; } rbNode = _rbTree.GetNext( rbNode ); } } public override void GetAllKeys( ArrayList keys_offsets ) { RBNodeBase rbNode = _rbTree.GetMinimumNode(); while ( rbNode != null ) { BTreePage page = PreparePage( (BTreeNode)rbNode.Key ); if ( page.GetAllKeys( keys_offsets ) == 0 ) { break; } rbNode = _rbTree.GetNext( rbNode ); } } public override IEnumerable GetAllKeys() { throw new NotImplementedException( "Use OmniaMeaBTree." ); } public override void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, IntArrayList offsets ) { _searchNode.ChangeMinKey( beginKey, 0 ); RBNodeBase rbNode = _rbTree.GetMaximumLess( _searchNode ); if ( rbNode == null ) { rbNode = _rbTree.GetMinimumNode(); } while ( rbNode != null && ((BTreeNode)rbNode.Key).MinKey.CompareTo( endKey ) <= 0 ) { BTreePage page = PreparePage( (BTreeNode)rbNode.Key ); page.SearchForRange( beginKey, endKey, offsets ); rbNode = _rbTree.GetNext( rbNode ); } } public override void SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey, ArrayList keys_offsets ) { _searchNode.ChangeMinKey( beginKey, 0 ); RBNodeBase rbNode = _rbTree.GetMaximumLess( _searchNode ); if ( rbNode == null ) { rbNode = _rbTree.GetMinimumNode(); } while ( rbNode != null && ((BTreeNode)rbNode.Key).MinKey.CompareTo( endKey ) <= 0 ) { BTreePage page = PreparePage( (BTreeNode)rbNode.Key ); page.SearchForRange( beginKey, endKey, keys_offsets ); rbNode = _rbTree.GetNext( rbNode ); } } public override IEnumerable SearchForRange( IFixedLengthKey beginKey, IFixedLengthKey endKey ) { throw new NotImplementedException( "Use OmniaMeaBTree." ); } public override void DeleteKey( IFixedLengthKey key, int offset ) { RBNodeBase rbNode; BTreeNode foundNode = SearchBTreeNode( key, offset, out rbNode ); if ( foundNode != null ) { BTreePage page = PreparePage( foundNode ); _count -= foundNode.Count; page.DeleteKey( key, offset ); int pageCount = foundNode.Count; _count += pageCount; long pageOffset; if ( page.Empty() ) { pageOffset = page.BTreeNode.PageOffset; freePages.Push( pageOffset ); _rbTree.RB_Delete( page.BTreeNode ); _cache.Remove( pageOffset ); } else if( pageCount < (_maxCount >> 2) && (rbNode = _rbTree.GetNext( rbNode )) != null ) { BTreeNode rightNode = (BTreeNode) rbNode.Key; if( pageCount + rightNode.Count < (_maxCount >> 1) ) { BTreePage rightPage = PreparePage( rightNode ); pageOffset = rightPage.BTreeNode.PageOffset; page.Merge( rightPage ); freePages.Push( pageOffset ); _rbTree.RB_Delete( rightPage.BTreeNode ); _cache.Remove( pageOffset ); } } } } public override void InsertKey( IFixedLengthKey key, int offset ) { _count++; RBNodeBase rbNode; BTreeNode foundNode = SearchBTreeNode( key, offset, out rbNode ); if ( foundNode == null ) { if ( _rbTree.Count == 0 ) { BTreeNode newNode = new BTreeNode( key.FactoryMethod(), offset, GetOffsetForNewPage() ); _rbTree.RB_Insert( newNode ); BTreePage page = NewPage( newNode ); page.InsertKey( key, offset ); page.Write(); _cache.CacheObject( newNode.PageOffset, page ); return; } else { RBNodeBase rbMinNode = _rbTree.GetMinimumNode(); foundNode = (BTreeNode)rbMinNode.Key; } } else { BTreePage page = PreparePage( foundNode ); if ( page.Full() ) { float splitFactor = ( _rbTree.GetNext( rbNode ) == null ) ? 0.875f : 0.5f; BTreePage splittedPage = page.Split( key, offset, GetOffsetForNewPage(), splitFactor ); _rbTree.RB_Insert( splittedPage.BTreeNode ); splittedPage.Write(); _cache.CacheObject( splittedPage.BTreeNode.PageOffset, splittedPage ); } else { page.InsertKey( key, offset ); } } } public override int MaxCount { get { return _maxCount; } } public override int Count { get { return _count; } } public override void SetCacheSize( int numberOfPages ) {} public override int GetCacheSize() { return CACHE_SIZE; } #endregion private long GetOffsetForNewPage() { if ( freePages.Count > 0 ) { return (long)freePages.Pop(); } return _stream.Length; } private void _cache_ObjectRemoved( object sender, ObjectCacheEventArgs e ) { _freeNode = (BTreePage) e.Object; _freeNode.Write(); } private BTreePage NewPage( BTreeNode treeNode ) { BTreePage result = _freeNode; if( result == null ) { result = new BTreePage( treeNode, _maxCount, _stream, _factoryKey ); } else { result.SetPageData( treeNode, _maxCount, _factoryKey ); _freeNode = null; } return result; } private BTreeNode SearchBTreeNode( IFixedLengthKey key, int offset, out RBNodeBase rbNode ) { _searchNode.ChangeMinKey( key, offset ); rbNode = _rbTree.GetEqualOrLess( _searchNode ); if ( rbNode == null ) { rbNode = _rbTree.GetMinimumNode(); } return ( rbNode != null ) ? (BTreeNode)rbNode.Key : null ; } private BTreePage PreparePage( BTreeNode foundNode ) { BTreePage page = (BTreePage)_cache.TryKey( foundNode.PageOffset ); if ( page == null ) { page = NewPage( foundNode ); page.Read(); _cache.CacheObject( foundNode.PageOffset, page ); } return page; } public override int GetLoadedPages() { throw new NotImplementedException(); } public override int GetPageSize() { throw new NotImplementedException(); } } }