github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/inspectkv/inspectkv.go (about) 1 // Copyright 2015 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 inspectkv 15 16 import ( 17 "io" 18 "reflect" 19 20 "github.com/insionng/yougam/libraries/juju/errors" 21 "github.com/insionng/yougam/libraries/ngaut/log" 22 "github.com/insionng/yougam/libraries/pingcap/tidb/column" 23 "github.com/insionng/yougam/libraries/pingcap/tidb/kv" 24 "github.com/insionng/yougam/libraries/pingcap/tidb/meta" 25 "github.com/insionng/yougam/libraries/pingcap/tidb/model" 26 "github.com/insionng/yougam/libraries/pingcap/tidb/mysql" 27 "github.com/insionng/yougam/libraries/pingcap/tidb/table" 28 "github.com/insionng/yougam/libraries/pingcap/tidb/table/tables" 29 "github.com/insionng/yougam/libraries/pingcap/tidb/terror" 30 "github.com/insionng/yougam/libraries/pingcap/tidb/util" 31 "github.com/insionng/yougam/libraries/pingcap/tidb/util/types" 32 ) 33 34 // DDLInfo is for DDL information. 35 type DDLInfo struct { 36 SchemaVer int64 37 ReorgHandle int64 // it's only used for DDL information. 38 Owner *model.Owner 39 Job *model.Job 40 } 41 42 // GetDDLInfo returns DDL information. 43 func GetDDLInfo(txn kv.Transaction) (*DDLInfo, error) { 44 var err error 45 info := &DDLInfo{} 46 t := meta.NewMeta(txn) 47 48 info.Owner, err = t.GetDDLJobOwner() 49 if err != nil { 50 return nil, errors.Trace(err) 51 } 52 info.Job, err = t.GetDDLJob(0) 53 if err != nil { 54 return nil, errors.Trace(err) 55 } 56 info.SchemaVer, err = t.GetSchemaVersion() 57 if err != nil { 58 return nil, errors.Trace(err) 59 } 60 if info.Job == nil { 61 return info, nil 62 } 63 64 info.ReorgHandle, err = t.GetDDLReorgHandle(info.Job) 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 69 return info, nil 70 } 71 72 // GetBgDDLInfo returns background DDL information. 73 func GetBgDDLInfo(txn kv.Transaction) (*DDLInfo, error) { 74 var err error 75 info := &DDLInfo{} 76 t := meta.NewMeta(txn) 77 78 info.Owner, err = t.GetBgJobOwner() 79 if err != nil { 80 return nil, errors.Trace(err) 81 } 82 info.Job, err = t.GetBgJob(0) 83 if err != nil { 84 return nil, errors.Trace(err) 85 } 86 info.SchemaVer, err = t.GetSchemaVersion() 87 if err != nil { 88 return nil, errors.Trace(err) 89 } 90 91 return info, nil 92 } 93 94 func nextIndexVals(data []types.Datum) []types.Datum { 95 // Add 0x0 to the end of data. 96 return append(data, types.Datum{}) 97 } 98 99 // RecordData is the record data composed of a handle and values. 100 type RecordData struct { 101 Handle int64 102 Values []types.Datum 103 } 104 105 // GetIndexRecordsCount returns the total number of the index records from startVals. 106 // If startVals = nil, returns the total number of the index records. 107 func GetIndexRecordsCount(txn kv.Transaction, kvIndex kv.Index, startVals []types.Datum) (int64, error) { 108 it, _, err := kvIndex.Seek(txn, startVals) 109 if err != nil { 110 return 0, errors.Trace(err) 111 } 112 defer it.Close() 113 114 var cnt int64 115 for { 116 _, _, err := it.Next() 117 if terror.ErrorEqual(err, io.EOF) { 118 break 119 } else if err != nil { 120 return 0, errors.Trace(err) 121 } 122 cnt++ 123 } 124 125 return cnt, nil 126 } 127 128 // ScanIndexData scans the index handles and values in a limited number, according to the index information. 129 // It returns data and the next startVals until it doesn't have data, then returns data is nil and 130 // the next startVals is the values which can't get data. If startVals = nil and limit = -1, 131 // it returns the index data of the whole. 132 func ScanIndexData(txn kv.Transaction, kvIndex kv.Index, startVals []types.Datum, limit int64) ( 133 []*RecordData, []types.Datum, error) { 134 it, _, err := kvIndex.Seek(txn, startVals) 135 if err != nil { 136 return nil, nil, errors.Trace(err) 137 } 138 defer it.Close() 139 140 var idxRows []*RecordData 141 var curVals []types.Datum 142 for limit != 0 { 143 val, h, err1 := it.Next() 144 if terror.ErrorEqual(err1, io.EOF) { 145 return idxRows, nextIndexVals(curVals), nil 146 } else if err1 != nil { 147 return nil, nil, errors.Trace(err1) 148 } 149 idxRows = append(idxRows, &RecordData{Handle: h, Values: val}) 150 limit-- 151 curVals = val 152 } 153 154 nextVals, _, err := it.Next() 155 if terror.ErrorEqual(err, io.EOF) { 156 return idxRows, nextIndexVals(curVals), nil 157 } else if err != nil { 158 return nil, nil, errors.Trace(err) 159 } 160 161 return idxRows, nextVals, nil 162 } 163 164 // CompareIndexData compares index data one by one. 165 // It returns nil if the data from the index is equal to the data from the table columns, 166 // otherwise it returns an error with a different set of records. 167 func CompareIndexData(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error { 168 err := checkIndexAndRecord(txn, t, idx) 169 if err != nil { 170 return errors.Trace(err) 171 } 172 173 return checkRecordAndIndex(txn, t, idx) 174 } 175 176 func checkIndexAndRecord(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error { 177 kvIndex := kv.NewKVIndex(t.IndexPrefix(), idx.Name.L, idx.ID, idx.Unique) 178 it, err := kvIndex.SeekFirst(txn) 179 if err != nil { 180 return errors.Trace(err) 181 } 182 defer it.Close() 183 184 cols := make([]*column.Col, len(idx.Columns)) 185 for i, col := range idx.Columns { 186 cols[i] = t.Cols()[col.Offset] 187 } 188 189 for { 190 vals1, h, err := it.Next() 191 if terror.ErrorEqual(err, io.EOF) { 192 break 193 } else if err != nil { 194 return errors.Trace(err) 195 } 196 197 vals2, err := rowWithCols(txn, t, h, cols) 198 if terror.ErrorEqual(err, kv.ErrNotExist) { 199 record := &RecordData{Handle: h, Values: vals1} 200 err = errDateNotEqual.Gen("index:%v != record:%v", record, nil) 201 } 202 if err != nil { 203 return errors.Trace(err) 204 } 205 if !reflect.DeepEqual(vals1, vals2) { 206 record1 := &RecordData{Handle: h, Values: vals1} 207 record2 := &RecordData{Handle: h, Values: vals2} 208 return errDateNotEqual.Gen("index:%v != record:%v", record1, record2) 209 } 210 } 211 212 return nil 213 } 214 215 func checkRecordAndIndex(txn kv.Transaction, t table.Table, idx *column.IndexedCol) error { 216 cols := make([]*column.Col, len(idx.Columns)) 217 for i, col := range idx.Columns { 218 cols[i] = t.Cols()[col.Offset] 219 } 220 221 startKey := t.RecordKey(0, nil) 222 kvIndex := kv.NewKVIndex(t.IndexPrefix(), idx.Name.L, idx.ID, idx.Unique) 223 filterFunc := func(h1 int64, vals1 []types.Datum, cols []*column.Col) (bool, error) { 224 isExist, h2, err := kvIndex.Exist(txn, vals1, h1) 225 if terror.ErrorEqual(err, kv.ErrKeyExists) { 226 record1 := &RecordData{Handle: h1, Values: vals1} 227 record2 := &RecordData{Handle: h2, Values: vals1} 228 return false, errDateNotEqual.Gen("index:%v != record:%v", record2, record1) 229 } 230 if err != nil { 231 return false, errors.Trace(err) 232 } 233 if !isExist { 234 record := &RecordData{Handle: h1, Values: vals1} 235 return false, errDateNotEqual.Gen("index:%v != record:%v", nil, record) 236 } 237 238 return true, nil 239 } 240 err := iterRecords(txn, t, startKey, cols, filterFunc) 241 242 if err != nil { 243 return errors.Trace(err) 244 } 245 246 return nil 247 } 248 249 func scanTableData(retriever kv.Retriever, t table.Table, cols []*column.Col, startHandle, limit int64) ( 250 []*RecordData, int64, error) { 251 var records []*RecordData 252 253 startKey := t.RecordKey(startHandle, nil) 254 filterFunc := func(h int64, d []types.Datum, cols []*column.Col) (bool, error) { 255 if limit != 0 { 256 r := &RecordData{ 257 Handle: h, 258 Values: d, 259 } 260 records = append(records, r) 261 limit-- 262 return true, nil 263 } 264 265 return false, nil 266 } 267 err := iterRecords(retriever, t, startKey, cols, filterFunc) 268 if err != nil { 269 return nil, 0, errors.Trace(err) 270 } 271 272 if len(records) == 0 { 273 return records, startHandle, nil 274 } 275 276 nextHandle := records[len(records)-1].Handle + 1 277 278 return records, nextHandle, nil 279 } 280 281 // ScanTableRecord scans table row handles and column values in a limited number. 282 // It returns data and the next startHandle until it doesn't have data, then returns data is nil and 283 // the next startHandle is the handle which can't get data. If startHandle = 0 and limit = -1, 284 // it returns the table data of the whole. 285 func ScanTableRecord(retriever kv.Retriever, t table.Table, startHandle, limit int64) ( 286 []*RecordData, int64, error) { 287 return scanTableData(retriever, t, t.Cols(), startHandle, limit) 288 } 289 290 // ScanSnapshotTableRecord scans the ver version of the table data in a limited number. 291 // It returns data and the next startHandle until it doesn't have data, then returns data is nil and 292 // the next startHandle is the handle which can't get data. If startHandle = 0 and limit = -1, 293 // it returns the table data of the whole. 294 func ScanSnapshotTableRecord(store kv.Storage, ver kv.Version, t table.Table, startHandle, limit int64) ( 295 []*RecordData, int64, error) { 296 snap, err := store.GetSnapshot(ver) 297 if err != nil { 298 return nil, 0, errors.Trace(err) 299 } 300 defer snap.Release() 301 302 records, nextHandle, err := ScanTableRecord(snap, t, startHandle, limit) 303 304 return records, nextHandle, errors.Trace(err) 305 } 306 307 // CompareTableRecord compares data and the corresponding table data one by one. 308 // It returns nil if data is equal to the data that scans from table, otherwise 309 // it returns an error with a different set of records. If exact is false, only compares handle. 310 func CompareTableRecord(txn kv.Transaction, t table.Table, data []*RecordData, exact bool) error { 311 m := make(map[int64][]types.Datum, len(data)) 312 for _, r := range data { 313 if _, ok := m[r.Handle]; ok { 314 return errRepeatHandle.Gen("handle:%d is repeated in data", r.Handle) 315 } 316 m[r.Handle] = r.Values 317 } 318 319 startKey := t.RecordKey(0, nil) 320 filterFunc := func(h int64, vals []types.Datum, cols []*column.Col) (bool, error) { 321 vals2, ok := m[h] 322 if !ok { 323 record := &RecordData{Handle: h, Values: vals} 324 return false, errDateNotEqual.Gen("data:%v != record:%v", nil, record) 325 } 326 if !exact { 327 delete(m, h) 328 return true, nil 329 } 330 331 if !reflect.DeepEqual(vals, vals2) { 332 record1 := &RecordData{Handle: h, Values: vals2} 333 record2 := &RecordData{Handle: h, Values: vals} 334 return false, errDateNotEqual.Gen("data:%v != record:%v", record1, record2) 335 } 336 337 delete(m, h) 338 339 return true, nil 340 } 341 err := iterRecords(txn, t, startKey, t.Cols(), filterFunc) 342 if err != nil { 343 return errors.Trace(err) 344 } 345 346 for h, vals := range m { 347 record := &RecordData{Handle: h, Values: vals} 348 return errDateNotEqual.Gen("data:%v != record:%v", record, nil) 349 } 350 351 return nil 352 } 353 354 // GetTableRecordsCount returns the total number of table records from startHandle. 355 // If startHandle = 0, returns the total number of table records. 356 func GetTableRecordsCount(txn kv.Transaction, t table.Table, startHandle int64) (int64, error) { 357 startKey := t.RecordKey(startHandle, nil) 358 it, err := txn.Seek(startKey) 359 if err != nil { 360 return 0, errors.Trace(err) 361 } 362 363 var cnt int64 364 prefix := t.RecordPrefix() 365 for it.Valid() && it.Key().HasPrefix(prefix) { 366 handle, err := tables.DecodeRecordKeyHandle(it.Key()) 367 if err != nil { 368 return 0, errors.Trace(err) 369 } 370 371 it.Close() 372 rk := t.RecordKey(handle+1, nil) 373 it, err = txn.Seek(rk) 374 if err != nil { 375 return 0, errors.Trace(err) 376 } 377 378 cnt++ 379 } 380 381 it.Close() 382 383 return cnt, nil 384 } 385 386 func rowWithCols(txn kv.Retriever, t table.Table, h int64, cols []*column.Col) ([]types.Datum, error) { 387 v := make([]types.Datum, len(cols)) 388 for i, col := range cols { 389 if col.State != model.StatePublic { 390 return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) 391 } 392 if col.IsPKHandleColumn(t.Meta()) { 393 v[i].SetInt64(h) 394 continue 395 } 396 397 k := t.RecordKey(h, col) 398 data, err := txn.Get(k) 399 if terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(col.Flag) { 400 continue 401 } else if err != nil { 402 return nil, errors.Trace(err) 403 } 404 405 val, err := tables.DecodeValue(data, &col.FieldType) 406 if err != nil { 407 return nil, errors.Trace(err) 408 } 409 v[i] = val 410 } 411 return v, nil 412 } 413 414 func iterRecords(retriever kv.Retriever, t table.Table, startKey kv.Key, cols []*column.Col, 415 fn table.RecordIterFunc) error { 416 it, err := retriever.Seek(startKey) 417 if err != nil { 418 return errors.Trace(err) 419 } 420 defer it.Close() 421 422 if !it.Valid() { 423 return nil 424 } 425 426 log.Debugf("startKey:%q, key:%q, value:%q", startKey, it.Key(), it.Value()) 427 428 prefix := t.RecordPrefix() 429 for it.Valid() && it.Key().HasPrefix(prefix) { 430 // first kv pair is row lock information. 431 // TODO: check valid lock 432 // get row handle 433 handle, err := tables.DecodeRecordKeyHandle(it.Key()) 434 if err != nil { 435 return errors.Trace(err) 436 } 437 438 data, err := rowWithCols(retriever, t, handle, cols) 439 if err != nil { 440 return errors.Trace(err) 441 } 442 more, err := fn(handle, data, cols) 443 if !more || err != nil { 444 return errors.Trace(err) 445 } 446 447 rk := t.RecordKey(handle, nil) 448 err = kv.NextUntil(it, util.RowKeyPrefixFilter(rk)) 449 if err != nil { 450 return errors.Trace(err) 451 } 452 } 453 454 return nil 455 } 456 457 // inspectkv error codes. 458 const ( 459 codeDataNotEqual terror.ErrCode = 1 460 codeRepeatHandle = 2 461 codeInvalidColumnState = 3 462 ) 463 464 var ( 465 errDateNotEqual = terror.ClassInspectkv.New(codeDataNotEqual, "data isn't equal") 466 errRepeatHandle = terror.ClassInspectkv.New(codeRepeatHandle, "handle is repeated") 467 errInvalidColumnState = terror.ClassInspectkv.New(codeInvalidColumnState, "invalid column state") 468 )