OB比赛记录

当时比赛期间因为太赶了,没来得及写,比完初赛论文又快截稿了。过年期间终于得闲,也算是重温一下OB比赛的心路。

[比赛介绍]{https://oceanbase.github.io/miniob/game/introduction/}
[代码仓库]{https://github.com/oceanbase/miniob}

架构

请求处理链路

一条 SQL 请求在 observer 中的标准处理路径如下:

Communicator(read_event) -> SessionEvent -> SqlTaskHandler::handle_sql ->
QueryCacheStage -> ParseStage -> ResolveStage -> OptimizeStage -> ExecuteStage -> Communicator(write_result)

说明:

  • QueryCacheStage 当前实现为透传(默认返回成功,不做实质缓存处理)。
  • 对需要物理计划的语句,ExecuteStage 负责把物理算子交给 SqlResult,实际执行由回包阶段调用 SqlResult::open/next_tuple 驱动。

Session 层说明

每次Client和Observer连接,都用一个session管理。

Session 维护的上下文:

  • 当前选中的数据库(Db)。
  • 唯一事务指针(Trx,按需创建)。
  • 记录当前请求(current_request)。
  • 保存 SQL 运行参数(例如 execution_modehash_joinuse_cascadesql_debug)。

补充说明:

  • DefaultHandler 属于全局对象,在系统 init 阶段创建,不属于 session 生命周期内对象。

对应代码文件:

  • src/observer/session/session.h
  • src/observer/session/session.cpp
  • src/observer/net/server.cpp
  • src/observer/common/init.cpp
  • src/observer/storage/default/default_handler.h
  • src/observer/storage/default/default_handler.cpp

Parser 层说明

Parser 层分为词法分析和语法分析两部分:

  • Lexer:对应 lex_sql.l,负责把字符流切分为词法单元。
  • Parser:对应 yacc_sql.y,负责将词法单元按语法规则归约组合成AST树。

Parser 输出对象为 ParsedSqlNode,作为后续 Resolve 阶段的输入。

对应代码文件:

  • src/observer/sql/parser/lex_sql.l
  • src/observer/sql/parser/yacc_sql.y
  • src/observer/sql/parser/parse.cpp
  • src/observer/sql/parser/parse_defs.h
  • src/observer/sql/parser/parse_stage.cpp

Resolve 层说明

ResolveStage 的职责是把 ParsedSqlNode 转换成语义化的 Stmt 对象(入口为 Stmt::create_stmt)。即语义解析

表达式语义绑定ExpressionBinder 完成,通常发生在各类 Stmt::create(...) 过程中(如 SelectStmtUpdateStmtFilterStmt),用于完成字段解析、类型检查与表达式重写前的语义准备。

对应代码文件:

  • src/observer/sql/parser/resolve_stage.cpp
  • src/observer/sql/stmt/stmt.cpp
  • src/observer/sql/parser/expression_binder.h
  • src/observer/sql/parser/expression_binder.cpp
  • src/observer/sql/stmt/select_stmt.cpp
  • src/observer/sql/stmt/update_stmt.cpp
  • src/observer/sql/stmt/filter_stmt.cpp

Optimizer 层说明

stmt生成不同的query plan(查询计划)并优化执行计划,后面会以此找到对应的operator(算子)。核心流程为:

Stmt -> Logical Plan -> Rewrite -> Physical Plan

语句类别与优化路径:

  1. DDL / 命令类语句:通常不生成物理计划,执行时走 CommandExecutor
  2. DML / DQL 语句:通常生成逻辑计划与物理计划后执行。

当前实现特性:

  • 支持 rewrite 迭代执行,直到计划不再变化。
  • 支持常规物理计划生成与 cascade 路径(由 session 开关控制)。
  • 支持 tuple/chunk 两种执行模式(由 session 变量控制并在优化阶段落地)。

对应代码文件:

  • src/observer/sql/optimizer/optimize_stage.h
  • src/observer/sql/optimizer/optimize_stage.cpp
  • src/observer/sql/optimizer/logical_plan_generator.h
  • src/observer/sql/optimizer/logical_plan_generator.cpp
  • src/observer/sql/optimizer/physical_plan_generator.h
  • src/observer/sql/optimizer/physical_plan_generator.cpp

Execute 层说明

Execute 层根据是否存在物理计划分流:

  • 存在 physical operator:将算子注册到 SqlResult,由输出阶段逐步执行并产出结果。
  • 不存在 physical operator 但存在 Stmt:按语句类型走 CommandExecutor(如 DDL、SET、事务控制语句等)。

对应代码文件:

  • src/observer/sql/executor/execute_stage.h
  • src/observer/sql/executor/execute_stage.cpp
  • src/observer/sql/executor/command_executor.h
  • src/observer/sql/executor/command_executor.cpp
  • src/observer/sql/executor/sql_result.h
  • src/observer/sql/executor/sql_result.cpp

Storage 层说明

存储层的metadataengine需要额外注意。每次操作都要注意元数据的存取或者更新,同样,最终交互的“契约”(CRUD)是在执行引擎中实现的。

存储侧主要分层如下:

DefaultHandler(全局入口)
-> Db(数据库生命周期、表/视图管理、buffer pool、log handler、trx kit)
-> Table(表级逻辑对象,持有 unique_ptr<TableEngine>
-> TableEngine(具体存储实现:HeapTableEngine / LsmTableEngine
-> Record / Index(记录与索引读写)
-> BufferPool + Log/WAL + DoubleWrite(页缓存与持久化保障)

开发关注点:

  • 当前代码同时支持 heap 与 lsm 两种表引擎,lsm还未实现。
  • Db 层包含恢复逻辑(recover),属于启动路径关键部分。
  • Db 不仅管理 table,也管理 view 的创建、删除和查找。

对应代码文件:

  • src/observer/storage/default/default_handler.h
  • src/observer/storage/default/default_handler.cpp
  • src/observer/storage/db/db.h
  • src/observer/storage/db/db.cpp
  • src/observer/storage/table/table.h
  • src/observer/storage/table/table.cpp
  • src/observer/storage/table/table_engine.h
  • src/observer/storage/table/heap_table_engine.h
  • src/observer/storage/table/heap_table_engine.cpp
  • src/observer/storage/table/lsm_table_engine.h
  • src/observer/storage/table/lsm_table_engine.cpp
  • src/observer/storage/buffer/disk_buffer_pool.h
  • src/observer/storage/clog/log_handler.h

事务(Trx)说明

事务对象与 session 绑定,按需创建,并下传到 record 级别的读写路径。

当前可选事务模型:

  • vacuous
  • mvcc
  • lsm

具体模式由启动参数选择,并通过 TrxKit 抽象创建和管理。

对应代码文件:

  • src/observer/storage/trx/trx.h
  • src/observer/storage/trx/trx.cpp
  • src/observer/storage/trx/vacuous_trx.h
  • src/observer/storage/trx/vacuous_trx.cpp
  • src/observer/storage/trx/mvcc_trx.h
  • src/observer/storage/trx/mvcc_trx.cpp
  • src/observer/storage/trx/lsm_mvcc_trx.h
  • src/observer/storage/trx/lsm_mvcc_trx.cpp

索引(Index)说明

索引元信息由 IndexMeta 描述,具体索引结构由 table engine 与索引实现类协同维护。

当前索引能力包括:

  • B+ 树索引。
  • 其它扩展索引实现(例如全文相关实现)。

B+ 树常用接口:

  • insert_entry
  • delete_entry
  • get_entry
  • create_scanner

对应代码文件:

  • src/observer/storage/index/index.h
  • src/observer/storage/index/index.cpp
  • src/observer/storage/index/index_meta.h
  • src/observer/storage/index/index_meta.cpp
  • src/observer/storage/index/bplus_tree.h
  • src/observer/storage/index/bplus_tree.cpp
  • src/observer/storage/index/bplus_tree_index.h
  • src/observer/storage/index/bplus_tree_index.cpp
  • src/observer/storage/index/full_text_index.h