コード例 #1
0
        public void TestBatchedInserts()
        {
            var   rng      = new Random();
            var   keyBuff  = new byte[8];
            var   value    = new byte[64];
            ulong key      = 0;
            var   txnId    = 0ul;
            var   inserted = new HashSet <ulong>();

            inserted.Add(0); // Not using enumerable initializer because its not supported in the mobile build
            using (var pageStore = TestUtils.CreateEmptyPageStore("TestBatchedInserts.data"))
            {
                var tree = new BPlusTree(pageStore);
                for (int i = 1; i <= 10000; i++)
                {
                    while (inserted.Contains(key))
                    {
                        rng.NextBytes(keyBuff);
                        key = BitConverter.ToUInt64(keyBuff, 0);
                    }
                    inserted.Add(key);
                    tree.Insert(txnId, key, value);
                    if (i % 250 == 0)
                    {
                        tree.Save((ulong)i / 250, null);
                        pageStore.Commit((ulong)i / 250, null);
                        Assert.AreEqual(i, tree.Scan(0, ulong.MaxValue, null).Count());
                        Console.WriteLine("Dump tree @ commit after {0}", i);
                        tree.DumpStructure();
                    }
                }
            }
        }
コード例 #2
0
        public void TestValuelessBTree()
        {
            var   insertedValues = new List <Guid>();
            ulong treeRoot;
            var   txnId = 0ul;

            using (var pageStore = TestUtils.CreateEmptyPageStore("TestValuelessBTree.data"))
            {
                var tree = new BPlusTree(0, pageStore, 16, 0);
                for (int i = 0; i < 1000; i++)
                {
                    var g = Guid.NewGuid();
                    tree.Insert(txnId, g.ToByteArray(), null);
                    insertedValues.Add(g);
                }
                tree.Save(0, null);
                treeRoot = tree.RootId;
                pageStore.Commit(0ul, null);
                //tree.DumpStructure();
            }

            using (var pageStore = TestUtils.OpenPageStore("TestValuelessBTree.data", false))
            {
                var tree = new BPlusTree(pageStore, treeRoot, 16, 0);
                tree.DumpStructure();
                var buff = new byte[0];
                foreach (var g in insertedValues)
                {
                    Assert.IsTrue(tree.Search(g.ToByteArray(), buff, null));
                }
            }
        }
コード例 #3
0
        public void TestCoalesceRootLeafNode()
        {
            const string storeName = "Coalesce.RootLeafNode.data";
            ulong        srcRootId, targetRootId;
            var          txnId = 0ul;

            using (var store = TestUtils.CreateEmptyPageStore(storeName))
            {
                var sourceTree = new BPlusTree(0, store);
                var config     = sourceTree.Configuration;
                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 config     = sourceTree.Configuration;
                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);
                var config     = targetTree.Configuration;
                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));
                }
            }
        }
コード例 #4
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");
            }
        }
コード例 #5
0
        public void TestInsertInReverseOrder()
        {
            using (var pageStore = TestUtils.CreateEmptyPageStore("TestInsertInReverseOrder.data"))
            {
                var txnId  = 0ul;
                var tree   = new BPlusTree(txnId, pageStore);
                var config = tree.Configuration;

                for (int i = 100000; i > 0; i--)
                {
                    tree.Insert(txnId, (ulong)i, BitConverter.GetBytes(i));
                }
                Console.WriteLine("Tree after 100,000 inserts:");
                tree.DumpStructure();

                var buff = new byte[config.ValueSize];
                for (int i = 100000; i > 0; i--)
                {
                    Assert.IsTrue(tree.Search((ulong)i, buff, null), "Cannot find entry for key {0}", i);
                    TestUtils.AssertBuffersEqual(BitConverter.GetBytes(i), buff);
                }
            }
        }
コード例 #6
0
        public void TestInsertAndDeleteAllEntries()
        {
            var       value = new byte[64];
            ulong     rootPageId;
            const int keyCount = 20000;

            using (var pageStore = TestUtils.CreateEmptyPageStore("TestInsertAndDeleteAllEntries.data"))
            {
                var tree = new BPlusTree(pageStore);
                for (int i = 0; i < keyCount; i++)
                {
                    tree.Insert(0, (ulong)i, value);
                }
                rootPageId = tree.Save(0, null);
                pageStore.Commit(0, null);
            }

            using (var pageStore = TestUtils.OpenPageStore("TestInsertAndDeleteAllEntries.data", true))
            {
                var tree = new BPlusTree(pageStore, rootPageId);
                for (int i = 0; i < keyCount; i++)
                {
                    Assert.IsTrue(tree.Search((ulong)i, value, null), "Could not find key {0} after insert and save.");
                }
            }

            using (var pageStore = TestUtils.OpenPageStore("TestInsertAndDeleteAllEntries.data", false))
            {
                var tree = new BPlusTree(pageStore, rootPageId);
                for (int i = 0; i < keyCount; i += 2)
                {
                    tree.Delete(1ul, (ulong)i, null);
                    Assert.IsFalse(tree.Search((ulong)i, value, null), "Still found entry for key {0} after delete", i);
                }
                rootPageId = tree.Save(1, null);
                pageStore.Commit(1, null);
            }

            using (var pageStore = TestUtils.OpenPageStore("TestInsertAndDeleteAllEntries.data", true))
            {
                var tree = new BPlusTree(pageStore, rootPageId);
                for (int i = 1; i < keyCount; i += 2)
                {
                    Assert.IsTrue(tree.Search((ulong)i, value, null), "Could not find key {0} after deletion of even numbered keys.", i);
                    Assert.IsFalse(tree.Search((ulong)i - 1, value, null), "Found key {0} after deletion of even numbered keys", i - 1);
                }
            }

            using (var pageStore = TestUtils.OpenPageStore("TestInsertAndDeleteAllEntries.data", false))
            {
                var tree = new BPlusTree(pageStore, rootPageId);
                for (int i = 1; i < keyCount; i += 2)
                {
                    tree.Delete(2ul, (ulong)i, null);
                    Assert.IsFalse(tree.Search((ulong)i, value, null), "Key {0} was still found by a search after it was deleted", i);
                }
                rootPageId = tree.Save(2, null);
                pageStore.Commit(2, null);
            }

            using (var pageStore = TestUtils.OpenPageStore("TestInsertAndDeleteAllEntries.data", true))
            {
                var tree = new BPlusTree(pageStore, rootPageId);
                Console.WriteLine("After load\r\n");
                tree.DumpStructure();
                Assert.AreEqual(0, tree.Scan(null).Count(), "Expected an empty tree after deleting all odd-numbered entries");
            }
        }
