Week Log Entry No.3

Mindset

最近一直在忙开学相关的事情。所以已经有一到两周没有写周报了,来了学校这边的精神状态从刚开始的郁闷到现在已经完全适应了。我个人在来到一个新环境之前和来到这里的一小段时间总会非常焦虑和抑郁,不适应感让我感到不安。不知道这是大多数人这样还是少部分人。我通常需要花一些时间来熟悉周围的环境,好在我适应速度比较快,一天多一点就和在上海没什么区别了。

来到学校之后大部分时间放在了oceanbase大赛的准备上。最近在拿miniob练手,不得不说配置环境和debug真的很折磨。今天几乎花了一天的时间去找一个bug,关于bug的问题和学到的东西在后面做记录。

来到学校也被迫养成了早睡早起的习惯,因为早上有课,而且特别饿,也逐渐开始吃早饭了。

Fitness

关于运动,我每天上课要从宿舍到教室走将近20分钟。回宿舍、扔垃圾什么的需要爬上爬下五楼。肉眼可见我脸上养出来的水肿消失了,脸部形状恢复到了之前比较瘦的状态。

我还打算办一张健身卡继续我的健身,以及游泳卡。但迟迟没有行动,争取下个星期搞定。

Entertainment

来学校后的娱乐也仅限于打打游戏了。

这周六去电影院看了IMAX的奥本海默。这部片子给我最大的共鸣就是,当科学家们在考虑自己的研究是否会毁灭世界时,那些势利的政客们仍然抛不开猜疑嫉妒别人的心理,渴望用自己的权利来教科学家“做人”。还有一幕相当讽刺,在讨论轰炸日本哪里时,美国的政客轻描淡写的指点炸哪,却不考虑老百姓的生命。奥本海默要求与苏联共享成果,为了确保人类和平而不陷入军备战争,却遭到杜鲁门的强烈拒绝...

Learn

最近书没怎么读,时间在上课和完成miniob的练习上。

周日花了接近一整个下午的时间(8h左右)去找一个bug。

这个bug的问题是:当miniob在vscode中,如果采用gdb或者lldb进行debug,首先创建一个table,然后在这个table上创建一个index。这一切暂时没有问题。如果我退出debugger,再次启动时,server端会报错。

Successfully load /Users/drcooper/cslab/miniob/etc/observer.ini
Invalid arguments, item_size:0, pool_num:1, item_num_per_pool:128, this->name:./miniob/db/sys/t-t_idx.index.
Failed to open index. table=t, index=t_idx, file=./miniob/db/sys/t-t_idx.index, rc=12:NOMEM
Failed to open table. filename=t.table
Failed to open db: sys. error=12

通过一步步的debug,定位到问题在于index的文件创建是成功了,但有关index的必要信息没有写到index文件里。也就是说index文件没有任何有效信息,因此在server重启,做index文件合法性校验时,会产生报错。

但令人奇怪的是,table meta文件的校验没有出错,而且我如果insert数据到table里,重启sever也还是可以查询到table里插入的数据的。

又一轮debug发现,原来是执行阶段(execute stage)在执行插入操作的时候,会把相关的操作append到日志文件,并且进行刷盘操作。保证数据的持久性。当重启server时,数据库会读取log,并且执行recover函数,恢复内存中table的数据,具体细节打算之后写一篇记录。

而在创建index的时候,miniob的test分支的代码没有实现写入log的操作。更不提恢复index一说。

所以就会出现,第二次启动server,index检查失败的情况。因为第一次的index数据是存在于内存中的,既没有写入log也没有写入硬盘。

解决方案有两个:

  1. 加入index写入log的支持操作,但限于时间原因,我打算后续实现(可能会涉及很多修改,比较繁杂)。
  2. 不支持index写入log,进一步探寻问题的本质。我选择方案二。

进一步问题的本质是什么呢?

通过阅读日志文件,我发现在结束debugger时,和在终端启动server结束终端时,日志信息有区别。

在正常终端中结束server时,miniob在背后启动着一个捕获信号的线程,这个线程会捕获用户输入的ctrl+c指令(UNIX信号为SIGINT)。在macos下,我需要输入两次ctrl+c才可以终止终端的server。进程捕获这些后,会执行server quit函数。最后执行cleanup函数,cleanup会释放内存中所有的object并且对重要信息进行flush to disk。

而我终止debugger时,所有一切就戛然而止了,没有任何的flush to disk日志信息。

这就把问题引到了,为什么debugger终止时不会让server正常退出。观察条是控制台发现是因为它执行的是强制杀死进程的命令,不会执行任何后续操作。解决办法是手动输入process signal SIGINT。

但在macos环境下,使用lldb还会出现一个问题。无论我输入process signal SIGINT,还是process signal SIGSTOP,还是process signal SIGTERM,都会暂停debugger,而不是退出。

进一步排查发现,有一个叫做信号拦截的概念。可以输入process signal handle SIGINT查看。

我们需要输入process handle --pass true --stop false --notify true SIGINT,把PASS STOP以及NOTIFY标识为正确设置(默认是false,true,true)。然后我们需要手动输入两次process signal SIGINT(在调试控制台),模拟两次ctrl+c。会发现,进程正确退出了,而且也执行了cleanup的所有操作。再启动进程,发现没有任何报错,成功启动。

NOTE:每次启动debugger都要执行一次process handle --pass true --stop false --notify true SIGINT,因此可以在launch.json中设置:

"configurations": [
    {
        "name": "(lldb) 启动",
        "type": "lldb",
        "request": "launch",
        "program": "${workspaceFolder}/build/bin/observer",
        "args": ["-f", "${workspaceFolder}/etc/observer.ini"],
        "cwd": "${workspaceFolder}/.vscode",
        "preLaunchTask": "CMake Build",
        "preRunCommands": ["process handle --pass true --stop false --notify true SIGINT"],
        "sourceMap": {
            "/Users/drcooper/cslab/miniob/build/src/observer/yacc_sql.y": "/Users/drcooper/cslab/miniob/src/observer/sql/parser/yacc_sql.y",
            "/Users/drcooper/cslab/miniob/build/src/observer/yacc_sql.tab.c": "/Users/drcooper/cslab/miniob/src/observer/sql/parser/yacc_sql.tab.c",
            "/Users/drcooper/cslab/miniob/build/src/observer/lex_sql.l": "/Users/drcooper/cslab/miniob/src/observer/sql/parser/lex_sql.;",
            "/Users/drcooper/cslab/miniob/build/src/observer/lex.yy.c": "/Users/drcooper/cslab/miniob/src/observer/sql/parser/lex.yy.c",
          },
    }
]

这时自然而然会想,那我可以设置一个exitCommands,内部包含两次process signal SIGINT,然后直接点关闭debugger。但这样不会成功,正确的方法仍然是需要手动输入两次process signal SIGINT,具体原因还没排查。