关键点一
节点的移动采用从后往前逐一移动的方式,并且采用判断当前操作数据所在缓存行是否写满,将要写到下一个缓存行。也就是以一个缓存行为单位调用刷新指令,将缓存行的脏数据刷新到NVM
在对数组进行插入时,我们会发现总会有一个关键字下的左右孩子指针是相同的,即存在短暂的不一致性。左右指针相同的地方才允许插入。
可以提高FAST插入时得并发能力
研究目的
解决论文作者提出的两个挑战:
1、当前基于B+树变形的研究为了保持叶子节点有序,通常需要调用大量内存刷新指令和使数据能够按运行顺序存储的指令。
2、当前基于B+树变形的研究为保持数据一致性,使数据结构在遭遇未知的系统崩溃后能够快速恢复,通常需要采用log记录数据的变化。
研究背景
当前基于B+树变形的研究,为保持数据的一致性和持久化,以及系统崩溃后可以快速的恢复数据,通常利用内存的8字节的原子写、修改节点的结构,在节点中引入version、slot array、bitmap等来保证数据的一致性和完成数据的持久化;而为了提高数据结构的并发性,使用HTM亦或是在节点中引入lock等。为了做数据崩溃后的恢复,通常需要使用log来完成数据结构的恢复。这些都极大的带来了大量内存开销,影响了数据结构的影响。
研究概述
主要提出了FAST和FAIR两种算法,以解决
关键技术
数据结构的节点采用数组的方式存储键值对
一、Failure-Atomic ShifT (FAST)
1、节点中数据的移动需要一系列的指令集刷新数据,保证数据的一致性,作者提出以缓存行为单位刷新脏数据到NVM,即当一个缓存行的数据被修改后,此时需要移动到相邻行写数据时,会先将当前行的脏数据先刷新回NVM。
2、在进行写操作时(插入),当移动节点中键值对的过程之中,我们会发现过程中会出现一次两个相同的键值对,这时恰好有一个对当前节点的读操作,作者提出当查询到某个节点的左右指针时有相同地址时,就会跳过,继续读下一个,这样便可以使读操作读到正确的数据,这样的现象作者称为可忍受的暂时不一致性,过程如下图。
3、FAST算法的插入伪代码
首先比较当前节点是否分裂,比较当前key与下一节点第一个键值对的key的大小,如果大于下一节点的key,节点已经分裂了,则插入该节点如果小,则是插入当前节点。并在节点上设置flag字段,当flag是奇数时,如果节点没有执行删除操作后更新,那么表示对当前节点需要从右到左遍历,否则就会使flag加1,变为偶数,此时表示节点需要从左到右遍历,当移动数组元素时,只需要调用mefence,直到当前的节点是缓存行的边界时,然后调用clflush和mefence刷新数据。
flag为偶数时表示节点是被一个插入操作更新了,如果是奇数时则表示节点被一个删除操作更新。
其删除过程与插入相似的,仅仅是删除是将节点从左向右移,读操作也许遵循此顺序
二、Failure-Atomic In-place Rebalancing(FAIR)
即节点采用In-place的写操作
1、节点分裂
除了在完成分裂时,需要将新叶子节点插入叶子节点链表中此时的每一步需要立即持久化,其它的操作可以使用以缓存行为单位刷新。
2、节点融合
当节点由于删除操作导致需要融合时,将当前节点有其左节点融合,如果左节点有足够的键值对使得可以通过移动左节点的部分键值对到当前节点后,两个节点满足节点容量的需求,并重新更新当前节点的父节点的key。否则就将两个节点合为一个节点,并重新更新父节点的key。
3、无锁搜索查询
4、数据结构的重建与恢复
重建直接根据叶子节点来重建数据结构,对于节点中的不一致性,不会再读操作下处理,而是在写操作下处理。对于节点在分裂的时候系统崩溃导致的悬浮节点问题,在进行插入操作时检查插入节点是否未悬空节点,是悬空节点,则将检查其左节点是否可以融合,可以则进行融合操作。否则则将节点的最小key插入到其父节点中。
实验环境
基于DRAM的仿真NVM环境
研究总结
1、作者提出需要一个持久化flag字段来判断是否执行过插入或是删除操作,以便在读操作时可以获得正确的读结果,但是实际上我们是可以忍受数组元素中出现的短暂不一致性的,这其实并不会影响我们读到正确的结果,我们可以使用一个不需要持久化的变量flag字段来记录是否出现短暂不一致性,从而根据flag字段可便于采取二分查找或是线性查找,因为这种暂时的不一致性是可以在其它的插入过程中被处理的。
2、作者提出的整个设计空间利用率其实是不高的,当sibling在sibling.sibling ptr← node.sibling ptr;
clflush with mfence(sibling)操作完成后就崩溃了,那么这个节点便成为了一个悬浮节点,且该空间将一直无法回收。
3、对于作者对悬浮节点的处理是缺少更详细的介绍,所以这部分的实现是很难理解的