private void CombineIfNeeded(IBPlusTreeNode <TKey> node, IDictionary <long, IBPlusTreeNode <TKey> > nodesToUpdate) { if (IsSufficientlyFilled(node)) { return; } nodesToUpdate[node.Index] = node; if (node.HasPrevious) { var leftSibling = FetchNode(node.PreviousNodeIndex, nodesToUpdate); if (leftSibling.ParentNodeIndex == node.ParentNodeIndex) { if (leftSibling.Entries.Count + node.Entries.Count <= _nodeStorage.NodeCapacity) { Combine(leftSibling, node, nodesToUpdate); return; } } } if (node.HasNext) { var rightSibling = FetchNode(node.NextNodeIndex, nodesToUpdate); if (rightSibling.ParentNodeIndex == node.ParentNodeIndex) { if (rightSibling.Entries.Count + node.Entries.Count <= _nodeStorage.NodeCapacity) { Combine(node, rightSibling, nodesToUpdate); } } } }
/// <summary> /// Updates a node in storage. /// </summary> /// <param name="node">A node to save</param> public void Update(IBPlusTreeNode <TKey> node) { UnpinNode(node.Index); var page = NodeToPage(node); _pageManager.UpdatePage(page); }
private byte[] Serialize(IBPlusTreeNode <TKey> node) { var header = new BPlusTreeNodePageHeader { IsLeaf = node.IsLeaf, NextPageIndex = node.NextNodeIndex, PreviousPageIndex = node.PreviousNodeIndex, ParentPageIndex = node.ParentNodeIndex, SizeRange = _nodeEntrySizeRange }; var page = new Page(_pageManager, node.Index, new byte[_pageManager.PageSize]); int cnt = node.Entries.Count; lock (_locker) { for (int i = 0; i < cnt; i++) { var entry = node.Entries[i]; _dbItems[i].RawData = GetIndexEntryBytes(entry); } PageFormatter.FormatFixedSizeItemsPage(page, header, _dbItems.Take(cnt).ToArray()); } return(page.Content); }
public override void Prepare() { base.Prepare(); _currentNode = _index.GetFirstLeaf(); _enumerator = new ScanEnumerator(Table.TableDefinition, _index, Condition, IsLeftToRightCondition(Condition)); }
private void RedistributeEntries(IBPlusTreeNode <TKey> left, IBPlusTreeNode <TKey> right, IBPlusTreeNode <TKey> parent) { // get the index of parent entry referencing to the left node int index; FindSuitableEntry(parent.Entries, left.Entries.First().Key, out index); // get concatenated sequence of leaf entries var entries = left.Entries.Concat(right.Entries).ToList(); // clear entries of leaf nodes left.Entries.Clear(); right.Entries.Clear(); // break sequence in half int halfCount = entries.Count / 2; entries.Take(halfCount).ToList().ForEach(left.Entries.Add); entries.Skip(halfCount).ToList().ForEach(right.Entries.Add); var entry1ForParent = new KeyValuePair <TKey, DbItemReference>(left.Entries.Last().Key, new DbItemReference(left.Index, 0)); var entry2ForParent = new KeyValuePair <TKey, DbItemReference>(right.Entries.Last().Key, new DbItemReference(right.Index, 0)); // update references in parent node parent.Entries[index] = entry1ForParent; parent.Entries[index + 1] = entry2ForParent; }
public override void Prepare() { base.Prepare(); _currentNode = _index.GetFirstLeaf(); _currentIndex = -1; }
public IndexSeekOperation(LogicalElement logicalElement, Table table, IBPlusTreeNode index, Condition condition) : base(logicalElement) { Table = table; Condition = condition; _index = index; }
private bool CheckNodeRanges(IBPlusTreeNode <TKey> node, out string message) { message = string.Empty; //if (node.HasParent) //{ // var parent = FetchNode(node.ParentNodeIndex); // var largestKey = node.Entries.Last().Key; // var parentLargestKey = parent.Entries.Last().Key; // if(parentLargestKey.CompareTo(largestKey) < 0) // { // message = string.Format("Largest key ({0}) of node: {1} is greater than the largest key ({2}) of its parent node: {3}", // largestKey, node.Index, parentLargestKey, node.ParentNodeIndex); // return false; // } //} if (node.HasPrevious) { var previous = FetchNode(node.PreviousNodeIndex); var smallestKey = node.Entries.First().Key; var largestKey = previous.Entries.Last().Key; if (previous.Entries.Last().Key.CompareTo(node.Entries.First().Key) != -1) { message = string.Format("Smallest key ({0}) of node: {1} is smaller than the largest key ({2}) of previous node: {3}", smallestKey, node.Index, largestKey, node.PreviousNodeIndex); return(false); } } return(true); }
public ScanEnumerator(Relation relation, IBPlusTreeNode index, Condition condition, bool leftToRight) { Relation = relation; Index = index; Condition = condition as LeafCondition; LeftToRight = leftToRight; Reset(); }
private void Combine(IBPlusTreeNode <TKey> left, IBPlusTreeNode <TKey> right, IDictionary <long, IBPlusTreeNode <TKey> > nodesToUpdate) { var parent = FetchNode(right.ParentNodeIndex, nodesToUpdate); int index; // one node can be empty if (left.Entries.Any()) { FindSuitableEntry(parent.Entries, left.Entries.First().Key, out index); } else { FindSuitableEntry(parent.Entries, right.Entries.First().Key, out index); index--; } ChangeParentReferencesInChildNodes(right, left.Index, nodesToUpdate); _nodeStorage.Remove(right.Index); nodesToUpdate.Remove(right.Index); nodesToUpdate[left.Index] = left; left.NextNodeIndex = right.NextNodeIndex; foreach (var entry in right.Entries) { left.Entries.Add(entry); } if (right.HasNext) { var nextNode = FetchNode(right.NextNodeIndex, nodesToUpdate); nextNode.PreviousNodeIndex = left.Index; nodesToUpdate[nextNode.Index] = nextNode; } var entryForParent = new KeyValuePair <TKey, DbItemReference>(left.Entries.Last().Key, new DbItemReference(left.Index, 0)); parent.Entries[index] = entryForParent; parent.Entries.RemoveAt(index + 1); if (!parent.HasParent && parent.Entries.Count == 1) { // there are no more significant entries in the root node // we have a new root _nodeStorage.SetRoot(left.Index); left.ParentNodeIndex = -1; _nodeStorage.Remove(parent.Index); nodesToUpdate.Remove(parent.Index); } else { nodesToUpdate[parent.Index] = parent; CombineIfNeeded(parent, nodesToUpdate); } }
private bool CheckNodeReferencesAreValid(IBPlusTreeNode <TKey> node, out string message) { message = string.Empty; if (node.HasParent) { if (FetchNode(node.ParentNodeIndex) == null) { message = string.Format("Node: {0} has invalid reference ({1}) to parent node.", node.Index, node.ParentNodeIndex); return(false); } } if (node.HasPrevious) { var previous = FetchNode(node.PreviousNodeIndex); if (previous == null) { message = string.Format("Node: {0} has invalid reference ({1}) to previous node.", node.Index, node.PreviousNodeIndex); return(false); } if (previous.NextNodeIndex != node.Index) { message = string.Format("Node: {0} has reference to previous node: {1}. But this node references to next node: {2}", node.Index, node.PreviousNodeIndex, previous.NextNodeIndex); return(false); } } if (node.HasNext) { var next = FetchNode(node.NextNodeIndex); if (next == null) { message = string.Format("Node: {0} has invalid reference ({1}) to next node.", node.Index, node.NextNodeIndex); return(false); } if (next.PreviousNodeIndex != node.Index) { message = string.Format("Node: {0} has reference to next node: {1}. But this node references to previous node: {2}", node.Index, node.NextNodeIndex, next.PreviousNodeIndex); return(false); } } return(true); }
private void MoveSecondHalfEntries(IBPlusTreeNode <TKey> source, IBPlusTreeNode <TKey> receiver) { for (int i = _nodeStorage.NodeCapacity / 2; i < source.Entries.Count; i++) { receiver.Entries.Add(source.Entries[i]); } for (int i = source.Entries.Count - 1; i >= _nodeStorage.NodeCapacity / 2; i--) { source.Entries.RemoveAt(i); } }
private void CheckNode(IBPlusTreeNode <TKey> node) { if (!_nodes.ContainsKey(node.Index)) { throw new ArgumentException("B+Tree node has an invalid index", nameof(node)); } if (node.Entries.Count > _nodeCapacity) { throw new ArgumentException("B+Tree node has too many entries", nameof(node)); } }
private void ChangeParentReferencesInChildNodes(IBPlusTreeNode <TKey> node, long newIndex, IDictionary <long, IBPlusTreeNode <TKey> > nodesToUpdate) { if (node.IsLeaf) { return; } foreach (var entry in node.Entries) { var childNode = FetchNode(entry.Value.PageIndex, nodesToUpdate); childNode.ParentNodeIndex = newIndex; nodesToUpdate[childNode.Index] = childNode; } }
private bool CheckNodeEntriesAreOrdered(IBPlusTreeNode <TKey> node, out string message) { message = string.Empty; for (int i = 0; i < node.Entries.Count - 1; i++) { if (node.Entries[i].Key.CompareTo(node.Entries[i + 1].Key) != -1) { message = string.Format("Disordered entries in node: {0}", node.Index); return(false); } } return(true); }
private bool CheckNode(IBPlusTreeNode <TKey> node, out string message) { if (node.Entries.Count == 0 && node.HasParent) { message = string.Format("Empty node: {0}", node.Index); return(false); } if (!CheckNodeEntriesAreOrdered(node, out message)) { return(false); } if (!CheckNodeReferencesAreValid(node, out message)) { return(false); } if (!CheckNodeRanges(node, out message)) { return(false); } if (!node.IsLeaf) { foreach (var entry in node.Entries) { var child = FetchNode(entry.Value.PageIndex); if (child == null) { message = $"Invalid reference ({entry.Value.PageIndex}) to child in node: {node.Index}"; return(false); } if (!CheckNode(child, out message)) { return(false); } } } return(true); }
private bool Rotate(IBPlusTreeNode <TKey> node, IDictionary <long, IBPlusTreeNode <TKey> > nodesToUpdate) { if (node.HasPrevious) { var leftSibling = FetchNode(node.PreviousNodeIndex); if (leftSibling.ParentNodeIndex == node.ParentNodeIndex) { if (!IsFull(leftSibling)) { var parentNode = FetchNode(node.ParentNodeIndex, nodesToUpdate); RedistributeEntries(leftSibling, node, parentNode); nodesToUpdate[leftSibling.Index] = leftSibling; nodesToUpdate[node.Index] = node; nodesToUpdate[parentNode.Index] = parentNode; return(true); } } } if (node.HasNext) { var rightSibling = FetchNode(node.NextNodeIndex); if (rightSibling.ParentNodeIndex == node.ParentNodeIndex) { if (!IsFull(rightSibling)) { var parentNode = FetchNode(node.ParentNodeIndex, nodesToUpdate); RedistributeEntries(node, rightSibling, parentNode); nodesToUpdate[node.Index] = node; nodesToUpdate[rightSibling.Index] = rightSibling; nodesToUpdate[parentNode.Index] = parentNode; return(true); } } } return(false); }
private IBPlusTreeNode GetBTreeForIndex(Pointer rootBlock, Index index) { IBPlusTreeNode node = null; ValueType valueType = TableDefinition.GetAttributeByName(index.Column).Type; if (valueType == ValueType.String) { node = new BPlusTreeNode <string>(_relationManager.GetRelation(Constants.StringIndexRelationId), TableDefinition, MemoryManager, rootBlock); } else if (valueType == ValueType.Integer || valueType == ValueType.UnsignedInteger) { node = new BPlusTreeNode <int>(_relationManager.GetRelation(Constants.IntIndexRelationId), TableDefinition, MemoryManager, rootBlock); } node.IsRoot = true; node.ReadNode(); return(node); }
private IBPlusTreeNode <TKey> NextNodeForKey(TKey key, IBPlusTreeNode <TKey> node, bool returnNullIfOutOfRange = false) { int index; FindSuitableEntry(node.Entries, key, out index); if (index < node.Entries.Count) { return(FetchNode(node.Entries[index].Value.PageIndex)); } if (returnNullIfOutOfRange) { return(null); } if (index == node.Entries.Count) // tricky last node { return(FetchNode(node.Entries[index - 1].Value.PageIndex)); } Debug.Fail("Should never get here"); return(null); }
public override CustomTuple GetNext() { while (_currentNode != null) { int next = _currentIndex + 1; if (_currentNode.Values.Count > next) { Block block = Table.MemoryManager.Read(Table.TableDefinition, _currentNode.Values[next].Pointer); Record record = block.GetRecordForRowId(_currentNode.Values[next].Pointer.Index); _currentIndex++; return(new CustomTuple(Table.TableDefinition).FromRecord(record)); } else { _currentIndex = -1; _currentNode = _currentNode.RightSibling; } } return(null); }
private void Split(IBPlusTreeNode <TKey> node, IDictionary <long, IBPlusTreeNode <TKey> > nodesToUpdate) { if (!IsOverflow(node)) { return; } nodesToUpdate[node.Index] = node; var newNode = _nodeStorage.Create(node.IsLeaf); nodesToUpdate[newNode.Index] = newNode; // link nodes together newNode.PreviousNodeIndex = node.Index; newNode.NextNodeIndex = node.NextNodeIndex; node.NextNodeIndex = newNode.Index; if (newNode.HasNext) { var nextNode = FetchNode(newNode.NextNodeIndex, nodesToUpdate); nextNode.PreviousNodeIndex = newNode.Index; nodesToUpdate[nextNode.Index] = nextNode; } // move half of the entries to new node MoveSecondHalfEntries(node, newNode); // prepare new entries for parent node var entry1ForParent = new KeyValuePair <TKey, DbItemReference>(node.Entries.Last().Key, new DbItemReference(node.Index, 0)); var entry2ForParent = new KeyValuePair <TKey, DbItemReference>(newNode.Entries.Last().Key, new DbItemReference(newNode.Index, 0)); // change links in childs to new node ChangeParentReferencesInChildNodes(newNode, newNode.Index, nodesToUpdate); IBPlusTreeNode <TKey> parentNode; if (!node.HasParent) { // handle case of new root parentNode = _nodeStorage.Create(false); _nodeStorage.SetRoot(parentNode.Index); node.ParentNodeIndex = parentNode.Index; newNode.ParentNodeIndex = parentNode.Index; nodesToUpdate[parentNode.Index] = parentNode; parentNode.Entries.Add(entry1ForParent); parentNode.Entries.Add(entry2ForParent); return; } parentNode = FetchNode(node.ParentNodeIndex, nodesToUpdate); _nodeStorage.PinNode(parentNode.Index); nodesToUpdate[parentNode.Index] = parentNode; newNode.ParentNodeIndex = node.ParentNodeIndex; int index; FindSuitableEntry(parentNode.Entries, node.Entries.First().Key, out index); parentNode.Entries.RemoveAt(index); parentNode.Entries.Insert(index, entry2ForParent); parentNode.Entries.Insert(index, entry1ForParent); Split(parentNode, nodesToUpdate); }
public IndexScanOperation(LogicalElement logicalElement, Table table, IBPlusTreeNode index) : base(logicalElement) { Table = table; _index = index; }
private bool IsSufficientlyFilled(IBPlusTreeNode <TKey> node) { return((double)node.Entries.Count / _nodeStorage.NodeCapacity > _fillFactor); }
private bool IsFull(IBPlusTreeNode <TKey> node) { return(node.Entries.Count == _nodeStorage.NodeCapacity); }
private bool IsOverflow(IBPlusTreeNode <TKey> node) { return(node.Entries.Count > _nodeStorage.NodeCapacity); }
private IPage NodeToPage(IBPlusTreeNode <TKey> node) { return(new Page(_pageManager, node.Index, () => Serialize(node), node)); }
public void Update(IBPlusTreeNode <TKey> node) { CheckNode(node); _nodes[node.Index] = node; }