最近大家问题都比较多,开一个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

  1. 在编译时,碰到了包含'march=native'相关的错误时,只需在CMakeList.txt文件中搜索'march=native',将其去掉即可。
  2. 运行单个测试时,出现IMPORTANCE NOTICE: This test program did not call testing::InitGoogleTest() before calling RUN_ALL_TESTS(). This is INVALID.类似的错误,原因正在排查中。目前可以暂时使用运行所有测试来代替。运行所有测试时,可以通过指定Filter(在main_test.cpp中注释的那行)来选择需要运行的测试用例。
  3. 很多同学在用GDB调试时发现调试信息很少,大概率是没有用DEBUG模式。在执行cmake命令时,指定-DBUILD_TYPE=Debug再重新编译即可。

    #8.1 DISK & BUFFER

#8.2 RECORD

  1. TablePage::InsertTuple函数中,ASSERT(write_bytes = serialized_size, "Unexpected behavior in row serialize.")代码有误,应将=改成==

    #8.3 INDEX

#8.4 CATALOG

  1. 在调用CreateIndex创建索引操作对象的时候,如何确定Index对象的模板类型?以及为什么需要传入BufferPoolManager对象

    对于第一个问题,需要根据该索引的模式进行计算,得到该索引Key的最大长度,然后按照计算长度进行判断,比如最大长度为10就选用Generic<16>的Key,最大长度为48就选用Generic<64>的Key。此外,这个地方的设计是存在一定问题的,既然Index对象在构造时能够接受一个Schema作为参数,那么对于最大索引键长度的计算应该交给Index对象来进行计算以及选择合适的KeySize。比较遗憾的是,现在的框架在处理这个问题上非常棘手,该问题将会在之后重构Index模块得到解决。 对于第二个问题,Index模块需要用到BufferPoolManager对象,至于为什么要用到,这就需要去了解那个模块的代码实现了。 另外每个索引的RootPageId是由Index模块通过IndexRootsPage进行维护的,Catalog模块不需要进行维护。

  2. IndexMetadata::Create函数中,参数key_mapCatalogManager::CreateIndex函数中,参数index_keys的含义分别是?

    PS:善用全局搜索,用全局搜索一下这些变量在哪里被用到可以更好地帮助理解这个变量的作用。 对于前者,通过全局搜索引用,可以发现它在Schema::ShallowCopySchema中有被用到,且该函数的注释中给出了一个例子。实际上key_map可以简单地理解成,索引键分别位于元组中的哪几列(即它们在元组中的下标)。对于后者,表示创建索引时,哪几列(列名,字符串类型)是需要作为索引键的。

  3. TableMetadata类中,root_page_id_指的是TableHeaproot_page_id_

    #8.5 EXECUTOR

  4. 对于PRIMARY KEY的列如何进行区分?

    对于PK列,可以在表创建的时候,将PK列的信息写入TableMetaData中,此外,在TableInfo对象中,也可以增加有关PK列的属性,以在内存中维护PK信息。

  5. 语法树可视化时,生成的DOT文件在哪里?

    正常情况下,是在buildbuild/bin或者build/test下面,可以通过find命令查找。

  6. 执行器好难写啊,能不能偷懒呢?

    基本能够猜到大家都是在IF-ELSE地写。当然,问题不大,因为大家可能不太了解执行器是怎么设计的,文档中也没有给出比较详细的说明。但至少需要保证你编写的执行器能够通过第7个文档中的测试,这样在验收的时候基本就没什么大问题。 另外执行器模块在之后也会更加细化,使之更容易编写、扩展和维护。对于执行器的设计,可以在空余时间了解基本的“火山模型”,不需要在这个程序上应用(当然有时间做更好),只需要作为一个编程思想去学习即可。

  7. 事务Transaction模块需要实现吗?

    今年不需要实现,因为没有确定好事务的框架。但是明年估计就要了(所以说好好学,争取不重修)。

  8. ExecuteContext这个类有什么用呢?

    用于向上层传递一些信息,保留一些上下文的状态。但如果你在执行层直接打印结果的话,那么这个类其实就不太用得到,忽略即可。

  9. drop index语句目前只给出了index name而没有给出table name(设计上的问题),这里可以通过不考虑重复index name的问题或是对所有tableindex进行搜索来解决。

  10. create index语句使用using时,using关键字的语法树结点在打印时会出现error type(缺少using关键字的语法树结点定义)。如果没有选做另外的索引类型,可以直接忽略这个问题。如果选做了另外的索引类型,那么可以暂且忽略using关键字的语法树结点的类型,在其子结点中获取索引类型。
  11. 源代码src/parser/syntax_tree.c中的 CreateSyntaxNode函数存在BUG,详见PR
  12. 在使用多个数据库的情况下,怎么知道我创建了哪几个数据库呢?

    可以单独开一个文件简单记录一下即可。


  13. #8.6 已知问题优化

  14. Index模块的设计基本沿用了CMU-15445的设计,在总结了一些问题之后,发现原有基于模板的设计在封装性、可维护性和设计上都存在一定的问题,此外部分代码注释也存在一定问题。在本学期结束后,将会对Index模块的实现进行重构。

    1. RemoveAndDeleteRecord中,注释有误,NOTE部分应为ensure all key & value pairs store in continuous storage.RETURN部分应为node size after deletion