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