From 509a92bd71ca379ccc3a01ef94ea35ef158e8cd6 Mon Sep 17 00:00:00 2001 From: cyq <1056374449@qq.com> Date: Sat, 2 Nov 2024 04:00:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=A0=B7=E4=BE=8B=EF=BC=8C=E5=B9=B6=E4=B8=94?= =?UTF-8?q?debug=EF=BC=8C=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90=E4=BA=86?= =?UTF-8?q?=E5=AE=9E=E9=AA=8C=E6=8A=A5=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 8 +-- README.md | 81 +++++++++++++++++++++++++++---- db/memtable.cc | 28 +++++------ pics/da6bc07dc11bd2c25fcf89dd3675b75.png | Bin 0 -> 49963 bytes pics/屏幕截图 2024-11-02 020856.png | Bin 0 -> 148783 bytes pics/屏幕截图 2024-11-02 022217.png | Bin 0 -> 66660 bytes pics/屏幕截图 2024-11-02 031718.png | Bin 0 -> 36206 bytes pics/屏幕截图 2024-11-02 032436.png | Bin 0 -> 31323 bytes pics/屏幕截图 2024-11-02 033420.png | Bin 0 -> 13722 bytes pics/屏幕截图 2024-11-02 033625.png | Bin 0 -> 49615 bytes pics/微信截图_20241102034943.png | Bin 0 -> 138955 bytes pics/微信截图_20241102035048.png | Bin 0 -> 107142 bytes table/table.cc | 1 + test/ttl_test.cc | 44 +++++++++++++++++ 14 files changed, 134 insertions(+), 28 deletions(-) create mode 100644 pics/da6bc07dc11bd2c25fcf89dd3675b75.png create mode 100644 pics/屏幕截图 2024-11-02 020856.png create mode 100644 pics/屏幕截图 2024-11-02 022217.png create mode 100644 pics/屏幕截图 2024-11-02 031718.png create mode 100644 pics/屏幕截图 2024-11-02 032436.png create mode 100644 pics/屏幕截图 2024-11-02 033420.png create mode 100644 pics/屏幕截图 2024-11-02 033625.png create mode 100644 pics/微信截图_20241102034943.png create mode 100644 pics/微信截图_20241102035048.png diff --git a/CMakeLists.txt b/CMakeLists.txt index a9b1c5e..951bf61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,10 +525,10 @@ add_executable(db_test2 ) target_link_libraries(db_test2 PRIVATE leveldb) -add_executable(ttl_mmtable_test - "${PROJECT_SOURCE_DIR}/test/ttl_mmtable_test.cc" -) -target_link_libraries(ttl_mmtable_test PRIVATE leveldb) +# add_executable(ttl_mmtable_test +# "${PROJECT_SOURCE_DIR}/test/ttl_mmtable_test.cc" +# ) +# target_link_libraries(ttl_mmtable_test PRIVATE leveldb) add_executable(ttl_test "${PROJECT_SOURCE_DIR}/test/ttl_test.cc" diff --git a/README.md b/README.md index 59f6a9a..4b0ea1a 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,98 @@ # 实验报告 + ## 1. 设计思路和实现过程 + ### 1.1 实验总体流程介绍 -实验总体上分为了两个阶段。第一个阶段修改了key的编码,增加了ttl信息,并只修改memtable中的逻辑,分割简化任务,保证编码、写入与读memtable逻辑的正确性。这可以通过插入少量数据,不触发大小合并进行阶段性测试。 + +实验总体上分为了两个阶段。第一个阶段修改了key的编码,增加了ttl信息,并只修改memtable中的逻辑,分割简化任务,保证编码、写入与读memtable逻辑的正确性。这可以通过插入少量数据,不触发大小合并进行阶段性测试。 第二个阶段进一步修改sstable中读取与合并的逻辑,并通过最终的测试样例。 ### 1.2 编码 + 考虑到leveldb中key本身附带有额外的信息(seq和type),我们选择将ttl的信息一并存入key中,也便于读写合并过程中直接对key进行逻辑判断,不涉及获取value的额外操作。编码修改如下: internal key中末尾的tag,原本是56位的seq加8位的type,但实际type只需要最后一位表示是否是delete,其余7位为0。为节省空间,我们用倒数第二位表示该键是否有ttl,如果有,则在tag前增加一个64位的时间戳deadTime,表示过期时间。(deadTime并不是一定有,要先依靠存储在固定位置的标识确定,所以放在tag前而非后) ![alt text](pics/175ef32d68bfd3ca20b972b066f3056.png) lookup key一定需要一个当前时间在查询中进行比较,因此不再设置标识位,仅在tag前加64位的nowTime。 ![alt text](pics/f535cd48ec424ab7e91e200092b3bb0.png) +为了便于对于新编码的操作,我们也修改了相应的`ParsedInternalKey`结构体和`parseInternalKey`函数等。 + +//这里或许可以多贴一点代码 ### 1.3 写入 -新的put接口多了一个默认参数ttl,当调用时不加这个参数,则这一次写入没有ttl,与原来的leveldb写入逻辑一致。否则需要进行两处的修改: + +新的put接口多了一个默认参数ttl,当调用时不加这个参数,则这一次写入没有ttl,与原来的leveldb写入逻辑一致。否则需要进行两处的修改: 一是writebatch中信息的记录,这里同样进行编码的修改,8位havettl接可能有的64位deadtime(当前时间+传入的ttl),以及WriteBatch::Iterate中相应的信息解码。 ![alt text](pics/f1c63a4cb1afbdf658ce72e191d9ae7.png) 二是memtable::Add中对于key新的编码。 ### 1.4 读取 -读取分为memtable和sstable两部分,在构建lookupkey时记录了当前时间。 + +在构建lookupkey时记录了当前时间,读取过程需要根据这个时间返回未过期的序列号最大的值。读取分为memtable和sstable两部分,下面将对两部分分别进行阐述。 + +#### Memtable的读取操作 + memtable中,迭代器找到原本的位置(即同userkey,seq为查询前最大的那个),这时有了ttl需要新的判断:是否超时。超时的话迭代器继续后移,直到userkey不同了说明没找到,或是找到了没过期的数据。这样就能得到没过期的数据中,seq最大的那条。 +核心代码如下: + +![1730482529350](pics/da6bc07dc11bd2c25fcf89dd3675b75.png) + +#### SSTable的读取操作 +SSTable的读取流程虽然涉及到了level、SSTable、indexblock、datablock多个层级,但是整体思路并没有发生改变,仍然是使用迭代器原来的`seek`方法找到这一系列数据的"基准位置",然后根据TTL,不断的向后找,直到userkey不同为止。 +具体的流程在`Table::InternalGet`中实现。由于这个函数使用了indexblock和datablock两层迭代器,所以这里嵌套了两层循环。 +具体代码如下: +![alt text](pics/屏幕截图%202024-11-02%20020856.png) -... +## 1.5 合并 +合并包含小合并和大合并。此处也将分开进行阐述 +#### 小合并 +实际产生小合并结果文件(L0)的地方是`BuildTable`函数,因此我们加入kv对的循环中增加对于TTL的判断来实现小合并中的过期数据删除。 +具体代码如下:(其中包括了部分后面会提到的代码逻辑) +![](pics/屏幕截图%202024-11-02%20022217.png) +#### 大合并 +大合并实际产生结果文件的地方是`DoCompactionWork`函数。和小合并类似,如果存在一个过期的数据,那么直接drop这个数据,但是只要这个数据没有过期且存在TTL,那么这个数据就不能drop。如果只是忽略过期数据的话,那么可能会出现多个未过期的相同key的数据进行合并,按照leveldb原来的逻辑,此时只有seq最大的数据会被保留,其他的数据都会被丢弃。这在原本的leveldb中并没有问题,但是如果附带了TTL,那么我们就不能够保证数据严格的排序关系,有可能seq最大的数据的TTL反而很短,会先于TTL较长但是seq较小的数据前失效,那么如果将seq较小的数据合并的话,会产生数据的丢失。 +当然,有可能会出现首先是一个不包含TTL(TTL无限长)的delete记录或者Value记录,然后是一串带有或者不带有TTL的数据,此时我们也可以将这些数据删除。不过处于简便考虑,我们保留所有带有TTL且没有过期的数据,因为这至少在逻辑上是对的,虽然可能会产生一些空间浪费。 +具体代码如下: +![](pics/屏幕截图%202024-11-02%20031718.png) + +## 小结 +至此,ttl功能得到实现。对于手动合并过程中合并不完全的情况,采用的是强制对每一层进行合并的方式。至此,所有的测试都能够通过 + +## 3. 扩展特性和未来展望 +### 3.1 文件元数据更新 +我们对于文件元数据内容进行了修改,来帮助我们更好的进行相关操作。我们增加了`smallest_deadtime`和`largest_deadtime`字段,用来表示某个SSTable中所有数据的生存期的范围。修改如下: +![](pics/屏幕截图%202024-11-02%20032436.png) +为了支持文件元数据的写入和读取,我们更改了`AddFile`、`EncodeTo`、`DecodeFrom`等相关函数,并在所有调用处也进行了相应的修改。 +在leveldb中,只有在小合并和大合并的过程中才会产生新的文件,所以只要在这两个流程中进行代码的添加,就能够完成新增文件元数据的获取。 +小合并中的代码逻辑在上一章有关小合并的部分已经展示。在大合并中,由于首先生成的是`out`结构体,在合并结束时候才将out结构体转换为`Filemetadata`,所以我们对于out结构体也进行了修改。`out`结构体和大合并获取新增元数据的逻辑如下: +![](pics/屏幕截图%202024-11-02%20033420.png) +![](pics/屏幕截图%202024-11-02%20033625.png) + +### 3.2 用于合并流程 +有了文件所含数据的生存期的范围,我们就可以很容易的判断一个文件是否存在有效的数据,如果一个文件的所有数据全部无效,那么我们只要在合并过程中删除整个文件就行。 +由于所有的文件元数据全部都保存在内存中,我们可以高效的去遍历所有元数据筛选出所有数据全都无效的文件并进行删除。在原版大合并流程之前进行这样的删除操作,可以减少大合并过程中的开销。原版的流程中需要遍历文件中所有的数据才能完成合并,但是现在只需要判断元数据信息即可。同时也增加了大合并的效果完成之后的大合并可以选择额外的输入文件进行合并。此外,通过扫描所有的文件元数据,可以在不更改手动合并流程去强制合并每一个level的情况下就能够通过原先的test。 +由于大合并的入口函数是可以递归调用的,所以完成文件删除后可以直接返回,在递归调用中可以启动原版的大合并。 +代码逻辑如下: +![](pics/微信截图_20241102034943.png) +![](pics/微信截图_20241102035048.png) + +### 3.3 用于加快get访问 +上文提到,读取的时候会按照level、文件、indexblock、datablock这样的顺序进行读取操作。因此,我们利用文件的新增元数据信息,可以跳过那些所含数据全部失效的文件,加快数据的搜索速度。 ## 2. 测试用例和结果 + ### 2.1 测试用例 -除了原本提供的测试用例,新增: -GetEarlierData:该样例插入两次key相同但value不同的数据,后一次的ttl短于前一次。在后插入的数据过期,而前插入的未过期时,查询应得到前一次插入的value。 -### 2.2 结果 +除了原本提供的测试用例,新增: + +1. GetEarlierData:该样例插入两次key相同但value不同的数据,后一次的ttl短于前一次。在后插入的数据过期,而前插入的未过期时,查询应得到前一次插入的value。 +2. ReadWithoutTTL: 该样例插入两次key相同但value不同的数据,前一次没有ttl,而后一次插入附带ttl。在后插入的数据过期时,查询应得到前一次插入的value。 + +### 2.2 结果 ## 3. 问题和解决方案 -总结几个实验过程中遇到的大bug和设计问题: -1. 查询判断过期数据的逻辑最初放在了internal key比较器内部,但后来发现memtable、sstable、compact等多处比较的逻辑都有不同,一起调用比较器,内部实现逻辑过于复杂,最终修改为处理外部调用的迭代器。 -2. 查询最后插入的那条数据,此时比较器中seq是相等的,按照原本的leveldb,tag也是相等的,但是由于编码修改加入了havettl位,原本代码仅比较了tag,大小出现了问题。由于仅有这一条数据会出问题,没有意识到seq会相等而新增位影响了比较,调试了许久。修改非常简单:单独拿出tag中的seq比较。 +总结几个实验过程中遇到的大bug和设计问题: + +1. 查询判断过期数据的逻辑最初放在了internal key比较器内部,但后来发现memtable、sstable、compact等多处比较的逻辑都有不同,一起调用比较器,内部实现逻辑过于复杂,并且在数据查询的过程中会有许多二分查找的过程,由于ttl的存在,单独修改比较器无法保证数据的偏序关系,并不适配二分查找的实现。最终修改为处理外部调用的迭代器。 +2. 一开始对于SSTable的读取实现中,我们是在seek内部进行修改的,但是出了很多问题,调试了很久后发现,这是由于indexblock和datablock是公用一种迭代器导致的。由于indexblock是datablock的“缩略信息”,所以会存在indexblock中所存的值表示该条目所对应datablock全部过期了,所以在查找的时候会直接跳过这个datablock,但是实际上这个datablock中存在着deadtime更久的记录。这本质上还是由于ttl的存在导致无法保证偏序关系。因此,我们放弃了直接修改迭代器内部实现的方式,改为在外部调用迭代器。 +3. 查询最后插入的那条数据,此时比较器中seq是相等的,按照原本的leveldb,tag也是相等的,但是由于编码修改加入了havettl位,原本代码仅比较了tag,大小出现了问题。由于仅有这一条数据会出问题,没有意识到seq会相等而新增位影响了比较,调试了许久。修改非常简单:单独拿出tag中的seq比较。 diff --git a/db/memtable.cc b/db/memtable.cc index c80a05b..28bd193 100644 --- a/db/memtable.cc +++ b/db/memtable.cc @@ -57,20 +57,20 @@ class MemTableIterator : public Iterator { bool Valid() const override { return iter_.Valid(); } void Seek(const Slice& k) override { iter_.Seek(EncodeKey(&tmp_, k)); - MemTable::KeyComparator comp_ = iter_.get_comparator(); - while(Valid()) { - Slice now = key(); - ParsedInternalKey parsed_k,parsed_now; - ParseInternalKey(k,&parsed_k); - ParseInternalKey(now,&parsed_now); - uint64_t deadtime_k = parsed_k.deadTime; - uint64_t deadtime_now = parsed_now.deadTime; - if(deadtime_k == 0) deadtime_k = UINT64_MAX; - if(deadtime_now == 0) deadtime_now = UINT64_MAX; - if(deadtime_k > deadtime_now) {Next();continue;}; - if(comp_.comparator.Compare(k,now) <= 0) return; - Next(); - } + // MemTable::KeyComparator comp_ = iter_.get_comparator(); + // while(Valid()) { + // Slice now = key(); + // ParsedInternalKey parsed_k,parsed_now; + // ParseInternalKey(k,&parsed_k); + // ParseInternalKey(now,&parsed_now); + // uint64_t deadtime_k = parsed_k.deadTime; + // uint64_t deadtime_now = parsed_now.deadTime; + // if(deadtime_k == 0) deadtime_k = UINT64_MAX; + // if(deadtime_now == 0) deadtime_now = UINT64_MAX; + // if(deadtime_k > deadtime_now) {Next();continue;}; + // if(comp_.comparator.Compare(k,now) <= 0) return; + // Next(); + // } } void SeekToFirst() override { iter_.SeekToFirst(); } void SeekToLast() override { iter_.SeekToLast(); } diff --git a/pics/da6bc07dc11bd2c25fcf89dd3675b75.png b/pics/da6bc07dc11bd2c25fcf89dd3675b75.png new file mode 100644 index 0000000000000000000000000000000000000000..dc91f31599fe3bd31b586a92c20079bcbd08dfaf GIT binary patch literal 49963 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