diff --git a/ddl/index.go b/ddl/index.go index 668ca5edd6..7b049c78b8 100644 --- a/ddl/index.go +++ b/ddl/index.go @@ -483,10 +483,7 @@ func (d *ddl) backfillTableIndex(t table.Table, indexInfo *model.IndexInfo, hand } func (d *ddl) dropTableIndex(t table.Table, indexInfo *model.IndexInfo) error { - prefix, err := kv.GenIndexPrefix(t.IndexPrefix(), indexInfo.ID) - if err != nil { - return errors.Trace(err) - } + prefix := kv.GenIndexPrefix(t.IndexPrefix(), indexInfo.ID) prefixBytes := []byte(prefix) diff --git a/kv/index_iter.go b/kv/index_iter.go index 44173f6842..e030dc0b8b 100644 --- a/kv/index_iter.go +++ b/kv/index_iter.go @@ -20,6 +20,7 @@ import ( "strings" "github.com/juju/errors" + "github.com/pingcap/tidb/util/codec" ) var ( @@ -101,13 +102,11 @@ type kvIndex struct { } // GenIndexPrefix generates the index prefix. -func GenIndexPrefix(indexPrefix string, indexID int64) (string, error) { - indexKey, err := EncodeValue(indexID) - if err != nil { - return "", errors.Trace(err) - } - - return indexPrefix + string(indexKey), nil +func GenIndexPrefix(indexPrefix string, indexID int64) string { + buf := make([]byte, 0, len(indexPrefix)+8) + buf = append(buf, indexPrefix...) + buf = codec.EncodeInt(buf, indexID) + return string(buf) } // NewKVIndex builds a new kvIndex object. @@ -118,11 +117,7 @@ func NewKVIndex(indexPrefix string, indexName string, indexID int64, unique bool unique: unique, } - var err error - index.prefix, err = GenIndexPrefix(indexPrefix, indexID) - if err != nil { - return nil, errors.Trace(err) - } + index.prefix = GenIndexPrefix(indexPrefix, indexID) return index, nil } diff --git a/table/tables/tables.go b/table/tables/tables.go index 35e7f2da99..85ab90ed38 100644 --- a/table/tables/tables.go +++ b/table/tables/tables.go @@ -19,7 +19,6 @@ package tables import ( "bytes" - "fmt" "reflect" "strings" "time" @@ -37,6 +36,7 @@ import ( "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/terror" "github.com/pingcap/tidb/util" + "github.com/pingcap/tidb/util/codec" "github.com/pingcap/tidb/util/types" ) @@ -53,9 +53,7 @@ type Table struct { writableColumns []*column.Col indices []*column.IndexedCol recordPrefix string - encRecordPrefix []byte indexPrefix string - encIndexPrefix []byte alloc autoid.Allocator state model.SchemaState } @@ -108,26 +106,13 @@ func NewTable(tableID int64, tableName string, cols []*column.Col, alloc autoid. t := &Table{ ID: tableID, Name: name, - recordPrefix: fmt.Sprintf("%d_r", tableID), - indexPrefix: fmt.Sprintf("%d_i", tableID), + recordPrefix: string(genTableRecordPrefix(tableID)), + indexPrefix: string(genTableIndexPrefix(tableID)), alloc: alloc, Columns: cols, state: model.StatePublic, } - var err error - t.encRecordPrefix, err = kv.EncodeValue(t.recordPrefix) - if err != nil { - return t, errors.Trace(err) - } - t.encRecordPrefix = append(TablePrefix, []byte(t.encRecordPrefix)...) - - t.encIndexPrefix, err = kv.EncodeValue(t.indexPrefix) - if err != nil { - return t, errors.Trace(err) - } - t.encIndexPrefix = append(TablePrefix, []byte(t.encIndexPrefix)...) - t.publicColumns = t.Cols() t.writableColumns = t.writableCols() return t, nil @@ -264,24 +249,21 @@ func (t *Table) flatten(data interface{}) (interface{}, error) { // KeyPrefix implements table.Table KeyPrefix interface. func (t *Table) KeyPrefix() string { - return string(t.encRecordPrefix) + return t.recordPrefix } // IndexPrefix implements table.Table IndexPrefix interface. func (t *Table) IndexPrefix() string { - return string(t.encIndexPrefix) + return t.indexPrefix } // RecordKey implements table.Table RecordKey interface. func (t *Table) RecordKey(h int64, col *column.Col) []byte { - var key []byte + colID := int64(0) if col != nil { - key = EncodeRecordKey(t.recordPrefix, h, col.ID) - } else { - key = EncodeRecordKey(t.recordPrefix, h, 0) + colID = col.ID } - - return append(TablePrefix, key...) + return encodeRecordKey(t.recordPrefix, h, colID) } // FirstKey implements table.Table FirstKey interface. @@ -753,47 +735,85 @@ func GetColDefaultValue(ctx context.Context, col *model.ColumnInfo) (interface{} return col.DefaultValue, true, nil } -// EncodeRecordKey encodes the string value to a byte slice. -func EncodeRecordKey(tablePrefix string, h int64, columnID int64) []byte { - var ( - buf []byte - err error - ) +var ( + recordPrefixSep = []byte("_r") + indexPrefixSep = []byte("_i") +) - if columnID == 0 { // Ignore columnID. - buf, err = kv.EncodeValue(tablePrefix, h) - } else { - buf, err = kv.EncodeValue(tablePrefix, h, columnID) - } - if err != nil { - log.Fatal("should never happend") +// record prefix is "t[tableID]_r" +func genTableRecordPrefix(tableID int64) []byte { + buf := make([]byte, 0, len(TablePrefix)+8+len(recordPrefixSep)) + buf = append(buf, TablePrefix...) + buf = codec.EncodeInt(buf, tableID) + buf = append(buf, recordPrefixSep...) + return buf +} + +// index prefix is "t[tableID]_i" +func genTableIndexPrefix(tableID int64) []byte { + buf := make([]byte, 0, len(TablePrefix)+8+len(indexPrefixSep)) + buf = append(buf, TablePrefix...) + buf = codec.EncodeInt(buf, tableID) + buf = append(buf, indexPrefixSep...) + return buf +} + +func encodeRecordKey(recordPrefix string, h int64, columnID int64) []byte { + buf := make([]byte, 0, len(recordPrefix)+16) + buf = append(buf, recordPrefix...) + buf = codec.EncodeInt(buf, h) + + if columnID != 0 { + buf = codec.EncodeInt(buf, columnID) } return buf } -// DecodeRecordKey decodes the key and gets the values. -func DecodeRecordKey(key []byte) ([]interface{}, error) { +// EncodeRecordKey encodes the record key for a table column. +func EncodeRecordKey(tableID int64, h int64, columnID int64) []byte { + prefix := genTableRecordPrefix(tableID) + return encodeRecordKey(string(prefix), h, columnID) +} + +// DecodeRecordKey decodes the key and gets the tableID, handle and columnID. +func DecodeRecordKey(key []byte) (tableID int64, handle int64, columnID int64, err error) { + k := key if !bytes.HasPrefix(key, TablePrefix) { - return nil, errors.Errorf("invalid record key - %v", key) + return 0, 0, 0, errors.Errorf("invalid record key - %q", k) } key = key[len(TablePrefix):] - vals, err := kv.DecodeValue(key) + key, tableID, err = codec.DecodeInt(key) if err != nil { - return nil, errors.Trace(err) + return 0, 0, 0, errors.Trace(err) } - return vals, nil + if !bytes.HasPrefix(key, recordPrefixSep) { + return 0, 0, 0, errors.Errorf("invalid record key - %q", k) + } + + key = key[len(recordPrefixSep):] + + key, handle, err = codec.DecodeInt(key) + if err != nil { + return 0, 0, 0, errors.Trace(err) + } + if len(key) == 0 { + return + } + + key, columnID, err = codec.DecodeInt(key) + if err != nil { + return 0, 0, 0, errors.Trace(err) + } + + return } // DecodeRecordKeyHandle decodes the key and gets the record handle. func DecodeRecordKeyHandle(key string) (int64, error) { - vals, err := DecodeRecordKey([]byte(key)) - if err != nil { - return 0, errors.Trace(err) - } - - return vals[1].(int64), nil + _, handle, _, err := DecodeRecordKey([]byte(key)) + return handle, errors.Trace(err) } func init() { diff --git a/table/tables/tables_test.go b/table/tables/tables_test.go index ccf609a3ff..bc5e3ce23b 100644 --- a/table/tables/tables_test.go +++ b/table/tables/tables_test.go @@ -198,21 +198,43 @@ func (ts *testSuite) TestUniqueIndexMultipleNullEntries(c *C) { func (ts *testSuite) TestRowKeyCodec(c *C) { table := []struct { - prefix string - h int64 - ID int64 + tableID int64 + h int64 + ID int64 }{ - {"123abc##!@#((_)((**&&^^%$", 1234567890, 0}, - {"", 1, 0}, - {"", -1, 0}, - {"", -1, 1}, + {1, 1234567890, 0}, + {2, 1, 0}, + {3, -1, 0}, + {4, -1, 1}, } for _, t := range table { - b := tables.EncodeRecordKey(t.prefix, t.h, t.ID) - key := append(tables.TablePrefix, b...) - handle, err := tables.DecodeRecordKeyHandle(string(key)) + b := tables.EncodeRecordKey(t.tableID, t.h, t.ID) + tableID, handle, columnID, err := tables.DecodeRecordKey(b) + c.Assert(err, IsNil) + c.Assert(tableID, Equals, t.tableID) + c.Assert(handle, Equals, t.h) + c.Assert(columnID, Equals, t.ID) + + handle, err = tables.DecodeRecordKeyHandle(string(b)) c.Assert(err, IsNil) c.Assert(handle, Equals, t.h) } + + // test error + tbl := []string{ + "", + "x", + "t1", + "t12345678", + "t12345678_i", + "t12345678_r1", + "t12345678_r1234567", + "t12345678_r123456781", + } + + for _, t := range tbl { + _, err := tables.DecodeRecordKeyHandle(t) + c.Assert(err, NotNil) + } }