diff --git a/README.md b/README.md index 97783bbddd714024b1aa6f827355b2b933c2c782..deacc41f1fdb31ee5b4c5537238b339d6d39e40b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,11 @@ MiniOB 是 [OceanBase](https://github.com/oceanbase/oceanbase) 与华中科技 MiniOB 设计的目标是面向在校学生、数据库从业者、爱好者,或者对基础技术有兴趣的爱好者, 整体代码量少,易于上手并学习, 是一个系统性的数据库学习项目。miniob 设置了一系列由浅入深的题目,以帮助同学们"零"基础入门, 让同学们快速了解数据库并深入学习数据库内核,期望通过相关训练之后,能够熟练掌握数据库内核模块的功能与协同关系, 并能够在使用数据库时,设计出高效的 SQL 。miniob 为了更好的学习数据库实现原理, 对诸多模块都做了简化,比如不考虑并发操作, 安全特性, 复杂的事物管理等功能。 -## 快速上手 +# GitHub Pages +代码配套文档和相关代码注释已经生成文档并通过 GitHub Pages 发布, 可以直接访问: +[MiniOB GitHub Pages](https://oceanbase.github.io/miniob/). + +# 快速上手 为了帮助开发者更好的上手并学习 miniob, 建议阅读: @@ -17,8 +21,6 @@ MiniOB 设计的目标是面向在校学生、数据库从业者、爱好者, 6. [MiniOB 各模块文档](docs/src/design/introduction.md) 7. [doxygen 代码文档](docs/doxy/html/index.html) -或者直接看 [MiniOB GitHub Pages](https://oceanbase.github.io/miniob/). - 更多的文档, 可以参考 docs 目录下的文档, 为了帮助大家更好的学习数据库基础知识, OceanBase 社区提供了一系列教程, 建议学习: 1. [《从0到1数据库内核实战教程》 视频教程](https://open.oceanbase.com/activities/4921877?id=4921946) @@ -53,7 +55,7 @@ MiniOB 整体架构如下图所示: - 客户端:作为测试工具,接收用户请求,向服务端发起请求。 -## [OceanBase 大赛](https://open.oceanbase.com/competition) +# [OceanBase 大赛](https://open.oceanbase.com/competition) 2022 OceanBase 数据库大赛是由中国计算机学会(CCF)数据库专业委员会指导,OceanBase 与蚂蚁技术研究院学术合作团队联合举办的数据库内核实战赛事。本次大赛主要面向全国爱好数据库的高校学生,以“竞技、交流、成长”为宗旨,搭建基于赛事的技术交流平台,促进高校创新人才培养机制,不仅帮助学生从0开始系统化学习数据库理论知识,提升学生数据库实践能力,更能帮助学生走向企业积累经验,促进国内数据库人才的发展,碰撞出创新的火花。 @@ -81,7 +83,7 @@ OceanBase 初赛基于一套适合初学者实践的数据库实训平台 miniob [大赛 FAQ ](https://ask.oceanbase.com/t/topic/35601465) -## 在线开发平台 +# 在线开发平台 本仓库基于 Gitpod 建立了快速在线开发平台, 点击下面按钮一键体验(建议使用 Chrome 浏览器) @@ -89,15 +91,15 @@ OceanBase 初赛基于一套适合初学者实践的数据库实训平台 miniob 首次进入 Gitpod 时需要安装一些依赖,依赖安装完成后,终端界面会显示 "Dependency installed successfully"。运行 `bash build.sh --make -j4` 命令即可编译miniob。 -## Contributing +# Contributing OceanBase 社区热情欢迎每一位对数据库技术热爱的开发者,期待携手开启思维碰撞之旅。无论是文档格式调整或文字修正、问题修复还是增加新功能,都是对 OceanBase 社区参与和贡献方式之一,立刻开启您的 First Contribution 吧!更多详情, 请参考 [社区贡献](CONTRIBUTING.md). -## License +# License MiniOB 采用 [木兰宽松许可证,第2版](https://license.coscl.org.cn/MulanPSL2), 可以自由拷贝和使用源码, 当做修改或分发时, 请遵守 [木兰宽松许可证,第2版](https://license.coscl.org.cn/MulanPSL2). -## 社区组织 +# 社区组织 - [OceanBase 社区交流群 33254054](https://h5.dingtalk.com/circle/healthCheckin.html?corpId=dingd88359ef5e4c49ef87cda005313eea7a&1fe0ca69-72d=16c86a07-83c&cbdbhh=qwertyuiop&origin=1) - [OceanBase 大赛官方交流群 35326455](https://qr.dingtalk.com/action/joingroup?code=v1,k1,g61jI0RwHQA8UMocuTbys2cyM7vck2c6jNE87vdxz9o=&_dt_no_comment=1&origin=11) diff --git a/benchmark/bplus_tree_concurrency_test.cpp b/benchmark/bplus_tree_concurrency_test.cpp index 605c4d2fe07c18abda4723c6c10a333aa76abd80..9f46bac0618c2a7d8e594f12035f41ce26fab59c 100644 --- a/benchmark/bplus_tree_concurrency_test.cpp +++ b/benchmark/bplus_tree_concurrency_test.cpp @@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */ #include #include "storage/index/bplus_tree.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "common/log/log.h" #include "integer_generator.h" diff --git a/benchmark/record_manager_concurrency_test.cpp b/benchmark/record_manager_concurrency_test.cpp index b68e766be0085b8d381dffc1f76e652ebbde5d31..218ae6fe9a74abde4d6d10fe6cdc1a1acc16c181 100644 --- a/benchmark/record_manager_concurrency_test.cpp +++ b/benchmark/record_manager_concurrency_test.cpp @@ -18,7 +18,7 @@ See the Mulan PSL v2 for more details. */ #include #include "storage/record/record_manager.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/common/condition_filter.h" #include "storage/trx/vacuous_trx.h" #include "common/log/log.h" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 63656faf2db0e5dac992227131a85d745f8c8d52..8b10af70ee43cb2176228cddc90500840ff4bb86 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -9,6 +9,7 @@ - [开发环境搭建(远程调试, 适用于 Window, Linux 和 Mac)](./dev-env/how_to_dev_in_docker_container_by_vscode.md) - [Windows 使用Docker开发MiniOB](./dev-env/how_to_dev_miniob_by_docker_on_windows.md) - [使用Docker开发MiniOB](./dev-env/how-to-dev-using-docker.md) + - [MiniOB 调试](./dev-env/miniob-how-to-debug.md) - [功能模块设计说明文档](./design/introduction.md) - [事务](./design/miniob-transaction.md) @@ -20,8 +21,12 @@ - [提交测试需要满足的输出要求](./game/miniob-output-convention.md) - [2021届大赛题目介绍](./game/miniob_topics.md) - [大赛手把手入门教程](./game/gitee-instructions.md) + - [date 测试说明](./game/miniob-test-comment-date.md) + - [date 实现解析](./game/miniob-date-implementation.md) + - [drop table 实现解析](./game/miniob-drop-table-implementation.md) - [数据库基础理论课程](./lectures/index.md) + - [版权声明](./lectures/copyright.md) - [第1章 数据库管理系统概述](./lectures/lecture-1.md) - [第2章 数据库的存储结构](./lectures/lecture-2.md) - [第3章 索引结构](./lectures/lecture-3.md) @@ -29,4 +34,3 @@ - [第5章 查询优化](./lectures/lecture-5.md) - [第6章 事务处理](./lectures/lecture-6.md) - [参考资料](./lectures/references.md) - - [版权声明](./lectures/copyright.md) \ No newline at end of file diff --git a/docs/src/dev-env/introduction.md b/docs/src/dev-env/introduction.md index 7234fc4fc93d9f945c25b45c07342832a12aed28..32b84d6407a1bc9627155e8b1c378d2915c04055 100644 --- a/docs/src/dev-env/introduction.md +++ b/docs/src/dev-env/introduction.md @@ -6,4 +6,5 @@ MiniOB 当前可以在Linux/MacOS上编译,所以开发环境最好是Linux或 - [开发环境搭建(本地调试, 适用 Linux 和 Mac)](how_to_dev_miniob_by_vscode.md) - [开发环境搭建(远程调试, 适用于 Window, Linux 和 Mac)](how_to_dev_in_docker_container_by_vscode.md) - [Windows 使用Docker开发MiniOB](how_to_dev_miniob_by_docker_on_windows.md) -- [使用Docker开发MiniOB](how-to-dev-using-docker.md) \ No newline at end of file +- [使用Docker开发MiniOB](how-to-dev-using-docker.md) +- [MiniOB 调试](./dev-env/miniob-how-to-debug.md) \ No newline at end of file diff --git a/docs/src/dev-env/miniob-how-to-debug.md b/docs/src/dev-env/miniob-how-to-debug.md new file mode 100644 index 0000000000000000000000000000000000000000..38571df660aeb7567fcc7578a9220b99b7d3647e --- /dev/null +++ b/docs/src/dev-env/miniob-how-to-debug.md @@ -0,0 +1,227 @@ +# miniob调试篇 + +-- by caizj + +调试c/c++程序,常用的有两种方式,一是打印日志调试,二是gdb调试,调试不仅可以定位问题,也可以用来熟悉代码。 + +## miniob关键代码 + +首先,拿到一份陌生的代码,要先确定代码的大致结构,一些关键数据结构和方法,这里的技巧和经验不展开了 + +### miniob的关键数据结构 + +部分关键数据结构: + +```c++ +parse_def.h: + struct Selects;//查询相关 + struct CreateTable;//建表相关 + struct DropTable;//删表相关 + enum SqlCommandFlag;//sql语句对应的command枚举 + union Queries;//各类dml和ddl操作的联合 +table.h + class Table; +db.h + class Db; +``` + +### miniob的关键接口 + +部分关键接口 + +```c++ +RC parse(const char *st, Query *sqln);//sql parse入口 +ExecuteStage::handle_request +ExecuteStage::do_select +DefaultStorageStage::handle_event +DefaultHandler::create_index +DefaultHandler::insert_record +DefaultHandler::delete_record +DefaultHandler::update_record +Db::create_table +Db::find_table +Table::create +Table::scan_record +Table::insert_record +Table::update_record +Table::delete_record +Table::scan_record +Table::create_index +``` + +### 打印日志调试 + +miniob提供的日志接口 + +```c++ +deps/common/log/log.h: +#define LOG_PANIC(fmt, ...) +#define LOG_ERROR(fmt, ...) +#define LOG_WARN(fmt, ...) +#define LOG_INFO(fmt, ...) +#define LOG_DEBUG(fmt, ...) +#define LOG_TRACE(fmt, ...) +``` + +日志相关配置项`observer.ini` + +``` +LOG_FILE_NAME = observer.log +# LOG_LEVEL_PANIC = 0, +# LOG_LEVEL_ERR = 1, +# LOG_LEVEL_WARN = 2, +# LOG_LEVEL_INFO = 3, +# LOG_LEVEL_DEBUG = 4, +# LOG_LEVEL_TRACE = 5, +# LOG_LEVEL_LAST +LOG_FILE_LEVEL=5 +LOG_CONSOLE_LEVEL=1 +``` + +### gdb调试 + +调试工具有很多种,但是它们的关键点都是类似的,比如关联到进程、运行时查看变量值、单步运行、跟踪变量等。GDB是在Linux环境中常用的调试工具。其它环境上也有类似的工具,比如LLDB,或者Windows可能使用Visual Studio直接启动调试。Java的调试工具是jdb。 + +另外,很多同学喜欢使用Visual Studio Code(vscode)开发项目,vscode提供了很多插件,包括调试的插件,这些调试插件支持gdb、lldb等,可以按照自己的平台环境,设置不同的调试工具。 + +这里介绍了gdb的基本使用,其它工具的使用方法类似。 + +1. Attach进程 + + ``` + [caizj@localhost run]$ gdb -p `pidof observer` + + GNU gdb (GDB) Red Hat Enterprise Linux 8.2-15.el8 Copyright (C) 2018 Free Software Foundation, Inc. + + (gdb) + ``` + +2. 设置断点 + + ``` + (gdb) break do_select + Breakpoint 1 at 0x44b636: file /home/caizj/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp, line 526. + (gdb) info b + Num Type Disp Enb Address What + 1 breakpoint keep y 0x000000000044b636 in ExecuteStage::do_select(char const*, Query*, SessionEvent*) + at /home/caizj/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526 + ``` + + ``` + (gdb) break Table::scan_record + Breakpoint 2 at 0x50b82b: Table::scan_record. (2 locations) + (gdb) inf b + Num Type Disp Enb Address What + 1 breakpoint keep y 0x000000000044b636 in ExecuteStage::do_select(char const*, Query*, SessionEvent*) + at /home/caizj/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526 + 2 breakpoint keep y + 2.1 y 0x000000000050b82b in Table::scan_record(Trx*, ConditionFilter*, int, void*, void (*)(char const*, void*)) + at /home/caizj/source/stunning-engine/src/observer/storage/common/table.cpp:421 + 2.2 y 0x000000000050ba00 in Table::scan_record(Trx*, ConditionFilter*, int, void*, RC (*)(Record*, void*)) + at /home/caizj/source/stunning-engine/src/observer/storage/common/table.cpp:426 + (gdb) + ``` + +3. 继续执行 + + ``` + (gdb) c + Continuing. + ``` + +4. 触发断点 + + 执行:miniob > select * from t1; + + ``` + [Switching to Thread 0x7f51345f9700 (LWP 54706)] + + Thread 8 "observer" hit Breakpoint 1, ExecuteStage::do_select (this=0x611000000540, + db=0x6040000005e0 "sys", sql=0x620000023080, session_event=0x608000003d20) + at /home/caizj/source/stunning-engine/src/observer/sql/executor/execute_stage.cpp:526 + 526 RC rc = RC::SUCCESS; + (gdb) + ``` + +5. 单步调式 + + ``` + 575 std::vector tuple_sets; + (gdb) next + 576 for (SelectExeNode *&node: select_nodes) { + (gdb) n + 577 TupleSet tuple_set; + (gdb) + 578 rc = node->execute(tuple_set); + (gdb) + ``` + +6. 跳入 + 跟踪到函数内部 + + ``` + (gdb) s + SelectExeNode::execute (this=0x60700002ce80, tuple_set=...) + at /home/caizj/source/stunning-engine/src/observer/sql/executor/execution_node.cpp:43 + 43 CompositeConditionFilter condition_filter; + (gdb) + + ``` + +7. 打印变量 + + ``` + (gdb) p tuple_set + $3 = (TupleSet &) @0x7f51345f1760: {tuples_ = std::vector of length 0, capacity 0, schema_ = { + fields_ = std::vector of length 0, capacity 0}} + (gdb) + ``` + +8. watch变量 + + ``` + (gdb) n + 443 RC rc = RC::SUCCESS; + (gdb) n + 444 RecordFileScanner scanner; + (gdb) n + 445 rc = scanner.open_scan(*data_buffer_pool_, file_id_, filter); + (gdb) watch -l rc + Hardware watchpoint 3: -location rc + (gdb) c + Continuing. + + Thread 8 "observer" hit Hardware watchpoint 3: -location rc + + Old value = SUCCESS + New value = RECORD_EOF + 0x000000000050c2de in Table::scan_record (this=0x60f000007840, trx=0x606000009920, + filter=0x7f51345f12a0, limit=2147483647, context=0x7f51345f11c0, + record_reader=0x50b74a ) + at /home/caizj/source/stunning-engine/src/observer/storage/common/table.cpp:454 + 454 for ( ; RC::SUCCESS == rc && record_count < limit; rc = scanner.get_next_record(&record)) { + (gdb) + ``` + +9. 结束函数调用 + + ``` + (gdb) finish + Run till exit from #0 0x000000000050c2de in Table::scan_record (this=0x60f000007840, + trx=0x606000009920, filter=0x7f51345f12a0, limit=2147483647, context=0x7f51345f11c0, + record_reader=0x50b74a ) + at /home/caizj/source/stunning-engine/src/observer/storage/common/table.cpp:454 + ``` + +10. 结束调试 + + ``` + (gdb) quit + A debugging session is active. + + Inferior 1 [process 54699] will be detached. + + Quit anyway? (y or n) y + Detaching from program: /home/caizj/local/bin/observer, process 54699 + [Inferior 1 (process 54699) detached] + ``` \ No newline at end of file diff --git a/docs/src/game/introduction.md b/docs/src/game/introduction.md index 0713d630b3e5a6405f272f4423f64d5ab91df1c0..5b2457e453b7956a8f764867460d52acb2cdbd3f 100644 --- a/docs/src/game/introduction.md +++ b/docs/src/game/introduction.md @@ -10,6 +10,11 @@ 作为参考,这里有第一届数据库大赛的题目介绍: [第一届数据库大赛题目介绍](./miniob_topics.md) +还有往届选手给出了一些题解: +- [date 测试说明](./miniob-test-comment-date.md) +- [date 实现解析](./miniob-date-implementation.md) +- [drop table 实现解析](./miniob-drop-table-implementation.md) + 在参赛前,除了学习基础的理论知识,还可以使用OceanBase提供的训练营,来快速上手: [训练营](https://open.oceanbase.com/train?questionId=200001) diff --git a/docs/src/game/miniob-date-implementation.md b/docs/src/game/miniob-date-implementation.md new file mode 100644 index 0000000000000000000000000000000000000000..2875347bfe8ce8868915f1c553dc2f7197545190 --- /dev/null +++ b/docs/src/game/miniob-date-implementation.md @@ -0,0 +1,162 @@ +# Date实现解析 + +> 此实现解析有往届选手提供。具体代码实现已经有所变更,因此仅供参考。 + +- by caizj + +## DATE的存储 + + +一种实现方式:date以int类型的YYYYMMDD格式保存,比如2021-10-21,保存为整数就是2021\*1000 + 10\*100 + 21,在select展示时转成字符串YYYY-MM-DD格式,注意月份和天数要使用0填充。 + +在parse.cpp中,参考 + +```c++ +int value_init_date(Value* value, const char* v) { + value->type = DATES; + int y,m,d; + sscanf(v, "%d-%d-%d", &y, &m, &d);//not check return value eq 3, lex guarantee + bool b = check_date(y,m,d); + if(!b) return -1; + int dv = y*10000+m*100+d; + value->data = malloc(sizeof(dv));//TODO:check malloc failure + memcpy(value->data, &dv, sizeof(dv)); + return 0; +} +``` + +## 修改点 + +### 语法上修改支持 + +需要可匹配date的token词和DATE_STR值(一定要先于SSS,因为date的输入DATE_STR是SSS的子集) + +语法(yacc文件)上增加type,value里增加DATE_STR值 + +```c++ +[Dd][Aa][Tt][Ee] RETURN_TOKEN(DATE_T); // 增加DATE的token,需要在yacc文件中增加DATE_T的token + +{QUOTE}[0-9]{4}\-(0?[1-9]|1[012])\-(0?[1-9]|[12][0-9]|3[01]){QUOTE} yylval->string=strdup(yytext); RETURN_TOKEN(DATE_STR); // 使用正则表达式过滤DATE。需要在yacc文件中增加 %token DATE_STR +``` + +同时,需要增加一个DATE类型,与INTS,FLOATS等含义相同: + +```c++ +// in parse_defs.h +typedef enum { UNDEFINED, CHARS, INTS, FLOATS, DATES, TEXTS, NULLS } AttrType; +``` + +### Date的合法性判断 + +输入日期的格式可以在词法分析时正则表达式里过滤掉。润年,大小月日期的合法性在普通代码中再做进一步判断。 + +在parse阶段,对date做校验,并格式化成int值保存(参考最前面的代码),同时对日期的合法性做校验,参考: + +```c++ +bool check_date(int y, int m, int d) +{ + static int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + bool leap = (y%400==0 || (y%100 && y%4==0)); + return y > 0 + && (m > 0)&&(m <= 12) + && (d > 0)&&(d <= ((m==2 && leap)?1:0) + mon[m]); +} +``` + +### 增加新的类型date枚举 + +代码里有多处和类型耦合地方(增加一个类型,要动很多处离散的代码,基础代码在这方面的可维护性不好) + +包括不限于,以下几处: + +- DefaultConditionFilter +需要增加DATES类型的数据对比。因为这里将date作为整数存储,那么可以直接当做INTS来对比,比如: + +```c++ + case INTS: + case DATES: { + // 没有考虑大小端问题 + // 对int和float,要考虑字节对齐问题,有些平台下直接转换可能会跪 + int left = *(int *)left_value; + int right = *(int *)right_value; + cmp_result = left - right; + } break; +``` + +- BplusTreeScanner +与 `DefaultConditionFilter` 类似,也需要支持DATE类型的对比,可以直接当做整数比较。参考其中一块代码: + +```c++ +case INTS:case DATES: { + i1 = *(int *) pdata; + i2 = *(int *) pkey; + if (i1 > i2) + return 1; + if (i1 < i2) + return -1; + if (i1 == i2) + return 0; + } + break; +``` + +- ATTR_TYPE_NAME(storage/common/field_meta.cpp) +保存元数据时,需要这里的信息,比较简单,参考: + +```c++ +const char *ATTR_TYPE_NAME[] = { + "undefined", + "chars", + "ints", + "floats", + "dates" +}; +``` + +- insert_record_from_file(storage/default/default_storage_stage.cpp) + +这个接口主要是为了支持从文件导入数据的,同样,实现可以与int类型保持一致。 + +```c++ +switch (field->type()) { + case INTS: case DATES:{ + deserialize_stream.clear(); // 清理stream的状态,防止多次解析出现异常 + deserialize_stream.str(file_value); + + int int_value; + deserialize_stream >> int_value; + if (!deserialize_stream || !deserialize_stream.eof()) { + errmsg << "need an integer but got '" << file_values[i] + << "' (field index:" << i << ")"; + + rc = RC::SCHEMA_FIELD_TYPE_MISMATCH; + } else { + value_init_integer(&record_values[i], int_value); + } + } +``` + +### Date select展示 + +TupleRecordConverter::add_record时做格式转换,需要按照输出要求,将日期类型数据,转换成合适的字符串。参考: + +```c++ +case DATES: { + int value = *(int*)(record + field_meta->offset()); + char buf[16] = {0}; + snprintf(buf,sizeof(buf),"%04d-%02d-%02d",value/10000, (value%10000)/100,value%100); // 注意这里月份和天数,不足两位时需要填充0 + tuple.add(buf,strlen(buf)); +} +break; +``` + +### 异常失败处理 + +只要输入的日期不合法,输出都是FAILURE\n。包括查询的where条件、插入的日期值、更新的值等。这里在解析时(parse.cpp)中就可以直接返回错误。 + +## 自测覆盖点 + +1. 日期输入,包括合法和非法日期格式。非法日期可以写单元测试做。 +2. 日期值比较=、 >、 <、 >=、 <= +3. 日期字段当索引。很多同学漏掉了这个点。 +4. 日期展示格式,注意月份和天数补充0 \ No newline at end of file diff --git a/docs/src/game/miniob-drop-table-implementation.md b/docs/src/game/miniob-drop-table-implementation.md new file mode 100644 index 0000000000000000000000000000000000000000..62017f27e86c52ea2f62092f84dedda4af57e1bd --- /dev/null +++ b/docs/src/game/miniob-drop-table-implementation.md @@ -0,0 +1,103 @@ +# miniob - drop table 实现解析 + +> 此实现解析有往届选手提供。具体代码实现已经有所变更,因此仅供参考。 + +**代码部分主要添加在:** + +drop table 与create table相反,要清理掉所有创建表和表相关联的资源,比如描述表的文件、数据文件以及索引等相关数据和文件。 + +sql流转到default_storge阶段的时候,在处理sql的函数中,新增一个drop_table的case。 + +drop table就是删除表,在`create table t`时,会新建一个t.table文件,同时为了存储数据也会新建一个t.data文件存储下来。同时创建索引的时候,也会创建记录索引数据的文件,在删除表时也要一起删除掉。 + +那么删除表,就需要**删除t.table文件、t.data文件和关联的索引文件**。 + +同时由于buffer pool的存在,在新建表和插入数据的时候,会写入buffer pool缓存。所以drop table,不仅需要删除文件,也需要**清空buffer pool** ,防止在数据没落盘的时候,再建立同名表,仍然可以查询到数据。 + +如果建立了索引,比如t_id on t(id),那么也会新建一个t_id.index文件,也需要删除这个文件。 + +这些东西全部清空,那么就完成了drop table。 + +具体的代码实现如下: +在default_storage_stage.cpp 中的处理SQL语句的case中增加一个 + +```c++ + case SCF_DROP_TABLE: { + const DropTable& drop_table = sql->sstr[sql->q_size-1].drop_table; // 拿到要drop 的表 + rc = handler_->drop_table(current_db,drop_table.relation_name); // 调用drop table接口,drop table要在handler中实现 + snprintf(response,sizeof(response),"%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE"); // 返回结果,带不带换行符都可以 + } +break; +``` + +在default_handler.cpp文件中,实现handler的drop_table接口: + +```c++ +RC DefaultHandler::drop_table(const char *dbname, const char *relation_name) { + Db *db = find_db(dbname); // 这是原有的代码,用来查找对应的数据库,不过目前只有一个库 + if(db == nullptr) { + return RC::SCHEMA_DB_NOT_OPENED; + } + return db->drop_table(relation_name); // 直接调用db的删掉接口 +} +``` + +在db.cpp中,实现drop_table接口 + +```c++ +RC Db::drop_table(const char* table_name) +{ + auto it = opened_tables_.find(table_name); + if (it == opened_tables_.end()) + { + return SCHEMA_TABLE_NOT_EXIST; // 找不到表,要返回错误,测试程序中也会校验这种场景 + } + Table* table = it->second; + RC rc = table->destroy(path_.c_str()); // 让表自己销毁资源 + if(rc != RC::SUCCESS) return rc; + + opened_tables_.erase(it); // 删除成功的话,从表list中将它删除 + delete table; + return RC::SUCCESS; +} +``` + +table.cpp中清理文件和相关数据 + +```c++ +RC Table::destroy(const char* dir) { + RC rc = sync();//刷新所有脏页 + + if(rc != RC::SUCCESS) return rc; + + std::string path = table_meta_file(dir, name()); + if(unlink(path.c_str()) != 0) { + LOG_ERROR("Failed to remove meta file=%s, errno=%d", path.c_str(), errno); + return RC::GENERIC_ERROR; + } + + std::string data_file = std::string(dir) + "/" + name() + TABLE_DATA_SUFFIX; + if(unlink(data_file.c_str()) != 0) { // 删除描述表元数据的文件 + LOG_ERROR("Failed to remove data file=%s, errno=%d", data_file.c_str(), errno); + return RC::GENERIC_ERROR; + } + + std::string text_data_file = std::string(dir) + "/" + name() + TABLE_TEXT_DATA_SUFFIX; + if(unlink(text_data_file.c_str()) != 0) { // 删除表实现text字段的数据文件(后续实现了text case时需要考虑,最开始可以不考虑这个逻辑) + LOG_ERROR("Failed to remove text data file=%s, errno=%d", text_data_file.c_str(), errno); + return RC::GENERIC_ERROR; + } + + const int index_num = table_meta_.index_num(); + for (int i = 0; i < index_num; i++) { // 清理所有的索引相关文件数据与索引元数据 + ((BplusTreeIndex*)indexes_[i])->close(); + const IndexMeta* index_meta = table_meta_.index(i); + std::string index_file = index_data_file(dir, name(), index_meta->name()); + if(unlink(index_file.c_str()) != 0) { + LOG_ERROR("Failed to remove index file=%s, errno=%d", index_file.c_str(), errno); + return RC::GENERIC_ERROR; + } + } + return RC::SUCCESS; +} +``` \ No newline at end of file diff --git a/docs/src/game/miniob-output-convention.md b/docs/src/game/miniob-output-convention.md index 285c9ebc62e21c36e375d9abb0e170690be6b47b..7c59a8341b1533c57a2be8f881f80cbdcd6ea9ff 100644 --- a/docs/src/game/miniob-output-convention.md +++ b/docs/src/game/miniob-output-convention.md @@ -6,6 +6,8 @@ 输出是指服务端返回给客户端的数据。为了可以做测试,需要对输出的格式做约定。 NOTE:后台测试程序,是将预先编辑好的Case执行后,将执行结果与预期输出结果(预先编写完成)做对比,与mysql test工作原理类似,因此需要严格按照输出约束来输出。 +> 这里虽然列出了很多约束条件,但是同学们并不需要担心,当前的实现已经满足了这些约束条件,或者给出了满足约束的帮助函数,只要按照要求使用即可。 + 1. 语法解析错误,返回 FAILURE(只返回这个字符串,不带任何多余字符)。 2. 对于DML和DDL操作,执行成功返回SUCCESS,失败返回FAILURE。更新和删除操作时没有数据变更,只要没有错误,输出也是SUCCESS。 3. 对于QUERY操作,如果执行失败,返回FAILURE(包括语法错误)。否则按照下面的格式要求输出:列名显示和顺序说明: @@ -23,7 +25,7 @@ NOTE:后台测试程序,是将预先编辑好的Case执行后,将执行结 4. 所有输出不区分大小写 5. 日期(date)输出格式使用:"YYYY-mm-DD" 6. 输出的字符串不使用单引号双引号或其它括起来 -7. 浮点数输出,不要带后面多余的0,可以参考C sprintf的%g格式输出,保留两位小数。 +7. 浮点数输出,不要带后面多余的0,可以参考C sprintf的%g格式输出,保留两位小数。参考函数 double_to_str FAQ - 某张表或者某个查询结果一行数据都没有,但是依然需要输出表头信息 diff --git a/docs/src/game/miniob-test-comment-date.md b/docs/src/game/miniob-test-comment-date.md new file mode 100644 index 0000000000000000000000000000000000000000..02abe2542beabed8fd00d93adc2bd7cb6d735406 --- /dev/null +++ b/docs/src/game/miniob-test-comment-date.md @@ -0,0 +1,83 @@ + +> 此实现解析有往届选手提供。具体代码实现已经有所变更,因此仅供参考。 + +miniob-date 测试解说 + +本篇文章针对在miniob中增加date字段类型做解析,希望可以帮助参加比赛的同学能够顺利通过。 + +# 题目描述 + +date测试不会超过2038年2月,不会小于1970年1月1号。注意处理非法的date输入,需要返回FAILURE。 + +## 测试示例 + +create table t(id int, birthday date); + +insert into t values(1, '2020-09-10'); + +insert into t values(2, '2021-1-2'); + +select * from t; + +> 注意:所有的字符都是英文。浏览器如果将英文字符转成中文字符,请留意。 + +# 如何选择date的存储长度 + +当前已经有的字段类型有:INTS/FLOATS/CHARS,这几个字段的内存大小都是4个字节。而题目中要求 date 类型,时间范围在1970年1月1日和2038年2月之间,说明date 字段也可以用4个字段来存储。这个原理可以参考time函数的说明,4个字节存储的时间戳,如果起始时间是1970年1月1日,那么将会在2038年某一天越界,而这一天是在2038年2月之后的。因此 date 字段也可以使用 `4 字节`存储。 + +使用4字节存储的好处还有,可以将4字节数据直接当做一个整数来处理,这样做比较运算时,也可以直接使用整数运算。 + + +# 如何解析date 相关SQL + +date作为一个关键字,可以直接在lex文件中添加。 + +\[Dd\]\[Aa\]\[Tt\]\[Ee\] RETURN_TOKEN(DATE); + +当然也需要增加token DATE。 + +对于日期数据,比如"2021-10-25",建议不要在词法解析和语法解析模块中写正则表达式来解析,因为它本身就是一个字符串。如果写正则表达式来解析,那就不能再将它作为普通字符串来处理,另外,正则表达式规则将会非常复杂,难以维护和扩展。比如我想让日期支持更多的格式:"2021/10/25","2021年10月25日";对与普通的字符串字段,理论上是能够接收"2021-10-25",这样的字符串作为参数去更新或插入的,如果在词法/语法解析中处理,那还需要处理使用日期更新字符串字段的场景。 + + + +# 需要考虑的场景 + +## 日期解析 + +需要判断类型为日期的地方,都需要按照一定格式去解析日期。当前输入格式年月日是按照'-'来分隔的,这样就非常简单了。将字符串分割为3个字符串,然后分别当成数字解析就可以。 + + + +## 日期是否合法 + +用字符串表示日期是有合法性要求的。比如2021-02-30,就不能算是正确的日期。 + +可能出现日期的地方有(不一定全面): + +- 插入数据的值; + +- 更新数据的值; + +- 比较条件中的日期; + +考虑再周全一点,可以支持一下聚合函数中有date数据类型。 + + + +## 建表 + +建表需要支持date类型字段 + +## 建索引 + +当前Miniob默认支持了B+-Tree索引,需要对这个索引做扩展。 + +## 日期比较 + +查询条件中可能有日期,查询可能是通过索引查询,也可能只是普通的查询。 + + + +## 输出格式 + +注意按照题目提示来输出 "YYYY-mm-dd",位数不够,需要用'0'填充。 diff --git a/docs/src/how_to_run.md b/docs/src/how_to_run.md index e2467de3b99e85abff9c558a0a081cec50399119..64dc2ba78b742dbf6e220030ae07c4cdd906e724 100644 --- a/docs/src/how_to_run.md +++ b/docs/src/how_to_run.md @@ -32,5 +32,21 @@ ``` 这会连接到服务端的miniob.sock文件。 +**并发模式** + +默认情况下,编译出的程序是不支持并发的。如果需要支持并发,需要在编译时增加选项 `-DCONCURRENCY=ON`: +```bash +cmake -DCONCURRENCY=ON .. +``` + +或者 + +```bash +bash build.sh -DCONCURRENCY=ON +``` + +然后使用上面的命令启动服务端程序,就可以支持并发了。 + **更多** -observer还提供了一些其它参数,可以通过./bin/observer -h查看。 + +observer还提供了一些其它参数,可以通过`./bin/observer -h`查看。 diff --git a/docs/src/lectures/copyright.md b/docs/src/lectures/copyright.md index 5207193a548d5c5c52f762081fc25222ad0279ed..685063a54315f95839a876a592967f52cda23004 100644 --- a/docs/src/lectures/copyright.md +++ b/docs/src/lectures/copyright.md @@ -1,5 +1,7 @@ # 版权声明 +本版权声明仅针对《数据库管理系统实现基础讲义》(以下简称“本教材”)的所有内容。 + 1. 本教材刊载的所有内容,包括但不限于文字报道、图片、视频、图表、标志标识、商标、版面设计、专栏目录与名称、内容分类标准等,均受《中华人民共和国著作权法》、《中华人民共和国商标法》、《中华人民共和国专利法》及适用之国际公约中有关著作权、商标权、专利权以及或其它财产所有权法律的保护,相应的版权或许可使用权均属华中科技大学谢美意老师、左琼老师所有。 2. 凡未经华中科技大学谢美意老师、左琼老师授权,任何媒体、网站及个人不得转载、复制、重制、改动、展示或使用《数据库管理系统实现基础讲义》的局部或全部的内容。如果已转载,请自行删除。同时,我们保留进一步追究相关行为主体的法律责任的权利。 3. 本教材刊载的所有内容授权给北京奥星贝斯科技有限公司。 diff --git a/docs/src/lectures/index.md b/docs/src/lectures/index.md index b15007715730cdaeb31ef35ce7fadde53f0b6e53..3f50d6269393363bd6a59f7817483a8ccb6b2e21 100644 --- a/docs/src/lectures/index.md +++ b/docs/src/lectures/index.md @@ -2,6 +2,7 @@ 作者 华中科技大学谢美意 左琼 +[版权声明](copyright.md) [第1章 数据库管理系统概述](lecture-1.md) @@ -16,5 +17,3 @@ [第6章 事务处理](lecture-6.md) [参考资料](references.md) - -[版权声明](copyright.md) diff --git a/src/observer/common/init.cpp b/src/observer/common/init.cpp index 5f92ff8bba0d141aa71a6514c6663e1f14385d91..a415ebdaff7ae55d5b23ddc5703b22296286d02c 100644 --- a/src/observer/common/init.cpp +++ b/src/observer/common/init.cpp @@ -37,7 +37,7 @@ See the Mulan PSL v2 for more details. */ #include "sql/query_cache/query_cache_stage.h" #include "storage/default/default_storage_stage.h" #include "storage/mem/mem_storage_stage.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/default/default_handler.h" #include "storage/trx/trx.h" #include "global_context.h" diff --git a/src/observer/net/mysql_communicator.cpp b/src/observer/net/mysql_communicator.cpp index b24b41f5f90456a1bff42832bd8cc84873a1a068..fd57818a2df4b4a9a0e57bc4b66766a95a0817f8 100644 --- a/src/observer/net/mysql_communicator.cpp +++ b/src/observer/net/mysql_communicator.cpp @@ -115,7 +115,6 @@ enum enum_field_types * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int1(char *buf, int8_t value) { @@ -130,7 +129,6 @@ int store_int1(char *buf, int8_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int2(char *buf, int16_t value) { @@ -145,7 +143,6 @@ int store_int2(char *buf, int16_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int3(char *buf, int32_t value) { @@ -160,7 +157,6 @@ int store_int3(char *buf, int32_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int4(char *buf, int32_t value) { @@ -175,7 +171,6 @@ int store_int4(char *buf, int32_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int6(char *buf, int64_t value) { @@ -190,7 +185,6 @@ int store_int6(char *buf, int64_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_int8(char *buf, int64_t value) { @@ -205,7 +199,6 @@ int store_int8(char *buf, int64_t value) * @param value 要写入的值 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_lenenc_int(char *buf, uint64_t value) { @@ -238,7 +231,6 @@ int store_lenenc_int(char *buf, uint64_t value) * @param s 要写入的字符串 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_null_terminated_string(char *buf, const char *s) { @@ -259,7 +251,6 @@ int store_null_terminated_string(char *buf, const char *s) * @param len 字符串的长度 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_fix_length_string(char *buf, const char *s, int len) { @@ -278,7 +269,6 @@ int store_fix_length_string(char *buf, const char *s, int len) * @param s 要写入的字符串 * @return int 写入的字节数 * @ingroup MySQLProtocolStore - * @ingroup MySQLProtocol */ int store_lenenc_string(char *buf, const char *s) { @@ -290,8 +280,8 @@ int store_lenenc_string(char *buf, const char *s) /** * @brief 每个包都有一个包头 - * https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_packets.html - * https://mariadb.com/kb/en/0-packet/ + * @details [MySQL Basic Packet](https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_packets.html) + * [MariaDB Packet](https://mariadb.com/kb/en/0-packet/) * @ingroup MySQLProtocol */ struct PacketHeader @@ -302,7 +292,7 @@ struct PacketHeader /** * @brief 所有的包都继承自BasePacket - * @details 所有的包都有一个包头,所以BasePacket中包含了一个PacketHeader + * @details 所有的包都有一个包头,所以BasePacket中包含了一个 @ref PacketHeader * @ingroup MySQLProtocol */ class BasePacket @@ -320,8 +310,8 @@ public: /** * @brief 将当前包编码成网络包 * - * @param capabilities MySQL协议中的capability标志 - * @param net_packet 编码后的网络包 + * @param[in] capabilities MySQL协议中的capability标志 + * @param[out] net_packet 编码后的网络包 */ virtual RC encode(uint32_t capabilities, std::vector &net_packet) const = 0; }; @@ -331,7 +321,7 @@ public: * @ingroup MySQLProtocol * @details 先由服务端发送到客户端。 * 这个包会交互capability与用户名密码。 - * https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_v10.html + * [MySQL Handshake]https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_v10.html */ struct HandshakeV10 : public BasePacket { diff --git a/src/observer/sql/stmt/create_index_stmt.h b/src/observer/sql/stmt/create_index_stmt.h index fae56395c49fa557294c6b25671c3edc291e2bad..56504e15d1b55af58a9887f18db08009fcd75cb9 100644 --- a/src/observer/sql/stmt/create_index_stmt.h +++ b/src/observer/sql/stmt/create_index_stmt.h @@ -22,6 +22,10 @@ struct CreateIndex; class Table; class FieldMeta; +/** + * @brief 创建索引的语句 + * @ingroup Statement + */ class CreateIndexStmt : public Stmt { public: diff --git a/src/observer/sql/stmt/create_table_stmt.h b/src/observer/sql/stmt/create_table_stmt.h index 1db6c1978dc77d030652445f1ab4dad6fc6dfac5..00381c72066641c615533e0e12cf4de18668dfa0 100644 --- a/src/observer/sql/stmt/create_table_stmt.h +++ b/src/observer/sql/stmt/create_table_stmt.h @@ -23,6 +23,7 @@ class Db; /** * @brief 表示创建表的语句 + * @ingroup Statement * @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多 */ class CreateTableStmt : public Stmt diff --git a/src/observer/sql/stmt/delete_stmt.h b/src/observer/sql/stmt/delete_stmt.h index 54914fbff53277ceafb827af43f1f3ccc1529266..86a6752576947e8504a403100958f28802c3ead7 100644 --- a/src/observer/sql/stmt/delete_stmt.h +++ b/src/observer/sql/stmt/delete_stmt.h @@ -20,6 +20,10 @@ See the Mulan PSL v2 for more details. */ class Table; class FilterStmt; +/** + * @brief Delete 语句 + * @ingroup Statement + */ class DeleteStmt : public Stmt { public: diff --git a/src/observer/sql/stmt/desc_table_stmt.h b/src/observer/sql/stmt/desc_table_stmt.h index 53605685eeb43e1a8b31d4242e6c19c6e10ffec1..623209538bb7f0df9381bb10d239b5d1ad28e3cd 100644 --- a/src/observer/sql/stmt/desc_table_stmt.h +++ b/src/observer/sql/stmt/desc_table_stmt.h @@ -23,6 +23,7 @@ class Db; /** * @brief 描述表的语句 + * @ingroup Statement * @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多 */ class DescTableStmt : public Stmt diff --git a/src/observer/sql/stmt/exit_stmt.h b/src/observer/sql/stmt/exit_stmt.h index e7eb29c745b90f56fe8089a7a129912ce6be177f..aa91803bea517c25babd31327f1c460abaacd192 100644 --- a/src/observer/sql/stmt/exit_stmt.h +++ b/src/observer/sql/stmt/exit_stmt.h @@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */ /** * @brief Exit 语句,表示断开连接,现在什么成员都没有 + * @ingroup Statement */ class ExitStmt : public Stmt { diff --git a/src/observer/sql/stmt/explain_stmt.h b/src/observer/sql/stmt/explain_stmt.h index 31b27452019cda7d50b02e9c7bd98ccedda7e586..93c69482ce1c652cb689c85f56223caf9469f90e 100644 --- a/src/observer/sql/stmt/explain_stmt.h +++ b/src/observer/sql/stmt/explain_stmt.h @@ -17,6 +17,10 @@ See the Mulan PSL v2 for more details. */ #include #include "sql/stmt/stmt.h" +/** + * @brief explain语句 + * @ingroup Statement + */ class ExplainStmt : public Stmt { public: diff --git a/src/observer/sql/stmt/filter_stmt.h b/src/observer/sql/stmt/filter_stmt.h index 31bef245cbeb47247f0f7bccd65ff297eb6c5a38..79a29bb62f8371a5d2eab22d03f2a21e55de1109 100644 --- a/src/observer/sql/stmt/filter_stmt.h +++ b/src/observer/sql/stmt/filter_stmt.h @@ -84,6 +84,10 @@ private: FilterObj right_; }; +/** + * @brief Filter/谓词/过滤语句 + * @ingroup Statement + */ class FilterStmt { public: diff --git a/src/observer/sql/stmt/help_stmt.h b/src/observer/sql/stmt/help_stmt.h index 8b3b880d186829dff754a3dd4b78ff19b7c17088..518f8b92193fd205f465a2d68abc751862d2d4a4 100644 --- a/src/observer/sql/stmt/help_stmt.h +++ b/src/observer/sql/stmt/help_stmt.h @@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */ /** * @brief Help 语句,现在什么成员都没有 + * @ingroup Statement */ class HelpStmt : public Stmt { diff --git a/src/observer/sql/stmt/insert_stmt.h b/src/observer/sql/stmt/insert_stmt.h index 3af4f5e968e8ac79d7d7c4f1ce82a9433f9997a3..1fc6711e3216733e6aceffbc3b9c2ac448df9bab 100644 --- a/src/observer/sql/stmt/insert_stmt.h +++ b/src/observer/sql/stmt/insert_stmt.h @@ -20,6 +20,10 @@ See the Mulan PSL v2 for more details. */ class Table; class Db; +/** + * @brief 插入语句 + * @ingroup Statement + */ class InsertStmt : public Stmt { public: diff --git a/src/observer/sql/stmt/select_stmt.h b/src/observer/sql/stmt/select_stmt.h index c6766a88e95771dc554dd34327e04c5752fc5294..57bcef9aa957f58ccbd0d23eef5e57fffcaca577 100644 --- a/src/observer/sql/stmt/select_stmt.h +++ b/src/observer/sql/stmt/select_stmt.h @@ -25,6 +25,10 @@ class FilterStmt; class Db; class Table; +/** + * @brief 表示select语句 + * @ingroup Statement + */ class SelectStmt : public Stmt { public: diff --git a/src/observer/sql/stmt/show_tables_stmt.h b/src/observer/sql/stmt/show_tables_stmt.h index 08b456cfde5323de86764201a484c8c33b7fcc6b..62ffdd6c2c267736c0140bc25ba2c3da01a703d3 100644 --- a/src/observer/sql/stmt/show_tables_stmt.h +++ b/src/observer/sql/stmt/show_tables_stmt.h @@ -23,6 +23,7 @@ class Db; /** * @brief 描述表的语句 + * @ingroup Statement * @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多 */ class ShowTablesStmt : public Stmt diff --git a/src/observer/sql/stmt/stmt.h b/src/observer/sql/stmt/stmt.h index 2b1ccafb1fe8960b94b55e2f041eb8f25dc7616b..bdfbf1c9c796c4d0736dab4d75ce69d3a018c0f8 100644 --- a/src/observer/sql/stmt/stmt.h +++ b/src/observer/sql/stmt/stmt.h @@ -19,6 +19,16 @@ See the Mulan PSL v2 for more details. */ class Db; +/** + * @brief Statement SQL语句解析后通过Resolver转换成Stmt + * @defgroup Statement + * @file stmt.h + */ + +/** + * @brief Statement的类型 + * + */ #define DEFINE_ENUM() \ DEFINE_ENUM_ITEM(SELECT) \ DEFINE_ENUM_ITEM(INSERT) \ @@ -58,6 +68,7 @@ inline const char *stmt_type_name(StmtType type) /** * @brief Stmt for Statement + * @ingroup Statement * @details SQL解析后的语句,再进一步解析成Stmt,使用内部的数据结构来表示。 * 比如table_name,解析成具体的 Table对象,attr/field name解析成Field对象。 */ diff --git a/src/observer/sql/stmt/trx_begin_stmt.h b/src/observer/sql/stmt/trx_begin_stmt.h index f1335d9d1d71835ca8a744b46bcc65764b3cddad..555ce0ca70fe34c56ec38389f25ee34182da98a0 100644 --- a/src/observer/sql/stmt/trx_begin_stmt.h +++ b/src/observer/sql/stmt/trx_begin_stmt.h @@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */ /** * @brief 事务的Begin 语句,现在什么成员都没有 + * @ingroup Statement */ class TrxBeginStmt : public Stmt { diff --git a/src/observer/sql/stmt/trx_end_stmt.h b/src/observer/sql/stmt/trx_end_stmt.h index fc126b71e6a551d7231b7a38b7135e33af237ef8..476b60e59e4caf661fb48c3c9b901eb7ff1513b8 100644 --- a/src/observer/sql/stmt/trx_end_stmt.h +++ b/src/observer/sql/stmt/trx_end_stmt.h @@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */ /** * @brief 事务的 Commit/Rollback 语句,现在什么成员都没有 + * @ingroup Statement */ class TrxEndStmt : public Stmt { diff --git a/src/observer/sql/stmt/update_stmt.h b/src/observer/sql/stmt/update_stmt.h index 3148bb2a78de082fd3515462c14f8222a8513880..cc617fe4c3b7421ff80f00531a527efb52bc9554 100644 --- a/src/observer/sql/stmt/update_stmt.h +++ b/src/observer/sql/stmt/update_stmt.h @@ -19,6 +19,10 @@ See the Mulan PSL v2 for more details. */ class Table; +/** + * @brief 更新语句 + * @ingroup Statement + */ class UpdateStmt : public Stmt { public: diff --git a/src/observer/storage/default/disk_buffer_pool.cpp b/src/observer/storage/buffer/disk_buffer_pool.cpp similarity index 99% rename from src/observer/storage/default/disk_buffer_pool.cpp rename to src/observer/storage/buffer/disk_buffer_pool.cpp index 5dea9712dc2e442f3c4d9134bac8aee621347348..5c2e4a72d84bf2161163e20c87f8291a0ac7ee30 100644 --- a/src/observer/storage/default/disk_buffer_pool.cpp +++ b/src/observer/storage/buffer/disk_buffer_pool.cpp @@ -14,7 +14,7 @@ See the Mulan PSL v2 for more details. */ #include #include -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "common/lang/mutex.h" #include "common/log/log.h" #include "common/os/os.h" diff --git a/src/observer/storage/default/disk_buffer_pool.h b/src/observer/storage/buffer/disk_buffer_pool.h similarity index 94% rename from src/observer/storage/default/disk_buffer_pool.h rename to src/observer/storage/buffer/disk_buffer_pool.h index 10d0e53a8ee5cec06170b49bb0cb95f860a43a74..fc6412c60aecc8291f4ab736de0a20f3da14d972 100644 --- a/src/observer/storage/default/disk_buffer_pool.h +++ b/src/observer/storage/buffer/disk_buffer_pool.h @@ -37,10 +37,16 @@ See the Mulan PSL v2 for more details. */ class BufferPoolManager; class DiskBufferPool; +/** + * @brief BufferPool 的实现 + * @defgroup BufferPool + */ + #define BP_FILE_SUB_HDR_SIZE (sizeof(BPFileSubHeader)) /** - * BufferPool的文件第一个页面,存放一些元数据信息,包括了后面每页的分配信息。 + * @brief BufferPool的文件第一个页面,存放一些元数据信息,包括了后面每页的分配信息。 + * @ingroup BufferPool * TODO 1. 当前的做法,只能分配比较少的页面,你可以扩展一下,支持更多的页面或无限多的页面吗? * 可以参考Linux ext(n)和Windows NTFS等文件系统 * 2. 当前使用bitmap存放页面分配情况,但是这种方法在页面非常多的时候,查找空闲页面的 @@ -60,6 +66,10 @@ struct BPFileHeader std::string to_string() const; }; +/** + * @brief 管理页面Frame + * @ingroup BufferPool + */ class BPFrameManager { public: @@ -123,6 +133,10 @@ private: FrameAllocator allocator_; }; +/** + * @brief 用于遍历BufferPool中的所有页面 + * @ingroup BufferPool + */ class BufferPoolIterator { public: @@ -139,6 +153,10 @@ private: PageNum current_page_num_ = -1; }; +/** + * @brief BufferPool的实现 + * @ingroup BufferPool + */ class DiskBufferPool { public: @@ -252,6 +270,10 @@ private: friend class BufferPoolIterator; }; +/** + * @brief BufferPool的管理类 + * @ingroup BufferPool + */ class BufferPoolManager { public: diff --git a/src/observer/storage/buffer/frame.h b/src/observer/storage/buffer/frame.h index 47ec590eda4346454e0ef25dc7733961390196da..6b9e312e88206fe1891d1eb76034601e3284f719 100644 --- a/src/observer/storage/buffer/frame.h +++ b/src/observer/storage/buffer/frame.h @@ -26,6 +26,10 @@ See the Mulan PSL v2 for more details. */ #include "common/lang/mutex.h" #include "common/types.h" +/** + * @brief 页帧标识符 + * @ingroup BufferPool + */ class FrameId { public: @@ -42,6 +46,10 @@ private: PageNum page_num_; }; +/** + * @brief 页帧 + * @ingroup BufferPool + */ class Frame { public: diff --git a/src/observer/storage/buffer/page.h b/src/observer/storage/buffer/page.h index 0f08852015e2563cf5302ce9010a7abbcff9aee7..a16e7c9da16d4a1c84b3f2e5dd825791dfd63f60 100644 --- a/src/observer/storage/buffer/page.h +++ b/src/observer/storage/buffer/page.h @@ -30,6 +30,10 @@ static constexpr int LOG_BUFFER_SIZE = 1<<10; // TODO move to log record static constexpr const int BP_PAGE_SIZE = (1 << 13); static constexpr const int BP_PAGE_DATA_SIZE = (BP_PAGE_SIZE - sizeof(PageNum) - sizeof(LSN)); +/** + * @brief 表示一个页面,可能放在内存或磁盘上 + * @ingroup BufferPool + */ struct Page { PageNum page_num; diff --git a/src/observer/storage/index/bplus_tree.cpp b/src/observer/storage/index/bplus_tree.cpp index 9070cae157b0a5cfcba93a68d4cf5d702b24b829..590b9b3970579e59d23de5a2e57870e4efa8dfa9 100644 --- a/src/observer/storage/index/bplus_tree.cpp +++ b/src/observer/storage/index/bplus_tree.cpp @@ -13,7 +13,7 @@ See the Mulan PSL v2 for more details. */ // Rewritten by Longda & Wangyunlai // #include "storage/index/bplus_tree.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "common/log/log.h" #include "sql/parser/parse_defs.h" #include "common/lang/lower_bound.h" diff --git a/src/observer/storage/index/bplus_tree.h b/src/observer/storage/index/bplus_tree.h index 69c368c8ca10e4964cf1a00580b9eea98b281e47..91e8c66d382804085d1a76ee7cc0f6df3dbcccbe 100644 --- a/src/observer/storage/index/bplus_tree.h +++ b/src/observer/storage/index/bplus_tree.h @@ -23,15 +23,24 @@ See the Mulan PSL v2 for more details. */ #include #include "storage/record/record_manager.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/trx/latch_memo.h" #include "sql/parser/parse_defs.h" #include "common/lang/comparator.h" #include "common/log/log.h" +/** + * @brief B+树的实现 + * @defgroup B+Tree + */ + #define EMPTY_RID_PAGE_NUM -1 // TODO remove me #define EMPTY_RID_SLOT_NUM -1 +/** + * @brief B+树的操作类型 + * @ingroup B+Tree + */ enum class BplusTreeOperationType { READ, @@ -39,6 +48,10 @@ enum class BplusTreeOperationType DELETE, }; +/** + * @brief 属性比较 + * @ingroup B+Tree + */ class AttrComparator { public: @@ -77,6 +90,10 @@ private: int attr_length_; }; +/** + * @brief 键值比较 + * @ingroup B+Tree + */ class KeyComparator { public: @@ -106,6 +123,10 @@ private: AttrComparator attr_comparator_; }; +/** + * @brief 属性打印,调试使用 + * @ingroup B+Tree + */ class AttrPrinter { public: @@ -151,6 +172,10 @@ private: int attr_length_; }; +/** + * @brief 键值打印,调试使用 + * @ingroup B+Tree + */ class KeyPrinter { public: @@ -179,8 +204,9 @@ private: }; /** - * the meta information of bplus tree - * this is the first page of bplus tree. + * @brief the meta information of bplus tree + * @ingroup B+Tree + * @details this is the first page of bplus tree. * only one field can be supported, can you extend it to multi-fields? */ struct IndexFileHeader @@ -213,7 +239,8 @@ struct IndexFileHeader }; /** - * the common part of page describtion of bplus tree + * @brief the common part of page describtion of bplus tree + * @ingroup B+Tree * storage format: * | page type | item number | parent page id | */ @@ -227,7 +254,8 @@ struct IndexNode }; /** - * leaf page of bplus tree + * @brief leaf page of bplus tree + * @ingroup B+Tree * storage format: * | common header | prev page id | next page id | * | key0, rid0 | key1, rid1 | ... | keyn, ridn | @@ -249,7 +277,8 @@ struct LeafIndexNode : public IndexNode }; /** - * internal page of bplus tree + * @brief internal page of bplus tree + * @ingroup B+Tree * storage format: * | common header | * | key(0),page_id(0) | key(1), page_id(1) | ... | key(n), page_id(n) | @@ -268,7 +297,8 @@ struct InternalIndexNode : public IndexNode }; /** - * IndexNode 仅作为数据在内存或磁盘中的表示 + * @brief IndexNode 仅作为数据在内存或磁盘中的表示 + * @ingroup B+Tree * IndexNodeHandler 负责对IndexNode做各种操作。 * 作为一个类来说,虚函数会影响“结构体”真实的内存布局,所以将数据存储与操作分开 */ @@ -305,6 +335,10 @@ protected: IndexNode *node_; }; +/** + * @brief 叶子节点的操作 + * @ingroup B+Tree + */ class LeafIndexNodeHandler : public IndexNodeHandler { public: @@ -352,6 +386,10 @@ private: LeafIndexNode *leaf_node_; }; +/** + * @brief 内部节点的操作 + * @ingroup B+Tree + */ class InternalIndexNodeHandler : public IndexNodeHandler { public: @@ -413,6 +451,10 @@ private: InternalIndexNode *internal_node_ = nullptr; }; +/** + * @brief B+树的实现 + * @ingroup B+Tree + */ class BplusTreeHandler { public: @@ -543,6 +585,10 @@ private: friend class BplusTreeTester; }; +/** + * @brief B+树的扫描器 + * @ingroup B+Tree + */ class BplusTreeScanner { public: @@ -550,7 +596,7 @@ public: ~BplusTreeScanner(); /** - * 扫描指定范围的数据 + * @brief 扫描指定范围的数据 * @param left_user_key 扫描范围的左边界,如果是null,则没有左边界 * @param left_len left_user_key 的内存大小(只有在变长字段中才会关注) * @param left_inclusive 左边界的值是否包含在内 diff --git a/src/observer/storage/index/bplus_tree_index.h b/src/observer/storage/index/bplus_tree_index.h index 5d4b1aecd8357ba86b01eeb7d42f6514cde4b362..ba7b2ec25738be0fc4ccff400ab4b9a2510c8986 100644 --- a/src/observer/storage/index/bplus_tree_index.h +++ b/src/observer/storage/index/bplus_tree_index.h @@ -17,7 +17,12 @@ See the Mulan PSL v2 for more details. */ #include "storage/index/index.h" #include "storage/index/bplus_tree.h" -class BplusTreeIndex : public Index { +/** + * @brief B+树索引 + * @ingroup Index + */ +class BplusTreeIndex : public Index +{ public: BplusTreeIndex() = default; virtual ~BplusTreeIndex() noexcept; @@ -42,7 +47,12 @@ private: BplusTreeHandler index_handler_; }; -class BplusTreeIndexScanner : public IndexScanner { +/** + * @brief B+树索引扫描器 + * @ingroup Index + */ +class BplusTreeIndexScanner : public IndexScanner +{ public: BplusTreeIndexScanner(BplusTreeHandler &tree_handle); ~BplusTreeIndexScanner() noexcept override; diff --git a/src/observer/storage/index/index.h b/src/observer/storage/index/index.h index 8bc72c86e3dfdd79193e733c78ff16f0dc176407..b3151988438392314f826bfe8c8c5debe0801396 100644 --- a/src/observer/storage/index/index.h +++ b/src/observer/storage/index/index.h @@ -22,18 +22,20 @@ See the Mulan PSL v2 for more details. */ #include "storage/field/field_meta.h" #include "storage/record/record_manager.h" -class IndexDataOperator -{ -public: - virtual ~IndexDataOperator() = default; - virtual int compare(const void *data1, const void *data2) const = 0; - virtual size_t hash(const void *data) const = 0; -}; - class IndexScanner; -class Index { - +/** + * @brief 索引 + * @defgroup Index + * @details 索引可能会有很多种实现,比如B+树、哈希表等,这里定义了一个基类,用于描述索引的基本操作。 + */ + +/** + * @brief 索引基类 + * @ingroup Index + */ +class Index +{ public: Index() = default; virtual ~Index() = default; @@ -43,23 +45,55 @@ public: return index_meta_; } + /** + * @brief 插入一条数据 + * + * @param record 插入的记录,当前假设记录是定长的 + * @param[out] rid 插入的记录的位置 + */ virtual RC insert_entry(const char *record, const RID *rid) = 0; + + /** + * @brief 删除一条数据 + * + * @param record 删除的记录,当前假设记录是定长的 + * @param[in] rid 删除的记录的位置 + */ virtual RC delete_entry(const char *record, const RID *rid) = 0; + /** + * @brief 创建一个索引数据的扫描器 + * + * @param left_key 要扫描的左边界 + * @param left_len 左边界的长度 + * @param left_inclusive 是否包含左边界 + * @param right_key 要扫描的右边界 + * @param right_len 右边界的长度 + * @param right_inclusive 是否包含右边界 + */ virtual IndexScanner *create_scanner(const char *left_key, int left_len, bool left_inclusive, const char *right_key, int right_len, bool right_inclusive) = 0; + /** + * @brief 同步索引数据到磁盘 + * + */ virtual RC sync() = 0; protected: RC init(const IndexMeta &index_meta, const FieldMeta &field_meta); protected: - IndexMeta index_meta_; - FieldMeta field_meta_; /// 当前实现仅考虑一个字段的索引 + IndexMeta index_meta_; ///< 索引的元数据 + FieldMeta field_meta_; ///< 当前实现仅考虑一个字段的索引 }; -class IndexScanner { +/** + * @brief 索引扫描器 + * @ingroup Index + */ +class IndexScanner +{ public: IndexScanner() = default; virtual ~IndexScanner() = default; diff --git a/src/observer/storage/index/index_meta.h b/src/observer/storage/index/index_meta.h index 81af4d6a2d1c867cd65fc239e011038c03d89844..1c3750e027155cf2cf16b1fbbb27e51fdf295926 100644 --- a/src/observer/storage/index/index_meta.h +++ b/src/observer/storage/index/index_meta.h @@ -24,6 +24,12 @@ namespace Json { class Value; } // namespace Json +/** + * @brief 描述一个索引 + * @ingroup Index + * @details 一个索引包含了表的哪些字段,索引的名称等。 + * 如果以后实现了多种类型的索引,还需要记录索引的类型,对应类型的一些元数据等 + */ class IndexMeta { public: diff --git a/src/observer/storage/record/record_manager.h b/src/observer/storage/record/record_manager.h index 5dd5e1fcdaae24641c5f7c8fa2cf25dadc133f24..b8959242e09ebb933caa2df127eb66aad33be1f2 100644 --- a/src/observer/storage/record/record_manager.h +++ b/src/observer/storage/record/record_manager.h @@ -15,7 +15,7 @@ See the Mulan PSL v2 for more details. */ #include #include -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/trx/latch_memo.h" #include "storage/record/record.h" #include "common/lang/bitmap.h" @@ -26,8 +26,9 @@ class Trx; class Table; /** - * @defgroup RecordManager * @brief 这里负责管理在一个文件上表记录(行)的组织/管理 + * @defgroup RecordManager + * * @file record_manager.h * * @details 表记录管理的内容包括如何在文件上存放、读取、检索。也就是记录的增删改查。 diff --git a/src/observer/storage/table/table.cpp b/src/observer/storage/table/table.cpp index 92dc038a336102f4e12d55ec6d801c8a836bee70..41ee6a96ca44e35be5d902eebe2b867c89c9b104 100644 --- a/src/observer/storage/table/table.cpp +++ b/src/observer/storage/table/table.cpp @@ -21,7 +21,7 @@ See the Mulan PSL v2 for more details. */ #include "storage/table/table_meta.h" #include "common/log/log.h" #include "common/lang/string.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/record/record_manager.h" #include "storage/common/condition_filter.h" #include "storage/common/meta_util.h" diff --git a/src/observer/storage/trx/latch_memo.cpp b/src/observer/storage/trx/latch_memo.cpp index 13d05ae9705e738d490f8d8eb77629b5e47ac8d1..9ca13ed83eaa01320515a4a0c9c0a35775bacc6c 100644 --- a/src/observer/storage/trx/latch_memo.cpp +++ b/src/observer/storage/trx/latch_memo.cpp @@ -14,7 +14,7 @@ See the Mulan PSL v2 for more details. */ #include "storage/trx/latch_memo.h" #include "storage/buffer/frame.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "common/lang/mutex.h" LatchMemoItem::LatchMemoItem(LatchMemoType type, Frame *frame) diff --git a/unittest/bp_manager_test.cpp b/unittest/bp_manager_test.cpp index 835a9f8bd642d00417924b64bc26d6ff33652f43..36f231ffd5ee2c3c235a26a4fe709468ef47cc0c 100644 --- a/unittest/bp_manager_test.cpp +++ b/unittest/bp_manager_test.cpp @@ -12,7 +12,7 @@ See the Mulan PSL v2 for more details. */ // Created by wangyunlai.wyl on 2021 // -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "gtest/gtest.h" void test_get(BPFrameManager &frame_manager) diff --git a/unittest/bplus_tree_test.cpp b/unittest/bplus_tree_test.cpp index 2850adbab1c29603376c2ac77f5ae0885a4d7680..960824b94d1e1be9b550e0764eb4be574a92f7fb 100644 --- a/unittest/bplus_tree_test.cpp +++ b/unittest/bplus_tree_test.cpp @@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */ #include #include "storage/index/bplus_tree.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "common/log/log.h" #include "sql/parser/parse_defs.h" #include "gtest/gtest.h" diff --git a/unittest/record_manager_test.cpp b/unittest/record_manager_test.cpp index 01da85ed163a09e1b643035d44a4ba94a6eaa0bf..7fc60db5afc350742438d51321aa60a05f2db10e 100644 --- a/unittest/record_manager_test.cpp +++ b/unittest/record_manager_test.cpp @@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */ #include #include "gtest/gtest.h" -#include "storage/default/disk_buffer_pool.h" +#include "storage/buffer/disk_buffer_pool.h" #include "storage/record/record_manager.h" #include "storage/trx/vacuous_trx.h"