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  }