最近从武汉迁徙到了深圳,机会没有我想象的那么多,也仔细思考过这条路该怎么走,却怎么都走不好,找了一份相关的工作,工资不高,但好在有时间去自己学习.Anyway 还是来讲讲今天的正题.

过年那段时间看着tidb-dashboard有个挺简单的Feature,就自己做着玩玩,慢慢了解到这家公司思想和所做的事都是非常宏伟的,最近面试完了在深圳这边等着入职(大专应届像我这样的渣渣想入行还是非常困难的),下午有时间就顺着把路径1 Project1给做了,是个大坑可能会更新的比较慢,让基础的我非常的尴尬,好在相关文档还是讲的比较清晰的.

Part1

首先是几道SQL,这里就不再赘述了,除了最后一题需要思考一下,其他的都还是非常简单的,主要还是CASE确实用的比较少,下面从评论区搞了一份答案过来讲讲思路.

SELECT CASE
	WHEN P IS NULL THEN CONCAT(N, ' Root')
	WHEN N IN (SELECT DISTINCT P FROM BST) THEN CONCAT(N, ' Inner')
	ELSE CONCAT(N, ' Leaf')
	END
FROM BST
ORDER BY N ASC

只有当P col为null时,N才能为Root节点,否则的话,判断N的值是否出现在P列中,true 则为中间节点,else则为叶子结点.

Part2

首先Clone一份代码到本地,先不用忙着Make,Project 1的案例不需要.

tablecodec.goL39至L70代码就可以发现一些端倪,首先我们先理解EncodeRowKeyWithHandle这个function.

var (
	tablePrefix     = []byte{'t'}
	recordPrefixSep = []byte("_r")
	indexPrefixSep  = []byte("_i")
)

const (
	idLen     = 8
	prefixLen = 1 + idLen /*tableID*/ + 2
	// RecordRowKeyLen is public for calculating average row size.
	RecordRowKeyLen       = prefixLen + idLen /*handle*/
	tablePrefixLength     = 1
	recordPrefixSepLength = 2
)

// TableSplitKeyLen is the length of key 't{table_id}' which is used for table split.
const TableSplitKeyLen = 1 + idLen

// TablePrefix returns table's prefix 't'.
func TablePrefix() []byte {
	return tablePrefix
}

// appendTableRecordPrefix appends table record prefix  "t[tableID]_r".
func appendTableRecordPrefix(buf []byte, tableID int64) []byte {
	buf = append(buf, tablePrefix...)				//实际上将't'插入到slice head.
	buf = codec.EncodeInt(buf, tableID)				//对Tableid序列化插入到t后面.
	buf = append(buf, recordPrefixSep...)			//插入recordPrefixSep标识符"_r"
	return buf
}

// EncodeRowKeyWithHandle encodes the table id, row handle into a kv.Key
func EncodeRowKeyWithHandle(tableID int64, handle int64) kv.Key {
	buf := make([]byte, 0, RecordRowKeyLen)			//创建一个byte Slice,其len为0,cap为(prefixLen + idLen)=8+1+8+2=19.
	buf = appendTableRecordPrefix(buf, tableID)		//将空slice和tableID传入appendTableRecordPrefix.跳转到25行
	buf = codec.EncodeInt(buf, handle)
	return buf
}

让我们来看看codec.EncodeInt究竟对我们的TableID进行了什么操作

var (
	tablePrefix     = []byte{'t'}
	recordPrefixSep = []byte("_r")
	indexPrefixSep  = []byte("_i")
)

const (
	idLen     = 8
	prefixLen = 1 + idLen /*tableID*/ + 2
	// RecordRowKeyLen is public for calculating average row size.
	RecordRowKeyLen       = prefixLen + idLen /*handle*/
	tablePrefixLength     = 1
	recordPrefixSepLength = 2
)

// TableSplitKeyLen is the length of key 't{table_id}' which is used for table split.
const TableSplitKeyLen = 1 + idLen

// TablePrefix returns table's prefix 't'.
func TablePrefix() []byte {
	return tablePrefix
}

// appendTableRecordPrefix appends table record prefix  "t[tableID]_r".
func appendTableRecordPrefix(buf []byte, tableID int64) []byte {
	buf = append(buf, tablePrefix...)				//实际上将't'插入到slice head.
	buf = codec.EncodeInt(buf, tableID)				//对Tableid序列化插入到t后面.
	buf = append(buf, recordPrefixSep...)			//插入recordPrefixSep标识符"_r"
	return buf
}

// EncodeRowKeyWithHandle encodes the table id, row handle into a kv.Key
func EncodeRowKeyWithHandle(tableID int64, handle int64) kv.Key {
	buf := make([]byte, 0, RecordRowKeyLen)			//创建一个byte Slice,其len为0,cap为(prefixLen + idLen)=8+1+8+2=19.
	buf = appendTableRecordPrefix(buf, tableID)		//将空slice和tableID传入appendTableRecordPrefix.跳转到25行
	buf = codec.EncodeInt(buf, handle)
	return buf
}
func EncodeInt(b []byte, v int64) []byte {
	var data [8]byte								//生成一个长度为8的Array
	u := EncodeIntToCmpUint(v)						//跳转到第50行
	binary.BigEndian.PutUint64(data[:], u)			//根据u来generate TableID
	return append(b, data[:]...)					//世界线收束
}

const signMask uint64 = 0x8000000000000000

// EncodeIntToCmpUint make int v to comparable uint type
func EncodeIntToCmpUint(v int64) uint64 {
	return uint64(v) ^ signMask						//进行一次异或操作
}
func (bigEndian) PutUint64(b []byte, v uint64) {
	_ = b[7] // early bounds check to guarantee safety of writes below
	b[0] = byte(v >> 56)
	b[1] = byte(v >> 48)
	b[2] = byte(v >> 40)
	b[3] = byte(v >> 32)
	b[4] = byte(v >> 24)
	b[5] = byte(v >> 16)
	b[6] = byte(v >> 8)
	b[7] = byte(v)
}
//进行一次位移操作

这时,我们的TableID看起来应该是这样

"t{TableId}_r{rowhandle}"

这下子Decode就非常简单了,因为序列化后的长度我们是已知的为8:对于t后的slice进行一次还原操作,以及对r后的slice进行一次还原,就可以得到tableID和handle.

这里处理前需要做个判断,如果len(key)≠prefixLen + idLen,那么这个table是非法的.

咱们再来看看DecodeIndexKeyPrefix

// appendTableIndexPrefix appends table index prefix  "t[tableID]_i".
func appendTableIndexPrefix(buf []byte, tableID int64) []byte {
	buf = append(buf, tablePrefix...)
	buf = codec.EncodeInt(buf, tableID)
	buf = append(buf, indexPrefixSep...)
	return buf
}

// EncodeIndexSeekKey encodes an index value to kv.Key.
func EncodeIndexSeekKey(tableID int64, idxID int64, encodedValue []byte) kv.Key {
	key := make([]byte, 0, prefixLen+idLen+len(encodedValue))
	key = appendTableIndexPrefix(key, tableID)
	key = codec.EncodeInt(key, idxID)
	key = append(key, encodedValue...)
	return key
}

其实大同小异,无非是添加了一个encodedValue,这里留给大家思考

具体的解码在codec.DecodeInt这个函数中,PingCAP的老师们已经帮忙写好了,非常的银杏化哈哈

算是开了个大坑,有机会的话所有路径全部都做一遍,算是对自己的锻炼吧

拜拜👋