github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/store/localstore/local_region.go (about)

     1  package localstore
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  
     7  	"github.com/insionng/yougam/libraries/golang/protobuf/proto"
     8  	"github.com/insionng/yougam/libraries/juju/errors"
     9  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    10  	"github.com/insionng/yougam/libraries/pingcap/tidb/mysql"
    11  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    12  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/codec"
    13  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    14  	"github.com/insionng/yougam/libraries/pingcap/tidb/xapi/tablecodec"
    15  	"github.com/insionng/yougam/libraries/pingcap/tidb/xapi/xeval"
    16  	"github.com/insionng/yougam/libraries/pingcap/tipb/go-tipb"
    17  )
    18  
    19  // local region server.
    20  type localRegion struct {
    21  	id       int
    22  	store    *dbStore
    23  	startKey []byte
    24  	endKey   []byte
    25  }
    26  
    27  type regionRequest struct {
    28  	Tp       int64
    29  	data     []byte
    30  	startKey []byte
    31  	endKey   []byte
    32  }
    33  
    34  type regionResponse struct {
    35  	req  *regionRequest
    36  	err  error
    37  	data []byte
    38  	// If region missed some request key range, newStartKey and newEndKey is returned.
    39  	newStartKey []byte
    40  	newEndKey   []byte
    41  }
    42  
    43  type selectContext struct {
    44  	sel          *tipb.SelectRequest
    45  	txn          kv.Transaction
    46  	eval         *xeval.Evaluator
    47  	whereColumns map[int64]*tipb.ColumnInfo
    48  }
    49  
    50  func (rs *localRegion) Handle(req *regionRequest) (*regionResponse, error) {
    51  	resp := &regionResponse{
    52  		req: req,
    53  	}
    54  	if req.Tp == kv.ReqTypeSelect || req.Tp == kv.ReqTypeIndex {
    55  		sel := new(tipb.SelectRequest)
    56  		err := proto.Unmarshal(req.data, sel)
    57  		if err != nil {
    58  			return nil, errors.Trace(err)
    59  		}
    60  		txn := newTxn(rs.store, kv.Version{Ver: uint64(*sel.StartTs)})
    61  		ctx := &selectContext{
    62  			sel: sel,
    63  			txn: txn,
    64  		}
    65  		if sel.Where != nil {
    66  			ctx.eval = &xeval.Evaluator{Row: make(map[int64]types.Datum)}
    67  			ctx.whereColumns = make(map[int64]*tipb.ColumnInfo)
    68  			collectColumnsInWhere(sel.Where, ctx)
    69  		}
    70  		var rows []*tipb.Row
    71  		if req.Tp == kv.ReqTypeSelect {
    72  			rows, err = rs.getRowsFromSelectReq(ctx)
    73  		} else {
    74  			rows, err = rs.getRowsFromIndexReq(txn, sel)
    75  		}
    76  		selResp := new(tipb.SelectResponse)
    77  		selResp.Error = toPBError(err)
    78  		selResp.Rows = rows
    79  		resp.err = err
    80  		data, err := proto.Marshal(selResp)
    81  		if err != nil {
    82  			return nil, errors.Trace(err)
    83  		}
    84  		resp.data = data
    85  	}
    86  	if bytes.Compare(rs.startKey, req.startKey) < 0 || bytes.Compare(rs.endKey, req.endKey) > 0 {
    87  		resp.newStartKey = rs.startKey
    88  		resp.newEndKey = rs.endKey
    89  	}
    90  	return resp, nil
    91  }
    92  
    93  func collectColumnsInWhere(expr *tipb.Expr, ctx *selectContext) error {
    94  	if expr == nil {
    95  		return nil
    96  	}
    97  	if expr.GetTp() == tipb.ExprType_ColumnRef {
    98  		_, i, err := codec.DecodeInt(expr.Val)
    99  		if err != nil {
   100  			return errors.Trace(err)
   101  		}
   102  		var columns []*tipb.ColumnInfo
   103  		if ctx.sel.TableInfo != nil {
   104  			columns = ctx.sel.TableInfo.Columns
   105  		} else {
   106  			columns = ctx.sel.IndexInfo.Columns
   107  		}
   108  		for _, c := range columns {
   109  			if c.GetColumnId() == i {
   110  				ctx.whereColumns[i] = c
   111  				return nil
   112  			}
   113  		}
   114  		return xeval.ErrInvalid.Gen("column %d not found", i)
   115  	}
   116  	for _, child := range expr.Children {
   117  		err := collectColumnsInWhere(child, ctx)
   118  		if err != nil {
   119  			return errors.Trace(err)
   120  		}
   121  	}
   122  	return nil
   123  }
   124  
   125  func (rs *localRegion) getRowsFromSelectReq(ctx *selectContext) ([]*tipb.Row, error) {
   126  	kvRanges, desc := rs.extractKVRanges(ctx.sel)
   127  	var rows []*tipb.Row
   128  	limit := int64(-1)
   129  	if ctx.sel.Limit != nil {
   130  		limit = ctx.sel.GetLimit()
   131  	}
   132  	for _, ran := range kvRanges {
   133  		if limit == 0 {
   134  			break
   135  		}
   136  		ranRows, err := rs.getRowsFromRange(ctx, ran, limit, desc)
   137  		if err != nil {
   138  			return nil, errors.Trace(err)
   139  		}
   140  		rows = append(rows, ranRows...)
   141  		limit -= int64(len(ranRows))
   142  	}
   143  	return rows, nil
   144  }
   145  
   146  // extractKVRanges extracts kv.KeyRanges slice from a SelectRequest, and also returns if it is in descending order.
   147  func (rs *localRegion) extractKVRanges(sel *tipb.SelectRequest) (kvRanges []kv.KeyRange, desc bool) {
   148  	var (
   149  		tid   int64
   150  		idxID int64
   151  	)
   152  	if sel.IndexInfo != nil {
   153  		tid = sel.IndexInfo.GetTableId()
   154  		idxID = sel.IndexInfo.GetIndexId()
   155  	} else {
   156  		tid = sel.TableInfo.GetTableId()
   157  	}
   158  	for _, kran := range sel.Ranges {
   159  		var upperKey, lowerKey kv.Key
   160  		if idxID == 0 {
   161  			upperKey = tablecodec.EncodeRowKey(tid, kran.GetHigh())
   162  			if bytes.Compare(upperKey, rs.startKey) <= 0 {
   163  				continue
   164  			}
   165  			lowerKey = tablecodec.EncodeRowKey(tid, kran.GetLow())
   166  		} else {
   167  			upperKey = tablecodec.EncodeIndexSeekKey(tid, idxID, kran.GetHigh())
   168  			if bytes.Compare(upperKey, rs.startKey) <= 0 {
   169  				continue
   170  			}
   171  			lowerKey = tablecodec.EncodeIndexSeekKey(tid, idxID, kran.GetLow())
   172  		}
   173  		if bytes.Compare(lowerKey, rs.endKey) >= 0 {
   174  			break
   175  		}
   176  		var kvr kv.KeyRange
   177  		if bytes.Compare(lowerKey, rs.startKey) <= 0 {
   178  			kvr.StartKey = rs.startKey
   179  		} else {
   180  			kvr.StartKey = lowerKey
   181  		}
   182  		if bytes.Compare(upperKey, rs.endKey) <= 0 {
   183  			kvr.EndKey = upperKey
   184  		} else {
   185  			kvr.EndKey = rs.endKey
   186  		}
   187  		kvRanges = append(kvRanges, kvr)
   188  	}
   189  	if sel.OrderBy != nil {
   190  		desc = *sel.OrderBy[0].Desc
   191  	}
   192  	if desc {
   193  		reverseKVRanges(kvRanges)
   194  	}
   195  	return
   196  }
   197  
   198  func (rs *localRegion) getRowsFromRange(ctx *selectContext, ran kv.KeyRange, limit int64, desc bool) ([]*tipb.Row, error) {
   199  	if limit == 0 {
   200  		return nil, nil
   201  	}
   202  	var rows []*tipb.Row
   203  	if ran.IsPoint() {
   204  		_, err := ctx.txn.Get(ran.StartKey)
   205  		if terror.ErrorEqual(err, kv.ErrNotExist) {
   206  			return nil, nil
   207  		} else if err != nil {
   208  			return nil, errors.Trace(err)
   209  		}
   210  		h, err := tablecodec.DecodeRowKey(ran.StartKey)
   211  		if err != nil {
   212  			return nil, errors.Trace(err)
   213  		}
   214  		match, err := rs.evalWhereForRow(ctx, h)
   215  		if err != nil {
   216  			return nil, errors.Trace(err)
   217  		}
   218  		if !match {
   219  			return nil, nil
   220  		}
   221  		row, err := rs.getRowByHandle(ctx, h)
   222  		if err != nil {
   223  			return nil, errors.Trace(err)
   224  		}
   225  		if row != nil {
   226  			rows = append(rows, row)
   227  		}
   228  		return rows, nil
   229  	}
   230  	var seekKey kv.Key
   231  	if desc {
   232  		seekKey = ran.EndKey
   233  	} else {
   234  		seekKey = ran.StartKey
   235  	}
   236  	for {
   237  		if limit == 0 {
   238  			break
   239  		}
   240  		var (
   241  			it  kv.Iterator
   242  			err error
   243  		)
   244  		if desc {
   245  			it, err = ctx.txn.SeekReverse(seekKey)
   246  		} else {
   247  			it, err = ctx.txn.Seek(seekKey)
   248  		}
   249  		if err != nil {
   250  			return nil, errors.Trace(err)
   251  		}
   252  		if !it.Valid() {
   253  			break
   254  		}
   255  		if desc {
   256  			if it.Key().Cmp(ran.StartKey) < 0 {
   257  				break
   258  			}
   259  			seekKey = tablecodec.TruncateToRowKeyLen(it.Key())
   260  		} else {
   261  			if it.Key().Cmp(ran.EndKey) >= 0 {
   262  				break
   263  			}
   264  			seekKey = it.Key().PrefixNext()
   265  		}
   266  		h, err := tablecodec.DecodeRowKey(it.Key())
   267  		if err != nil {
   268  			return nil, errors.Trace(err)
   269  		}
   270  		match, err := rs.evalWhereForRow(ctx, h)
   271  		if err != nil {
   272  			return nil, errors.Trace(err)
   273  		}
   274  		if !match {
   275  			continue
   276  		}
   277  		row, err := rs.getRowByHandle(ctx, h)
   278  		if err != nil {
   279  			return nil, errors.Trace(err)
   280  		}
   281  		if row != nil {
   282  			rows = append(rows, row)
   283  			limit--
   284  		}
   285  	}
   286  	return rows, nil
   287  }
   288  
   289  func (rs *localRegion) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) {
   290  	tid := ctx.sel.TableInfo.GetTableId()
   291  	columns := ctx.sel.TableInfo.Columns
   292  	row := new(tipb.Row)
   293  	var d types.Datum
   294  	d.SetInt64(handle)
   295  	var err error
   296  	row.Handle, err = codec.EncodeValue(nil, d)
   297  	if err != nil {
   298  		return nil, errors.Trace(err)
   299  	}
   300  	for _, col := range columns {
   301  		if *col.PkHandle {
   302  			if mysql.HasUnsignedFlag(uint(*col.Flag)) {
   303  				// PK column is Unsigned
   304  				var ud types.Datum
   305  				ud.SetUint64(uint64(handle))
   306  				uHandle, err1 := codec.EncodeValue(nil, ud)
   307  				if err1 != nil {
   308  					return nil, errors.Trace(err1)
   309  				}
   310  				row.Data = append(row.Data, uHandle...)
   311  			} else {
   312  				row.Data = append(row.Data, row.Handle...)
   313  			}
   314  		} else {
   315  			colID := col.GetColumnId()
   316  			if ctx.whereColumns[colID] != nil {
   317  				// The column is saved in evaluator, use it directly.
   318  				datum := ctx.eval.Row[colID]
   319  				row.Data, err = codec.EncodeValue(row.Data, datum)
   320  				if err != nil {
   321  					return nil, errors.Trace(err)
   322  				}
   323  			} else {
   324  				key := tablecodec.EncodeColumnKey(tid, handle, colID)
   325  				data, err1 := ctx.txn.Get(key)
   326  				if isDefaultNull(err1, col) {
   327  					row.Data = append(row.Data, codec.NilFlag)
   328  					continue
   329  				} else if err1 != nil {
   330  					return nil, errors.Trace(err1)
   331  				}
   332  				row.Data = append(row.Data, data...)
   333  			}
   334  		}
   335  	}
   336  	return row, nil
   337  }
   338  
   339  func (rs *localRegion) evalWhereForRow(ctx *selectContext, h int64) (bool, error) {
   340  	if ctx.sel.Where == nil {
   341  		return true, nil
   342  	}
   343  	tid := ctx.sel.TableInfo.GetTableId()
   344  	for colID, col := range ctx.whereColumns {
   345  		if col.GetPkHandle() {
   346  			ctx.eval.Row[colID] = types.NewIntDatum(h)
   347  		} else {
   348  			key := tablecodec.EncodeColumnKey(tid, h, colID)
   349  			data, err := ctx.txn.Get(key)
   350  			if isDefaultNull(err, col) {
   351  				ctx.eval.Row[colID] = types.Datum{}
   352  				continue
   353  			} else if err != nil {
   354  				return false, errors.Trace(err)
   355  			}
   356  			_, datum, err := codec.DecodeOne(data)
   357  			if err != nil {
   358  				return false, errors.Trace(err)
   359  			}
   360  			ctx.eval.Row[colID] = datum
   361  		}
   362  	}
   363  	result, err := ctx.eval.Eval(ctx.sel.Where)
   364  	if err != nil {
   365  		return false, errors.Trace(err)
   366  	}
   367  	if result.Kind() == types.KindNull {
   368  		return false, nil
   369  	}
   370  	boolResult, err := result.ToBool()
   371  	if err != nil {
   372  		return false, errors.Trace(err)
   373  	}
   374  	return boolResult == 1, nil
   375  }
   376  
   377  func toPBError(err error) *tipb.Error {
   378  	if err == nil {
   379  		return nil
   380  	}
   381  	perr := new(tipb.Error)
   382  	code := int32(1)
   383  	perr.Code = &code
   384  	errStr := err.Error()
   385  	perr.Msg = &errStr
   386  	return perr
   387  }
   388  
   389  func (rs *localRegion) getRowsFromIndexReq(txn kv.Transaction, sel *tipb.SelectRequest) ([]*tipb.Row, error) {
   390  	kvRanges, desc := rs.extractKVRanges(sel)
   391  	var rows []*tipb.Row
   392  	limit := int64(-1)
   393  	if sel.Limit != nil {
   394  		limit = sel.GetLimit()
   395  	}
   396  	for _, ran := range kvRanges {
   397  		if limit == 0 {
   398  			break
   399  		}
   400  		ranRows, err := getIndexRowFromRange(sel.IndexInfo, txn, ran, desc, limit)
   401  		if err != nil {
   402  			return nil, errors.Trace(err)
   403  		}
   404  		rows = append(rows, ranRows...)
   405  		limit -= int64(len(ranRows))
   406  	}
   407  	return rows, nil
   408  }
   409  
   410  func reverseKVRanges(kvRanges []kv.KeyRange) {
   411  	for i := 0; i < len(kvRanges)/2; i++ {
   412  		j := len(kvRanges) - i - 1
   413  		kvRanges[i], kvRanges[j] = kvRanges[j], kvRanges[i]
   414  	}
   415  }
   416  
   417  func getIndexRowFromRange(idxInfo *tipb.IndexInfo, txn kv.Transaction, ran kv.KeyRange, desc bool, limit int64) ([]*tipb.Row, error) {
   418  	var rows []*tipb.Row
   419  	var seekKey kv.Key
   420  	if desc {
   421  		seekKey = ran.EndKey
   422  	} else {
   423  		seekKey = ran.StartKey
   424  	}
   425  	for {
   426  		if limit == 0 {
   427  			break
   428  		}
   429  		var it kv.Iterator
   430  		var err error
   431  		if desc {
   432  			it, err = txn.SeekReverse(seekKey)
   433  			if err != nil {
   434  				return nil, errors.Trace(err)
   435  			}
   436  			seekKey = it.Key()
   437  		} else {
   438  			it, err = txn.Seek(seekKey)
   439  			if err != nil {
   440  				return nil, errors.Trace(err)
   441  			}
   442  			seekKey = it.Key().PrefixNext()
   443  		}
   444  		if !it.Valid() {
   445  			break
   446  		}
   447  		if desc {
   448  			if it.Key().Cmp(ran.StartKey) < 0 {
   449  				break
   450  			}
   451  		} else {
   452  			if it.Key().Cmp(ran.EndKey) >= 0 {
   453  				break
   454  			}
   455  		}
   456  
   457  		datums, err := tablecodec.DecodeIndexKey(it.Key())
   458  		if err != nil {
   459  			return nil, errors.Trace(err)
   460  		}
   461  		var handle types.Datum
   462  		if len(datums) > len(idxInfo.Columns) {
   463  			handle = datums[len(idxInfo.Columns)]
   464  			datums = datums[:len(idxInfo.Columns)]
   465  		} else {
   466  			var intHandle int64
   467  			intHandle, err = decodeHandle(it.Value())
   468  			if err != nil {
   469  				return nil, errors.Trace(err)
   470  			}
   471  			handle.SetInt64(intHandle)
   472  		}
   473  		data, err := codec.EncodeValue(nil, datums...)
   474  		if err != nil {
   475  			return nil, errors.Trace(err)
   476  		}
   477  		handleData, err := codec.EncodeValue(nil, handle)
   478  		if err != nil {
   479  			return nil, errors.Trace(err)
   480  		}
   481  		row := &tipb.Row{Handle: handleData, Data: data}
   482  		rows = append(rows, row)
   483  		limit--
   484  	}
   485  
   486  	return rows, nil
   487  }
   488  
   489  func decodeHandle(data []byte) (int64, error) {
   490  	var h int64
   491  	buf := bytes.NewBuffer(data)
   492  	err := binary.Read(buf, binary.BigEndian, &h)
   493  	return h, errors.Trace(err)
   494  }
   495  
   496  func buildLocalRegionServers(store *dbStore) []*localRegion {
   497  	return []*localRegion{
   498  		{
   499  			id:       1,
   500  			store:    store,
   501  			startKey: []byte(""),
   502  			endKey:   []byte("t"),
   503  		},
   504  		{
   505  			id:       2,
   506  			store:    store,
   507  			startKey: []byte("t"),
   508  			endKey:   []byte("u"),
   509  		},
   510  		{
   511  			id:       3,
   512  			store:    store,
   513  			startKey: []byte("u"),
   514  			endKey:   []byte("z"),
   515  		},
   516  	}
   517  }
   518  
   519  func isDefaultNull(err error, col *tipb.ColumnInfo) bool {
   520  	return terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(uint(col.GetFlag()))
   521  }