Featured image of post CMU 15445 Project#0

CMU 15445 Project#0

熟悉现代 C++17 的一个小型实验,由于条约限制,所以在这里不会把代码放出来Primer

# Project#0 C++ Primer

# 环境配置

由于换到了 Linux 上来,所以就先把环境的配置都解释一下。

首先,官方仓库在

title: BusTub
link: https://github.com/cmu-db/bustub
logo: https://virgil-civil-1311056353.cos.ap-shanghai.myqcloud.com/img/20230628182840.png

上,根据仓库中的 README 把文件拉到本地(注意需要建立的仓库是 private 而不是 public 的)

关于 Arch Linux 下不能使用 sudo build_support/packages.sh 的解决方法

这个脚本只支持 Ubuntu 系列的安装,但实际上就是安装几个包而已,这几个包是:

install_linux() {
  # Update apt-get.
  apt-get -y update
  # Install packages.
  apt-get -y install \
      build-essential \
      clang-14 \
      clang-format-14 \
      clang-tidy-14 \
      cmake \
      doxygen \
      git \
      pkg-config \
      zlib1g-dev
}

所以在 Arch 系中,只需要 yay 安装这些就行(但其实如果安装过 gcc 环境,那么这里只需要装一下 doxygencmakepkg-configzlib1g-dev 即可(不会安装请 STFW

接下来就可以进行构建了:

mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DBUSTUB_SANITIZER=thread ..
make -j`nproc`

关于调试

我这里使用了 vs code 进行调试(不是不想用 Clion ,而是 ClionSTL 的调试不知道为什么解决不了),所以就切换到 vs code

对于 vs code 的插件安装:

  1. C/C++
  2. Better C++ Syntax
  3. clangd
  4. CMake, CMake Tools
  5. Git Graph
  6. Github Copilot
  7. Makefile Creator
  8. Todo Tree

具体的配置按照个人喜好来即可

接下来就可以开始进行 launch.json 的编写了

首先我们知道,运行的均为测试,也就是在 build/test 文件夹下的一些可执行文件,所以一个简单的 launch.json 如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cppdbg",
            "request": "launch",
            "name": "GDB",
            "program": "${workspaceFolder}/build/test/${fileBasenameNoExtension}",
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "MIMode": "gdb",
        }
    ]
}

这样我们需要调试什么文件时,只需要打开文件,按 F5 即可(请注意,是打开 test 文件夹下的文件,而不是 src 中需要你补全的文件)

调试 STL 容器时显示的东西是 _M_I _Rb_Tree

修改 launch.json 如下:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "cppdbg",
            "request": "launch",
            "name": "GDB",
            "program": "${workspaceFolder}/build/test/${fileBasenameNoExtension}",
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "setupCommands": [
                {
                    "description": "Text",
                    "text": "python import sys;sys.path.insert(0, '/usr/share/gcc-12.2.1/python');from libstdcxx.v6.printers import register_libstdcxx_printers;register_libstdcxx_printers(None)",
                    "ignoreFailures": false
                },
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "MIMode": "gdb",
        }
    ]
}

注意 text/usr/share/gcc-12.2.1 这里,需要根据自己电脑的 gcc 版本号来填写

# 实验过程

这里解释一下实验的一些坑点

涉及到需要修改的文件:

image-20230524151303791

# TASK#1

  1. 智能指针的使用,可以询问 GPT 解决
  2. 建议的实验过程为:
    1. 首先实现一个正常版本的字典树(即不考虑 COW ,正常增删改查)
    2. 考虑 COW 的实现,我们只需要修改插入与删除的部分即可
    3. 对于插入部分,显然,当一个节点存在时,我们需要去克隆这个节点,然后插入到新树上(注意我们每次在一开始都会克隆 root_ 节点,这样就变成了一颗新树),否则我们只是新建一个节点并插入
    4. 对于删除部分,显然,我们在遍历 key 时,若能找到子节点,那么我们才需要去克隆,否则直接抛出 Key not Found 异常即可,在遍历到 key 的最后一个字符时,我们需要特判这个节点是否为叶子节点,如果是的话,直接释放(意思是我们的新树中没有这个节点了),否则我们需要克隆这个节点。

# TASK#2

并发处理,注意加锁的顺序

  1. 对于 Get 而言,在取数据时需要加 root
  2. 对于 PutRemove 而言,在一开始我们就需要加上 write 锁,在更新树的根节点时,我们需要加上 root

# TASK#3

debug 技巧,在 trie_debug_test.cpp 中打上端点,并调试,可以在 gdb 中查看对应的答案,当然你也可以使用 cout 来得出答案

# TASK#4

文件的搜索可以使用 <C-p> 输入文件名可以搜索找到对应的文件

string_expression.h 中,添加 upperlower 函数,这两个函数的含义是,将传入的字符串根据对应的选项,全部转为大写或小写

plan_func_call.cpp 中,添加函数的定义,这里其实有点类似 RPC 调用?首先判断函数的名称,然后根据函数名称选择对应选项(转为大写还是小写),判断参数的个数,最后传入参数

# 实验提交

cd build
make submit-p0

https://www.gradescope.com/courses/500628 上提交 project0-submission.zip ,等待评测,我的评测如图:

image-20230524151145553

使用 Hugo 构建