コード例 #1
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
                    }
                }
            }
        }
コード例 #2
0
        /// <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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        public override void Prepare()
        {
            base.Prepare();

            _currentNode = _index.GetFirstLeaf();
            _enumerator  = new ScanEnumerator(Table.TableDefinition, _index, Condition, IsLeftToRightCondition(Condition));
        }
コード例 #5
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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;
        }
コード例 #6
0
        public override void Prepare()
        {
            base.Prepare();

            _currentNode  = _index.GetFirstLeaf();
            _currentIndex = -1;
        }
コード例 #7
0
 public IndexSeekOperation(LogicalElement logicalElement, Table table, IBPlusTreeNode index, Condition condition)
     : base(logicalElement)
 {
     Table     = table;
     Condition = condition;
     _index    = index;
 }
コード例 #8
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #9
0
        public ScanEnumerator(Relation relation, IBPlusTreeNode index, Condition condition, bool leftToRight)
        {
            Relation    = relation;
            Index       = index;
            Condition   = condition as LeafCondition;
            LeftToRight = leftToRight;

            Reset();
        }
コード例 #10
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
            }
        }
コード例 #11
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #12
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
            }
        }
コード例 #13
0
        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));
            }
        }
コード例 #14
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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;
            }
        }
コード例 #15
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #16
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #17
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #18
0
        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);
        }
コード例 #19
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #20
0
        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);
        }
コード例 #21
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
        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);
        }
コード例 #22
0
 public IndexScanOperation(LogicalElement logicalElement, Table table, IBPlusTreeNode index)
     : base(logicalElement)
 {
     Table  = table;
     _index = index;
 }
コード例 #23
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
 private bool IsSufficientlyFilled(IBPlusTreeNode <TKey> node)
 {
     return((double)node.Entries.Count / _nodeStorage.NodeCapacity > _fillFactor);
 }
コード例 #24
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
 private bool IsFull(IBPlusTreeNode <TKey> node)
 {
     return(node.Entries.Count == _nodeStorage.NodeCapacity);
 }
コード例 #25
0
ファイル: BPlusTree.cs プロジェクト: guojianbin/DataTanker
 private bool IsOverflow(IBPlusTreeNode <TKey> node)
 {
     return(node.Entries.Count > _nodeStorage.NodeCapacity);
 }
コード例 #26
0
 private IPage NodeToPage(IBPlusTreeNode <TKey> node)
 {
     return(new Page(_pageManager, node.Index, () => Serialize(node), node));
 }
コード例 #27
0
        public void Update(IBPlusTreeNode <TKey> node)
        {
            CheckNode(node);

            _nodes[node.Index] = node;
        }