tidb笔记1
语法解析
tidb的语法解析有一些语句并没有作支持: REPLACE
go build -ldflags参数
在Makefile中, 有这么一句:
|
|
我们来看看ldflags的意义
|
|
这个参数是传递给go tool link的, 我们看看go tool:
|
|
这个-X选项的意思是, 在二进制中增加一个定义, 格式是importpath.variable_name=value, 所以我们看到了printer.TiDBBuildTS和printer.TiDBGitHash的两个变量的定义. 在看看这两个变量在代码中的位置:
|
|
这就知道了这个选项的目的了
从Slice转换到String 避免复制
|
|
slice转string之后,如果slice的值有变化,string也会跟着改变,如下:
|
|
但是string转slice之后,就不能更改slice了,如下:
上面为什么会崩溃我猜想可能是string是immutable的,可能对应的内存地址也是不允许改动的。
另外,上面这个崩溃在defer里面是recover不回来的,真的就崩溃了,原因可能就跟c的非法内存访问一样,os不跟你玩了。
并发控制
tiDB里面利用channel实现了一种沙漏算法, 详情见: server/tokenlimiter.go 以及Server.getToken, releaseToken函数
bootstrap(tidb/bootstrap.go:89)
每次tidb启动, 都会执行这个启动函数一次.
compile
|
|
我们看到这里有一个判断是不是抽象语法树ast.Node的, tidb里面心很大它实现了两套statement对象, 一套是ast包里面的, 可以用调用stm, err := optimizer.Compile(node)
来优化, 一套是stmt包里面的, 详见parser.y:
|
|
然而, 并没什么卵用, 在parser.y中可以看到, 所有的Statement都是stmt包里面的, 所以Compile中的optimizer.Compile(node)
不会运行.
并行Create database会失败
看到:
如果在别的goroutine中别人更改了meta.SchemaMetaVersionKey, 那么此次create database就会失败, 也不会重试
事务实现
参考: mysql事务
基本借鉴了percolater那种利用时间戳来实现多版本的方式, 在事务中修改的值通过dbTxn.LockKeys
函数来把key锁住, 如果在别的事务中对这些key修改了, 那么此事务commit的时候将不能成功, 具体的实现在dbTxn.doCommit:
|
|
在向leveldb写入值之前, 先用tryConditionLockKey看能否锁住那些值, 同时判断现在存在的版本是否已经被别人修改过(通过值绑定的版本, 也就是时间戳来判断):
|
|
然而, 即使如此, 还是会有write skew问题, 因为其并没有对读取的值锁住. 所以, tidb也对Select for update做出了相应的支持
|
|
infoSchema.tables 构造
|
|
infoSchema.tables成员是用来存放table定义的, 但是让我感觉迷惑的是, 在ddl.CreateTable中, 并没有对这个值进行构造:
|
|
只设置了model.TableInfo, 那么, 到底infoSchema.tables是在哪里更新的呢, 我们看到CreateTable还会触发Domain.onDDLChange, 这个函数里面:
调用了Handle.Set
所以每次新建一个Table, tidb都会重建infoSchema.tables变量(这样不好吧? 为何不增量的增加)
codec.EncodeBytes
我们看到每次插入leveldb之前, 都会对其key作Encode
|
|
其用意可从下面这段注释中窥得一二:
|
|
INSERT … ON DUPLICATE KEY UPDATE Syntax
具体详情见:mysql: ON DUPLICATE KEY UPDATE Syntax
这里举个例子:
|
|
这种写法比较麻烦, 用on duplicate key update 的做法如下: