未验证 提交 f4e52131 编写于 作者: 羽飞's avatar 羽飞 提交者: GitHub

增加一些文档 (#200)

### What problem were solved in this pull request?

Issue Number: ref #165 
ref #174 

Problem:
一些文档需要优化
上级 380fea38
......@@ -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)
......
......@@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */
#include <benchmark/benchmark.h>
#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"
......
......@@ -18,7 +18,7 @@ See the Mulan PSL v2 for more details. */
#include <benchmark/benchmark.h>
#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"
......
......@@ -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
......@@ -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
# 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 <MULTIPLE>
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<TupleSet> 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 <scan_record_reader_adapter(Record*, void*)>)
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 <scan_record_reader_adapter(Record*, void*)>)
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
......@@ -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)
......
# 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 <string> 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
# 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
......@@ -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
- 某张表或者某个查询结果一行数据都没有,但是依然需要输出表头信息
......
> 此实现解析有往届选手提供。具体代码实现已经有所变更,因此仅供参考。
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'填充。
......@@ -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`查看。
# 版权声明
本版权声明仅针对《数据库管理系统实现基础讲义》(以下简称“本教材”)的所有内容。
1. 本教材刊载的所有内容,包括但不限于文字报道、图片、视频、图表、标志标识、商标、版面设计、专栏目录与名称、内容分类标准等,均受《中华人民共和国著作权法》、《中华人民共和国商标法》、《中华人民共和国专利法》及适用之国际公约中有关著作权、商标权、专利权以及或其它财产所有权法律的保护,相应的版权或许可使用权均属华中科技大学谢美意老师、左琼老师所有。
2. 凡未经华中科技大学谢美意老师、左琼老师授权,任何媒体、网站及个人不得转载、复制、重制、改动、展示或使用《数据库管理系统实现基础讲义》的局部或全部的内容。如果已转载,请自行删除。同时,我们保留进一步追究相关行为主体的法律责任的权利。
3. 本教材刊载的所有内容授权给北京奥星贝斯科技有限公司。
......
......@@ -2,6 +2,7 @@
作者 华中科技大学谢美意 左琼
[版权声明](copyright.md)
[第1章 数据库管理系统概述](lecture-1.md)
......@@ -16,5 +17,3 @@
[第6章 事务处理](lecture-6.md)
[参考资料](references.md)
[版权声明](copyright.md)
......@@ -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"
......
......@@ -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<char> &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
{
......
......@@ -22,6 +22,10 @@ struct CreateIndex;
class Table;
class FieldMeta;
/**
* @brief 创建索引的语句
* @ingroup Statement
*/
class CreateIndexStmt : public Stmt
{
public:
......
......@@ -23,6 +23,7 @@ class Db;
/**
* @brief 表示创建表的语句
* @ingroup Statement
* @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多
*/
class CreateTableStmt : public Stmt
......
......@@ -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:
......
......@@ -23,6 +23,7 @@ class Db;
/**
* @brief 描述表的语句
* @ingroup Statement
* @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多
*/
class DescTableStmt : public Stmt
......
......@@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */
/**
* @brief Exit 语句,表示断开连接,现在什么成员都没有
* @ingroup Statement
*/
class ExitStmt : public Stmt
{
......
......@@ -17,6 +17,10 @@ See the Mulan PSL v2 for more details. */
#include <memory>
#include "sql/stmt/stmt.h"
/**
* @brief explain语句
* @ingroup Statement
*/
class ExplainStmt : public Stmt
{
public:
......
......@@ -84,6 +84,10 @@ private:
FilterObj right_;
};
/**
* @brief Filter/谓词/过滤语句
* @ingroup Statement
*/
class FilterStmt
{
public:
......
......@@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */
/**
* @brief Help 语句,现在什么成员都没有
* @ingroup Statement
*/
class HelpStmt : public Stmt
{
......
......@@ -20,6 +20,10 @@ See the Mulan PSL v2 for more details. */
class Table;
class Db;
/**
* @brief 插入语句
* @ingroup Statement
*/
class InsertStmt : public Stmt
{
public:
......
......@@ -25,6 +25,10 @@ class FilterStmt;
class Db;
class Table;
/**
* @brief 表示select语句
* @ingroup Statement
*/
class SelectStmt : public Stmt
{
public:
......
......@@ -23,6 +23,7 @@ class Db;
/**
* @brief 描述表的语句
* @ingroup Statement
* @details 虽然解析成了stmt,但是与原始的SQL解析后的数据也差不多
*/
class ShowTablesStmt : public Stmt
......
......@@ -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对象。
*/
......
......@@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */
/**
* @brief 事务的Begin 语句,现在什么成员都没有
* @ingroup Statement
*/
class TrxBeginStmt : public Stmt
{
......
......@@ -21,6 +21,7 @@ See the Mulan PSL v2 for more details. */
/**
* @brief 事务的 Commit/Rollback 语句,现在什么成员都没有
* @ingroup Statement
*/
class TrxEndStmt : public Stmt
{
......
......@@ -19,6 +19,10 @@ See the Mulan PSL v2 for more details. */
class Table;
/**
* @brief 更新语句
* @ingroup Statement
*/
class UpdateStmt : public Stmt
{
public:
......
......@@ -14,7 +14,7 @@ See the Mulan PSL v2 for more details. */
#include <errno.h>
#include <string.h>
#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"
......
......@@ -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:
......
......@@ -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:
......
......@@ -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;
......
......@@ -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"
......
......@@ -23,15 +23,24 @@ See the Mulan PSL v2 for more details. */
#include <memory>
#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 左边界的值是否包含在内
......
......@@ -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;
......
......@@ -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;
......
......@@ -24,6 +24,12 @@ namespace Json {
class Value;
} // namespace Json
/**
* @brief 描述一个索引
* @ingroup Index
* @details 一个索引包含了表的哪些字段,索引的名称等。
* 如果以后实现了多种类型的索引,还需要记录索引的类型,对应类型的一些元数据等
*/
class IndexMeta
{
public:
......
......@@ -15,7 +15,7 @@ See the Mulan PSL v2 for more details. */
#include <sstream>
#include <limits>
#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 表记录管理的内容包括如何在文件上存放、读取、检索。也就是记录的增删改查。
......
......@@ -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"
......
......@@ -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)
......
......@@ -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)
......
......@@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */
#include <iostream>
#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"
......
......@@ -16,7 +16,7 @@ See the Mulan PSL v2 for more details. */
#include <sstream>
#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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册