最近大家问题都比较多,开一个Q&A的文档总结一些问得比较多的问题。该文档会持续更新,有问题也可以在评论区里问,一些代表性的问题会贴到这个Q&A文档中。
此外,由于是第一年使用,框架中测试代码较为匮乏,很多测试代码是需要同学们自己编写的。因此,也希望大家能够在GitLab仓库中以Merge Request的方式提交高质量的测试代码来共同协作完善整个框架。RELEASE
模式下,ASSERT
语句会被优化,从而不被执行。在小规模数据测试时,为了确保ASSERT
能够被正常运行起到检测作用,请使用DEBUG
模式进行。RELEASE
模式下DBStorageEngine
类的Bug修复详见:BugFix。该Bug会导致DBStorageEngine
时预分配CATALOG_META_PAGE
以及INDEX_ROOTS_PAGE
这两个数据页的过程被跳过。
#8.0 START
- 在编译时,碰到了包含
'march=native'
相关的错误时,只需在CMakeList.txt
文件中搜索'march=native'
,将其去掉即可。 - 运行单个测试时,出现
IMPORTANCE NOTICE: This test program did not call testing::InitGoogleTest() before calling RUN_ALL_TESTS(). This is INVALID.
类似的错误,原因正在排查中。目前可以暂时使用运行所有测试来代替。运行所有测试时,可以通过指定Filter
(在main_test.cpp
中注释的那行)来选择需要运行的测试用例。 - 很多同学在用GDB调试时发现调试信息很少,大概率是没有用
DEBUG
模式。在执行cmake
命令时,指定-DBUILD_TYPE=Debug
再重新编译即可。#8.1 DISK & BUFFER
#8.2 RECORD
TablePage::InsertTuple
函数中,ASSERT(write_bytes = serialized_size, "Unexpected behavior in row serialize.")
代码有误,应将=
改成==
。#8.3 INDEX
#8.4 CATALOG
在调用
CreateIndex
创建索引操作对象的时候,如何确定Index
对象的模板类型?以及为什么需要传入BufferPoolManager
对象对于第一个问题,需要根据该索引的模式进行计算,得到该索引Key的最大长度,然后按照计算长度进行判断,比如最大长度为10就选用Generic<16>的Key,最大长度为48就选用Generic<64>的Key。此外,这个地方的设计是存在一定问题的,既然Index对象在构造时能够接受一个Schema作为参数,那么对于最大索引键长度的计算应该交给Index对象来进行计算以及选择合适的KeySize。比较遗憾的是,现在的框架在处理这个问题上非常棘手,该问题将会在之后重构Index模块得到解决。 对于第二个问题,Index模块需要用到
BufferPoolManager
对象,至于为什么要用到,这就需要去了解那个模块的代码实现了。 另外每个索引的RootPageId是由Index模块通过IndexRootsPage进行维护的,Catalog模块不需要进行维护。IndexMetadata::Create
函数中,参数key_map
和CatalogManager::CreateIndex
函数中,参数index_keys
的含义分别是?PS:善用全局搜索,用全局搜索一下这些变量在哪里被用到可以更好地帮助理解这个变量的作用。 对于前者,通过全局搜索引用,可以发现它在
Schema::ShallowCopySchema
中有被用到,且该函数的注释中给出了一个例子。实际上key_map
可以简单地理解成,索引键分别位于元组中的哪几列(即它们在元组中的下标)。对于后者,表示创建索引时,哪几列(列名,字符串类型)是需要作为索引键的。TableMetadata
类中,root_page_id_
指的是TableHeap
的root_page_id_
#8.5 EXECUTOR
对于
PRIMARY KEY
的列如何进行区分?对于PK列,可以在表创建的时候,将PK列的信息写入
TableMetaData
中,此外,在TableInfo
对象中,也可以增加有关PK列的属性,以在内存中维护PK信息。语法树可视化时,生成的
DOT
文件在哪里?正常情况下,是在
build
或build/bin
或者build/test
下面,可以通过find
命令查找。执行器好难写啊,能不能偷懒呢?
基本能够猜到大家都是在IF-ELSE地写。当然,问题不大,因为大家可能不太了解执行器是怎么设计的,文档中也没有给出比较详细的说明。但至少需要保证你编写的执行器能够通过第7个文档中的测试,这样在验收的时候基本就没什么大问题。 另外执行器模块在之后也会更加细化,使之更容易编写、扩展和维护。对于执行器的设计,可以在空余时间了解基本的“火山模型”,不需要在这个程序上应用(当然有时间做更好),只需要作为一个编程思想去学习即可。
事务
Transaction
模块需要实现吗?今年不需要实现,因为没有确定好事务的框架。但是明年估计就要了(所以说好好学,争取不重修)。
ExecuteContext
这个类有什么用呢?用于向上层传递一些信息,保留一些上下文的状态。但如果你在执行层直接打印结果的话,那么这个类其实就不太用得到,忽略即可。
drop index
语句目前只给出了index name
而没有给出table name
(设计上的问题),这里可以通过不考虑重复index name
的问题或是对所有table
的index
进行搜索来解决。create index
语句使用using
时,using
关键字的语法树结点在打印时会出现error type
(缺少using
关键字的语法树结点定义)。如果没有选做另外的索引类型,可以直接忽略这个问题。如果选做了另外的索引类型,那么可以暂且忽略using
关键字的语法树结点的类型,在其子结点中获取索引类型。- 源代码
src/parser/syntax_tree.c
中的CreateSyntaxNode
函数存在BUG,详见PR。 在使用多个数据库的情况下,怎么知道我创建了哪几个数据库呢?
可以单独开一个文件简单记录一下即可。
-
#8.6 已知问题优化
Index
模块的设计基本沿用了CMU-15445的设计,在总结了一些问题之后,发现原有基于模板的设计在封装性、可维护性和设计上都存在一定的问题,此外部分代码注释也存在一定问题。在本学期结束后,将会对Index
模块的实现进行重构。RemoveAndDeleteRecord
中,注释有误,NOTE
部分应为ensure all key & value pairs store in continuous storage.
,RETURN
部分应为node size after deletion
。