public void DeleteFromIndexRecord(BTreeOnHeapIndex index, HeapID heapID) { int recordIndex = index.GetIndexOfRecord(heapID); index.Records.RemoveAt(recordIndex); if (index.Records.Count > 0) { // will always replace in place (smaller size) ReplaceHeapItem(index.HeapID, index.GetBytes()); } else { if (index.ParentIndex == null) { // this is the root node BTreeHeader.hidRoot = HeapID.EmptyHeapID; BTreeHeader.bIdxLevels = 0; UpdateBTreeHeader(); } else { DeleteFromIndexRecord(index.ParentIndex, index.HeapID); } } }
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 void UpdateIndexRecord(BTreeOnHeapIndex index, HeapID oldHeapID, HeapID newHeapID, byte[] newKey) { int recordIndex = index.GetIndexOfRecord(oldHeapID); index.Records[recordIndex].hidNextLevel = newHeapID; index.Records[recordIndex].key = newKey; // will always replace in place (same size) ReplaceHeapItem(index.HeapID, index.GetBytes()); if (recordIndex == 0 && index.ParentIndex != null) { UpdateIndexRecord(index.ParentIndex, index.HeapID, index.HeapID, index.NodeKey); } }
public BTreeOnHeapIndex Split() { int newNodeStartIndex = Records.Count / 2; BTreeOnHeapIndex newNode = new BTreeOnHeapIndex(this.KeyLength); newNode.ParentIndex = ParentIndex; // Heap ID will be given when the item will be added for (int index = newNodeStartIndex; index < Records.Count; index++) { newNode.Records.Add(Records[index]); } Records.RemoveRange(newNodeStartIndex, Records.Count - newNodeStartIndex); return(newNode); }
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); }