簡體   English   中英

CSharpTest.Net.Collections.BPlusTree最近緩存錯誤?

[英]CSharpTest.Net.Collections.BPlusTree RecentCache bug?

我使用B Plus Tree的這種實現已有一段時間了。 我注意到“最近”緩存存在錯誤。 錯誤產生的方式如下:

  1. 我添加一些KVP,並提交樹。
  2. 我添加了一些KVP並回滾了樹。
  3. 我再添加一些KVP並提交樹。
  4. 我重新啟動我的應用程序並重復步驟1,2和3

重新啟動后執行步驟3時,樹會拋出InvalidNodeHandleException異常

at CSharpTest.Net.Collections.BPlusTree`2.NodeCacheNormal.Lock(NodePin parent, LockType ltype, NodeHandle child)
at CSharpTest.Net.Collections.BPlusTree`2.RootLock..ctor(BPlusTree`2 tree, LockType type, Boolean exclusiveTreeAccess, String methodName)
at CSharpTest.Net.Collections.BPlusTree`2.LockRoot(LockType ltype, String methodName)

以下斷言失敗。

InvalidNodeHandleException.Assert(Storage.TryGetNode(child.StoreHandle, out node, NodeSerializer)
                                                    && node != null
                                                    && node.StorageHandle.Equals(entry.Handle.StoreHandle));

因為StorageHandle相等性返回false,這又是由於兩個根存儲句柄的Unique性不同而不僅僅是增量不同而引起的,它們是兩個不同的隨機數。 問題的根源是NodeCacheNormal的行為。

在第一次運行中創建樹后,第一次在第二次執行中加載樹時,將通過LoadStorage()調用完成該過程,該調用將_root.Node設置為從存儲讀取的RootNode 讀取的RootNode包含上一次執行到磁盤的執行時間的Unique性,並且從不與在此執行中創建的新Root Handle的Unique進行比較,直到樹回滾為止。

回滾導致清除緩存,從而清除緩存中的RootNode。 回滾后,如果再次訪問RootNode,則這次從存儲中取出並插入到緩存中,但這次是通過主NodePin Lock(NodePin parent, LockType ltype, NodeHandle child)調用完成的,該調用檢查句柄是否相等在上述通話中。

是否有任何已知的修復程序? 緩存已經很好地融入了實現中,我無法找到一個很好的解決方法。

編輯1:

這是產生該錯誤的類:

 public class TreeBugTest
    {
        private BPlusTree<long, long> _tree;

        public TreeBugTest()
        {
            var options = new BPlusTree<long, long>.OptionsV2(new PrimitiveSerializer(), new PrimitiveSerializer());
            options.BTreeOrder = 4;
            options.CachePolicy = CachePolicy.Recent;
            options.CallLevelLock = new SimpleReadWriteLocking();
            options.FileName = ConfigurationSettings.AppSettings["Path"];
            options.CreateFile = CreatePolicy.IfNeeded;
            options.StorageType = StorageType.Disk;
            options.LockingFactory = new LockFactory<WriterOnlyLocking>();
            options.StoragePerformance = StoragePerformance.Default;
            _tree = new BPlusTree<long, long>(options);
        }

        public void AddSomeData(long start, long end)
        {
            while (start <= end)
            {
                _tree.Add(start, start++);
            }
        }

        public void ProduceBug()
        {
            AddSomeData(1, 1000);
            _tree.Commit();
            AddSomeData(1001,2000);
            _tree.Rollback();
            AddSomeData(2001, 3000); //This is where it occurs
            _tree.Commit();
        }
    }

只需提供一個文件路徑,創建其實例並調用ProduceBug()方法即可。

好的,顯然代碼是錯誤的。 對於新創建的根節點,需要跳過句柄比較。 為此,我將Lock方法的邏輯移到了帶簽名的私有LockInternal方法中:

private NodePin LockInternal(NodePin parent, LockType ltype, NodeHandle child, bool ignoreHandleComparison)

並更改了以下語句:

InvalidNodeHandleException.Assert(Storage.TryGetNode(child.StoreHandle, out node, NodeSerializer) && node != null && node.StorageHandle.Equals(entry.Handle.StoreHandle));

至:

InvalidNodeHandleException.Assert(Storage.TryGetNode(child.StoreHandle, out node, NodeSerializer) && node != null && ignoreHandleComparison?true:node.StorageHandle.Equals(entry.Handle.StoreHandle));

並從原始Lock方法調用此私有LockInternal方法,並將falseignoreHandleComparison 我修改了第二位的是LockRoot方法,其中最初,我提出的方法和虛擬中的超馳NodeCacheNormal ,我改變從呼叫LockLockInternaltrue用於ignoreHandleComparison 這對我有用。

我想我會向此項目的存儲庫提出此修復請求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM