|
|
@ -201,7 +201,7 @@ std::vector FindKeysByField(leveldb::DB* db, const Field& field) { |
|
|
|
|
|
|
|
##### 相关代码文件 |
|
|
|
- [`/db/db_impl.cc`](./db/db_impl.cc): 修改函数 DBImpl::Get, DBImpl::Put 和 DBImpl::Delete,添加函数 Put_fields, Get_fields, get_slot_num,SerializeValue, DeserializeValue |
|
|
|
- [`/db/db_impl.h`](./db/db_impl.h): 添加两个结构体 SlotPage *slot_page_; VlogSet *vlog_set_ ,添加增加的相关函数的声明 |
|
|
|
- [`/db/db_impl.h`](./db/db_impl.h): 添加相关结构体和函数声明 |
|
|
|
- [`/db/shared_lock.h`](./db/shared_lock.h): 定义了一个 SharedLock 类,用于实现读写锁机制。该类支持两种锁模式:软锁(soft_lock/soft_unlock)和硬锁(hard_lock/hard_unlock); |
|
|
|
- [`/db/slotpage.h`](./db/slotpage.h): |
|
|
|
1. 定义了 slot_content 结构体: |
|
|
@ -220,7 +220,7 @@ struct slot_content { |
|
|
|
3. 定义了 BitMap 类,类中函数: dealloc_slot, alloc_slot, alloc_new_bitmap; |
|
|
|
4. 定义了 Slot_page 类,类中函数: get_slot, set_slot, alloc_slot, dealloc_slot |
|
|
|
- [`/db/vlog.h`](./db/vlog.h) |
|
|
|
1. 定义了 vlog_info 结构体: |
|
|
|
1. 定义了 vlog_info 结构体(存放 value_log 的相关信息): |
|
|
|
```` |
|
|
|
struct vlog_info { |
|
|
|
std::mutex vlog_info_latch_; // 保护对vlog_info本身的并发修改 |
|
|
@ -269,7 +269,7 @@ struct vlog_handler { |
|
|
|
```` |
|
|
|
- [`/db/vlog_gc.h`](./db/vlog_gc.h): |
|
|
|
|
|
|
|
定义 VlogGC 类,声明类中函数:do_gc, exec_gc, gc_counter_increment, gc_counter_decrement, get_gc_num, vlog_in_gc, add_vlog_in_gc, del_vlog_in_gc |
|
|
|
定义 VlogGC 类,声明类中函数 |
|
|
|
- [`/db/vlog_gc.cpp`](./db/vlog_gc.cpp): |
|
|
|
1. 定义了 executor_param 结构体: |
|
|
|
```` |
|
|
@ -279,15 +279,15 @@ struct executor_param { |
|
|
|
size_t new_vlog_num; |
|
|
|
}; |
|
|
|
```` |
|
|
|
2. 定义函数:add_executor_params, get_executor_params, del_executor_params, add_vlog_gc, get_vlog_gc, del_vlog_gc, gc_counter_increment, gc_counter_decrement, do_gc, exec_gc |
|
|
|
- [`/db/vlog_set.h`](./db/vlog_set.h): |
|
|
|
2. 实现 vlog_gc 中声明的函数 |
|
|
|
- [`/db/vlog_set.h`](./db/vlog_set.h)(用于管理 vlog): |
|
|
|
定义 VlogSet 结构体 |
|
|
|
- [`/db/vlog_set.cpp`](./db/vlog_set.cpp): |
|
|
|
实现 vlog_set 中的函数 |
|
|
|
- [`/db/vlog_cache.h`](./db/vlog_cache.h): |
|
|
|
1. 定义结构体:frame_info, block_frame |
|
|
|
2. 定义类 VlogCache |
|
|
|
- [`/db/vlog_cache.cpp`](./db/vlog_cache.cpp):实现 VlogCache 类中的函数 |
|
|
|
- [`/db/vlog_set.cpp`](./db/vlog_set.cpp): |
|
|
|
定义函数: get_value, get_writable_vlog_info, put_value, del_value, register_new_vlog, remove_old_vlog, vlog_need_gc, register_inconfig_file, remove_from_config_file, create_vlog, restore_vlog_inmaps, register_vlog_inmaps, remove_vlog_from_maps, read_vlog_value, write_vlog_value, mark_del_value |
|
|
|
- [`/db/vlog_cache.cpp`](./db/vlog_cache.cpp):实现 vlog_cache 中的函数 |
|
|
|
- [`CMakeLists.txt`](CMakeLists.txt):添加可执行文件 |
|
|
|
|
|
|
|
**数据结构设计:** |
|
|
@ -308,12 +308,11 @@ struct executor_param { |
|
|
|
将传入的字段数组插入数据库中 |
|
|
|
|
|
|
|
**步骤:** |
|
|
|
1. 为当前 KV 对分配一个 size_t 类型的 slot_num; |
|
|
|
3. 调用 SerializeValue 函数将字段数组和 slot_num_str 序列化为字符串 serialized_value; |
|
|
|
4. 实例化 slot_content 结构体 sc; |
|
|
|
5. 调用 put_value 函数,以 sc 中的 vlog_num(vlog编号) 和 value_offset(在vlog中的偏移量) 为参数,将字符串 serialized_value 写入 vlog 中; |
|
|
|
6. 调用 set_slot 函数,将 slot_content 中的内容赋值给 slot_num; |
|
|
|
7. 将 slot_num 作为 value 写入数据库中。 |
|
|
|
1. 在 bit_map 中分配一个空闲位置; |
|
|
|
2. 调用 SerializeValue 函数将字段数组序列化为字符串 serialized_value; |
|
|
|
3. 调用 put_value 函数,将字符串 serialized_value 写入 vlog 中; |
|
|
|
4. 调用 set_slot 函数,将 sc 写入缓存中; |
|
|
|
5. 将 slot_num 作为 value 写入数据库中。 |
|
|
|
|
|
|
|
**代码实现:** |
|
|
|
```` |
|
|
@ -322,15 +321,15 @@ const FieldArray& fields) { |
|
|
|
std::string serialized_value; |
|
|
|
// alloc_slot 函数作用:分配一个 slot_num |
|
|
|
size_t slot_num = slot_page_->alloc_slot(); |
|
|
|
// SerializeValue 函数作用:将字段数组和 slot_num_str 序列化为字符串 serialized_value |
|
|
|
// SerializeValue 函数作用:将字段数组序列化为字符串 serialized_value |
|
|
|
SerializeValue(fields, serialized_value, slot_num); |
|
|
|
// 实例化 slot_content 结构体 sc |
|
|
|
struct slot_content sc; |
|
|
|
// put_value函数作用:将序列化后的字符串 serialized_value 插入 value_log 中 |
|
|
|
vlog_set_->put_value(sc, slot_num, serialized_value); |
|
|
|
// set_slot函数作用: 将 slot_num 写入到 缓冲块中 |
|
|
|
// set_slot函数作用: 将 sc 写入内存中 |
|
|
|
slot_page_->set_slot(slot_num, &sc); |
|
|
|
// 将 slot_num 作为 value 插入 memtable 中 |
|
|
|
// 将 slot_num 作为 value 插入 sstable 中 |
|
|
|
char data[sizeof(size_t)]; |
|
|
|
memcpy(data, &slot_num, sizeof(size_t)); |
|
|
|
Slice slot_val(data, sizeof(data)); |
|
|
@ -339,7 +338,7 @@ return DB::Put(opt, key, slot_val); |
|
|
|
```` |
|
|
|
`size_t alloc_slot()` |
|
|
|
|
|
|
|
**功能:** 分配一个 slot_num |
|
|
|
**功能:** 在 bitmap 中分配一个空闲的槽位 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 获取互斥锁; |
|
|
@ -386,7 +385,7 @@ size_t alloc_slot() { |
|
|
|
```` |
|
|
|
`void set_slot(size_t slot_num, struct slot_content *sc)` |
|
|
|
|
|
|
|
**功能:** 将一个槽位的内容设置到缓存块中 |
|
|
|
**功能:** 将 sc 写入缓存块中,缓存块与 bitmap 有对应关系 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 计算块编号:通过 slotnum_hash2_blocknum 函数将槽位编号转换为块编号 |
|
|
@ -420,9 +419,7 @@ void set_slot(size_t slot_num, struct slot_content *sc) { |
|
|
|
|
|
|
|
`void VlogSet::put_value(struct slot_content &sc, size_t slot_num, const leveldb::Slice &value)` |
|
|
|
|
|
|
|
**功能:** 将序列化后的字符串 serialized_value 插入 value_log 中,位置由 slot_content 确定 |
|
|
|
|
|
|
|
**输入:** 待插入的字符串 value,slot_num,slot_content |
|
|
|
**功能:** 做前期准备,并调用 write_vlog_value 将序列化后的字符串 serialized_value 插入 value_log 中 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 获取互斥锁; |
|
|
@ -476,8 +473,6 @@ void VlogSet::put_value(struct slot_content &sc, size_t slot_num, const leveldb: |
|
|
|
|
|
|
|
**功能:** 将字符串 value 写入 vlog 中 |
|
|
|
|
|
|
|
**输入:** slot_content,slot_num,字符串 value |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 获取 vlog 名称; |
|
|
|
2. 打开 vlog 文件; |
|
|
@ -519,7 +514,7 @@ void VlogSet::write_vlog_value(const struct slot_content &sc, size_t slot_num, c |
|
|
|
**实现步骤:** |
|
|
|
1. 读取 key 对应的 slot_num |
|
|
|
2. 调用 get_slot 函数,根据 slot_num 从 slot_page 中获取 slot_content |
|
|
|
4. 调用 get_value 函数,根据 slot_content 中的 vlog_num(vlog编号) 和 value_offset(在vlog中的偏移量) 从 vlog 中读取字符串 |
|
|
|
4. 调用 get_value 函数,从 vlog 中读取字符串 |
|
|
|
5. 将字符串解码得到 value |
|
|
|
|
|
|
|
**代码实现:** |
|
|
@ -582,7 +577,7 @@ void get_slot(size_t slot_num, struct slot_content *sc) { |
|
|
|
|
|
|
|
`void VlogSet::get_value(const struct slot_content &sc, std::string *value)` |
|
|
|
|
|
|
|
**功能:** 根据 slot_content 从 vlog 中读取字符串并存放到 value 中 |
|
|
|
**功能:** 做准备工作,并调用 read_vlog_value 函数从 vlog 中读取字符串 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 根据 sc.vlog_num 获取 vinfo 和 vlog_handler; |
|
|
@ -662,16 +657,17 @@ void VlogSet::read_vlog_value(const struct slot_content &sc, std::string *value) |
|
|
|
handler.close(); |
|
|
|
} |
|
|
|
```` |
|
|
|
|
|
|
|
`Status DBImpl::Delete(const WriteOptions& options, const Slice& key)` |
|
|
|
|
|
|
|
**功能:** 删除 key 对应的条目 |
|
|
|
|
|
|
|
**步骤:** |
|
|
|
1. 从 sstable 中获取 key 对应的 slot_num; |
|
|
|
1. 获取 key 对应的 slot_num; |
|
|
|
2. 获取 slot_num 对应的 slot_content; |
|
|
|
3. 删除 vlog 中 slot_content 对应的条目; |
|
|
|
4. 释放 slot_num 中对应的 slot_content;? |
|
|
|
5. 删除 sstable 中 key 对应的条目。 |
|
|
|
4. 释放 slot_num 中对应的 slot_content; |
|
|
|
5. 删除 k-v对。 |
|
|
|
|
|
|
|
**代码实现:** |
|
|
|
```` |
|
|
@ -686,9 +682,9 @@ return s; |
|
|
|
struct slot_content sc; |
|
|
|
// get_slot 函数作用: 获取 slot_num 对应的 slot_content |
|
|
|
slot_page_->get_slot(slot_num, &sc); |
|
|
|
// del_value 函数作用:删除 vlog 中 slot_content 对应的条目 |
|
|
|
// del_value 函数作用:删除 vlog 中 slot_content 对应的 value |
|
|
|
vlog_set_->del_value(sc); |
|
|
|
// dealloc_slot 函数作用: 释放 slot_num 对应的 slot |
|
|
|
// dealloc_slot 函数作用: 释放 slot_num |
|
|
|
slot_page_->dealloc_slot(slot_num); |
|
|
|
|
|
|
|
return DB::Delete(options, key); |
|
|
@ -696,7 +692,7 @@ return DB::Delete(options, key); |
|
|
|
```` |
|
|
|
`void VlogSet::del_value(const struct slot_content &sc)` |
|
|
|
|
|
|
|
**功能:** 删除 vlog 中 slot_content 对应的条目 |
|
|
|
**功能:** 做准备工作,调用 mark_del_value 删除 vlog 中的条目 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 加锁:使用互斥锁 mtx 确保线程安全。 |
|
|
@ -704,7 +700,7 @@ return DB::Delete(options, key); |
|
|
|
3. 检查状态:如果 vlog 无效或正在处理垃圾回收,则更新处理器为垃圾回收的 vlog。 |
|
|
|
4. 加锁并增加访问计数:对 vlog 处理器加锁,并增加访问线程数。 |
|
|
|
5. 解锁:释放互斥锁和 vlog 信息锁。 |
|
|
|
6. 标记删除:调用 mark_del_value 标记删除操作。 |
|
|
|
6. 标记删除:调用 mark_del_value 标记并进行删除操作。 |
|
|
|
7. 减少访问计数并解锁:减少访问线程数并解锁 vlog |
|
|
|
|
|
|
|
**具体实现如下:** |
|
|
@ -730,7 +726,7 @@ void VlogSet::del_value(const struct slot_content &sc) { |
|
|
|
```` |
|
|
|
`void VlogSet::mark_del_value(const struct slot_content &sc)` |
|
|
|
|
|
|
|
**功能:** 标记 slot_content 对应的条目为删除并判断是否需要调用 GC |
|
|
|
**功能:** 标记 slot_content 对应的条目为删除并判断是否需要调用 GC,如果需要,调用do_gc |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
1. 根据 sc.vlog_num 获取 vlog 文件信息; |
|
|
@ -755,6 +751,7 @@ void VlogSet::mark_del_value(const struct slot_content &sc) { |
|
|
|
if (vlog_need_gc(sc.vlog_num) && !vinfo->processing_gc) { |
|
|
|
// create new vlog |
|
|
|
vinfo->processing_gc = true; |
|
|
|
// 分配一个新的 vlog |
|
|
|
vinfo->vlog_num_for_gc = register_new_vlog(); |
|
|
|
// 启动垃圾回收过程 |
|
|
|
vlog_gc->do_gc(sc.vlog_num, vinfo->vlog_num_for_gc); |
|
|
@ -764,7 +761,7 @@ void VlogSet::mark_del_value(const struct slot_content &sc) { |
|
|
|
|
|
|
|
`void VlogGC::do_gc(size_t old_vlog_num, size_t new_vlog_num)` |
|
|
|
|
|
|
|
**功能:** 启动垃圾回收过程 |
|
|
|
**功能:** 做 GC 的前期准备,并启动垃圾回收过程 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
|
|
|
@ -778,7 +775,7 @@ void VlogSet::mark_del_value(const struct slot_content &sc) { |
|
|
|
**具体实现如下:** |
|
|
|
```` |
|
|
|
void VlogGC::do_gc(size_t old_vlog_num, size_t new_vlog_num) { |
|
|
|
// 判断old_vlog_num是否正在进行gc,如果是,直接返回 |
|
|
|
// 判断旧的 vlog 是否正在进行gc,如果是,直接返回 |
|
|
|
if (vlog_in_gc(old_vlog_num)) { |
|
|
|
return ; |
|
|
|
} |
|
|
@ -807,7 +804,7 @@ void VlogGC::do_gc(size_t old_vlog_num, size_t new_vlog_num) { |
|
|
|
|
|
|
|
`void VlogGC::exec_gc(size_t gc_num_)` |
|
|
|
|
|
|
|
**功能:** 执行GC任务 |
|
|
|
**功能:** GC 相关线程调度,并执行GC任务 |
|
|
|
|
|
|
|
**实现步骤:** |
|
|
|
|
|
|
|