Table Codec – 编写tinysql的解码器

1. 编码规则

整体上的规则是一个信息前缀+信息ID

设置的前缀有

1
2
3
4
5
var (
tablePrefix = []byte{'t'}
recordPrefixSep = []byte("_r")
indexPrefixSep = []byte("_i")
)

相关信息和前缀的长度

1
2
3
4
5
6
7
8
const (
idLen = 8
prefixLen = 1 + idLen /*tableID*/ + 2
// RecordRowKeyLen is public for calculating average row size.
RecordRowKeyLen = prefixLen + idLen /*handle*/
tablePrefixLength = 1
recordPrefixSepLength = 2
)
1
2
3
4
5
6
t[table ID]_r[rowID]
得到的是这一行的数据
t[table ID]_i[indexID]_indexColval
得到的是行的id
t[table ID]_i[indexID]_ColVal_rowID
唯一编码

DecodeRecordKey

对含有tableID的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
func DecodeRecordKey(key kv.Key) (tableID int64, handle int64, err error) {
/* Project 1-2: your code here
* DecodeRecordKey decodes the key and gets the tableID, handle.
* Decode is actually the reverse of encoding, so you can refer to EncodeRowKeyWithHandle.
*
* Parameters
* key: the key needs to be decoded. It may be invalid.
*
* Return value
* tableID: decoded value.
* handle: decoded value.
* err: error during decoding, otherwise nil.
*
* DecodeRecordKey may need to follow the steps:
* 1. check if the key is valid.
* 2. get the table prefix and decode.
* 3. get the record prefix and decode.
* 4. create handle.
* 5. return decoded value.
*
* Some hints:
* 1. you may need codec.DecodeInt to decode string to int
* 2. const `prefixLen`, `tablePrefixLength` and `recordPrefixSepLength` are useful.
* 3. errInvalidRecordKey.GenWithStack is a useful function to generate invalid record key errors.
* 4. if an error occurs, return 0 as tableID, nil as handle and the error.
* 5. understanding the coding rules is a prerequisite for implementing this function,
* you can learn it in the projection 1-2 course documentation.
*/
// t[tableID]_i
// 后缀:_i
// len: RecordRowKeyLen
// 1. 查看合法性
error_return := func() (tableID int64, handle int64, err error) {
return 0, 0, errInvalidRecordKey.GenWithStack("Invaild Record Key- %q", key)

}

if len(key) < RecordRowKeyLen || key[0] != tablePrefix[0] {
return error_return()
}

// 减去t
key = key[tablePrefixLength:]

// 2. 进行解码
key, tableID, err = codec.DecodeInt(key)

// 判断解码是否成功
if err != nil {
return 0, 0, errors.Trace(err)
}

// 判断前缀部位recordPrefixsep
if !key.HasPrefix(recordPrefixSep) {
return error_return()
}
key = key[recordPrefixSepLength:]
key, handle, err = codec.DecodeInt(key)

if err != nil {
return 0, 0, errors.Trace(err)
}
return tableddddID, handle, nil
}

DecodeIndexKeyPrefix

和上面的是相似的处理方式,去除前缀,解码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
func DecodeIndexKeyPrefix(key kv.Key) (tableID int64, indexID int64, indexValues []byte, err error) {
/* Project 1-2: your code here
* DecodeIndexKeyPrefix decodes the key and gets the tableID, indexID, indexValues.
* Decode is actually the reverse of encoding, so you can refer to EncodeIndexSeekKey.
*
* Parameters
* key: the key needs to be decoded. It may be invalid.
*
* Return value
* tableID: decoded value.
* indexID: decoded value.
* indexValues: decoded value.
* err: error during decoding, otherwise nil.
*
* DecodeRecordKey may need to follow the steps:
* 1. check if the key is valid.
* 2. decode tableID.
* 3. decode indexID.
* 4. decode indexValues.
* 5. return decoded value.
*
* Some hints:
* 1. you may need codec.DecodeInt to decode string to int
* 2. const `prefixLen`, `idLen` and others are useful.
* 3. errInvalidRecordKey.GenWithStack is a useful function to generate invalid record key errors.
* 4. if an error occurs, return 0 as tableID, 0 as indexID, nil as indexValues and the error.
* 5. understanding the coding rules is a prerequisite for implementing this function,
* you can learn it in the projection 1-2 course documentation.
*/
// 错误返回
error_return := func() (table int64, indexID int64, indexValues []byte, err error) {
return 0, 0, nil, errInvalidIndexKey.GenWithStack("invalid index key - %q", key)
}

// 判断长度和开头的格式
if len(key) < RecordRowKeyLen || key[0] != 't' {
return error_return()
}

//去除开头的t
key = key[tablePrefixLength:]

// 进行解码得到tableID
key, tableID, err = codec.DecodeInt(key)
if err != nil {
return 0, 0, nil, errors.Trace(err)
}

// 判断是否存储index前缀
if !key.HasPrefix(indexPrefixSep) {
return error_return()
}

// 去除前缀
key = key[recordPrefixSepLength:]

// 进行解码
key, indexID, err = codec.DecodeInt(key)

// 是否解码发生错误
if err != nil {
return 0, 0, nil, errors.Trace(err)
}
return tableID, indexID, key, nil

}