# 规划的Bonus实现方式
- 缓存：LRU
- 空间回收
- 快照：贯通于数据库系统和火车票系统整体，以文件为单位夹打快照（类似于git，在火车票系统后端处于非活动状态时操作，比对stage区和版本库中的最后一次commit，然后打一个新的commit进去），额外消耗空间为 当前文件实际大小 + 压缩后的 当前文件实际大小+变化量，使用zstd算法压缩。交互方式：`./core-cli snapshot [options]`。而stage功能内置于DiskManager，当收到信号后，会把工作文件夹的变化打进stage区。
- 并发：内置于数据库系统，基于`std::shared_mutex`的简单并发，可以真正意义上支持读操作的并发，但写操作会独占数据库的控制权。（但火车票系统会直接在整个业务层面上加读写锁，因此不会直接使用数据库系统的并发安全）。
- 容错：commit功能不内置于数据库系统，由火车票系统针对实际业务逻辑记录日志。在文件系统层级上修复完损伤后，运行`./core-cli fsck`检查是否有可能有损坏，借助快照系统和日志修复可能的损伤。具体而言，每条指令视为一个事务，每隔1e3~1e4个事务之后，Flush数据库，调用快照系统，把数据库文件塞进stage区域（直接由DiskManager异步完成，不会阻塞数据库运行），并在事务日志里记录“截至当前已存档”。当需要修复时，先借助快照系统恢复到最近的快照（或从stage区恢复），然后把未反映进该checkpoint的数量较少的事务再重新操作一下（考虑到后端的执行速率，重新执行1e3到1e4个事务的代价是可以接受的）。此时，恢复的即时性就由新增事务多长时间内会实际存入磁盘决定，单独开启一个线程，以最快的可能速度往某个单独的日志文件末尾追加。
- 前端：一个使用正经框架写的简洁美观的UI，无响应式设计。

## 快照系统
一个仿照git的直接针对文件的快照库，有Work Tree、Stage、Commit等概念。虽然快照系统作用于数据库系统，但何时触发操作由火车票系统决定，数据库系统会拿到一个用于暂存自己下辖文件的handler，但对用户开放的操作是以整个火车票系统为单位的。火车票系统会每隔数秒或数千比交易执行一次暂存，此时数据库系统会把缓存写回磁盘，记录数据操作日志，以及在快照系统中执行Stash；打快照时，会依次把缓存写回磁盘、记录日志（以单笔业务为最小单位）、stage工作目录、创建commit。暂存可以在运行时执行，但创建快照、还原快照、删除快照、从暂存区复原工作目录等功能无法在火车票系统运行时执行。

因为详细的数据库相关知识没学，所以正经并发和更细粒度的容错就不打算自己瞎搓了。

# 内核设计
- STLite：提供STL中被ban掉的那些功能
- bpt：原始B+树以及相关简单封装，和其他一些涉及具体磁盘存储的东西
- 一个火车票系统执行引擎
- 一个直接的命令行交互系统，用于OJ测试/单会话模式/快照管理/数据错误检查
- 一个Socket服务端，用于对接服务端

## B+树
基本参考：<https://en.wikipedia.org/wiki/B%2B_tree>
- p[i]子树中的所有key K都满足： k[i-1] \< K \<= k[i]，且k[i]一定能取到，即直接无缝对接lower_bound
- 对外接口提供类似于迭代器的东西，但该迭代器只支持向后单项移动、读取value值、修改value值，并且，迭代器会保留PageGuard，因此如果B+树在迭代器之前析构，会出现访问越界。
- 由于子区间**左开右闭**，于是绝大多数Internal Page和Leaf Page一样，都没有尾后指针，整棵树的左下角会有一大片的leaf like pages，它们都有个共同特性，即指针数量和键值数量相同，但真正的leaf page还需要额外维护page状态标号和p_n指针。

# UI设计
- 语言：Python
- 与内核的交互：Socket
- Web框架：FastAPI + socket.IO + (React?) + BootStrap

___
# 使用到的第三方库
均为在不涉及核心功能的情况下为了让程序更优雅而使用：
- argparse：提供优雅的命令行参数解析
- googletest：调试用
- spdlog：运行日志，调试用（不是数据库系统日志）
- sockpp：服务器模式下与Python交互用
- zstd：为快照系统提供数据压缩（只使用最基本的压缩功能，不借用其patch功能）