github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/table_readers_required_rows_test.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 interlock 15 16 import ( 17 "context" 18 "fmt" 19 "math/rand" 20 21 "github.com/cznic/mathutil" 22 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 23 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 24 . "github.com/whtcorpsinc/check" 25 "github.com/whtcorpsinc/fidelpb/go-fidelpb" 26 "github.com/whtcorpsinc/milevadb/allegrosql" 27 "github.com/whtcorpsinc/milevadb/causet/blocks" 28 "github.com/whtcorpsinc/milevadb/causet/embedded" 29 "github.com/whtcorpsinc/milevadb/ekv" 30 "github.com/whtcorpsinc/milevadb/memex" 31 "github.com/whtcorpsinc/milevadb/soliton/chunk" 32 "github.com/whtcorpsinc/milevadb/statistics" 33 "github.com/whtcorpsinc/milevadb/stochastikctx" 34 "github.com/whtcorpsinc/milevadb/types" 35 ) 36 37 type requiredEventsSelectResult struct { 38 retTypes []*types.FieldType 39 totalEvents int 40 count int 41 expectedEventsRet []int 42 numNextCalled int 43 } 44 45 func (r *requiredEventsSelectResult) Fetch(context.Context) {} 46 func (r *requiredEventsSelectResult) NextRaw(context.Context) ([]byte, error) { return nil, nil } 47 func (r *requiredEventsSelectResult) Close() error { return nil } 48 49 func (r *requiredEventsSelectResult) Next(ctx context.Context, chk *chunk.Chunk) error { 50 defer func() { 51 if r.numNextCalled >= len(r.expectedEventsRet) { 52 return 53 } 54 rowsRet := chk.NumEvents() 55 expected := r.expectedEventsRet[r.numNextCalled] 56 if rowsRet != expected { 57 panic(fmt.Sprintf("unexpected number of rows returned, obtain: %v, expected: %v", rowsRet, expected)) 58 } 59 r.numNextCalled++ 60 }() 61 chk.Reset() 62 if r.count > r.totalEvents { 63 return nil 64 } 65 required := mathutil.Min(chk.RequiredEvents(), r.totalEvents-r.count) 66 for i := 0; i < required; i++ { 67 chk.AppendEvent(r.genOneEvent()) 68 } 69 r.count += required 70 return nil 71 } 72 73 func (r *requiredEventsSelectResult) genOneEvent() chunk.Event { 74 event := chunk.MutEventFromTypes(r.retTypes) 75 for i := range r.retTypes { 76 event.SetValue(i, r.genValue(r.retTypes[i])) 77 } 78 return event.ToEvent() 79 } 80 81 func (r *requiredEventsSelectResult) genValue(valType *types.FieldType) interface{} { 82 switch valType.Tp { 83 case allegrosql.TypeLong, allegrosql.TypeLonglong: 84 return int64(rand.Int()) 85 case allegrosql.TypeDouble: 86 return rand.Float64() 87 default: 88 panic("not implement") 89 } 90 } 91 92 func mockDistsqlSelectCtxSet(totalEvents int, expectedEventsRet []int) context.Context { 93 ctx := context.Background() 94 ctx = context.WithValue(ctx, "totalEvents", totalEvents) 95 ctx = context.WithValue(ctx, "expectedEventsRet", expectedEventsRet) 96 return ctx 97 } 98 99 func mockDistsqlSelectCtxGet(ctx context.Context) (totalEvents int, expectedEventsRet []int) { 100 totalEvents = ctx.Value("totalEvents").(int) 101 expectedEventsRet = ctx.Value("expectedEventsRet").([]int) 102 return 103 } 104 105 func mockSelectResult(ctx context.Context, sctx stochastikctx.Context, ekvReq *ekv.Request, 106 fieldTypes []*types.FieldType, fb *statistics.QueryFeedback, copCausetIDs []int) (allegrosql.SelectResult, error) { 107 totalEvents, expectedEventsRet := mockDistsqlSelectCtxGet(ctx) 108 return &requiredEventsSelectResult{ 109 retTypes: fieldTypes, 110 totalEvents: totalEvents, 111 expectedEventsRet: expectedEventsRet, 112 }, nil 113 } 114 115 func buildBlockReader(sctx stochastikctx.Context) InterlockingDirectorate { 116 e := &BlockReaderInterlockingDirectorate{ 117 baseInterlockingDirectorate: buildMockBaseInterDirc(sctx), 118 causet: &blocks.BlockCommon{}, 119 posetPosetDagPB: buildMockPosetDagRequest(sctx), 120 selectResultHook: selectResultHook{mockSelectResult}, 121 } 122 return e 123 } 124 125 func buildMockPosetDagRequest(sctx stochastikctx.Context) *fidelpb.PosetDagRequest { 126 builder := newInterlockingDirectorateBuilder(sctx, nil) 127 req, _, err := builder.constructPosetDagReq([]embedded.PhysicalCauset{&embedded.PhysicalBlockScan{ 128 DeferredCausets: []*perceptron.DeferredCausetInfo{}, 129 Block: &perceptron.BlockInfo{ID: 12345, PKIsHandle: false}, 130 Desc: false, 131 }}, ekv.EinsteinDB) 132 if err != nil { 133 panic(err) 134 } 135 return req 136 } 137 138 func buildMockBaseInterDirc(sctx stochastikctx.Context) baseInterlockingDirectorate { 139 retTypes := []*types.FieldType{types.NewFieldType(allegrosql.TypeDouble), types.NewFieldType(allegrosql.TypeLonglong)} 140 defcaus := make([]*memex.DeferredCauset, len(retTypes)) 141 for i := range retTypes { 142 defcaus[i] = &memex.DeferredCauset{Index: i, RetType: retTypes[i]} 143 } 144 schemaReplicant := memex.NewSchema(defcaus...) 145 baseInterDirc := newBaseInterlockingDirectorate(sctx, schemaReplicant, 0) 146 return baseInterDirc 147 } 148 149 func (s *testInterDircSuite) TestBlockReaderRequiredEvents(c *C) { 150 maxChunkSize := defaultCtx().GetStochastikVars().MaxChunkSize 151 testCases := []struct { 152 totalEvents int 153 requiredEvents []int 154 expectedEvents []int 155 expectedEventsDS []int 156 }{ 157 { 158 totalEvents: 10, 159 requiredEvents: []int{1, 5, 3, 10}, 160 expectedEvents: []int{1, 5, 3, 1}, 161 expectedEventsDS: []int{1, 5, 3, 1}, 162 }, 163 { 164 totalEvents: maxChunkSize + 1, 165 requiredEvents: []int{1, 5, 3, 10, maxChunkSize}, 166 expectedEvents: []int{1, 5, 3, 10, (maxChunkSize + 1) - 1 - 5 - 3 - 10}, 167 expectedEventsDS: []int{1, 5, 3, 10, (maxChunkSize + 1) - 1 - 5 - 3 - 10}, 168 }, 169 { 170 totalEvents: 3*maxChunkSize + 1, 171 requiredEvents: []int{3, 10, maxChunkSize}, 172 expectedEvents: []int{3, 10, maxChunkSize}, 173 expectedEventsDS: []int{3, 10, maxChunkSize}, 174 }, 175 } 176 for _, testCase := range testCases { 177 sctx := defaultCtx() 178 ctx := mockDistsqlSelectCtxSet(testCase.totalEvents, testCase.expectedEventsDS) 179 exec := buildBlockReader(sctx) 180 c.Assert(exec.Open(ctx), IsNil) 181 chk := newFirstChunk(exec) 182 for i := range testCase.requiredEvents { 183 chk.SetRequiredEvents(testCase.requiredEvents[i], maxChunkSize) 184 c.Assert(exec.Next(ctx, chk), IsNil) 185 c.Assert(chk.NumEvents(), Equals, testCase.expectedEvents[i]) 186 } 187 c.Assert(exec.Close(), IsNil) 188 } 189 } 190 191 func buildIndexReader(sctx stochastikctx.Context) InterlockingDirectorate { 192 e := &IndexReaderInterlockingDirectorate{ 193 baseInterlockingDirectorate: buildMockBaseInterDirc(sctx), 194 posetPosetDagPB: buildMockPosetDagRequest(sctx), 195 index: &perceptron.IndexInfo{}, 196 selectResultHook: selectResultHook{mockSelectResult}, 197 } 198 return e 199 } 200 201 func (s *testInterDircSuite) TestIndexReaderRequiredEvents(c *C) { 202 maxChunkSize := defaultCtx().GetStochastikVars().MaxChunkSize 203 testCases := []struct { 204 totalEvents int 205 requiredEvents []int 206 expectedEvents []int 207 expectedEventsDS []int 208 }{ 209 { 210 totalEvents: 10, 211 requiredEvents: []int{1, 5, 3, 10}, 212 expectedEvents: []int{1, 5, 3, 1}, 213 expectedEventsDS: []int{1, 5, 3, 1}, 214 }, 215 { 216 totalEvents: maxChunkSize + 1, 217 requiredEvents: []int{1, 5, 3, 10, maxChunkSize}, 218 expectedEvents: []int{1, 5, 3, 10, (maxChunkSize + 1) - 1 - 5 - 3 - 10}, 219 expectedEventsDS: []int{1, 5, 3, 10, (maxChunkSize + 1) - 1 - 5 - 3 - 10}, 220 }, 221 { 222 totalEvents: 3*maxChunkSize + 1, 223 requiredEvents: []int{3, 10, maxChunkSize}, 224 expectedEvents: []int{3, 10, maxChunkSize}, 225 expectedEventsDS: []int{3, 10, maxChunkSize}, 226 }, 227 } 228 for _, testCase := range testCases { 229 sctx := defaultCtx() 230 ctx := mockDistsqlSelectCtxSet(testCase.totalEvents, testCase.expectedEventsDS) 231 exec := buildIndexReader(sctx) 232 c.Assert(exec.Open(ctx), IsNil) 233 chk := newFirstChunk(exec) 234 for i := range testCase.requiredEvents { 235 chk.SetRequiredEvents(testCase.requiredEvents[i], maxChunkSize) 236 c.Assert(exec.Next(ctx, chk), IsNil) 237 c.Assert(chk.NumEvents(), Equals, testCase.expectedEvents[i]) 238 } 239 c.Assert(exec.Close(), IsNil) 240 } 241 }