public BTreeOnHeapLeaf <T> GetLeaf(HeapID leafHeapID, BTreeOnHeapIndexRecord leafIndexRecord) { BTreeOnHeapLeaf <T> result; if (!m_leavesCache.ContainsKey(leafHeapID.Value)) { BTreeOnHeapLeaf <T> leaf = GetLeafFromHeap(leafHeapID); if (leaf != null) { m_leavesCache.Add(leafHeapID.Value, leaf); } result = leaf; } else { result = m_leavesCache[leafHeapID.Value]; } if (result != null && leafIndexRecord != null) { // The BTH index node might have changed since the leaf was stored, // We must not use the index node stored in the cache. result.Index = leafIndexRecord.Index; } return(result); }
public int InsertSorted(BTreeOnHeapIndexRecord recordToInsert) { int insertIndex = GetSortedInsertIndex(recordToInsert); Records.Insert(insertIndex, recordToInsert); return(insertIndex); }
public void InsertIndexRecord(BTreeOnHeapIndex index, BTreeOnHeapIndexRecord record) { HeapID existingHeapID = index.HeapID; if (index.Records.Count < index.MaximumNumberOfRecords) { int insertIndex = index.InsertSorted(record); index.HeapID = ReplaceHeapItem(existingHeapID, index.GetBytes()); if (index.HeapID.Value != existingHeapID.Value) { if (index.ParentIndex == null) { // this is the root node UpdateRootHeapID(index.HeapID); } else { UpdateIndexRecord(index.ParentIndex, existingHeapID, index.HeapID, index.NodeKey); } } else if (insertIndex == 0 && index.ParentIndex != null) { // Node key has been modified, we must update the parent UpdateIndexRecord(index.ParentIndex, existingHeapID, index.HeapID, index.NodeKey); } } else { // The node is full, we have to split it BTreeOnHeapIndex newNode = index.Split(); if (record.CompareTo(newNode.NodeKey) > 0) { newNode.InsertSorted(record); } else { int insertIndex = index.InsertSorted(record); if (insertIndex == 0 && index.ParentIndex != null) { // Node key has been modified, we must update the parent UpdateIndexRecord(index.ParentIndex, index.HeapID, index.HeapID, index.NodeKey); } } if (index.ParentIndex == null) { // this is a root page and it's full, we have to create a new root index.ParentIndex = CreateNewRoot(index.NodeKey); } // Item will be replaced in place, because it has less items than before ReplaceHeapItem(index.HeapID, index.GetBytes()); HeapID newNodeHeapID = AddItemToHeap(newNode.GetBytes()); // We made sure we have a parent to add our new page to InsertIndexRecord(index.ParentIndex, newNode.NodeKey, newNodeHeapID); } }
public void InsertIndexRecord(BTreeOnHeapIndex index, byte[] key, HeapID hidNextLevel) { BTreeOnHeapIndexRecord indexRecord = new BTreeOnHeapIndexRecord(); indexRecord.key = key; indexRecord.hidNextLevel = hidNextLevel; InsertIndexRecord(index, indexRecord); }
/// <summary> /// Find the leaf BTreePage where the entry with the given key should be located /// We use this method for search and insertion /// Note: you can use record.Index to find the BTreeOnHeapIndex of the record /// </summary> private BTreeOnHeapIndexRecord FindLeafIndexRecord(byte[] key) { int keyLength = BTreeHeader.cbKey; if (keyLength != key.Length) { throw new ArgumentException("Key length is not valid"); } if (BTreeHeader.bIdxLevels > 0) { if (BTreeHeader.hidRoot.IsEmpty) { throw new Exception("PST is corrupted, bIdxLevels > 0 and BTH root is empty"); } byte level = BTreeHeader.bIdxLevels; byte[] indexBytes = GetHeapItem(BTreeHeader.hidRoot); BTreeOnHeapIndex index = new BTreeOnHeapIndex(indexBytes, keyLength); index.HeapID = BTreeHeader.hidRoot; while (level > 0) { BTreeOnHeapIndexRecord lastToMatch = index.Records[0]; for (int recordIndex = 1; recordIndex < index.Records.Count; recordIndex++) { BTreeOnHeapIndexRecord record = index.Records[recordIndex]; // All the entries in the child have key values greater than or equal to this key value. if (record.CompareTo(key) <= 0) { lastToMatch = record; } else { break; } } level--; if (level == 0) { lastToMatch.Index = index; return(lastToMatch); } else { byte[] bytes = GetHeapItem(lastToMatch.hidNextLevel); BTreeOnHeapIndex childIndex = new BTreeOnHeapIndex(bytes, keyLength); childIndex.ParentIndex = index; childIndex.HeapID = lastToMatch.hidNextLevel; index = childIndex; } } } return(null); }
public int GetSortedInsertIndex(BTreeOnHeapIndexRecord recordToInsert) { int insertIndex = 0; while (insertIndex < Records.Count && recordToInsert.CompareTo(Records[insertIndex]) > 0) { insertIndex++; } return(insertIndex); }
public BTreeOnHeapIndex(byte[] heapItemBytes, int keyLength) { KeyLength = keyLength; int offset = 0; while (offset < heapItemBytes.Length) { BTreeOnHeapIndexRecord record = new BTreeOnHeapIndexRecord(heapItemBytes, offset, keyLength); Records.Add(record); offset += keyLength + HeapID.Length; } }
public BTreeOnHeapIndex CreateNewRoot(byte[] nextLevelKey) { BTreeOnHeapIndex newRoot = new BTreeOnHeapIndex(nextLevelKey.Length); BTreeOnHeapIndexRecord rootIndexRecord = new BTreeOnHeapIndexRecord(); rootIndexRecord.key = nextLevelKey; rootIndexRecord.hidNextLevel = BTreeHeader.hidRoot; newRoot.Records.Add(rootIndexRecord); newRoot.HeapID = AddItemToHeap(newRoot.GetBytes()); BTreeHeader.hidRoot = newRoot.HeapID; BTreeHeader.bIdxLevels++; UpdateBTreeHeader(); return(newRoot); }
public BTreeOnHeapLeaf <T> FindLeaf(byte[] key) { BTreeOnHeapIndexRecord leafIndexRecord = FindLeafIndexRecord(key); // note: the leaf we refer to here is one level below the leaf index record HeapID leafHeapID; if (leafIndexRecord == null) { leafHeapID = BTreeHeader.hidRoot; } else { leafHeapID = leafIndexRecord.hidNextLevel; } return(GetLeaf(leafHeapID, leafIndexRecord)); }
public int CompareTo(BTreeOnHeapIndexRecord record) { return(CompareTo(record.key)); }