github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/union_scan.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 "runtime/trace" 20 21 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 22 "github.com/whtcorpsinc/milevadb/causet" 23 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 24 "github.com/whtcorpsinc/milevadb/ekv" 25 "github.com/whtcorpsinc/milevadb/memex" 26 "github.com/whtcorpsinc/milevadb/soliton/chunk" 27 "github.com/whtcorpsinc/milevadb/types" 28 ) 29 30 // UnionScanInterDirc merges the rows from dirty causet and the rows from allegrosql request. 31 type UnionScanInterDirc struct { 32 baseInterlockingDirectorate 33 34 memBuf ekv.MemBuffer 35 memBufSnap ekv.Getter 36 37 // usedIndex is the defCausumn offsets of the index which Src interlock has used. 38 usedIndex []int 39 desc bool 40 conditions []memex.Expression 41 conditionsWithVirDefCaus []memex.Expression 42 defCausumns []*perceptron.DeferredCausetInfo 43 causet causet.Block 44 // belowHandleDefCauss is the handle's position of the below scan plan. 45 belowHandleDefCauss causetembedded.HandleDefCauss 46 47 addedEvents [][]types.Causet 48 cursor4AddEvents int 49 sortErr error 50 snapshotEvents [][]types.Causet 51 cursor4SnapshotEvents int 52 snapshotChunkBuffer *chunk.Chunk 53 mublockEvent chunk.MutEvent 54 // virtualDeferredCausetIndex records all the indices of virtual defCausumns and sort them in definition 55 // to make sure we can compute the virtual defCausumn in right order. 56 virtualDeferredCausetIndex []int 57 } 58 59 // Open implements the InterlockingDirectorate Open interface. 60 func (us *UnionScanInterDirc) Open(ctx context.Context) error { 61 if err := us.baseInterlockingDirectorate.Open(ctx); err != nil { 62 return err 63 } 64 return us.open(ctx) 65 } 66 67 func (us *UnionScanInterDirc) open(ctx context.Context) error { 68 var err error 69 reader := us.children[0] 70 71 // If the push-downed condition contains virtual defCausumn, we may build a selection upon reader. Since unionScanInterDirc 72 // has already contained condition, we can ignore the selection. 73 if sel, ok := reader.(*SelectionInterDirc); ok { 74 reader = sel.children[0] 75 } 76 77 defer trace.StartRegion(ctx, "UnionScanBuildEvents").End() 78 txn, err := us.ctx.Txn(false) 79 if err != nil { 80 return err 81 } 82 83 mb := txn.GetMemBuffer() 84 mb.RLock() 85 defer mb.RUnlock() 86 87 us.memBuf = mb 88 us.memBufSnap = mb.SnapshotGetter() 89 90 // 1. select without virtual defCausumns 91 // 2. build virtual defCausumns and select with virtual defCausumns 92 switch x := reader.(type) { 93 case *BlockReaderInterlockingDirectorate: 94 us.addedEvents, err = buildMemBlockReader(us, x).getMemEvents() 95 case *IndexReaderInterlockingDirectorate: 96 us.addedEvents, err = buildMemIndexReader(us, x).getMemEvents() 97 case *IndexLookUpInterlockingDirectorate: 98 us.addedEvents, err = buildMemIndexLookUpReader(us, x).getMemEvents() 99 default: 100 err = fmt.Errorf("unexpected union scan children:%T", reader) 101 } 102 if err != nil { 103 return err 104 } 105 us.snapshotChunkBuffer = newFirstChunk(us) 106 return nil 107 } 108 109 // Next implements the InterlockingDirectorate Next interface. 110 func (us *UnionScanInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 111 us.memBuf.RLock() 112 defer us.memBuf.RUnlock() 113 req.GrowAndReset(us.maxChunkSize) 114 mublockEvent := chunk.MutEventFromTypes(retTypes(us)) 115 for i, batchSize := 0, req.Capacity(); i < batchSize; i++ { 116 event, err := us.getOneEvent(ctx) 117 if err != nil { 118 return err 119 } 120 // no more data. 121 if event == nil { 122 return nil 123 } 124 mublockEvent.SetCausets(event...) 125 126 for _, idx := range us.virtualDeferredCausetIndex { 127 causet, err := us.schemaReplicant.DeferredCausets[idx].EvalVirtualDeferredCauset(mublockEvent.ToEvent()) 128 if err != nil { 129 return err 130 } 131 // Because the memex might return different type from 132 // the generated defCausumn, we should wrap a CAST on the result. 133 castCauset, err := causet.CastValue(us.ctx, causet, us.defCausumns[idx], false, true) 134 if err != nil { 135 return err 136 } 137 mublockEvent.SetCauset(idx, castCauset) 138 } 139 140 matched, _, err := memex.EvalBool(us.ctx, us.conditionsWithVirDefCaus, mublockEvent.ToEvent()) 141 if err != nil { 142 return err 143 } 144 if matched { 145 req.AppendEvent(mublockEvent.ToEvent()) 146 } 147 } 148 return nil 149 } 150 151 // Close implements the InterlockingDirectorate Close interface. 152 func (us *UnionScanInterDirc) Close() error { 153 us.cursor4AddEvents = 0 154 us.cursor4SnapshotEvents = 0 155 us.addedEvents = us.addedEvents[:0] 156 us.snapshotEvents = us.snapshotEvents[:0] 157 return us.children[0].Close() 158 } 159 160 // getOneEvent gets one result event from dirty causet or child. 161 func (us *UnionScanInterDirc) getOneEvent(ctx context.Context) ([]types.Causet, error) { 162 snapshotEvent, err := us.getSnapshotEvent(ctx) 163 if err != nil { 164 return nil, err 165 } 166 addedEvent := us.getAddedEvent() 167 168 var event []types.Causet 169 var isSnapshotEvent bool 170 if addedEvent == nil { 171 event = snapshotEvent 172 isSnapshotEvent = true 173 } else if snapshotEvent == nil { 174 event = addedEvent 175 } else { 176 isSnapshotEvent, err = us.shouldPickFirstEvent(snapshotEvent, addedEvent) 177 if err != nil { 178 return nil, err 179 } 180 if isSnapshotEvent { 181 event = snapshotEvent 182 } else { 183 event = addedEvent 184 } 185 } 186 if event == nil { 187 return nil, nil 188 } 189 190 if isSnapshotEvent { 191 us.cursor4SnapshotEvents++ 192 } else { 193 us.cursor4AddEvents++ 194 } 195 return event, nil 196 } 197 198 func (us *UnionScanInterDirc) getSnapshotEvent(ctx context.Context) ([]types.Causet, error) { 199 if us.cursor4SnapshotEvents < len(us.snapshotEvents) { 200 return us.snapshotEvents[us.cursor4SnapshotEvents], nil 201 } 202 var err error 203 us.cursor4SnapshotEvents = 0 204 us.snapshotEvents = us.snapshotEvents[:0] 205 for len(us.snapshotEvents) == 0 { 206 err = Next(ctx, us.children[0], us.snapshotChunkBuffer) 207 if err != nil || us.snapshotChunkBuffer.NumEvents() == 0 { 208 return nil, err 209 } 210 iter := chunk.NewIterator4Chunk(us.snapshotChunkBuffer) 211 for event := iter.Begin(); event != iter.End(); event = iter.Next() { 212 var snapshotHandle ekv.Handle 213 snapshotHandle, err = us.belowHandleDefCauss.BuildHandle(event) 214 if err != nil { 215 return nil, err 216 } 217 checkKey := us.causet.RecordKey(snapshotHandle) 218 if _, err := us.memBufSnap.Get(context.TODO(), checkKey); err == nil { 219 // If src handle appears in added rows, it means there is conflict and the transaction will fail to 220 // commit, but for simplicity, we don't handle it here. 221 continue 222 } 223 us.snapshotEvents = append(us.snapshotEvents, event.GetCausetEvent(retTypes(us.children[0]))) 224 } 225 } 226 return us.snapshotEvents[0], nil 227 } 228 229 func (us *UnionScanInterDirc) getAddedEvent() []types.Causet { 230 var addedEvent []types.Causet 231 if us.cursor4AddEvents < len(us.addedEvents) { 232 addedEvent = us.addedEvents[us.cursor4AddEvents] 233 } 234 return addedEvent 235 } 236 237 // shouldPickFirstEvent picks the suiblock event in order. 238 // The value returned is used to determine whether to pick the first input event. 239 func (us *UnionScanInterDirc) shouldPickFirstEvent(a, b []types.Causet) (bool, error) { 240 var isFirstEvent bool 241 addedCmpSrc, err := us.compare(a, b) 242 if err != nil { 243 return isFirstEvent, err 244 } 245 // Compare result will never be 0. 246 if us.desc { 247 if addedCmpSrc > 0 { 248 isFirstEvent = true 249 } 250 } else { 251 if addedCmpSrc < 0 { 252 isFirstEvent = true 253 } 254 } 255 return isFirstEvent, nil 256 } 257 258 func (us *UnionScanInterDirc) compare(a, b []types.Causet) (int, error) { 259 sc := us.ctx.GetStochastikVars().StmtCtx 260 for _, defCausOff := range us.usedIndex { 261 aDeferredCauset := a[defCausOff] 262 bDeferredCauset := b[defCausOff] 263 cmp, err := aDeferredCauset.CompareCauset(sc, &bDeferredCauset) 264 if err != nil { 265 return 0, err 266 } 267 if cmp != 0 { 268 return cmp, nil 269 } 270 } 271 return us.belowHandleDefCauss.Compare(a, b) 272 }