コード例 #7
0
        public void TestMergeRight()
        {
            using (var pageStore = TestUtils.CreateEmptyPageStore("TestMergeRight.data"))
            {
                var txnId     = 0ul;
                var tree      = new BPlusTree(txnId, pageStore);
                var testBytes = new byte[] { 1, 2, 3, 4 };
                var config    = tree.Configuration;
                var buff      = new byte[config.ValueSize];
                for (int i = 0; i < config.LeafLoadFactor * config.InternalBranchFactor; i++)
                {
                    try
                    {
                        tree.Insert(txnId, (ulong)i, testBytes);
                    }
                    catch (Exception ex)
                    {
                        Assert.Fail("Insert failed for key {0} with exception {1}", i, ex);
                    }
                }

                var rootNode         = tree.GetNode(tree.RootId, null);
                var childId          = (rootNode as IInternalNode).GetChildNodeId(rootNode.RightmostKey);
                var child            = tree.GetNode(childId, null) as IInternalNode;
                var childLeftmostKey = BitConverter.ToUInt64(child.LeftmostKey, 0);
                var grandchild       =
                    tree.GetNode(child.GetChildNodeId(BitConverter.GetBytes(childLeftmostKey - 1)), null) as ILeafNode;
                var deleteFrom = BitConverter.ToUInt64(grandchild.LeftmostKey, 0);

                var findChildId = (rootNode as IInternalNode).GetChildNodeId(BitConverter.GetBytes(deleteFrom));
                Assert.AreEqual(child.PageId, findChildId, "Incorrect node id returned for key {0}", deleteFrom);

                tree.DumpStructure();

                for (ulong i = 0; i < 4; i++)
                {
                    var deleteKey = deleteFrom + i;
                    tree.Delete(txnId, deleteKey, null); // Should be enough to force a right merge
                    //Console.WriteLine("\n\nDeleted {0}\n", deleteKey);
                    //tree.DumpStructure();
                    Assert.IsTrue(tree.Search(10395ul, buff, null));
                }

                for (ulong i = 0; i < (ulong)(config.LeafLoadFactor * config.InternalBranchFactor); i++)
                {
                    try
                    {
                        Assert.IsTrue(tree.Search(i, buff, null) ^ (i - deleteFrom >= 0 && i - deleteFrom < 4),
                                      "Could not find key {0}. deleteFrom={1}", i, deleteFrom);
                    }
                    catch (AssertionException)
                    {
                        Console.WriteLine("\nFailed tree structure:\n");
                        tree.DumpStructure();
                        throw;
                    }
                }

                deleteFrom = (ulong)(config.LeafLoadFactor * config.InternalBranchFactor) - 5;
                for (ulong i = 0; i < 4; i++)
                {
                    var deleteKey = deleteFrom + i;
                    tree.Delete(txnId, deleteKey, null);
                }
            }
        }
コード例 #8
0
        public void TestCoalesceLeafLoadPlusOne()
        {
            const string storeName = "Coalesce.LeafLoadPlusOne.data";
            ulong        srcRootId, targetRootId;
            var          txnId = 0ul;

            using (var store = TestUtils.CreateEmptyPageStore(storeName))
            {
                var sourceTree = new BPlusTree(0, store);
                var config     = sourceTree.Configuration;
                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);
            }

            using (var store = TestUtils.OpenPageStore(storeName, false))
            {
                var sourceTree = new BPlusTree(store, srcRootId);
                var config     = sourceTree.Configuration;
                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);
                var config     = targetTree.Configuration;

                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 IInternalNode;
                Assert.IsNotNull(root);
                Assert.AreEqual(1, root.KeyCount);
                var leftChild  = targetTree.GetNode(root.GetChildPointer(0), null) as ILeafNode;
                var rightChild = targetTree.GetNode(root.GetChildPointer(1), null) as ILeafNode;
                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
            }
        }