数据库专题训练 Lab 3


Lab 3 多版本并发控制

记录可见性的判断方法

src/table/table_scan.cpp - IsVisible() 中的具体实现.

可重复读隔离级别:

  • 记录被删除:
    • 默认可见;
    • 如果对应的事务在当前事务之后, 则记录可见;
    • 如果对应的事务不是活跃事务, 则记录不可见.
  • 记录未被删除:
    • 默认可见;
    • 如果对应的事务是当前事务, 则记录不可见;
    • 如果对应的事务在当前事务之后, 则记录不可见;
    • 如果对应的事务是活跃事务, 则记录不可见.

读已提交/串行化隔离级别:

  • 记录被删除:
    • 默认可见;
    • 如果对应的事务是当前事务, 则记录不可见;
    • 如果对应的事务不是活跃事务, 则记录不可见.
  • 记录未被删除:
    • 默认可见;
    • 如果对应的事务是当前事务, 则记录不可见;
    • 如果对应的事务是活跃事务但不是当前事务, 则记录不可见.

基础功能

解决万圣节问题

添加记录头信息src/table/table_page.cpp.

  • 通过 record->SetCid(), record->SetXmin(), record->SetXmax() 设置相应的记录头信息.

修改可见性判断条件src/table/table_scan.cpp.

  • 满足 record->GetXmax() == NULL_XIDrecord->GetXmin() != xid || record->GetCid() != cid 的记录是可见的, 即记录未被删除且不由当前命令设置.

实现可重复读隔离 / 实现读已提交隔离

设置活跃事务集合src/executors/seqscan_executor.cpp.

  • 分别通过 GetSnapshot()GetActiveTransactions() 获取事务开始时的活跃事务集合以及即时的活跃事务集合.

修改可见性判断条件src/table/table_scan.cpp.

  • 分已删除记录和未删除记录进行处理, 见报告第一节.

强两阶段锁

实现锁管理器 LockManagersrc/transaction/lock_manager.cpp.

  • 使用 std::vector 保存表锁和数据行锁信息.

    struct TableLock {
      LockType lock_type;
      xid_t xid;
      oid_t oid;
    };
    
    struct RowLock {
      LockType lock_type;
      xid_t xid;
      oid_t oid;
      Rid rid;
    };
    
    class LockManager {
      ...
      private:
      std::vector<TableLock> table_locks_;
      std::vector<RowLock> row_locks_;
    }
  • LockTable()LockRow() 先检查是否存在其他事务加的锁, 以及锁的类型相容性, 再检查本事务是否持有锁, 并升级锁的类型, 最后成功获取锁.

  • Compatible() 实现参考 PPT 给出的意向锁相容性矩阵.

  • Upgrade() 实现如下, 需要注意的是特殊判断 SIX 锁的获取.

    LockType LockManager::Upgrade(LockType self, LockType other) const {
      if (self == other) {
        return self;
      }
      if (self == LockType::S && other == LockType::IX) {
        return LockType::SIX;
      }
      return other;
    }

为修改操作加锁src/executors/*.

  • 普通 select 语句对表加 IS 锁; 数据修改操作对表加 IX 锁, 对修改的数据行加 X 锁.

实现可串行化隔离

实现 select for update/share 加锁src/executors/lock_rows_executor.cpp.

  • 根据 plan_lock type, 对表加 IS/ IX 锁, 对相应数据行加 S/X 锁.

设置活跃事务集合src/executors/seqscan_executor.cpp.

  • 完全与读已提交隔离相同.

修改可见性判断条件src/table/table_scan.cpp.

  • 完全与读已提交隔离相同.

实验耗时

  1. 基础功能
    • 解决万圣节问题: 1h.
    • 通过多版本并发控制实现可重复读隔离: 0.5h.
    • 实现读已提交隔离: 1h.
    • 强两阶段锁: 1h.
    • 通过多版本两阶段锁实现可串行化隔离: 0.5h.

文章作者: Chengsx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Chengsx !
  目录