|
|
@ -62,8 +62,8 @@ |
|
|
|
对于vlog文件,我们在内存中维护一个bitmap,用来表示每一个slot的使用情况,并在插入和GC删除kv时进行动态的分配和释放。对于vlog文件的GC,我们用一个后台线程来扫描所有vlog的discard计数器。当某些vlog的discard计数器超过某个阈值(比如1024),我们就对这些vlog文件进行GC过程,当GC完成之后将slot_page中的slot元数据进行更新,再将原来的vlog文件进行删除,GC过程就完成了。 |
|
|
|
|
|
|
|
##### 2.2.1 相关代码文件 |
|
|
|
- [`/db/db_impl.cc`](./db/db_impl.cc) |
|
|
|
- [`/db/db_impl.h`](./db/db_impl.h) |
|
|
|
- [`/db/db_impl.cc`](./db/db_impl.cc): 修改 DBImpl::Get, DBImpl::Put 和 DBImpl::Delete |
|
|
|
- [`/db/db_impl.h`](./db/db_impl.h): 添加两个结构体 SlotPage *slot_page_; VlogSet *vlog_set_; |
|
|
|
- |
|
|
|
- [`/db/shared_lock.h`](./db/shared_lock.h) 定义了一个 SharedLock 类,用于实现读写锁机制,包含四种操作:soft_lock():获取共享读锁,确保在没有写操作时允许多个读操作并发进行;soft_unlock():释放共享读锁;hard_lock():获取独占写锁,确保只有当没有其他读写操作时,允许写入操作进行;hard_unlock():释放独占写锁。 |
|
|
|
- [`/db/slotpage.h`](./db/slotpage.h) |
|
|
@ -79,6 +79,66 @@ |
|
|
|
- [`/test/db_test5.cc`](./test/db_test5.cc) |
|
|
|
- |
|
|
|
- [`CMakeLists.txt`](CMakeLists.txt):添加可执行文件 |
|
|
|
##### 2.2.1 具体流程 |
|
|
|
写入流程 |
|
|
|
```` |
|
|
|
Status DBImpl::Put(const WriteOptions& o, const Slice& key, const Slice& val) { |
|
|
|
// TODO(begin): allocate slot_num in slotpage and put value in vlog |
|
|
|
|
|
|
|
size_t slot_num = slot_page_->alloc_slot(); |
|
|
|
struct slot_content sc; |
|
|
|
vlog_set_->put_value(&sc.vlog_num, &sc.value_offset, val); |
|
|
|
slot_page_->set_slot(slot_num, &sc); |
|
|
|
|
|
|
|
char data[sizeof(size_t)]; |
|
|
|
memcpy(data, &slot_num, sizeof(size_t)); |
|
|
|
Slice slot_val(data, sizeof(data)); |
|
|
|
|
|
|
|
return DB::Put(o, key, slot_val); |
|
|
|
// TODO(end) |
|
|
|
} |
|
|
|
```` |
|
|
|
1. 调用编码函数,将 val 编码为字符串 |
|
|
|
2. 在 slot_page_ 中为 K-V 对分配一个 slot ,编号为 slot_num |
|
|
|
3. 实例化 slot_content 结构体 sc |
|
|
|
4. 以 sc 中的 vlog_num(vlog编号) 和 value_offset(在vlog中的偏移量) 为参数,将字符串写入 vlog 中 |
|
|
|
5. 将 slot_content 中的内容赋值给 slot_num |
|
|
|
6. 将 slot_num 作为 key 的 value 写入数据库中 |
|
|
|
|
|
|
|
读取流程 |
|
|
|
```` |
|
|
|
// TODO(begin): search the slotpage and get value from vlog |
|
|
|
size_t slot_num = *(size_t *)value->c_str(); |
|
|
|
struct slot_content sc; |
|
|
|
std::string vlog_value; |
|
|
|
slot_page_->get_slot(slot_num, &sc); |
|
|
|
vlog_set_->get_value(sc.vlog_num, sc.value_offset, &vlog_value); |
|
|
|
*value = vlog_value; |
|
|
|
// TODO(end) |
|
|
|
```` |
|
|
|
1. 读取 key 对应的 value, 也就是 slot_num |
|
|
|
2. 实例化 slot_content 结构体 sc |
|
|
|
3. 根据 slot_num 从 slot_page_ 中读取 slot_content |
|
|
|
4. 利用 sc 中的 vlog_num(vlog编号) 和 value_offset(在vlog中的偏移量) 从 vlog 中读取字符串 |
|
|
|
5. 将字符串进行解码得到 value |
|
|
|
|
|
|
|
删除流程 |
|
|
|
```` |
|
|
|
// TODO(begin) |
|
|
|
ReadOptions ro; |
|
|
|
ro.verify_checksums = true; |
|
|
|
ro.fill_cache = false; |
|
|
|
ro.snapshot = nullptr; |
|
|
|
std::string value; |
|
|
|
Get(ro, key, &value); |
|
|
|
size_t slot_num = *(size_t *)value.c_str(); |
|
|
|
struct slot_content sc; |
|
|
|
std::string vlog_value; |
|
|
|
slot_page_->get_slot(slot_num, &sc); |
|
|
|
vlog_set_->del_value(sc.vlog_num, sc.value_offset); |
|
|
|
// TODO(end) |
|
|
|
```` |
|
|
|
1. 读取 key 对应 |
|
|
|
### 锁机制 |
|
|
|
|
|
|
|
### 3. 数据结构设计 |
|
|
@ -129,7 +189,6 @@ |
|
|
|
|
|
|
|
5. Get_Fields (待实现) |
|
|
|
#### 4.2 实现KV分离 |
|
|
|
这里只展示和vlog以及GC无关的接口,vlog的创建,管理以及后台线程的GC设计到vlog等新数据结构的实现,较为复杂和庞大,这里不做展示。我们只列出与kv的插入有关的新接口: |
|
|
|
1. 搜索slot_page文件: Status find_slot(const Slice& key, Slot *slot); |
|
|
|
2. 搜索vlog文件: Status find_value(Slot *slot); |
|
|
|
3. 分配新的slot: Status allocate_slot(Bitmap *map, uint64_t *s); |
|
|
|