# RocksDB: 写入 (继续...)

__*Level*__
__*compaction*__

![`smart`](./student-guide/diagram/RocksDBWrite02_aa_001_20220511.png)

-------------------------------------------------------------

磁盘上的文件被分成多层进行组织。我们叫它们为 `Level-1`, `Level-2`, `...` 等等, 或者简单的 `L1`, `L2`, `...` 等等。一个特殊的层, `Level-0 (L0)`,会包含刚从内存 `MemTable` 落盘的数据,到达 4 个会触发向下一层的`compaction`, 如果积压达到 20 个,会触发 `write stall`。每个(除了 `Level0`) 都是一个独立的排序结果。

在每一层（除了`Level-0`）,数据被切分成多个`SST`文件。

每个 `SST` 文件中的 `key` 都是排好序的。如果需要定位一个 `key`,我们先二分查找所有文件的起始和结束`key`,定位哪个文件有这个`key`,然后二分查找具体的文件,来定位`key`的位置。总的来说,就是在该层的所有`key`里面进行二分查找。

除了 `L0`, 其它的层都有压缩目标大小。压缩的目标是限制这些层的数据大小, 目标通常是指数增加的。

最后,关于 `WAL`, `WAL` 会把 `MemTable` 的操作序列化之后以日志文件形式存储在持久化介质中。当发生系统崩溃的时候,`WAL` 日志文件可以用于重新构建 `MemTable`,帮助数据库恢复数据库到一个一致的状态。当一个 `MemTable` 被安全地保存到持久化介质之后,相关的 `WAL` 日志会变成过期的,然后被归档。最终归档的日志会在一定时间后被从硬盘上删除。

到此为止,数据就被持久化写入了,我们可以看到,`WAL` 一开始就保证了写不丢失,接下来我们总结一下 `RocksDB` 的 `CRUD` 大致流程:

写入操作
- 写操作首先需要通过 `WAL` 将数据写入到磁盘日志中,防止数据丢失,然后数据会被写入到内存的 `MemTable` 中,这样一次写操作已经完成了,只需要 1 次磁盘 `IO`,再加 1 次内存操作。相较于 `B+ Tree`的多次磁盘随机 `IO`,大大提高了效率。随后,这些在 `MemTable` 中的数据会被批量地合并到磁盘中的 `SSTable` 当中,将随机写变为了顺序写。

删除操作
- 当有删除操作时,并不需要像 `B+ Tree`一样,在磁盘中找到相应的数据后再删除,只需要在 `MemTable` 中插入一条数据当作标志,如 `delete key:1233` ,当读操作读到 `MemTable` 中的这个标志时,就会知道这个 `key` 已被删除。随后在日志合并中,这条被删除的数据会在合并的过程中一起被删除。

更新操作
- 更新操作和删除操作类似,都是只操作 `MemTable`,写入一个标志,随后真正的更新操作被延迟在合并时一并完成。

















