C++ Primer
- Task1 Copy-On-Write Trie
- Task2 Concurrent Key-Value Store
- Task3 Debugging
- Task4 SQL String Functions
CMU-15445汇总
本文对应的project版本为CMU-Spring-2023的project0
默认读者已经学会了字典树Trie
Task1 Copy-On-Write Trie
Task1要求实现一个可持久化字典树,可持久化字典树的定义大概就是,每次更改操作(Put或者Remove)都会生成一个新的字典树版本,并保留历史版本,且各版本间的查询操作不相互影响。
 按照文档要求,我们主要实现Trie类中的三个方法:
- const T* Get(std::string_view key) const
- Trie Put(std::string_view key, T value) const
- Trie Remove(std::string_view key) const
对于Get方法,比较简单,就是普通的字典树查询而已,顺着树往下走到节点处,取出值即可。
 对于Put方法,相对复杂一点。假设key的长度为n,那么需要新建出n + 1个结点(包括一个新根),我的具体做法是从原始的根开始,在旧的树上沿着key的每个字符往下走,走到某个结点时,复制这个结点(包括该结点的children_指针),并修改上一个复制结点的children_(如果有上一个的话,即当前复制结点不为根)。举个例子,假设当前的字符为c,上一个复制出来的结点为A,当前复制出来的结点为B,则需要把结点A的children_[c]指向B。
 最后,对于Remove方法,和Put有点像,在树上走的过程中也要复制路径上的所有结点,不同点在于最后走到的点要从TrieNodeWithValue变为TrieNode,且如果一个结点不为TrieNodeWithValue并且没有任何孩子,则需要删除。
 其实思路上不是特别复杂,但是在打代码时,会一直编译报错,通过这个Task对智能指针更加的熟悉了。不过还对C++的几个类型转换函数不是很懂(比如dynamic_cast),后续研究下并输出博客。
Task2 Concurrent Key-Value Store
这个Task相对比较简单,就是利用上一个Task的可持久化Trie加上互斥锁实现一个支持并发读写Trie,也是实现上述几个方法。
 对于Get方法,比较简单,获取root_lock_之后拿到可持久化Trie(其实就是拿到某个版本的根节点),调用该版本的Get方法即可。
 对于Put方法,要先获取write_lock_保证只有一个写者,然后调用可持久化Trie的Put方法即可,再获取root_lock_并将当前指向的根节点更新。
 Remove方法与Put一致,不再赘述。
Task3 Debugging
这个Task相对也比较简单,就是运行下程序输出结果而已,但是随机数生成在我本地wsl与在gradescope上生成的不同,导致无法通过gradescope测试,于是寻找解决办法,最后发现discord上有助教发的一段话
 
 替换一下代码重新看结果即可
  auto trie = Trie();
  trie = trie.Put<uint32_t>("65", 25);
  trie = trie.Put<uint32_t>("61", 65);
  trie = trie.Put<uint32_t>("82", 84);
  trie = trie.Put<uint32_t>("2", 42);
  trie = trie.Put<uint32_t>("16", 67);
  trie = trie.Put<uint32_t>("94", 53);
  trie = trie.Put<uint32_t>("20", 35);
  trie = trie.Put<uint32_t>("3", 57);
  trie = trie.Put<uint32_t>("93", 30);
  trie = trie.Put<uint32_t>("75", 29);
Task4 SQL String Functions
这个Task最简单吧,添加一个大小写转换功能而已,主要修改的文件为(文档里好像没有写清楚):
- src/include/execution/expressions/string_expression.h
- src/planner/plan_func_call.cpp
功能很简单实现也很简单就不多说啦!最后附上gradescope通过截图!
 



















