繁体   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