Beispiel #1
0
        public void Insert(ulong txnId, byte[] key, byte[] value, bool overwrite = false, BrightstarProfiler profiler = null)
        {
            using (profiler.Step("LeafNode.Insert"))
            {
                if (IsFull)
                {
                    throw new NodeFullException();
                }
                int insertIndex = Search(key);
                if (insertIndex >= 0)
                {
                    if (overwrite)
                    {
                        EnsureWriteable(txnId);
                        _page.SetData(value, 0,
                                      ValueOffset(insertIndex),
                                      Math.Min(value.Length, _config.ValueSize));
                        return;
                    }
                    throw new DuplicateKeyException();
                }
                EnsureWriteable(txnId);
                insertIndex = ~insertIndex;
                RightShiftFrom(insertIndex, 1);
                _page.SetData(key, 0, KeyOffset(insertIndex), _config.KeySize);
                if (_config.ValueSize > 0 && value != null)
                {
                    _page.SetData(value, 0, ValueOffset(insertIndex), Math.Min(_config.ValueSize, value.Length));
                }
                KeyCount++;
#if DEBUG_BTREE
                _config.BTreeDebug("LeafNode.Insert@{0}. Key={1}. Updated Node: {2}", PageId, key.Dump(), DumpKeys());
#endif
            }
        }
Beispiel #2
0
        public INode GetNode(ulong nodeId, BrightstarProfiler profiler)
        {
            using (profiler.Step("BPlusTree.GetNode"))
            {
                INode ret;
                if (_nodeCache.TryGetValue(nodeId, out ret))
                {
                    profiler.Incr("NodeCache Hit");
                    return(ret);
                }

                profiler.Incr("NodeCache Miss");
                using (profiler.Step("Load Node"))
                {
                    var nodePage = _pageStore.Retrieve(nodeId, profiler);
                    var header   = BitConverter.ToInt32(nodePage.Data, 0);
                    if (header < 0)
                    {
                        ret = MakeInternalNode(nodePage, ~header);
#if DEBUG_BTREE
                        _config.BTreeDebug("{0}: Loaded INTERNAL node from page {1}. {2}", _config.DebugId, nodePage.Id, ret.ToString());
#endif
                    }
                    else
                    {
                        ret = MakeLeafNode(nodePage, header);
#if DEBUG_BTREE
                        _config.BTreeDebug("{0}: Loaded LEAF node from page {1}. {2}", _config.DebugId, nodePage.Id, ret.ToString());
#endif
                    }
                    _nodeCache.Add(ret);
                    return(ret);
                }
            }
        }
        /// <summary>
        /// Splits this node into two internal nodes, creating a new node for the right-hand (upper) half of the keys
        /// </summary>
        /// <param name="txnId"></param>
        /// <param name="rightNodePage">The new page reserved to receive the newly created internal node</param>
        /// <param name="splitKey">Receives the value of the key used for the split</param>
        /// <returns>The new right-hand node</returns>
        public IInternalNode Split(ulong txnId, IPage rightNodePage, out byte[] splitKey)
        {
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Id={0}. Structure Before: {1}", PageId, Dump());
#endif
            EnsureWriteable(txnId);
            var splitIndex = _config.InternalSplitIndex;
            splitKey = GetKey(splitIndex);
            rightNodePage.SetData(_page.Data, KeyOffset(splitIndex + 1),
                                  KeyOffset(0),
                                  (KeyCount - (splitIndex + 1)) * _config.KeySize);
            var pointerCopyStart  = PointerOffset(splitIndex + 1);
            var pointerCopyLength = (KeyCount - splitIndex) * 8;
            rightNodePage.SetData(_page.Data, pointerCopyStart,
                                  PointerOffset(0),
                                  pointerCopyLength);
            var rightNodeKeyCount = KeyCount - (splitIndex + 1);
            rightNodePage.SetData(BitConverter.GetBytes(~rightNodeKeyCount), 0, 0, 4);
            var rightNode = new InternalNode(rightNodePage, rightNodeKeyCount, _config);
            KeyCount = splitIndex;
#if DEBUG_BTREE
            _config.BTreeDebug("InternalNode.Split. Structure After: Id={0} {1}\nRight Node After: Id={2} {3}",
                               PageId, Dump(), rightNode.PageId, rightNode.Dump());
#endif
            return(rightNode);
        }
        /// <summary>
        /// Initializes a new node using the data contained in the specified persisten storage page
        /// </summary>
        /// <param name="page">The page used to back the node</param>
        /// <param name="keyCount">The number of keys in the node (as read from page data)</param>
        /// <param name="treeConfig">The tree configuration parameters</param>
        /// <remarks>Strictly speaking we don't have to pass the key count because it can be read from
        /// the page data. However, the code that invokes this constructor needs to check the key
        /// count value to see if a node contains a leaf or an internal node and having this constructor
        /// separate from one that specifies that the page is empty initially is also convenient</remarks>
        public InternalNode(IPage page, int keyCount, BPlusTreeConfiguration treeConfig)
        {
            _config   = treeConfig;
            _page     = page;
            _keyCount = keyCount;
#if DEBUG_BTREE
            treeConfig.BTreeDebug("+Internal {0}", page.Id);
#endif
        }
