一.总览级架构分层图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| ┌────────────────────────────────────┐ │ Public API Layer(对外接口层) │ │ 参数校验 / 模式判断 / WAL / 调度 │ └───────────────▲────────────────────┘ │ ┌───────────────┴────────────────────┐ │ Apply Layer(应用层 / 状态变更层) │ │ 只负责:把操作应用到内存状态 │ └───────────────▲────────────────────┘ │ ┌───────────────┴────────────────────┐ │ Storage Engine(存储引擎层) │ │ B+Tree 的插入 / 删除 / 遍历 │ └───────────────▲────────────────────┘ │ ┌───────────────┴────────────────────┐ │ WAL / Snapshot(持久化层) │ │ 日志 / 快照 / replay / 校验 │ └────────────────────────────────────┘
|
越往上越“像业务”,越往下越“像工具”。
上面的模块调用下面的模块
二.函数归类
① Public API Layer(对外接口层)
对用户 / main / 测试程序(test_kvstore)可见、做参数校验、判断是否只读(read-only)、写 WAL 、再调用 Apply Layer
函数列表
1 2 3 4 5 6 7 8 9 10
| kvstore_create(const char *) kvstore_destroy(kvstore *)
kvstore_insert(kvstore *, int, long) kvstore_put(kvstore *, int, long) kvstore_del(kvstore *, int)
kvstore_search(kvstore *, int, long *)
kvstore_debug_set_mode(kvstore *, kvstore_mode_t)
|
kvstore_put / del 是对外写接口
② Apply Layer(应用层 / 状态变更层)
Apply Layer = 只做状态改变,不校验,不写日志,是系统中唯一允许修改内存状态的入口
函数列表
1 2
| kvstore_apply_put(kvstore *, int, long) kvstore_apply_del(kvstore *, int)
|
由public API、replay、snapshot load 调用,内部会操作 B+ Tree、更新统计信息(op_counts等)
③ Apply Internal(应用层内部 / 适配层)
给 Apply Layer 用,把 kvstore 逻辑,bptree 细节解耦开
Apply Layer(应用层)
↓(调用)
Apply Internal(贴近存储引擎)
④ Storage Engine(存储引擎层)
也就是 B+ Tree (bptree.c / h)
不在 kvstore 文件里,但逻辑上属于最底层
不知道 WAL, kvstore, snapshot
⑤ WAL / Log Layer(日志层)
负责持久化“操作”而不是“状态”
函数列表
1 2 3 4 5 6 7
| kvstore_open_log(kvstore *, const char *) kvstore_log_put(kvstore *, int, long) kvstore_log_del(kvstore *, int)
kvstore_log_header(const char *) crc32(const char *) kvstore_crc_check(const char *, const char *)
|
架构理解
- kvstore_log_put / del
- crc32 / crc_check()
- log_header
⑥ Replay Layer(重放层 / 恢复层)
崩溃恢复的核心
函数列表
1
| kvstore_replay_log(kvstore *)
|
replay = 只读 WAL + 调用 Apply Layer(或 Apply Internal),
物理层面:使用 fgets 把磁盘上已经存在的旧记录一行行读进内存,操作模式是 w(Read), 而不是 a+(Append)
逻辑层面:只读状态下的程序,只能 看日志内容,不能在重放过程中又往里面写新东西。
正常写入流程(用户调用 / mian 调用)
用户想存数据,必须走全套流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 1. 通过 public API,调用应用层函数 int kvstore_put(kvstore* store, int key, long val) { ... kvstore_write_log(store, "PUT", key, val); return kvstore_apply_put(store, key, value); }
2. 应用层函数调用应用层内部 / 适配层 static int kvstore_apply_put(kvstore* store, int key, long value) { ... return kvstore_apply_put_internal(store->tree, key, value, store->mode); }
3.应用层内部实现对数据的操作 static int kvstore_apply_put_internal(bptree* tree, int key, long value, kvstore_mode_t mode) { ... return bptree_insert(tree, key, value); }
|
重放流程(启动时调用)
重放时,绕过写日志的步骤,直接在内存里修改
1 2 3 4 5 6 7 8 9 10 11 12 13
| static int kvstore_replay_log(kvstore* store) { if (sscanf(line, "PUT %d %ld", &key, &val) == 2) { if kvstore_apply_put_internal(store->tree, key, val); else kvstore_apply_del_internal(store->tree, key); } }
|
⑦ Snapshot / Compaction(快照与压缩)
函数列表
1 2 3 4 5 6 7 8 9
| kvstore_compact(kvstore *) kvstore_maybe_compact(kvstore *)
compact_write_cb(int, long, void *)
kvstore_create_snapshot(kvstore *) kvstore_load_snapshot(kvstore *)
snapshot_write_cb(int, long, void *)
|
架构理解
- callback:(难点、难理解 !)
- snapshot:
- campact:
辅助 / 工具层