要使用官方的bustub-web-shell,就需要安装vercle,但是它用上了一些新的语法糖,比如:

if (typeof this._dest?.[method] === "function") {
(theme) => theme?.style)
store.hooksCleanup[index]?.();

所以我希望在一个早上的时间部署完,而短时间内我没法在我的ubuntu 20.04服务器上跑起来,所以我做了这个webshell。

仓库地址:https://github.com/Afeather2017/web-bustub

单个SQL

select * from test_simple_seq_2;
select * from __mock_t8;
select * from __mock_t8 where v4 > 4 and v4 < 7;
select * from __mock_t8 left join test_simple_seq_2 on v4 = col1;

由于SQL语句解析器的限制,不支持""形式的字符串,所以只能用''形式的字符串。

create table t1(a int, b varchar(4));
insert into t1 values (0, '0'), (1, '1'), (2, '234');
update t1 set a = 3 where b = '234';
select * from t1;
delete from t1 where a >= 2;
select * from t1;

使用快照隔离级别的事务

更改端口为8000,比如localhost:8000如果提示表创建失败,可能是别的面试官已经输入了相同的sql。 表不能够重复

  1. 打开2个网页

首先在网页A执行:

create table t1(a int, b int);
create index t1i1 on t1(a);
insert into t1 values (0, 0), (1, 1), (2, 234);

image

在网页B执行:

select * from t1;
insert into t1 values (0, 0), (1, 1), (2, 234);

image

此时B一定会Abort

  1. 打开1个网页,输入:
create table t2(a int);
insert into t2 values (0), (0), (1), (1);
commit;

image

同时新打开两个网页,分别输入:

update t2 set a = 1 where a = 0;
commit;

以及

update t2 set a = 0 where a = 1;
commit;

两者均会显示,由于事务不一样,所以可能略有不同:

image

再新打开一个网页,输入:

select * from t2;

image

可见,他不是串行化应该有的结果。串行化的结果应当是:要么全部是0,要么全部是1。

使用串行化隔离级别的事务

更改网页的端口为8001,比如localhost:8001如果提示表创建失败,可能是别的面试官已经输入了相同的sql。 表不能够重复

打开一个新网页,输入:

create table t3(a int);
insert into t3 values (0), (0), (1), (1);
commit;

image

同时打开两个网页,其中网页A输入:

update t3 set a = 1 where a = 0;
commit;

这个网页会显示:

image

另一个输入:

update t3 set a = 0 where a = 1;
commit;

此时会Abort

image

设计笔记

  1. 思路

整个项目依赖于bustub-nc-shell,它创建一个bustub数据库服务器。每次创建一个新的连接,都会给该连接绑定一个事务。也就是说一个连接只有一个事务。一旦这个事务长期未通讯(这里是6分钟),或者执行失败Abort了,或者commit了,这个事务都再也不能够用了。

而一个网页与一个事务一一对应,所以如果你commit了,或者手动Abort了,或者自动Abort了,你都要:复制网页域名和端口,重新打开一个网页即可。

  1. 潜在BUG

简单问题用简单方案。除非我要做一个完整好用的工业级客户端,否则目前的是够用的。留下这些BUG是功能和时间的取舍。

a. 由于TCP的特性,字符串长度比较长的SQL可能会导致输出错误。

比如你有一句长度是1M的SQL,中间有一处换行符,那么在TCP传输的时候可能会出现传完了换行符前面的前一半,而后一半没有传输完成的现象。而bustub-nc-shell会在读到换行符的时候输出...,这是因为bustub-nc-shell是为了交互式终端而设计的,所以它会有这种情况。

真的要修复它,需要修改bustub本身。

b. 长SQL阻塞

由于要等待SQL执行完成,所以长时间执行的SQL会阻塞这个网页服务器(而不是数据库服务器本身)。除非面试官真的很感兴趣,否则这大概率不会发生。要修复则必须改为异步架构

c. 自动重置数据库时段时间阻塞,见第5点

  1. 单引号和双引号

由于binder暂且不支持双引号,所以不可以使用它。

  1. 利用异常减少分支

Python中socket的recv方法在对方关闭连接的情况下再读取,会返回0。此时我们关闭套接字即可。之后再读取会触发文件描述符错误。

套接字的send也可能触发sigpipe。反正处理方式都是一样的,为什么非得多一个分支?

  1. 自动重置数据库

可能某个面试官插入了表t1,另一个面试官来试着执行相同的sql。此时必然无法插入表。

估计没有面试官会想着修改上述的例子吧……所以这一步是有必要的。

方法也很简单,killall杀死线程后,清理一下。网页服务器等待2秒。这样网页端可能要等待2秒。