github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/kv/kv.go (about) 1 // Copyright 2019 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package kv 15 16 import ( 17 "bytes" 18 "fmt" 19 "math" 20 "sort" 21 22 "github.com/pingcap/errors" 23 sst "github.com/pingcap/kvproto/pkg/import_sstpb" 24 "github.com/pingcap/log" 25 "github.com/pingcap/parser/model" 26 "github.com/pingcap/parser/mysql" 27 "github.com/pingcap/tidb/kv" 28 "github.com/pingcap/tidb/meta/autoid" 29 "github.com/pingcap/tidb/table" 30 "github.com/pingcap/tidb/table/tables" 31 "github.com/pingcap/tidb/tablecodec" 32 "github.com/pingcap/tidb/types" 33 "go.uber.org/zap" 34 35 "github.com/pingcap/br/pkg/logutil" 36 "github.com/pingcap/br/pkg/redact" 37 ) 38 39 var extraHandleColumnInfo = model.NewExtraHandleColInfo() 40 41 // Iter abstract iterator method for Ingester. 42 type Iter interface { 43 // Seek seek to specify position. 44 // if key not found, seeks next key position in iter. 45 Seek(key []byte) bool 46 // Error return current error on this iter. 47 Error() error 48 // First moves this iter to the first key. 49 First() bool 50 // Last moves this iter to the last key. 51 Last() bool 52 // Valid check this iter reach the end. 53 Valid() bool 54 // Next moves this iter forward. 55 Next() bool 56 // Key represents current position pair's key. 57 Key() []byte 58 // Value represents current position pair's Value. 59 Value() []byte 60 // Close close this iter. 61 Close() error 62 // OpType represents operations of pair. currently we have two types. 63 // 1. Put 64 // 2. Delete 65 OpType() sst.Pair_OP 66 } 67 68 // IterProducer produces iterator with given range. 69 type IterProducer interface { 70 // Produce produces iterator with given range [start, end). 71 Produce(start []byte, end []byte) Iter 72 } 73 74 // SimpleKVIterProducer represents kv iter producer. 75 type SimpleKVIterProducer struct { 76 pairs Pairs 77 } 78 79 // NewSimpleKVIterProducer creates SimpleKVIterProducer. 80 func NewSimpleKVIterProducer(pairs Pairs) IterProducer { 81 return &SimpleKVIterProducer{ 82 pairs: pairs, 83 } 84 } 85 86 // Produce implements Iter.Producer.Produce. 87 func (p *SimpleKVIterProducer) Produce(start []byte, end []byte) Iter { 88 startIndex := sort.Search(len(p.pairs), func(i int) bool { 89 return bytes.Compare(start, p.pairs[i].Key) < 1 90 }) 91 endIndex := sort.Search(len(p.pairs), func(i int) bool { 92 return bytes.Compare(end, p.pairs[i].Key) < 1 93 }) 94 if startIndex >= endIndex { 95 log.Warn("produce failed due to start key is large than end key", 96 zap.Binary("start", start), zap.Binary("end", end)) 97 return nil 98 } 99 return newSimpleKVIter(p.pairs[startIndex:endIndex]) 100 } 101 102 // SimpleKVIter represents simple pair iterator. 103 // which is used for log restore. 104 type SimpleKVIter struct { 105 index int 106 pairs Pairs 107 } 108 109 // newSimpleKVIter creates SimpleKVIter. 110 func newSimpleKVIter(pairs Pairs) Iter { 111 return &SimpleKVIter{ 112 index: -1, 113 pairs: pairs, 114 } 115 } 116 117 // Seek implements Iter.Seek. 118 func (s *SimpleKVIter) Seek(key []byte) bool { 119 s.index = sort.Search(len(s.pairs), func(i int) bool { 120 return bytes.Compare(key, s.pairs[i].Key) < 1 121 }) 122 return s.index < len(s.pairs) 123 } 124 125 // Error implements Iter.Error. 126 func (s *SimpleKVIter) Error() error { 127 return nil 128 } 129 130 // First implements Iter.First. 131 func (s *SimpleKVIter) First() bool { 132 if len(s.pairs) == 0 { 133 return false 134 } 135 s.index = 0 136 return true 137 } 138 139 // Last implements Iter.Last. 140 func (s *SimpleKVIter) Last() bool { 141 if len(s.pairs) == 0 { 142 return false 143 } 144 s.index = len(s.pairs) - 1 145 return true 146 } 147 148 // Valid implements Iter.Valid. 149 func (s *SimpleKVIter) Valid() bool { 150 return s.index >= 0 && s.index < len(s.pairs) 151 } 152 153 // Next implements Iter.Next. 154 func (s *SimpleKVIter) Next() bool { 155 s.index++ 156 return s.index < len(s.pairs) 157 } 158 159 // Key implements Iter.Key. 160 func (s *SimpleKVIter) Key() []byte { 161 if s.index >= 0 && s.index < len(s.pairs) { 162 return s.pairs[s.index].Key 163 } 164 return nil 165 } 166 167 // Value implements Iter.Value. 168 func (s *SimpleKVIter) Value() []byte { 169 if s.index >= 0 && s.index < len(s.pairs) { 170 return s.pairs[s.index].Val 171 } 172 return nil 173 } 174 175 // Close implements Iter.Close. 176 func (s *SimpleKVIter) Close() error { 177 return nil 178 } 179 180 // OpType implements Iter.KeyIsDelete. 181 func (s *SimpleKVIter) OpType() sst.Pair_OP { 182 if s.Valid() && s.pairs[s.index].IsDelete { 183 return sst.Pair_Delete 184 } 185 return sst.Pair_Put 186 } 187 188 // Encoder encodes a row of SQL values into some opaque type which can be 189 // consumed by OpenEngine.WriteEncoded. 190 type Encoder interface { 191 // Close the encoder. 192 Close() 193 194 // AddRecord encode encodes a row of SQL values into a backend-friendly format. 195 AddRecord( 196 row []types.Datum, 197 rowID int64, 198 columnPermutation []int, 199 ) (Row, int, error) 200 201 // RemoveRecord encode encodes a row of SQL delete values into a backend-friendly format. 202 RemoveRecord( 203 row []types.Datum, 204 rowID int64, 205 columnPermutation []int, 206 ) (Row, int, error) 207 } 208 209 // Row represents a single encoded row. 210 type Row interface { 211 // ClassifyAndAppend separates the data-like and index-like parts of the 212 // encoded row, and appends these parts into the existing buffers and 213 // checksums. 214 ClassifyAndAppend( 215 data *Pairs, 216 dataChecksum *Checksum, 217 indices *Pairs, 218 indexChecksum *Checksum, 219 ) 220 } 221 222 type tableKVEncoder struct { 223 tbl table.Table 224 se *session 225 recordCache []types.Datum 226 } 227 228 // NewTableKVEncoder creates the Encoder. 229 func NewTableKVEncoder(tbl table.Table, options *SessionOptions) Encoder { 230 se := newSession(options) 231 // Set CommonAddRecordCtx to session to reuse the slices and BufStore in AddRecord 232 recordCtx := tables.NewCommonAddRecordCtx(len(tbl.Cols())) 233 tables.SetAddRecordCtx(se, recordCtx) 234 return &tableKVEncoder{ 235 tbl: tbl, 236 se: se, 237 } 238 } 239 240 var kindStr = [...]string{ 241 types.KindNull: "null", 242 types.KindInt64: "int64", 243 types.KindUint64: "uint64", 244 types.KindFloat32: "float32", 245 types.KindFloat64: "float64", 246 types.KindString: "string", 247 types.KindBytes: "bytes", 248 types.KindBinaryLiteral: "binary", 249 types.KindMysqlDecimal: "decimal", 250 types.KindMysqlDuration: "duration", 251 types.KindMysqlEnum: "enum", 252 types.KindMysqlBit: "bit", 253 types.KindMysqlSet: "set", 254 types.KindMysqlTime: "time", 255 types.KindInterface: "interface", 256 types.KindMinNotNull: "min", 257 types.KindMaxValue: "max", 258 types.KindRaw: "raw", 259 types.KindMysqlJSON: "json", 260 } 261 262 // MarshalLogArray implements the zapcore.ArrayMarshaler interface. 263 func zapRow(key string, row []types.Datum) zap.Field { 264 return logutil.AbbreviatedArray(key, row, func(input interface{}) []string { 265 row := input.([]types.Datum) 266 vals := make([]string, 0, len(row)) 267 for _, datum := range row { 268 kind := datum.Kind() 269 var str string 270 var err error 271 switch kind { 272 case types.KindNull: 273 str = "NULL" 274 case types.KindMinNotNull: 275 str = "-inf" 276 case types.KindMaxValue: 277 str = "+inf" 278 default: 279 str, err = datum.ToString() 280 if err != nil { 281 vals = append(vals, err.Error()) 282 continue 283 } 284 } 285 vals = append(vals, 286 fmt.Sprintf("kind: %s, val: %s", kindStr[kind], redact.String(str))) 287 } 288 return vals 289 }) 290 } 291 292 // Pairs represents the slice of Pair. 293 type Pairs []Pair 294 295 // Close ... 296 func (kvcodec *tableKVEncoder) Close() { 297 } 298 299 // AddRecord encode a row of data into KV pairs. 300 // 301 // See comments in `(*TableRestore).initializeColumns` for the meaning of the 302 // `columnPermutation` parameter. 303 func (kvcodec *tableKVEncoder) AddRecord( 304 row []types.Datum, 305 rowID int64, 306 columnPermutation []int, 307 ) (Row, int, error) { 308 cols := kvcodec.tbl.Cols() 309 310 var value types.Datum 311 var err error 312 313 record := kvcodec.recordCache 314 if record == nil { 315 record = make([]types.Datum, 0, len(cols)+1) 316 } 317 318 isAutoRandom := false 319 if kvcodec.tbl.Meta().PKIsHandle && kvcodec.tbl.Meta().ContainsAutoRandomBits() { 320 isAutoRandom = true 321 } 322 323 for i, col := range cols { 324 j := columnPermutation[i] 325 isAutoIncCol := mysql.HasAutoIncrementFlag(col.Flag) 326 isPk := mysql.HasPriKeyFlag(col.Flag) 327 switch { 328 case j >= 0 && j < len(row): 329 value, err = table.CastValue(kvcodec.se, row[j], col.ToInfo(), false, false) 330 if err == nil { 331 err = col.HandleBadNull(&value, kvcodec.se.vars.StmtCtx) 332 } 333 case isAutoIncCol: 334 // we still need a conversion, e.g. to catch overflow with a TINYINT column. 335 value, err = table.CastValue(kvcodec.se, types.NewIntDatum(rowID), col.ToInfo(), false, false) 336 default: 337 value, err = table.GetColDefaultValue(kvcodec.se, col.ToInfo()) 338 } 339 if err != nil { 340 return nil, 0, errors.Trace(err) 341 } 342 343 record = append(record, value) 344 345 if isAutoRandom && isPk { 346 typeBitsLength := uint64(mysql.DefaultLengthOfMysqlTypes[col.Tp] * 8) 347 incrementalBits := typeBitsLength - kvcodec.tbl.Meta().AutoRandomBits 348 hasSignBit := !mysql.HasUnsignedFlag(col.Flag) 349 if hasSignBit { 350 incrementalBits-- 351 } 352 _ = kvcodec.tbl.RebaseAutoID(kvcodec.se, value.GetInt64()&((1<<incrementalBits)-1), false, autoid.AutoRandomType) 353 } 354 if isAutoIncCol { 355 // TODO use auto incremental type 356 _ = kvcodec.tbl.RebaseAutoID(kvcodec.se, getAutoRecordID(value, &col.FieldType), false, autoid.RowIDAllocType) 357 } 358 } 359 360 if TableHasAutoRowID(kvcodec.tbl.Meta()) { 361 j := columnPermutation[len(cols)] 362 if j >= 0 && j < len(row) { 363 value, err = table.CastValue(kvcodec.se, row[j], extraHandleColumnInfo, false, false) 364 } else { 365 value, err = types.NewIntDatum(rowID), nil 366 } 367 if err != nil { 368 return nil, 0, errors.Trace(err) 369 } 370 record = append(record, value) 371 _ = kvcodec.tbl.RebaseAutoID(kvcodec.se, value.GetInt64(), false, autoid.RowIDAllocType) 372 } 373 _, err = kvcodec.tbl.AddRecord(kvcodec.se, record) 374 if err != nil { 375 log.Error("kv add Record failed", 376 zapRow("originalRow", row), 377 zapRow("convertedRow", record), 378 zap.Error(err), 379 ) 380 return nil, 0, errors.Trace(err) 381 } 382 383 pairs, size := kvcodec.se.takeKvPairs() 384 kvcodec.recordCache = record[:0] 385 return Pairs(pairs), size, nil 386 } 387 388 // get record value for auto-increment field 389 // 390 // See: https://github.com/pingcap/tidb/blob/47f0f15b14ed54fc2222f3e304e29df7b05e6805/executor/insert_common.go#L781-L852 391 // TODO: merge this with pkg/lightning/backend/kv/sql2kv.go 392 func getAutoRecordID(d types.Datum, target *types.FieldType) int64 { 393 switch target.Tp { 394 case mysql.TypeFloat, mysql.TypeDouble: 395 return int64(math.Round(d.GetFloat64())) 396 case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong: 397 return d.GetInt64() 398 default: 399 panic(fmt.Sprintf("unsupported auto-increment field type '%d'", target.Tp)) 400 } 401 } 402 403 // RemoveRecord encode a row of data into KV pairs. 404 func (kvcodec *tableKVEncoder) RemoveRecord( 405 row []types.Datum, 406 rowID int64, 407 columnPermutation []int, 408 ) (Row, int, error) { 409 cols := kvcodec.tbl.Cols() 410 411 var value types.Datum 412 var err error 413 414 record := kvcodec.recordCache 415 if record == nil { 416 record = make([]types.Datum, 0, len(cols)+1) 417 } 418 419 for i, col := range cols { 420 j := columnPermutation[i] 421 isAutoIncCol := mysql.HasAutoIncrementFlag(col.Flag) 422 switch { 423 case j >= 0 && j < len(row): 424 value, err = table.CastValue(kvcodec.se, row[j], col.ToInfo(), false, false) 425 if err == nil { 426 err = col.HandleBadNull(&value, kvcodec.se.vars.StmtCtx) 427 } 428 case isAutoIncCol: 429 // we still need a conversion, e.g. to catch overflow with a TINYINT column. 430 value, err = table.CastValue(kvcodec.se, types.NewIntDatum(rowID), col.ToInfo(), false, false) 431 default: 432 value, err = table.GetColDefaultValue(kvcodec.se, col.ToInfo()) 433 } 434 if err != nil { 435 return nil, 0, errors.Trace(err) 436 } 437 record = append(record, value) 438 } 439 err = kvcodec.tbl.RemoveRecord(kvcodec.se, kv.IntHandle(rowID), record) 440 if err != nil { 441 log.Error("kv remove record failed", 442 zapRow("originalRow", row), 443 zapRow("convertedRow", record), 444 zap.Error(err), 445 ) 446 return nil, 0, errors.Trace(err) 447 } 448 449 pairs, size := kvcodec.se.takeKvPairs() 450 kvcodec.recordCache = record[:0] 451 return Pairs(pairs), size, nil 452 } 453 454 // ClassifyAndAppend split Pairs to data rows and index rows. 455 func (kvs Pairs) ClassifyAndAppend( 456 data *Pairs, 457 dataChecksum *Checksum, 458 indices *Pairs, 459 indexChecksum *Checksum, 460 ) { 461 dataKVs := *data 462 indexKVs := *indices 463 464 for _, kv := range kvs { 465 if kv.Key[tablecodec.TableSplitKeyLen+1] == 'r' { 466 dataKVs = append(dataKVs, kv) 467 dataChecksum.UpdateOne(kv) 468 } else { 469 indexKVs = append(indexKVs, kv) 470 indexChecksum.UpdateOne(kv) 471 } 472 } 473 474 *data = dataKVs 475 *indices = indexKVs 476 } 477 478 // Clear resets the Pairs. 479 func (kvs Pairs) Clear() Pairs { 480 return kvs[:0] 481 } 482 483 // NextKey return the smallest []byte that is bigger than current bytes. 484 // special case when key is empty, empty bytes means infinity in our context, so directly return itself. 485 func NextKey(key []byte) []byte { 486 if len(key) == 0 { 487 return []byte{} 488 } 489 490 // in tikv <= 4.x, tikv will truncate the row key, so we should fetch the next valid row key 491 // See: https://github.com/tikv/tikv/blob/f7f22f70e1585d7ca38a59ea30e774949160c3e8/components/raftstore/src/coprocessor/split_observer.rs#L36-L41 492 if tablecodec.IsRecordKey(key) { 493 tableID, handle, _ := tablecodec.DecodeRecordKey(key) 494 return tablecodec.EncodeRowKeyWithHandle(tableID, handle.Next()) 495 } 496 497 // if key is an index, directly append a 0x00 to the key. 498 res := make([]byte, 0, len(key)+1) 499 res = append(res, key...) 500 res = append(res, 0) 501 return res 502 }