public void TestBorrowLeft() { var config = new BPlusTreeConfiguration(8, 8, 4096); var leftNode = new LeafNode(1ul, 0ul, 0ul, config); var rightNode = new LeafNode(2ul, 0ul, 0ul, config); byte[] testBytes = new byte[] { 1, 2, 3, 4 }; leftNode.Insert(BitConverter.GetBytes(1ul), testBytes); leftNode.Insert(BitConverter.GetBytes(2ul), testBytes); leftNode.Insert(BitConverter.GetBytes(3ul), testBytes); leftNode.Insert(BitConverter.GetBytes(4ul), testBytes); leftNode.Insert(BitConverter.GetBytes(5ul), testBytes); rightNode.Insert(BitConverter.GetBytes(10ul), testBytes); rightNode.Insert(BitConverter.GetBytes(11ul), testBytes); Assert.IsTrue(rightNode.RedistributeFromLeft(leftNode)); Assert.IsTrue(rightNode.KeyCount == 3); TestUtils.AssertBuffersEqual(rightNode.LeftmostKey, BitConverter.GetBytes(5ul)); Assert.IsTrue(leftNode.KeyCount == 4); TestUtils.AssertBuffersEqual(leftNode.RightmostKey, BitConverter.GetBytes(4ul)); leftNode.Delete(BitConverter.GetBytes(1ul)); leftNode.Delete(BitConverter.GetBytes(2ul)); Assert.IsFalse(rightNode.RedistributeFromLeft(leftNode)); }
/// <summary> /// Creates a new tree in the page store /// </summary> /// <param name="txnId">The transaction id for the update</param> /// <param name="pageStore"></param> /// <param name="keySize">The size of the B+ tree's key (in bytes)</param> /// <param name="dataSize">The size of the values stored in leaf nodes (in bytes)</param> public BPlusTree(ulong txnId, IPageStore pageStore, int keySize = 8, int dataSize = 64) { _config = new BPlusTreeConfiguration(pageStore, keySize, dataSize, pageStore.PageSize); _pageStore = pageStore; var root = MakeLeafNode(txnId); _rootId = root.PageId; }
/// <summary> /// Opens an existing tree in the page store /// </summary> /// <param name="pageStore"></param> /// <param name="rootPageId">The page ID of the BTree root node</param> /// <param name="keySize"></param> /// <param name="dataSize"></param> /// <param name="profiler"></param> public BPlusTree(IPageStore pageStore, ulong rootPageId, int keySize = 8, int dataSize = 64, BrightstarProfiler profiler = null) { _config = new BPlusTreeConfiguration(pageStore, keySize, dataSize, pageStore.PageSize); _pageStore = pageStore; var root = GetNode(rootPageId, profiler); _rootId = root.PageId; }
public void TestBorrowLeft() { var config = new BPlusTreeConfiguration(8, 8, 4096); var leftNode = new LeafNode(1ul, 0ul, 0ul, config); var rightNode = new LeafNode(2ul, 0ul, 0ul, config); byte[] testBytes = new byte[]{1,2,3,4}; leftNode.Insert(BitConverter.GetBytes(1ul), testBytes); leftNode.Insert(BitConverter.GetBytes(2ul), testBytes); leftNode.Insert(BitConverter.GetBytes(3ul), testBytes); leftNode.Insert(BitConverter.GetBytes(4ul), testBytes); leftNode.Insert(BitConverter.GetBytes(5ul), testBytes); rightNode.Insert(BitConverter.GetBytes(10ul), testBytes); rightNode.Insert(BitConverter.GetBytes(11ul), testBytes); Assert.IsTrue(rightNode.RedistributeFromLeft(leftNode)); Assert.IsTrue(rightNode.KeyCount == 3); TestUtils.AssertBuffersEqual(rightNode.LeftmostKey, BitConverter.GetBytes(5ul)); Assert.IsTrue(leftNode.KeyCount == 4); TestUtils.AssertBuffersEqual(leftNode.RightmostKey, BitConverter.GetBytes(4ul)); leftNode.Delete(BitConverter.GetBytes(1ul)); leftNode.Delete(BitConverter.GetBytes(2ul)); Assert.IsFalse(rightNode.RedistributeFromLeft(leftNode)); }
public void TestLeafNodeSplit() { var pageStore = new MemoryPageStore(4096); var config = new BPlusTreeConfiguration(pageStore, 8, 8, 4096); var firstNode = new LeafNode(pageStore.Create(0), 0, 0, config); var testBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; for (int i = 0; i < config.LeafLoadFactor; i++) { firstNode.Insert(0, BitConverter.GetBytes((ulong)i), testBytes); } var secondNodePage = pageStore.Create(0); var splitKey = new byte[8]; var secondNode = firstNode.Split(0, secondNodePage, out splitKey); Assert.AreEqual(config.LeafSplitIndex, firstNode.KeyCount); Assert.AreEqual(config.LeafLoadFactor - config.LeafSplitIndex, secondNode.KeyCount); var firstNodePage = pageStore.Retrieve(0, null); var firstNodeKeyCount = BitConverter.ToInt32(firstNodePage.Data, 0); secondNodePage = pageStore.Retrieve(1, null); var secondNodeKeyCount = BitConverter.ToInt32(secondNodePage.Data, 0); Assert.AreEqual(config.LeafSplitIndex, firstNodeKeyCount); Assert.AreEqual(config.LeafLoadFactor - config.LeafSplitIndex, secondNodeKeyCount); }
public void TestBorrowRight() { var pageStore = new MemoryPageStore(4096); var config = new BPlusTreeConfiguration(pageStore, 8, 8, 4096); var leftNode = new LeafNode(pageStore.Create(0), 0, 0, config); var rightNode = new LeafNode(pageStore.Create(0), 0, 0, config); byte[] testBytes = new byte[] { 1, 2, 3, 4 }; leftNode.Insert(1, BitConverter.GetBytes(1ul), testBytes); leftNode.Insert(1, BitConverter.GetBytes(2ul), testBytes); rightNode.Insert(1, BitConverter.GetBytes(10ul), testBytes); rightNode.Insert(1, BitConverter.GetBytes(11ul), testBytes); rightNode.Insert(1, BitConverter.GetBytes(12ul), testBytes); rightNode.Insert(1, BitConverter.GetBytes(13ul), testBytes); rightNode.Insert(1, BitConverter.GetBytes(14ul), testBytes); Assert.IsTrue(leftNode.RedistributeFromRight(1, rightNode)); Assert.IsTrue(leftNode.KeyCount == 3); TestUtils.AssertBuffersEqual(BitConverter.GetBytes(10ul), leftNode.RightmostKey); TestUtils.AssertBuffersEqual(BitConverter.GetBytes(11ul), rightNode.LeftmostKey); Assert.IsTrue(rightNode.KeyCount == 4); Assert.IsFalse(leftNode.RedistributeFromRight(1, rightNode)); }
public LeafNode(ulong nodeId, byte[] nodePage, int keyCount, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; _keyCount = keyCount; _prevPointer = BitConverter.ToUInt64(nodePage, 4); _nextPointer = BitConverter.ToUInt64(nodePage, 12); _keys = new byte[_config.LeafLoadFactor][]; _dataSegments = new byte[_config.LeafLoadFactor][]; for (int i = 0, j = BPlusTreeConfiguration.LeafNodeHeaderSize; i < _keyCount; i++,j += _config.KeySize) { _keys[i] = new byte[_config.KeySize]; Array.Copy(nodePage, j, _keys[i], 0, _config.KeySize); } if (_config.ValueSize > 0) { for (int i = 0, j = _config.LeafDataStartOffset; i < _keyCount; i++, j += (_config.ValueSize + 1)) { byte dataLength = nodePage[j]; _dataSegments[i] = new byte[dataLength]; Array.Copy(nodePage, j + 1, _dataSegments[i], 0, dataLength); } } PageId = nodeId; IsDirty = false; }
public void TestLeafNodeSplit() { var pageStore = new MemoryPageStore(4096); var config = new BPlusTreeConfiguration(pageStore, 8, 8, 4096); var firstNode = new LeafNode(pageStore.Create(0), 0, 0, config); var testBytes = new byte[]{1,2,3,4,5,6,7,8}; for (int i = 0; i < config.LeafLoadFactor; i++) { firstNode.Insert(0, BitConverter.GetBytes((ulong)i), testBytes); } var secondNodePage = pageStore.Create(0); var splitKey = new byte[8]; var secondNode = firstNode.Split(0, secondNodePage, out splitKey); Assert.AreEqual(config.LeafSplitIndex, firstNode.KeyCount); Assert.AreEqual(config.LeafLoadFactor - config.LeafSplitIndex, secondNode.KeyCount); var firstNodePage = pageStore.Retrieve(0, null); var firstNodeKeyCount = BitConverter.ToInt32(firstNodePage.Data, 0); secondNodePage = pageStore.Retrieve(1, null); var secondNodeKeyCount = BitConverter.ToInt32(secondNodePage.Data, 0); Assert.AreEqual(config.LeafSplitIndex, firstNodeKeyCount); Assert.AreEqual(config.LeafLoadFactor - config.LeafSplitIndex, secondNodeKeyCount); }
public ulong Write(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { var targetConfiguration = new BPlusTreeConfiguration(pageStore, Configuration.KeySize, Configuration.ValueSize, Configuration.PageSize); var builder = new BPlusTreeBuilder(pageStore, targetConfiguration); return(builder.Build(transactionId, Scan(profiler), profiler)); }
public BPlusTreeBuilder(IPageStore targetPageStore, BPlusTreeConfiguration targetTreeConfiguration) { _pageStore = targetPageStore; _config = targetTreeConfiguration; // These values are copied locally to allow us to later change the default loading from 100% to something lower if we want _leafLoadFactor = _config.LeafLoadFactor; _internalBranchFactor = _config.InternalBranchFactor; }
/// <summary> /// Creates a new tree in the page store /// </summary> /// <param name="txnId">The transaction id for the update</param> /// <param name="pageStore"></param> /// <param name="keySize">The size of the B+ tree's key (in bytes)</param> /// <param name="dataSize">The size of the values stored in leaf nodes (in bytes)</param> public BPlusTree(ulong txnId, IPageStore pageStore, int keySize = 8, int dataSize = 64) { _config = new BPlusTreeConfiguration(pageStore, keySize, dataSize, pageStore.PageSize); _pageStore = pageStore; var root = MakeLeafNode(txnId); _rootId = root.PageId; _nodeCache = new WeakReferenceNodeCache(); _nodeCache.Add(root); }
/// <summary> /// Opens an existing tree in the page store /// </summary> /// <param name="pageStore"></param> /// <param name="rootPageId">The page ID of the BTree root node</param> /// <param name="keySize"></param> /// <param name="dataSize"></param> /// <param name="profiler"></param> public BPlusTree(IPageStore pageStore, ulong rootPageId, int keySize = 8, int dataSize = 64, BrightstarProfiler profiler = null) { _config = new BPlusTreeConfiguration(keySize, dataSize, pageStore.PageSize); _pageStore = pageStore; _modifiedNodes = new Dictionary<ulong, INode>(); _nodeCache = new WeakReferenceNodeCache(); _root = GetNode(rootPageId, profiler); _nodeCache.Add(_root); }
public void TestRightShiftFrom() { var pageStore = new MemoryPageStore(1024); var config = new BPlusTreeConfiguration( pageStore, 8, 8, 1024); var n = new InternalNode(pageStore.Create(0), BitConverter.GetBytes(50ul), 2,3, config); n.Insert(1, BitConverter.GetBytes(100ul), 4); Assert.AreEqual(50ul, BitConverter.ToUInt64(n.LeftmostKey, 0)); Assert.AreEqual(100ul, BitConverter.ToUInt64(n.RightmostKey, 0)); }
/// <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 void TestRightShiftFrom() { var pageStore = new MemoryPageStore(1024); var config = new BPlusTreeConfiguration(pageStore, 8, 8, 1024); var n = new InternalNode(pageStore.Create(0), BitConverter.GetBytes(50ul), 2, 3, config); n.Insert(1, BitConverter.GetBytes(100ul), 4); Assert.AreEqual(50ul, BitConverter.ToUInt64(n.LeftmostKey, 0)); Assert.AreEqual(100ul, BitConverter.ToUInt64(n.RightmostKey, 0)); }
/// <summary> /// Creates a new tree in the page store /// </summary> /// <param name="pageStore"></param> /// <param name="keySize">The size of the B+ tree's key (in bytes)</param> /// <param name="dataSize">The size of the values stored in leaf nodes (in bytes)</param> public BPlusTree(IPageStore pageStore, int keySize = 8, int dataSize = 64) { _config = new BPlusTreeConfiguration(keySize, dataSize, pageStore.PageSize); _pageStore = pageStore; _modifiedNodes = new Dictionary<ulong, INode>(); _root = new LeafNode(pageStore.Create(), 0, 0, _config); _nodeCache = new WeakReferenceNodeCache(); _modifiedNodes[_root.PageId] = _root; _nodeCache.Add(_root); }
public ulong Write(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { using (profiler.Step("RelatedResourceIndex.Write")) { var targetConfiguration = new BPlusTreeConfiguration(pageStore, Configuration.KeySize, Configuration.ValueSize, Configuration.PageSize); var indexBuilder = new BPlusTreeBuilder(pageStore, targetConfiguration); return(indexBuilder.Build(transactionId, WritePredicateIndexes(pageStore, transactionId, profiler), profiler)); } }
public LeafNode(ulong reservedPageId, ulong prevPointer, ulong nextPointer, BPlusTreeConfiguration treeConfig) { _config = treeConfig; _keyCount = 0; _prevPointer = prevPointer; _nextPointer = nextPointer; _keys = new byte[_config.LeafLoadFactor][]; _dataSegments = new byte[_config.LeafLoadFactor][]; PageId = reservedPageId; IsDirty = true; }
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 }
private IEnumerable <KeyValuePair <byte[], byte []> > WritePredicateIndexes(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { foreach (var entry in EnumeratePredicateIndexes(profiler)) { var predicateId = entry.Key; var targetConfiguration = new BPlusTreeConfiguration(pageStore, entry.Value.Configuration.KeySize, entry.Value.Configuration.ValueSize, entry.Value.Configuration.PageSize); var builder = new BPlusTreeBuilder(pageStore, targetConfiguration); ulong newPredicateIndexId = builder.Build(transactionId, entry.Value.Scan(profiler), profiler); yield return(new KeyValuePair <byte[], byte[]>(BitConverter.GetBytes(predicateId), BitConverter.GetBytes(newPredicateIndexId))); } }
/// <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 }
public void TestCoalesceRootLeafNode() { const string storeName = "Coalesce.RootLeafNode.data"; ulong srcRootId, targetRootId; var config = new BPlusTreeConfiguration(8, 64, 4096); var txnId = 0ul; using (var store = TestUtils.CreateEmptyPageStore(storeName)) { var sourceTree = new BPlusTree(store); for (int i = 0; i < config.LeafLoadFactor; i++) { sourceTree.Insert(txnId, (ulong)i, BitConverter.GetBytes((ulong)i)); } sourceTree.DumpStructure(); srcRootId = sourceTree.Save(txnId, null); store.Commit(txnId, null); } using (var store = TestUtils.OpenPageStore(storeName, false)) { var sourceTree = new BPlusTree(store, srcRootId); var builder = new BPlusTreeBuilder(store, config); targetRootId = builder.Build(1, sourceTree.Scan(null)); var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } store.Commit(1, null); } using (var store = TestUtils.OpenPageStore(storeName, true)) { var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } } }
public void TestCoalesceRootLeafNode() { const string storeName = "Coalesce.RootLeafNode.data"; ulong srcRootId, targetRootId; var config = new BPlusTreeConfiguration(8, 64, 4096); var txnId = 0ul; using(var store = TestUtils.CreateEmptyPageStore(storeName)) { var sourceTree = new BPlusTree(store); for (int i = 0; i < config.LeafLoadFactor; i++) { sourceTree.Insert(txnId, (ulong)i, BitConverter.GetBytes((ulong)i)); } sourceTree.DumpStructure(); srcRootId = sourceTree.Save(txnId, null); store.Commit(txnId, null); } using(var store = TestUtils.OpenPageStore(storeName, false)) { var sourceTree = new BPlusTree(store, srcRootId); var builder = new BPlusTreeBuilder(store, config); targetRootId = builder.Build(1, sourceTree.Scan(null)); var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for(int i =0 ; i < config.LeafLoadFactor; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong) i, BitConverter.ToUInt64(valueBuff, 0)); } store.Commit(1, null); } using(var store = TestUtils.OpenPageStore(storeName, true)) { var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } } }
private void BuildAndScan(IPageStore pageStore, string pageStoreName, PersistenceType persistenceType, int keyCount) { var config = new BPlusTreeConfiguration(8, 64, pageStore.PageSize); var builder = new BPlusTreeBuilder(pageStore, config); var treeRoot = builder.Build(1, _testOrderedValues.Take(keyCount)); var treeBeforeSave = new BPlusTree(pageStore, treeRoot); treeBeforeSave.Save(1, null); //ValidateScan(treeBeforeSave.Scan(null), keyCount, pageStoreName + " before save"); pageStore.Commit(1, null); pageStore.Close(); using(var ps = TestUtils.OpenPageStore(pageStoreName, true, persistenceType, 1)) { var tree = new BPlusTree(ps, treeRoot); tree.DumpStructure(); ValidateScan(tree.Scan(null), keyCount, pageStoreName + " after save"); ValidateSearch(tree, keyCount, pageStoreName + "after save"); } }
private void BuildAndScan(IPageStore pageStore, string pageStoreName, PersistenceType persistenceType, int keyCount) { var config = new BPlusTreeConfiguration(8, 64, pageStore.PageSize); var builder = new BPlusTreeBuilder(pageStore, config); var treeRoot = builder.Build(1, _testOrderedValues.Take(keyCount)); var treeBeforeSave = new BPlusTree(pageStore, treeRoot); treeBeforeSave.Save(1, null); //ValidateScan(treeBeforeSave.Scan(null), keyCount, pageStoreName + " before save"); pageStore.Commit(1, null); pageStore.Close(); using (var ps = TestUtils.OpenPageStore(pageStoreName, true, persistenceType, 1)) { var tree = new BPlusTree(ps, treeRoot); tree.DumpStructure(); ValidateScan(tree.Scan(null), keyCount, pageStoreName + " after save"); ValidateSearch(tree, keyCount, pageStoreName + "after save"); } }
/// <summary> /// Creates a new leaf node with content loaded from an ordered enumeration of key/value pairs /// </summary> /// <param name="reservedPageId"></param> /// <param name="prevPointer"></param> /// <param name="nextPointer"></param> /// <param name="treeConfiguration"></param> /// <param name="orderedValues">The enumerateion of key-value pairs to load into the leaf node</param> /// <param name="numValuesToLoad">The maximum number of key-value pairs to insert into the new leaf node</param> public LeafNode(ulong reservedPageId, ulong prevPointer, ulong nextPointer, BPlusTreeConfiguration treeConfiguration, IEnumerable<KeyValuePair<byte[], byte []>> orderedValues, int numValuesToLoad) { _config = treeConfiguration; _prevPointer = prevPointer; _nextPointer = nextPointer; _keys = new byte[_config.LeafLoadFactor][]; _dataSegments = new byte[_config.LeafLoadFactor][]; PageId = reservedPageId; IsDirty = true; _keyCount = 0; foreach(var kvp in orderedValues.Take(numValuesToLoad)) { _keys[_keyCount] = new byte[_config.KeySize]; _dataSegments[_keyCount] = new byte[_config.ValueSize]; Array.Copy(kvp.Key, _keys[_keyCount], _config.KeySize); if (_config.ValueSize > 0) { Array.Copy(kvp.Value, _dataSegments[_keyCount], _config.ValueSize); } _keyCount++; } }
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 }
public void TestCoalesceLeafLoadPlusOne() { const string storeName = "Coalesce.LeafLoadPlusOne.data"; ulong srcRootId, targetRootId; var config = new BPlusTreeConfiguration(8, 64, 4096); var txnId = 0ul; using (var store = TestUtils.CreateEmptyPageStore(storeName)) { var sourceTree = new BPlusTree(store); for (int i = 0; i < config.LeafLoadFactor + 1; i++) { sourceTree.Insert(txnId, (ulong)i, BitConverter.GetBytes((ulong)i)); } sourceTree.DumpStructure(); srcRootId = sourceTree.Save(txnId, null); store.Commit(txnId, null); } txnId = 1; using (var store = TestUtils.OpenPageStore(storeName, false)) { var sourceTree = new BPlusTree(store, srcRootId); var builder = new BPlusTreeBuilder(store, config); targetRootId = builder.Build(1, sourceTree.Scan(null)); var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor + 1; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } store.Commit(1, null); } using (var store = TestUtils.OpenPageStore(storeName, true)) { var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor + 1; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } var root = targetTree.GetNode(targetTree.RootId, null) as InternalNode; Assert.IsNotNull(root); Assert.AreEqual(1, root.KeyCount); var leftChild = targetTree.GetNode(root.ChildPointers[0], null) as LeafNode; var rightChild = targetTree.GetNode(root.ChildPointers[1], null) as LeafNode; Assert.IsNotNull(leftChild); Assert.IsNotNull(rightChild); Assert.AreEqual(config.LeafLoadFactor + 1, leftChild.KeyCount + rightChild.KeyCount); // Key count in each node should be >= split index Assert.IsTrue(leftChild.KeyCount > config.LeafSplitIndex, "Left child has too few keys"); Assert.IsTrue(rightChild.KeyCount > config.LeafSplitIndex, "Right child has too few keys"); // And neither } }
private InternalNode(ulong pageId, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; PageId = pageId; _keys = new byte[_config.InternalBranchFactor][]; _childPointers = new ulong[_config.InternalBranchFactor + 1]; _keyCount = 0; IsDirty = true; }
public ulong Write(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { var targetConfiguration = new BPlusTreeConfiguration(pageStore, Configuration.KeySize, Configuration.ValueSize, Configuration.PageSize); var builder = new BPlusTreeBuilder(pageStore, targetConfiguration); return builder.Build(transactionId, Scan(profiler), profiler); }
public InternalNode(ulong pageId, byte[] key, ulong leftChild, ulong rightChild, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; PageId = pageId; _keys = new byte[_config.InternalBranchFactor][]; _childPointers = new ulong[_config.InternalBranchFactor + 1]; _keys[0] = key; // TODO: copy key ? _childPointers[0] = leftChild; _childPointers[1] = rightChild; _keyCount = 1; IsDirty = true; }
private IEnumerable<KeyValuePair<byte[], byte []>> WritePredicateIndexes(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { foreach (var entry in EnumeratePredicateIndexes(profiler)) { var predicateId = entry.Key; var targetConfiguration = new BPlusTreeConfiguration(pageStore, entry.Value.Configuration.KeySize, entry.Value.Configuration.ValueSize, entry.Value.Configuration.PageSize); var builder = new BPlusTreeBuilder(pageStore, targetConfiguration); ulong newPredicateIndexId = builder.Build(transactionId, entry.Value.Scan(profiler), profiler); yield return new KeyValuePair<byte[], byte[]>(BitConverter.GetBytes(predicateId), BitConverter.GetBytes(newPredicateIndexId)); } }
public ulong Write(IPageStore pageStore, ulong transactionId, BrightstarProfiler profiler) { using (profiler.Step("RelatedResourceIndex.Write")) { var targetConfiguration = new BPlusTreeConfiguration(pageStore, Configuration.KeySize, Configuration.ValueSize, Configuration.PageSize); var indexBuilder = new BPlusTreeBuilder(pageStore, targetConfiguration); return indexBuilder.Build(transactionId, WritePredicateIndexes(pageStore, transactionId, profiler), profiler); } }
public void TestCoalesceLeafLoadPlusOne() { const string storeName = "Coalesce.LeafLoadPlusOne.data"; ulong srcRootId, targetRootId; var config = new BPlusTreeConfiguration(8, 64, 4096); var txnId = 0ul; using (var store = TestUtils.CreateEmptyPageStore(storeName)) { var sourceTree = new BPlusTree(store); for (int i = 0; i < config.LeafLoadFactor + 1; i++) { sourceTree.Insert(txnId, (ulong)i, BitConverter.GetBytes((ulong)i)); } sourceTree.DumpStructure(); srcRootId = sourceTree.Save(txnId, null); store.Commit(txnId, null); } txnId = 1; using (var store = TestUtils.OpenPageStore(storeName, false)) { var sourceTree = new BPlusTree(store, srcRootId); var builder = new BPlusTreeBuilder(store, config); targetRootId = builder.Build(1, sourceTree.Scan(null)); var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor + 1; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } store.Commit(1, null); } using (var store = TestUtils.OpenPageStore(storeName, true)) { var targetTree = new BPlusTree(store, targetRootId); targetTree.DumpStructure(); byte[] valueBuff = new byte[64]; for (int i = 0; i < config.LeafLoadFactor + 1; i++) { Assert.IsTrue(targetTree.Search((ulong)i, valueBuff, null)); Assert.AreEqual((ulong)i, BitConverter.ToUInt64(valueBuff, 0)); } var root = targetTree.GetNode(targetTree.RootId, null) as InternalNode; Assert.IsNotNull(root); Assert.AreEqual(1, root.KeyCount); var leftChild = targetTree.GetNode(root.ChildPointers[0], null) as LeafNode; var rightChild = targetTree.GetNode(root.ChildPointers[1], null) as LeafNode; Assert.IsNotNull(leftChild); Assert.IsNotNull(rightChild); Assert.AreEqual(config.LeafLoadFactor+1, leftChild.KeyCount + rightChild.KeyCount); // Key count in each node should be >= split index Assert.IsTrue(leftChild.KeyCount > config.LeafSplitIndex, "Left child has too few keys"); Assert.IsTrue(rightChild.KeyCount > config.LeafSplitIndex, "Right child has too few keys"); // And neither } }
public InternalNode(ulong id, ulong onlyChild, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; PageId = id; _keyCount = 0; _keys = new byte[_config.InternalBranchFactor][]; _childPointers = new ulong[_config.InternalBranchFactor+1]; _childPointers[0] = onlyChild; }
public InternalNode(ulong id, byte[] nodePage, int keyCount, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; PageId = id; _keyCount = keyCount; _keys = new byte[_config.InternalBranchFactor][]; for (int i = 0, offset = BPlusTreeConfiguration.InternalNodeHeaderSize; i < _keyCount; i++, offset += _config.KeySize) { _keys[i] = new byte[_config.KeySize]; Array.Copy(nodePage, offset, _keys[i], 0, _config.KeySize); } _childPointers = ByteArrayHelper.ToUlongArray(nodePage, _config.InternalNodeChildStartOffset, _config.InternalBranchFactor + 1); }
public InternalNode(ulong id, List<byte[]> keys, List<ulong >childPointers, BPlusTreeConfiguration treeConfiguration) { _config = treeConfiguration; PageId = id; _keyCount = keys.Count; _keys = new byte[_config.InternalBranchFactor][]; _childPointers = new ulong[_config.InternalBranchFactor + 1]; for (int i = 0; i < _keyCount; i++) { _keys[i] = keys[i]; } for(int i = 0; i <= _keyCount; i++) { _childPointers[i] = childPointers[i]; } }