|
|
@ -2,7 +2,7 @@ |
|
|
|
|
|
|
|
<center> |
|
|
|
小组成员:谷杰 10222140408 朱维清 10215300402 |
|
|
|
</center> |
|
|
|
[TOC] |
|
|
|
|
|
|
|
## 项目概述
|
|
|
|
|
|
|
@ -111,7 +111,7 @@ |
|
|
|
|
|
|
|
## KV 分离
|
|
|
|
|
|
|
|
> KV 分离部分,由于我们小组最后定版设计为,使 VLog 代替原 LevelDB 中 WAL 的作用,同时具有从 LSM-Tree 中分离并保存超过某个 value 大小阈值(`separate_threshold`)的 kv 对数据的作用,关于 VLog 的读写类 `VlogReader/VlogWriter` 的实现参考了 `LogReader/LogWriter` 的部分内容,并能共享 `LogReader/LogWriter` 使用的所有读写接口(参见`env_posix.cc`,读写均为磁盘I/O)(去除了 CRC 校验功能)。
|
|
|
|
> KV 分离部分,由于我们小组最后定版设计为,使 VLog 代替原 LevelDB 中 WAL 的作用,同时具有从 LSM-Tree 中分离并保存超过某个 value 大小阈值(`separate_threshold`)的 kv 对数据的作用,关于 VLog 的读写类 `VlogReader/VlogWriter` 的实现参考了 `LogReader/LogWriter` 的部分内容,并能共享 `LogReader/LogWriter` 使用的所有读写接口(参见`env_posix.cc`,读写均为磁盘I/O)。
|
|
|
|
> |
|
|
|
> + **结构图/写入流程图**:
|
|
|
|
> 
|
|
|
@ -407,7 +407,7 @@ Status VlogWriter::EmitPhysicalRecord(const char* ptr, size_t length, |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
vlog_writer.cc文件中则是对于构造函数,AddRecord()以及EmitPhysicalRecord()。实现上与LogWriter基本一致,只是去除了Crc校验码的部分。对于EmitPhysicalRecord()函数,由于去除了校验码,则其header要从原本的8字节改为4字节,只保留length部分(4字节)。 |
|
|
|
vlog_writer.cc文件中则是对于构造函数,AddRecord()以及EmitPhysicalRecord()。实现上与LogWriter基本一致。对于EmitPhysicalRecord()函数,由于去除了校验码,则其header要从原本的8字节改为4字节,只保留length部分(4字节)。 |
|
|
|
|
|
|
|
改完vlog_writer部分后,让我们重新来梳理一遍写入过程。 |
|
|
|
|
|
|
@ -644,7 +644,7 @@ class SeparateManagement { |
|
|
|
#### 介绍部分函数
|
|
|
|
|
|
|
|
+ `ConvertQueue`: |
|
|
|
每次把 VLog 加入 GC 队列前需要更新数据库的 last_sequence,并确保所有 `need_updates_` 队列里的 VLog 都更新了 `last_sequence_`,以便对 VLog 中的有效 keys 重新插入新的 VLog 中: |
|
|
|
每次把 VLog 加入 GC 队列前需要更新数据库的 last_sequence,并确保所有 `need_updates_` 队列里的 VLog 都更新了 `last_sequence_`,以便对 VLog 中的有效 keys 重新插入数据库: |
|
|
|
|
|
|
|
```C++ |
|
|
|
bool SeparateManagement::ConvertQueue(uint64_t& db_sequence) { |
|
|
@ -736,15 +736,14 @@ void SeparateManagement::CollectionMap(){ |
|
|
|
|
|
|
|
### GC 的具体实现
|
|
|
|
|
|
|
|
> 1. 我们采用了类似 Compaction 的后台多线程调度机制来实现 GC;
|
|
|
|
> 1. 我们采用了类似 Compaction 的后台线程调度机制来实现 GC;
|
|
|
|
> 2. 支持在线自动 GC,也支持离线手动触发 GC;
|
|
|
|
> 3. GC 与 Snapshot 互相冲突:若数据库运行期间有 Snapshot 产生,则该 Snapshot 之后的所有数据不再进行任何在线 GC,直到该 Snapshot 被释放才会重启在线 GC;
|
|
|
|
> |
|
|
|
> **VLog 的 GC 的回收阈值: `Options::garbage_collection_threshold = max_value_log_size / 4 ( = 4MB)`**
|
|
|
|
> |
|
|
|
>**VLog 的 GC 的回收阈值: `Options::garbage_collection_threshold = max_value_log_size / 4 ( = 4MB)`** |
|
|
|
|
|
|
|
+ 所有 GC 流程都由 `SeparateManagement *DBImpl::garbage_collection_management_` 进行管理,并向所有 VLogs 的 `ValueLogInfo` 更新 GC 的结果。 |
|
|
|
|
|
|
|
#### 后台多线程调度机制
|
|
|
|
#### 后台线程调度机制
|
|
|
|
|
|
|
|
参考 Compaction 线程互斥锁的实现与后台调度机制: |
|
|
|
|
|
|
@ -880,7 +879,7 @@ Status DBImpl::OutLineGarbageCollection(){ |
|
|
|
} else if (!bg_error_.ok()) { |
|
|
|
// Already got an error; no more changes |
|
|
|
} else { |
|
|
|
// 设置调度变量,通过 detach 线程调度; detach 线程即使主线程退出,依然可以正常执行完成 |
|
|
|
// 设置调度变量 |
|
|
|
background_GarbageCollection_scheduled_ = true; |
|
|
|
env_->ScheduleForGarbageCollection(&DBImpl::GarbageCollectionBGWork, this); |
|
|
|
} |
|
|
@ -1002,31 +1001,9 @@ Status DBImpl::OutLineGarbageCollection(){ |
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
#### GC 与 Snapshot 的冲突机制
|
|
|
|
|
|
|
|
```c++ |
|
|
|
const Snapshot* DBImpl::GetSnapshot() { |
|
|
|
MutexLock l(&mutex_); |
|
|
|
// 建立快照,对快照之后的信息不用进行 GC |
|
|
|
finish_back_garbage_collection_ = true; |
|
|
|
return snapshots_.New(versions_->LastSequence()); |
|
|
|
} |
|
|
|
|
|
|
|
void DBImpl::ReleaseSnapshot(const Snapshot* snapshot) { |
|
|
|
MutexLock l(&mutex_); |
|
|
|
snapshots_.Delete(static_cast<const SnapshotImpl*>(snapshot)); |
|
|
|
// 没有快照,重新进行后台 GC |
|
|
|
if (snapshots_.empty()) { |
|
|
|
finish_back_garbage_collection_ = false; |
|
|
|
} |
|
|
|
} |
|
|
|
``` |
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
## 断电恢复
|
|
|
|
|
|
|
|
> 实现断电恢复的主要函数为 `DBImpl::Recover()`、`DBImpl::RecoverLogFile`、`DB::Open()`;
|
|
|
|
> 实现断电恢复的主要函数为 `DBImpl::Recover()`、`DBImpl::RecoverLogFile()`、`DB::Open()`;
|
|
|
|
|
|
|
|
### 大致恢复流程
|
|
|
|
|
|
|
@ -1487,7 +1464,7 @@ fillsync : 985.150 micros/op; 0.0 MB/s (100 ops) |
|
|
|
fillrandom : 4.337 micros/op; 4.0 MB/s |
|
|
|
overwrite : 4.503 micros/op; 3.8 MB/s |
|
|
|
fillgivenseq : 4.472 micros/op; 3.6 MB/s |
|
|
|
fillgivenrandom : 9.076 micros/op; 1.8 MB/s |
|
|
|
fillgivenrandom : 9.076 micros/op; 1.8 MB/s |
|
|
|
``` |
|
|
|
|
|
|
|
+ kv分离: |
|
|
@ -1498,7 +1475,7 @@ fillsync : 1005.810 micros/op; 0.0 MB/s (100 ops) |
|
|
|
fillrandom : 4.374 micros/op; 3.9 MB/s |
|
|
|
overwrite : 4.461 micros/op; 3.8 MB/s |
|
|
|
fillgivenseq : 4.503 micros/op; 3.6 MB/s |
|
|
|
fillgivenrandom : 4.789 micros/op; 3.4 MB/s |
|
|
|
fillgivenrandom : 4.789 micros/op; 3.4 MB/s |
|
|
|
``` |
|
|
|
|
|
|
|
#### 分析结论
|
|
|
@ -1516,7 +1493,6 @@ readrandom : 2.460 micros/op; (86501 of 100000 found) |
|
|
|
readrandom : 2.096 micros/op; (86354 of 100000 found) |
|
|
|
readseq : 0.258 micros/op; 188.5 MB/s |
|
|
|
readreverse : 1.250 micros/op; 38.9 MB/s |
|
|
|
findkeysbyfield : 1474764.000 micros/op; (3873 of 10000 found) |
|
|
|
``` |
|
|
|
|
|
|
|
+ kv分离: |
|
|
@ -1526,7 +1502,6 @@ readrandom : 13.775 micros/op; (86501 of 100000 found) |
|
|
|
readrandom : 9.095 micros/op; (86354 of 100000 found) |
|
|
|
readseq : 0.231 micros/op; 90.2 MB/s |
|
|
|
readreverse : 0.950 micros/op; 22.0 MB/s |
|
|
|
findkeysbyfield : 231171.000 micros/op; (0 of 10000 found) |
|
|
|
``` |
|
|
|
|
|
|
|
#### 分析结论
|
|
|
|