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 } }
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 }
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 }
/// <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 }
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 }