回顾
在这个项目中需要实现一个调表(skip_list)。这个项目的目的就是让帮助我们理解现代保序索引的细微差别。首先需要回顾Peloton中的编码规范。
这里给出几篇无锁数据结构的参考文献:
- Techniques for Implementing Concurrent Data Structures on Modern Multicore Machines
- The Bw-Tree:A B-Tree for New Hardware Platforms
- Lock-Free Linked List
- The Story Behind MemSQL’s Skiplist Indexes
提示: 先尝试着实现像STX B-tree中的接口。
介绍
同步更新项目库
与主项目的版本保持一致:
git remote add upstream git://github.com/cmu-db/peloton.git
git fetch upstream
git rebase -i upstream/master
git push --force
实现
此部分需要需要修改的五个文件:
- Skip List Data Structure source file
- Skip List Data Structure header file
- Skip List Index source file
- Skip List Index header file
- Index testing suite
提示:在"Data structure"文件中实现skip list。在"Index" 文件中实现skip list需要被调用的接口。
Pleoton当然也包含了Bw-Tree 索引。可以用作参考。
Skip_List的实现必须抽象出关键数据类型以及相关的比较器和等式检查器的详细信息,如下所示:
template <typename KeyType,
typename ValueType,
typename KeyComparator,
typenameKeyEqualityChecker,
typename ValueEqualityChecker>
class SkipListIndex {
};
其中下面这些类已经实现好了:
KeyType:索引中key的类型
ValueType:索引中value的类型
KeyConparator:此类用来比较两个KeyType实例的大小。
KeyEqualityChecker:此类用来比较连个KeyType实例是否相等。
ValueEqualityChecker:此类用来比较两个ValueType实例是否相等。
要求
实现的索引必须可以选择支持或者不支持value相等的重复key(因此必须带有一个设定参数)。
还必须要支持前序或者后序遍历,只有这样才能支持并发操作。
索引实现的功能必须与Peloton的Index API中给出的规范相匹配.
- InsertEntry函数将键-值对插入索引。如果配置为不支持重复键,那么InsertEntry函数在尝试将重复键插入索引时应该返回false。另一方面,如果它被配置为支持重复键,那么当我们试图将重复键插入索引时,它不应该返回false。
- DeleteEntry函数应该只删除与特定<Key,value>对匹配的索引项。
- CondInsertEntry函数查找与给定键匹配的所有键-值对,并测试它们是否满足给定谓词。如果所有键-值对都不满足谓词,那么就将给定的键-值对插入索引,将predicate_satisfy 设置为true,并返回true。否则,将predicate_satisfaction设置为false并返回false。
- Scan函数扫描索引中的范围并返回结果向量中的所有元素。要执行的扫描类型由给定的扫描谓词csp_p指定,它是以下类型之一:全面扫描、范围扫描或点查询。执行向前还是向后扫描由给定的scan_direction决定。
- ScanLimit函数与Scan函数具有相同的行为,只是扫描在读取偏移限制元素后停止。因此,在结果向量中返回极限元素的最大值。
- ScanAllKeys函数扫描索引中的所有键,并将值存储在结果向量中。
- ScanKey函数用给定的键查找索引中的所有值,并在结果向量中返回这些值。如果索引没有配置为存储重复的键,那么最多将返回一个值。
- PerformGC函数垃圾收集已删除的索引条目。
- 如果索引上需要垃圾收集,NeedGC函数将返回true。
- GetMemoryFootprint函数返回索引使用的堆空间总量。
提示:Skip_List实现可以模仿现有的Bw-Tree索引。如果不确定索引的正确输出或行为应该是什么,那么执行Bw-Tree并查看它返回的数据。skipListde的实现应该能够完全代替Bw-Tree。
还添加一个实用函数来验证索引数据结构的结构完整性。如果任何完整性检查失败,那么这个函数应该修复完整性问题。这个功能类似于fsck为文件系统提供的功能。
还要实现无锁存内存跟踪器(例如,基于epoch或RCU)。下周课程将讨论不同的方法(啥时候?咋实现。。。)。
必须定期垃圾收集已删除的索引项。数据库的API的工作方式是,一个单独的线程将调用NeedGC()来检查索引是否需要垃圾收集。为了测试垃圾收集实现,将在向索引中插入一组条目后计算内存占用。然后,删除这些条目的一个子集。最后,在索引上调用PerformGC函数之后,重新计算内存占用。如果内存占用没有像预期的那样下降,那么证明你的代码方案有点问题。
实现项目时必须通过在适当的时候调用索引API提供的stats方法来维护适当的统计信息。
在索引测试套件中添加多个单元测试用例,以测试索引数据结构的功能。
单元测试
可以通过使用索引测试套件来测试并发索引。在TestingIndexUtil中可以找到这些不同测试用例的实现。测试套件包含一组多线程测试用例,用于验证索引的功能和评估索引的性能。要具体地运行连接测试用例,请按照如下方法:
cd build
make skiplist_index_test
valgrind --trace-children=yes \
--leak-check=full \
--track-origins=yes \
--soname-synonyms=somalloc=*jemalloc* \
--error-exitcode=1 \
--suppressions=../third_party/valgrind/valgrind.supp \
./test/skiplist_index_test