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

     1  package localstore
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
     7  	"github.com/insionng/yougam/libraries/pingcap/tipb/go-tipb"
     8  )
     9  
    10  type dbClient struct {
    11  	store      *dbStore
    12  	regionInfo []*regionInfo
    13  }
    14  
    15  func (c *dbClient) Send(req *kv.Request) kv.Response {
    16  	it := &response{
    17  		client:      c,
    18  		concurrency: req.Concurrency,
    19  	}
    20  	it.tasks = buildRegionTasks(c, req)
    21  	if len(it.tasks) == 0 {
    22  		// Empty range doesn't produce any task.
    23  		it.finished = true
    24  		return it
    25  	}
    26  	if it.concurrency > len(it.tasks) {
    27  		it.concurrency = len(it.tasks)
    28  	} else if it.concurrency <= 0 {
    29  		it.concurrency = 1
    30  	}
    31  	it.taskChan = make(chan *task, it.concurrency)
    32  	it.errChan = make(chan error, it.concurrency)
    33  	it.respChan = make(chan *regionResponse, it.concurrency)
    34  	it.run()
    35  	return it
    36  }
    37  
    38  func (c *dbClient) SupportRequestType(reqType, subType int64) bool {
    39  	switch reqType {
    40  	case kv.ReqTypeSelect:
    41  		return supportExpr(tipb.ExprType(subType))
    42  	case kv.ReqTypeIndex:
    43  		switch subType {
    44  		case kv.ReqSubTypeDesc, kv.ReqSubTypeBasic:
    45  			return true
    46  		}
    47  	}
    48  	return false
    49  }
    50  
    51  func supportExpr(exprType tipb.ExprType) bool {
    52  	switch exprType {
    53  	case tipb.ExprType_Null, tipb.ExprType_Int64, tipb.ExprType_Uint64, tipb.ExprType_Float32,
    54  		tipb.ExprType_Float64, tipb.ExprType_String, tipb.ExprType_Bytes,
    55  		tipb.ExprType_MysqlDuration, tipb.ExprType_MysqlDecimal,
    56  		tipb.ExprType_ColumnRef,
    57  		tipb.ExprType_And, tipb.ExprType_Or,
    58  		tipb.ExprType_LT, tipb.ExprType_LE, tipb.ExprType_EQ, tipb.ExprType_NE,
    59  		tipb.ExprType_GE, tipb.ExprType_GT, tipb.ExprType_NullEQ,
    60  		tipb.ExprType_In, tipb.ExprType_ValueList,
    61  		tipb.ExprType_Not,
    62  		tipb.ExprType_Like:
    63  		return true
    64  	case kv.ReqSubTypeDesc:
    65  		return true
    66  	default:
    67  		return false
    68  	}
    69  }
    70  
    71  func (c *dbClient) updateRegionInfo() {
    72  	c.regionInfo = c.store.pd.GetRegionInfo()
    73  }
    74  
    75  type localResponseReader struct {
    76  	s []byte
    77  	i int64
    78  }
    79  
    80  func (r *localResponseReader) Read(b []byte) (n int, err error) {
    81  	if len(b) == 0 {
    82  		return 0, nil
    83  	}
    84  	if r.i >= int64(len(r.s)) {
    85  		return 0, io.EOF
    86  	}
    87  	n = copy(b, r.s[r.i:])
    88  	r.i += int64(n)
    89  	return
    90  }
    91  
    92  func (r *localResponseReader) Close() error {
    93  	r.i = int64(len(r.s))
    94  	return nil
    95  }
    96  
    97  type response struct {
    98  	client      *dbClient
    99  	reqSent     int
   100  	respGot     int
   101  	concurrency int
   102  	tasks       []*task
   103  	responses   []*regionResponse
   104  	taskChan    chan *task
   105  	respChan    chan *regionResponse
   106  	errChan     chan error
   107  	finished    bool
   108  }
   109  
   110  type task struct {
   111  	request *regionRequest
   112  	region  *localRegion
   113  }
   114  
   115  func (it *response) Next() (resp io.ReadCloser, err error) {
   116  	if it.finished {
   117  		return nil, nil
   118  	}
   119  	var regionResp *regionResponse
   120  	select {
   121  	case regionResp = <-it.respChan:
   122  	case err = <-it.errChan:
   123  	}
   124  	if err != nil {
   125  		it.Close()
   126  		return nil, err
   127  	}
   128  	if len(regionResp.newStartKey) != 0 {
   129  		it.client.updateRegionInfo()
   130  		retryTasks := it.createRetryTasks(regionResp)
   131  		it.tasks = append(it.tasks, retryTasks...)
   132  	}
   133  	if it.reqSent < len(it.tasks) {
   134  		it.taskChan <- it.tasks[it.reqSent]
   135  		it.reqSent++
   136  	}
   137  	it.respGot++
   138  	if it.reqSent == len(it.tasks) && it.respGot == it.reqSent {
   139  		it.Close()
   140  	}
   141  	return &localResponseReader{s: regionResp.data}, nil
   142  }
   143  
   144  func (it *response) createRetryTasks(resp *regionResponse) []*task {
   145  	return nil
   146  }
   147  
   148  func buildRegionTasks(client *dbClient, req *kv.Request) (tasks []*task) {
   149  	infoCursor := 0
   150  	rangeCursor := 0
   151  	var regionReq *regionRequest
   152  	infos := client.regionInfo
   153  	for rangeCursor < len(req.KeyRanges) && infoCursor < len(infos) {
   154  		info := infos[infoCursor]
   155  		ran := req.KeyRanges[rangeCursor]
   156  
   157  		rangeOnLeft := ran.EndKey.Cmp(info.startKey) <= 0
   158  		rangeOnRight := info.endKey.Cmp(ran.StartKey) <= 0
   159  		noDataOnRegion := rangeOnLeft || rangeOnRight
   160  		if noDataOnRegion {
   161  			if rangeOnLeft {
   162  				rangeCursor++
   163  			} else {
   164  				infoCursor++
   165  			}
   166  		} else {
   167  			regionReq = &regionRequest{
   168  				Tp:       req.Tp,
   169  				startKey: info.startKey,
   170  				endKey:   info.endKey,
   171  				data:     req.Data,
   172  			}
   173  			task := &task{
   174  				region:  info.rs,
   175  				request: regionReq,
   176  			}
   177  			tasks = append(tasks, task)
   178  			infoCursor++
   179  		}
   180  	}
   181  	if req.Desc {
   182  		for i := 0; i < len(tasks)/2; i++ {
   183  			j := len(tasks) - i - 1
   184  			tasks[i], tasks[j] = tasks[j], tasks[i]
   185  		}
   186  	}
   187  	return
   188  }
   189  
   190  func (it *response) Close() error {
   191  	// Make goroutines quit.
   192  	if it.finished {
   193  		return nil
   194  	}
   195  	close(it.taskChan)
   196  	it.finished = true
   197  	return nil
   198  }
   199  
   200  func (it *response) run() {
   201  	for i := 0; i < it.concurrency; i++ {
   202  		go func() {
   203  			for task := range it.taskChan {
   204  				resp, err := task.region.Handle(task.request)
   205  				if err != nil {
   206  					it.errChan <- err
   207  					break
   208  				}
   209  				it.respChan <- resp
   210  			}
   211  		}()
   212  		it.taskChan <- it.tasks[i]
   213  		it.reqSent++
   214  	}
   215  }