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  )