CMU_15445_Project4_Task1-2
到这部分, BUSTUB 数据库引擎的整体面容开始显现出来了, 在文件 src/include/common/bustub_instance.h
中, 当我们想要实例化一个 BUSTUB 对象的时候, 可以看到它的组成部分有:
// Currently the followings are directly referenced by recovery test, so// we cannot do anything on them until someone decides to refactor the recovery test.// 磁盘管理器std::unique_ptr<DiskManager> disk_manager_;// BPM, 管理缓冲区std::unique_ptr<BufferPoolManager> buffer_pool_manager_;// 锁管理器std::unique_ptr<LockManager> lock_manager_;// 事务管理器, 这是我们 Project4 需要完成的部分std::unique_ptr<TransactionManager> txn_manager_;// 日志管理工具std::unique_ptr<LogManager> log_manager_;// 事务管理中创建 checkpointsstd::unique_ptr<CheckpointManager> checkpoint_manager_;// 数据库表存储的画布std::unique_ptr<Catalog> catalog_;// 数据库执行引擎, 也就是我们的 Executorstd::unique_ptr<ExecutionEngine> execution_engine_;/** Coordination for catalog */std::shared_mutex catalog_lock_;
这些可以看作是构成一个数据库的核心部分.
Watermark
Watermark is the lowest read timestamp among all in-progress transactions.
在 TransactionManager
中可以通过下面的 version_info_
和 PageVersionInfo
获取某个 RID 对应的 Tuple 的当前最新版本的 VersionUndoLink
.
struct PageVersionInfo {/** protects the map */std::shared_mutex mutex_;/** Stores previous version info for all slots. Note: DO NOT use `[x]` to access it because* it will create new elements even if it does not exist. Use `find` instead. 使用 version_info_ 中的 page_id_t 与* slot_offset_t 可以得到一个 Tuple 的 RID, 用于访问某个 Tuple 的版本链*/std::unordered_map<slot_offset_t, VersionUndoLink> prev_version_;
};/** protects version info */
std::shared_mutex version_info_mutex_;
/** Stores the previous version of each tuple in the table heap. Do not directly access this field. Use the helper* functions in `transaction_manager_impl.cpp`. */
std::unordered_map<page_id_t, std::shared_ptr<PageVersionInfo>> version_info_;
可以从这个 VersionUndoLink
中获取这个 Tuple 的 UndoLink
.
UndoLink 和 UndoLog 是如何形成版本链的: 可以从 UndoLink
中获取前一个版本的事务的 ID(prev_txn_
). 然后在 txn_map_
事务 Map 中找到这个事务 ID 对应的事务 pre_txn, 在 UndoLink
中使用 prev_log_idx_
记录前一个版本的 UndoLog 在事务中的下标, 因此使用 ``pre_txn->GetUndoLog(UndoLink.prev_log_idx_);可以得到前一个事务的
UndoLog. 而在这个
UndoLog中又记录着更前一个事务的
UndoLink. 这种方式形成了 Tuple 的版本链, 并且从
TransactionManager` 开始就可以找到这条链.
关于 UndoLog 的一些问题
UndoLog 结构体的信息如下所示:
struct UndoLog {/* Whether this log is a deletion marker */bool is_deleted_;/** The fields modified by this undo log* modified_fields is a vector of bool that has the same length as the table schema. If one of the fields is set to* true, it indicates that the field is updated. The tuple field contains the partial tuple.*/std::vector<bool> modified_fields_;/* The modified fields */Tuple tuple_;/* Timestamp of this undo log */timestamp_t ts_{INVALID_TS};/* Undo log prev version */UndoLink prev_version_{};
};
我们下列问题需要明确:
- UndoLog 是什么时候生成的呢, 其中的
timestamp_t
是什么意思? - 在测试案例中, 为什么
is_deleted_ == true
的时候, 这个 UndoLog 对应的tuple_
是空的, 它不应该是记录删除之前的不为空的tuple_
吗? tuple_
是记录当前 Tuple 在当前对应的 UndoLog 修改之前还是修改之后的 Tuple.- 假设某个事务的
read_ts
等于当前 UndoLog 的ts_
, 是否需要执行这个 UndoLog 来进行回退当前事务
关于问题2, 为什么is_deleted_ == true
这个 UndoLog 对应的 tuple_
为空呢,
这是因为 UndoLog 记录都是这个 UndoLog 之前的状态, is_deleted_ == true
表示这个 UndoLog 之前的状态是删除状态, 所以 tuple_
存储的内容当然为空了
具体的对于一个 Tuple 而言, 删除这个 Tuple, 只是将 TupleMeta
中的 is_deleted
设置为 true
, 并没有对 Tuple 实际存储的数据进行修改, 所以 UndoLog 只需要记录一个标志位就可以了, 实际上没有任何数据修改
3. tuple_
很明显是记录当前的 UndoLog 修改之间的状态, 但是仅记录了修改的部分