- “再见是为了再次相见” —《EVA》
- Hi,这里是我记录笔记的地方,如果你感兴趣,可以通过下面的方式找到我一起交流学习!
Hugo配置Github Actions
最近把博客的构建工具从Hexo换成了Hugo,感觉Hugo配置和使用起来更简洁方便。 由于我的博客总体来说有两个仓库,一个私有仓库是放置建站工具的目录,其中包含博客 Markdown 内容、一些配置还有主题;另一个就是通过 GitHub Pages 来访问公共仓库。为了方便,之前在使用 Hexo 的使用使用了 Github Actions 来一键部署博客,换成 Hugo 后这个 actions 需要修改一下。 .github/workflows/hugo.yml: name: GitHub Pages on: push: branches: - master # 监听 master 分支的推送事件 pull_request: jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 with: submodules: true # 拉取 Hugo 主题子模块 fetch-depth: 0 # 获取完整提交历史 - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: '0.126.2' extended: true - name: Build run: hugo --minify # 启用压缩优化 - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: personal_token: ${{ secrets....
Linux下微信无法使用中文输入法问题解决
微信在不久前终于有了Linux原生版本,我的电脑是Fedora41,之前安装的是flatpak打包的微信,现在在官网下载rpm包后运行发现无法使用fcitx的中文输入法,找了一下是环境遍历的问题。 ...
在vscode中配置lldb
{ "version": "0.2.0", "configurations": [ { "name": "LLDB", "type": "lldb", "request": "launch", "program": "${command:cmake.launchTargetPath}", "args": [], "cwd": "${workspaceFolder}", } ] }
【CMU15-445 Fall2023】Project3 Query Execution 小结
该系列博客只是为了记录自己在写Lab时的思路,按照课程要求不会在Github和博客中公开源代码。欢迎与我一起讨论交流! 这个project和之前就不一样了,开始深入数据库内核的实现了。需要理清楚一条sql语句是如何被执行的,方才能写出代码。 前置奶酪 一条SQL语句的执行 这里需要去看看一条sql语句传入bustub内部之后的代码:src/common/bustub_instance.cpp:ExecuteSqlTxn: auto BustubInstance::ExecuteSqlTxn(const std::string &sql, ResultWriter &writer, Transaction *txn, std::shared_ptr<CheckOptions> check_options) -> bool { if (!sql.empty() && sql[0] == '\\') { // 处理元命令 ... } // binder,但是在其中会使用libpg_query来解析sql语句 bustub::Binder binder(*catalog_); binder.ParseAndSave(sql); // 经过上一步后,binder中的statement_nodes_存储着所有的语句解析节点 for (auto *stmt : binder.statement_nodes_) { // 将stmt转换成BoundStatement对象,方便后面处理数据 auto statement = binder.BindStatement(stmt); // 只有不需要构建plan树、不需要进行优化的sql语句才会在switch之后继续执行 switch (statement->type_) { ... } // 生成初步的执行计划 bustub::Planner planner(*catalog_); planner.PlanQuery(*statement); // 优化刚刚的执行计划 bustub::Optimizer optimizer(*catalog_, IsForceStarterRule()); auto optimized_plan = optimizer.Optimize(planner.plan_); ....
【MIT6.S081】Lab10 mmap
什么是mmap? mmap 是一种用于将文件或设备与进程的地址空间关联起来的内存映射技术。通过 mmap,可以将文件的内容直接映射到进程的虚拟内存地址空间,使得文件的内容可以像操作普通内存一样进行读取和写入。 ...
【MIT6.S081】Lab9 file system
Intro 在这个实验中,我们需要让xv6支持更大的文件和软链接。实验总体不是特别难,不过需要我们理解好文件系统是如何工作的。Lab8 lock中的Buffer Cache也是文件系统的一部分,不过它位于文件系统的下层,这里我们需要处理的更多在上层,偏应用层。 ...
【MIT6.S081】Lab8 lock
Intro 这个实验个人感觉挺难的,需要我们重新设计数据结构,还要考虑在并发(并行)情况下对于锁的操作,以减少多核情况下对于锁的竞争。其中主要涉及内存分配和IO缓冲块分配,在这个lab之前,xv6对于这两个分配都是使用的全局对象,并只有一把全局锁进行操作,这样的话在并行情况下锁的竞争是很激烈的,我们的任务就是重新设计这两个分配器,它们的重构思路并不完全一致,需要具体问题具体分析。 ...
【MIT6.S081】xv6进程调度分析
在做thread lab的时候,阅读xv6的源码后对于进程调度的实现有了大致的了解,但是其中锁的获取与释放顺序让我困惑了好久:在yield函数中,不是先获取了进程p的锁吗,那么之后在调度器中又获取p的锁,那不是会死锁吗?在调度器内使用swtch发生进程切换后,又会跳转到哪里? 而在我观摩大佬的一些博客和视频后,发现我之前的想法有很大的问题,归根结底是没有弄明白xv6何时发生了切换,切换后应该从哪里开始运行。这篇笔记就是对于分析xv6进程调度的总结。 ...
【MIT6.S081】Lab6 multithreading
本次的实验总体都不是很难,第一个练习让我们在用户态模拟了线程的切换,这里重要的就是进程/线程上下文的保存与恢复;第二三个练习则是让我们跳出了xv6,去熟悉pthread库和线程的同步互斥。 ...
【CMU15-445 Fall2023】Project2 Extendible Hash Index 小结
该系列博客只是为了记录自己在写Lab时的思路,按照课程要求不会在Github和博客中公开源代码。欢迎与我一起讨论交流! 太菜了,从没打过这么艰难的仗QAQ。由于课程的要求不能公开源代码,所以网上的资源会少很多,平台上的测试案例比较全面,有的还比较刁钻,需要考虑到可拓展哈希的实现细节。在自认为写完了后,提交了近40来次总有几个测试集过不了,还好没有崩溃,在看了几篇博客的方法后,加上自己画图理解,最后终于过了😭。不过回头写博客的时候再去看代码,也没有特别的复杂,还是得明白其中的算法逻辑是如何实现的。 Task1 - Read/Write Page Guards 简单来说,就是为Page实现一个RAII来自动管理资源。因为在BufferPoolManager::Unpin中,每次调用这个函数,都会让对应的page的pin_count_ - 1,当这个值为0时,这个page就可以被回收,或者说被替换了。但如果我们忘记去手动调用,该页面将永远不会被逐出缓冲池。由于缓冲池以更少的帧数运行,磁盘内外的页面交换将更多。不仅性能受到影响,而且很难检测到错误。 主要需要考虑如何编写移动构造、移动赋值的逻辑。移动了一个对象后,原来的对象的资源应该转移到了新对象上,那么原来的对象无法再访问资源(将原来对象的资源重置nullptr或清空)。 还有一个Drop()的接口,这是提供给使用者的释放资源的api,在实现虚构函数时可以直接调用它。Drop的实现就是调用Unpin,然后置空资源。需要注意的是,在进行移动赋值时,一开始也要Drop一下,考虑这样一种情况: auto p = std::move(basic_page_guard); p = std::move(basic_page_guard2); 这个时候同一个变量p接管了两个page,那么应该在第二个移动赋值时先drop掉第一个,因为第一个page不再使用了,自然要Unpin。 还有就是在三个page guard类重载移动赋值时,如果需要移动的对象和自身是同一个,那么直接返回自己就好: auto BasicPageGuard::operator=(BasicPageGuard &&that) noexcept -> BasicPageGuard & { if (&that == this) { return *this; } // ... 其他操作 } 在ReadPageGuard和WritePageGuard的Drop()中,还需要考虑释放管理的page的锁。对应的,锁的获取发生在FetchPageWrite()和FetchPageWrite()中。 Task2 - Extendible Hash Table Pages 为什么我们需要可扩展哈希? 下图来源:https://www.bilibili.com/video/BV1Qt421w7JT 在bustub的设计中,Header Page,Directory Page和Bucket Page都是无法直接构造出来的,即不能通过构造函数创建,只能通过各自的PageGuard中的As()或者AsMut()函数来转换。 Header header page中有一个max_depth_的成员变量,1 << max_depth_即为header page中能存放的目录的索引的数量。当我们有值需要放入哈希表时,获取hash(key)的二进制最高max_depth_位作为索引,再从header中对应位置去找到directory。对应的ExtendibleHTableHeaderPage中的功能实现并不难。 Directory directory中有两个depth: Global Depth:若global depth为n,那么这个Directory就有2^n个entry(相当于指向2^n个bucket) Local Depth:若local depth为n,则在这个对应的bucket下,每个元素的key的最后n位都相同 类似header中获取下一级页的索引,directory获取hash(key)的二进制最低global_depth_位作为索引。那local depth的作用是什么呢?...