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 := ®ionResponse{ 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 }