github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/partition_table.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 20 "github.com/opentracing/opentracing-go" 21 "github.com/whtcorpsinc/errors" 22 "github.com/whtcorpsinc/fidelpb/go-fidelpb" 23 "github.com/whtcorpsinc/milevadb/causet" 24 causetembedded "github.com/whtcorpsinc/milevadb/causet/embedded" 25 "github.com/whtcorpsinc/milevadb/soliton/chunk" 26 ) 27 28 // PartitionBlockInterlockingDirectorate is a InterlockingDirectorate for partitioned causet. 29 // It works by wrap the underlying BlockReader/IndexReader/IndexLookUpReader. 30 type PartitionBlockInterlockingDirectorate struct { 31 baseInterlockingDirectorate 32 33 nextPartition 34 partitions []causet.PhysicalBlock 35 cursor int 36 curr InterlockingDirectorate 37 } 38 39 type nextPartition interface { 40 nextPartition(context.Context, causet.PhysicalBlock) (InterlockingDirectorate, error) 41 } 42 43 type nextPartitionForBlockReader struct { 44 exec *BlockReaderInterlockingDirectorate 45 } 46 47 func (n nextPartitionForBlockReader) nextPartition(ctx context.Context, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 48 n.exec.causet = tbl 49 n.exec.ekvRanges = n.exec.ekvRanges[:0] 50 if err := uFIDelatePosetDagRequestBlockID(ctx, n.exec.posetPosetDagPB, tbl.Meta().ID, tbl.GetPhysicalID()); err != nil { 51 return nil, err 52 } 53 return n.exec, nil 54 } 55 56 type nextPartitionForIndexLookUp struct { 57 exec *IndexLookUpInterlockingDirectorate 58 } 59 60 func (n nextPartitionForIndexLookUp) nextPartition(ctx context.Context, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 61 n.exec.causet = tbl 62 return n.exec, nil 63 } 64 65 type nextPartitionForIndexReader struct { 66 exec *IndexReaderInterlockingDirectorate 67 } 68 69 func (n nextPartitionForIndexReader) nextPartition(ctx context.Context, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 70 exec := n.exec 71 exec.causet = tbl 72 exec.physicalBlockID = tbl.GetPhysicalID() 73 return exec, nil 74 } 75 76 type nextPartitionForIndexMerge struct { 77 exec *IndexMergeReaderInterlockingDirectorate 78 } 79 80 func (n nextPartitionForIndexMerge) nextPartition(ctx context.Context, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 81 exec := n.exec 82 exec.causet = tbl 83 return exec, nil 84 } 85 86 type nextPartitionForUnionScan struct { 87 b *interlockBuilder 88 us *causetembedded.PhysicalUnionScan 89 child nextPartition 90 } 91 92 // nextPartition implements the nextPartition interface. 93 // For union scan on partitioned causet, the interlock should be PartitionBlock->UnionScan->BlockReader rather than 94 // UnionScan->PartitionBlock->BlockReader 95 func (n nextPartitionForUnionScan) nextPartition(ctx context.Context, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 96 childInterDirc, err := n.child.nextPartition(ctx, tbl) 97 if err != nil { 98 return nil, err 99 } 100 101 n.b.err = nil 102 ret := n.b.buildUnionScanFromReader(childInterDirc, n.us) 103 return ret, n.b.err 104 } 105 106 func nextPartitionWithTrace(ctx context.Context, n nextPartition, tbl causet.PhysicalBlock) (InterlockingDirectorate, error) { 107 if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { 108 span1 := span.Tracer().StartSpan(fmt.Sprintf("nextPartition %d", tbl.GetPhysicalID()), opentracing.ChildOf(span.Context())) 109 defer span1.Finish() 110 ctx = opentracing.ContextWithSpan(ctx, span1) 111 } 112 return n.nextPartition(ctx, tbl) 113 } 114 115 // uFIDelatePosetDagRequestBlockID uFIDelate the causet ID in the PosetDag request to partition ID. 116 // EinsteinDB only use that causet ID for log, but TiFlash use it. 117 func uFIDelatePosetDagRequestBlockID(ctx context.Context, posetPosetDag *fidelpb.PosetDagRequest, blockID, partitionID int64) error { 118 // TiFlash set RootInterlockingDirectorate field and ignore InterlockingDirectorates field. 119 if posetPosetDag.RootInterlockingDirectorate != nil { 120 return uFIDelateInterlockingDirectorateBlockID(ctx, posetPosetDag.RootInterlockingDirectorate, blockID, partitionID, true) 121 } 122 for i := 0; i < len(posetPosetDag.InterlockingDirectorates); i++ { 123 exec := posetPosetDag.InterlockingDirectorates[i] 124 err := uFIDelateInterlockingDirectorateBlockID(ctx, exec, blockID, partitionID, false) 125 if err != nil { 126 return err 127 } 128 } 129 return nil 130 } 131 132 func uFIDelateInterlockingDirectorateBlockID(ctx context.Context, exec *fidelpb.InterlockingDirectorate, blockID, partitionID int64, recursive bool) error { 133 var child *fidelpb.InterlockingDirectorate 134 switch exec.Tp { 135 case fidelpb.InterDircType_TypeBlockScan: 136 exec.TblScan.BlockId = partitionID 137 // For test coverage. 138 if tmp := ctx.Value("nextPartitionUFIDelatePosetDagReq"); tmp != nil { 139 m := tmp.(map[int64]struct{}) 140 m[partitionID] = struct{}{} 141 } 142 case fidelpb.InterDircType_TypeIndexScan: 143 exec.IdxScan.BlockId = partitionID 144 case fidelpb.InterDircType_TypeSelection: 145 child = exec.Selection.Child 146 case fidelpb.InterDircType_TypeAggregation, fidelpb.InterDircType_TypeStreamAgg: 147 child = exec.Aggregation.Child 148 case fidelpb.InterDircType_TypeTopN: 149 child = exec.TopN.Child 150 case fidelpb.InterDircType_TypeLimit: 151 child = exec.Limit.Child 152 case fidelpb.InterDircType_TypeJoin: 153 // TiFlash currently does not support Join on partition causet. 154 // The causet should not generate this HoTT of plan. 155 // So the code should never run here. 156 return errors.New("wrong plan, join on partition causet is not supported on TiFlash") 157 default: 158 return errors.Trace(fmt.Errorf("unknown new fidelpb protodefCaus %d", exec.Tp)) 159 } 160 if child != nil && recursive { 161 return uFIDelateInterlockingDirectorateBlockID(ctx, child, blockID, partitionID, recursive) 162 } 163 return nil 164 } 165 166 // Open implements the InterlockingDirectorate interface. 167 func (e *PartitionBlockInterlockingDirectorate) Open(ctx context.Context) error { 168 e.cursor = 0 169 e.curr = nil 170 return nil 171 } 172 173 // Next implements the InterlockingDirectorate interface. 174 func (e *PartitionBlockInterlockingDirectorate) Next(ctx context.Context, chk *chunk.Chunk) error { 175 chk.Reset() 176 var err error 177 for e.cursor < len(e.partitions) { 178 if e.curr == nil { 179 n := e.nextPartition 180 e.curr, err = nextPartitionWithTrace(ctx, n, e.partitions[e.cursor]) 181 if err != nil { 182 return err 183 } 184 if err := e.curr.Open(ctx); err != nil { 185 return err 186 } 187 } 188 189 err = Next(ctx, e.curr, chk) 190 if err != nil { 191 return err 192 } 193 194 if chk.NumEvents() > 0 { 195 break 196 } 197 198 err = e.curr.Close() 199 if err != nil { 200 return err 201 } 202 e.curr = nil 203 e.cursor++ 204 } 205 return nil 206 } 207 208 // Close implements the InterlockingDirectorate interface. 209 func (e *PartitionBlockInterlockingDirectorate) Close() error { 210 var err error 211 if e.curr != nil { 212 err = e.curr.Close() 213 e.curr = nil 214 } 215 return err 216 }