Project 0
Project #0 - C++ Primer | CMU 15-445/645 :: Intro to Database Systems (Fall 2022) — 项目 #0 - C++ 入门 | CMU 15-445/645 :: 数据库系统简介(2022 年秋季)
前期准备
为完成该项目做的一些准备:
-
创建个人项目FarewellYi/BusTub-private: My CMU 15-445 2022 Fall course homework (github.com)
-
clone到本地,并pull 2022 Fall的原BusTubcmu-db/bustub at v20221128-2022fall (github.com)
期间遇到main和master分支不兼容的问题,于是删除已拉取的BusTub-private并重新拉取master版本;
可以使用如下命令拉取2022Fall版本:
git clone --branch v20221128-2022fall https://github.com/cmu-db/bustub.git
但是如果按照BusTub的如下说明:
相当于把本地仓库连接到远程的bustub下,本地会自动更新为最新的commit版本(大概,由于我也不是很会用git,缺点暴露);
于是我只能重新拉取个人仓库中的2022Fall版本,就此正式开始我的通关之旅。
-
编译BusTub环境
期间遇到无法安装clang-14依赖的问题
-
尝试更新软件包,并通过llvm密钥配置下载路径,但遇到众多依赖包版本不匹配的问题
-
尝试从llvm下载二进制源码并置为环境变量,但是貌似并没有被主机识别到
-
根据stack overflow上的某位回答,ubuntu18.04版本默认不支持clang-14,可以考虑将系统更新至20.04或者22.04版本,由于本人使用的环境是虚拟机,影响也不大,所以将系统备份后更新至20.04版本
经验证,重启后依旧无法直接通过bustub提供的packages脚本完成所有package的依赖安装
在Ubuntu上配置clang-14的环境_5436649486的博客-CSDN博客
根据上面这位博主的建议,通过wget获取llvm的软件包,再按照BusTub中Readme的步骤,则不会出现依赖不匹配的问题
-
-
按照BusTub Readme中的说明,build 项目,最终使用以下命令
$ cd build $ make check-tests
检查环境的搭建情况(虽然本意并非如此,而是检查各个模块的完成情况的)
-
拟采用VS Code + SSH 本地虚拟机的方式完成本项目,有关如何配置VSCode,可以参考下面这篇文章
CMU 15445 vscode/clion clang12 cmake环境配置 - 知乎 (zhihu.com)
由于2022 Fall中要求的使用clang-14完成编译,因此我的工具选择的是下图中底部蓝框所示的clang-14;
安装cmake后,可以使用CMakeLists.txt或者是选择底部蓝框右边的bulid完成构建,其中使用到的编译选项如图中蓝框所示,各选项的含义如下:
/usr/bin/cmake --no-warn-unused-cli -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_BUILD_TYPE:STRING=Debug // Debug模式, Release模式Debug改Release即可 -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-12 // 编译器路径,不指定默认gnu /usr/bin/gcc -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-12 // 同上 默认/usr/bin/g++ -S/home/wxx/bustub // 要构建的cmake项目根目录 -B/home/wxx/bustub/build // 构建目标目录 -G "Unix Makefiles" // 生成器 generators
CMake时遇到四个警告,如下图所示:
且不论第一个,因为即使默认选用clang12,但是并不影响编译;后面三个警告的意思就是没有找到这些包,以下是这些包的作用:
- clang-format:clang-format是一个用于代码格式化的工具。它基于一组配置规则,可以自动调整源代码的排版和格式,使其符合统一的风格和标准。使用clang-format可以帮助团队在代码库中保持一致的代码风格,提高代码的可读性和维护性。
- clang-tidy:clang-tidy是一个静态分析工具,用于检查C++代码中的潜在问题和常见错误。它基于一系列的检查器(checks),可以对代码进行静态分析,并给出相关的警告或建议。clang-tidy可以帮助开发者发现潜在的bug、不良的编码实践和可改进的代码片段,从而提高代码质量和可靠性(强大的工具,虽然有时有种矫枉过正的感觉)。
- clang-apply-replacements:clang-apply-replacements是一个用于应用由clang-tidy或其他工具生成的修复建议的工具。当clang-tidy检测到问题并给出修复建议时,这些建议通常以修复补丁(replacements)的形式提供。clang-apply-replacements可以接收这些修复补丁,并将其应用到源代码文件中,实现自动修复。
使用常规的装包命令装一下,重启窗口,这些警告就不复存在了。
-
拟计划采用VSCode在Windows端远程虚拟机完成编码,在Ubuntu端通过CLion完成独立test的调试
本项目的main target 是使用C++17完成一个Trie类,分为以下两个部分
TASK #1:Templated Trie
可以看到源文件中给出了三个类
说明也给的很清楚(这一点太强了,通过注释引导学生,就不会有从零开始的那种望而生畏感)。
官方文档关于如何做,一步一步写的都很清楚(一步一步坐下来只会有种爽快感)。
而且通过此次测试,才发现clang这个工具的强大。
本课的测试代码皆使用Google Test进行编写,在Clion环境中,可以进行每个Task的单元测试,如下图所示:
原本在函数TrieNodeInsertTest
前还会有一个前缀DISABLED_
,删去即可测试。
在VS Code中,看网上其他人的博客,完成整个Task之后才可以进行测试,根据下图,可以看出该Task一共有五个测试单元:
执行下面代码即可单独测试该Task:
$ cd build
$ make starter_trie_test
$ ./test/starter_trie_test
经我的实验,修改DISABLED_
选项后,重新编译该测试脚本,即可完成不同单元的测试。当我完成Task1之后,关闭了最后一个ConcurrentTest1
,测试结果如下:
所以使用VSCode测试也没有那么网上其他人说的那么麻烦。
此处有一点我要说明,我在实现Trie
类中的Insert
函数时,说明中有一点,当插入的key对应的最后一个结点是TrieNode时,应当修改为TrieNodeWithValue
,当我使用make_unique构造TrieNodeWithValue
时,调用的构造函数如下所示:
TrieNodeWithValue(TrieNode &&trieNode, T value);
我一开始使用的语句是:
std::make_unique<TrieNodeWithValue<T>>(std::move((*cur).get()), value);
因为文档中有提示,说使用std:unique_prt<TrieNode>*
,即一个指向unique_ptr对象的指针,可以一定程度上避免拷贝的问题,因此上文中的cur
对应一个指向unique_ptr对象的指针,解引用后则是unique_ptr对象,我起初向使用get方法获取unique_ptr管理的原对象,但是忘记了此处获取的是指针而非TrieNode,导致编译报错,理应如下:
std::make_unique<TrieNodeWithValue<T>>(std::move(*((*cur).get())), value);
这样写是没错的,但是clang-tidy会提示存在冗余,因此可以依赖clang修复为如下所示:
std::make_unique<TrieNodeWithValue<T>>(std::move(*(*cur)), value);
TASK #2:Concurrent Trie
可以使用Trie类中提供的读写锁ReaderWriterLatch latch_
来完成加锁
经过语法检查(所幸平时我的代码风格就是google的风格,在clang的帮助下,也是可以即使排查出它认为的不合理之处),首次提交到gradescope后,提示错误如下图所示:
之后所有的测试用例都是红框中所示的问题。
经过一番检查后,问题在于TrieNodeWithValue
类的某个构造函数中,忘记用列表初始化构造父类TrieNode
(这个错误在本地测试的时候竟然没有被检查出来)
修改后二次上传,最终百分之百通过,如下图所示: