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  }