From d4f86847a97433154a99da6e04172f81cb3fa5e1 Mon Sep 17 00:00:00 2001 From: hotwords <31656766+hotwords123@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:23:43 +0800 Subject: [PATCH] fix(mvcc): fix commit xid may be accidentally reused (#26) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **问题:** 在事务恢复阶段,`MTR_BEGIN` 日志对应的 trx id 会在 `MvccTrxManager` 类的 `create_trx(int32_t trx_id)` 方法中更新 `current_trx_id` 以避免重复使用,符合预期。但是 `MTR_COMMIT` 日志所使用的 commit xid 没有更新,可能会被重用而导致错误的结果。 **解决方案:** 增加 `update_trx_id` 方法用于确保 `current_trx_id` 不小于给定的参数。在 recover 阶段,`MvccTrx` 提交时应当调用该方法更新 `current_trx_id`。 --- .../include/storage_engine/transaction/mvcc_trx.h | 3 +++ src/server/storage_engine/transaction/mvcc_trx.cpp | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/server/include/storage_engine/transaction/mvcc_trx.h b/src/server/include/storage_engine/transaction/mvcc_trx.h index 03eb511..93cd24c 100644 --- a/src/server/include/storage_engine/transaction/mvcc_trx.h +++ b/src/server/include/storage_engine/transaction/mvcc_trx.h @@ -23,6 +23,9 @@ class MvccTrxManager : public TrxManager int32_t next_trx_id(); int32_t max_trx_id() const; + // 在 recover 场景下使用,确保当前事务 id 不小于 trx_id + void update_trx_id(int32_t trx_id); + private: std::vector<FieldMeta> fields_; // 存储事务数据需要用到的字段元数据,所有表结构都需要带 std::atomic<int32_t> current_trx_id_{0}; diff --git a/src/server/storage_engine/transaction/mvcc_trx.cpp b/src/server/storage_engine/transaction/mvcc_trx.cpp index aaef737..7570eab 100644 --- a/src/server/storage_engine/transaction/mvcc_trx.cpp +++ b/src/server/storage_engine/transaction/mvcc_trx.cpp @@ -95,6 +95,12 @@ int32_t MvccTrxManager::max_trx_id() const return numeric_limits<int32_t>::max(); } +void MvccTrxManager::update_trx_id(int32_t trx_id) +{ + int32_t old_trx_id = current_trx_id_; + while (old_trx_id < trx_id && !current_trx_id_.compare_exchange_weak(old_trx_id, trx_id)); +} + //////////////////////////////////////////////////////////////////////////////// MvccTrx::MvccTrx(MvccTrxManager &kit, LogManager *log_manager) : trx_kit_(kit), log_manager_(log_manager) {} @@ -168,6 +174,11 @@ RC MvccTrx::commit_with_trx_id(int32_t commit_xid) RC rc = RC::SUCCESS; started_ = false; + if (recovering_) { + // 在事务恢复时,更新当前事务 id 避免被后续事务重用 + trx_kit_.update_trx_id(commit_xid); + } + for (const Operation &operation : operations_) { switch (operation.type()) { case Operation::Type::INSERT: {