Beispiel #5
0
        public LeafNode(IPage page, int keyCount, BPlusTreeConfiguration treeConfiguration)
        {
            _page        = page;
            _keyCount    = keyCount;
            _prevPointer = BitConverter.ToUInt64(_page.Data, 4);
            _nextPointer = BitConverter.ToUInt64(_page.Data, 12);
            _config      = treeConfiguration;
#if DEBUG_BTREE
            _config.BTreeDebug("+Leaf2 {0}", _page.Id);
#endif
        }
        /// <summary>
        /// Creates a new node backed by the specified persistent storage page that has only
        /// a single child node pointer
        /// </summary>
        /// <param name="page">The page used to back the node. Must be writeable.</param>
        /// <param name="onlyChild">The child node pointer</param>
        /// <param name="treeConfiguration">The tree configuration</param>
        /// <exception cref="InvalidOperationException">Raised if <paramref name="page"/> is not a writeable page</exception>
        public InternalNode(IPage page, ulong onlyChild, BPlusTreeConfiguration treeConfiguration)
        {
            _config = treeConfiguration;
            AssertWriteable(page);
            _page = page;
            _page.SetData(BitConverter.GetBytes(onlyChild), 0, PointerOffset(0), 8);
            KeyCount = 0;
#if DEBUG_BTREE
            _config.BTreeDebug("+Internal {0}", _page.Id);
#endif
        }
Beispiel #7
0
        /// <summary>
        /// Creates a leaf node that will be backed by a new page
        /// </summary>
        /// <param name="reservedPage">The backing page for this node. Must be writeable</param>
        /// <param name="prevPointer">UNUSED</param>
        /// <param name="nextPointer">UNUSED</param>
        /// <param name="treeConfiguration">The tree configuration parameters</param>
        public LeafNode(IPage reservedPage, ulong prevPointer, ulong nextPointer,
                        BPlusTreeConfiguration treeConfiguration)
        {
            _config = treeConfiguration;
            AssertWriteable(reservedPage);
            _page    = reservedPage;
            KeyCount = 0;
            Prev     = prevPointer;
            Next     = nextPointer;
#if DEBUG_BTREE
            _config.BTreeDebug("+Leaf1 {0}", _page.Id);
#endif
        }
        /// <summary>
        /// Creates a new node backed by the specified persistent storage page with a single
        /// key and left and right pointers.
        /// </summary>
        /// <param name="page">The page used to back the node. Must be writeable.</param>
        /// <param name="splitKey">The key that separates left and right child pointers</param>
        /// <param name="leftPageId">The left child node pointer</param>
        /// <param name="rightPageId">The right child node pointer</param>
        /// <param name="treeConfiguration">The tree configuration</param>
        /// <exception cref="InvalidOperationException">Raised if <paramref name="page"/> is not a writeable page</exception>
        public InternalNode(IPage page, byte[] splitKey, ulong leftPageId, ulong rightPageId,
                            BPlusTreeConfiguration treeConfiguration)
        {
            _config = treeConfiguration;
            AssertWriteable(page);
            _page = page;
            _page.SetData(splitKey, 0, KeyOffset(0), _config.KeySize);
            _page.SetData(BitConverter.GetBytes(leftPageId), 0, PointerOffset(0), 8);
            _page.SetData(BitConverter.GetBytes(rightPageId), 0, PointerOffset(1), 8);
            KeyCount = 1;
#if DEBUG_BTREE
            _config.BTreeDebug("+Internal {0}", _page.Id);
#endif
        }
        /// <summary>
        /// Creates a new node backed by the specified persistent storage page
        /// containing a list of keys and child values
        /// </summary>
        /// <param name="page">The page used to back the node. Must be writeable</param>
        /// <param name="keys">The list of keys for the node</param>
        /// <param name="values">The list of values for the node</param>
        /// <param name="treeConfiguration">The tree configuration</param>
        public InternalNode(IPage page, List <byte[]> keys, List <ulong> values, BPlusTreeConfiguration treeConfiguration)
        {
            _config = treeConfiguration;
            AssertWriteable(page);
            _page    = page;
            KeyCount = keys.Count;
            int i, keyOffset, pointerOffset;

            for (i = 0, keyOffset = KeyOffset(0); i < keys.Count; i++, keyOffset += _config.KeySize)
            {
                _page.SetData(keys[i], 0, keyOffset, _config.KeySize);
            }
            for (i = 0, pointerOffset = PointerOffset(0); i < KeyCount + 1; i++, pointerOffset += 8)
            {
                _page.SetData(BitConverter.GetBytes(values[i]), 0, pointerOffset, 8);
            }
#if DEBUG_BTREE
            _config.BTreeDebug("+Internal {0}", _page.Id);
#endif
        }
Beispiel #10
0
        public LeafNode(IPage page, ulong prevPointer, ulong nextPointer,
                        BPlusTreeConfiguration treeConfiguration,
                        IEnumerable <KeyValuePair <byte[], byte[]> > orderedValues, int numValuesToLoad)
        {
            _page   = page;
            _config = treeConfiguration;
            Prev    = prevPointer;
            Next    = nextPointer;
            int numLoaded = 0;

            foreach (var kvp in orderedValues.Take(numValuesToLoad))
            {
                SetKey(numLoaded, kvp.Key);
                if (_config.ValueSize > 0)
                {
                    SetValue(numLoaded, kvp.Value);
                }
                numLoaded++;
            }
            KeyCount = numLoaded;
#if DEBUG_BTREE
            _config.BTreeDebug("+Leaf3 {0}", _page.Id);
#endif
        }