VirgilZhu пре 8 месеци
родитељ
комит
7d96557d45
3 измењених фајлова са 15 додато и 40 уклоњено
  1. +12
    -37
      README.md
  2. +1
    -1
      benchmarks/db_bench.cc
  3. +2
    -2
      include/leveldb/options.h

+ 12
- 37
README.md Прегледај датотеку

@ -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)。
>
> + **结构图/写入流程图**:
> ![kv_sep](./image/kv_sep.png)
@ -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)
```
#### 分析结论

+ 1
- 1
benchmarks/db_bench.cc Прегледај датотеку

@ -85,7 +85,7 @@ static int FLAGS_num_fields = 10000;
static int FLAGS_threads = 1;
// Size of each value
static int FLAGS_value_size = 100;
static int FLAGS_value_size = 1000;
// Arrange to generate values that shrink to this fraction of
// their original size after compression

+ 2
- 2
include/leveldb/options.h Прегледај датотеку

@ -114,7 +114,7 @@ struct LEVELDB_EXPORT Options {
// compactions and hence longer latency/performance hiccups.
// Another reason to increase this parameter might be when you are
// initially populating a large database.
size_t max_file_size = 2 * 1024 * 1024;
size_t max_file_size = 64 * 1024 * 1024;
// Compress blocks using the specified compression algorithm. This
// parameter can be changed dynamically.
@ -149,7 +149,7 @@ struct LEVELDB_EXPORT Options {
/* 注释:重要的 VLog 与 GC 设置 */
// value log
uint64_t max_value_log_size = 16 * 1024 * 1024;
uint64_t max_value_log_size = 64 * 1024 * 1024;
// VLog gc
uint64_t garbage_collection_threshold = max_value_log_size / 4;
// gc put kv

Loading…
Откажи
Сачувај