github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/mergetop/top_test.go (about)

     1  // Copyright 2021 Matrix Origin
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package mergetop
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"testing"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    23  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    24  	"github.com/matrixorigin/matrixone/pkg/container/types"
    25  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    26  	"github.com/matrixorigin/matrixone/pkg/testutil"
    27  	"github.com/matrixorigin/matrixone/pkg/vm"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  const (
    33  	Rows          = 10     // default rows
    34  	BenchmarkRows = 100000 // default rows for benchmark
    35  )
    36  
    37  // add unit tests for cases
    38  type topTestCase struct {
    39  	ds     []bool // Directions, ds[i] == true: the attrs[i] are in descending order
    40  	arg    *Argument
    41  	types  []types.Type
    42  	proc   *process.Process
    43  	cancel context.CancelFunc
    44  }
    45  
    46  var (
    47  	tcs []topTestCase
    48  )
    49  
    50  func init() {
    51  	tcs = []topTestCase{
    52  		newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 0}}),
    53  		newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 2}}),
    54  		newTestCase([]bool{false, false}, []types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 0}}),
    55  		newTestCase([]bool{true, false}, []types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 2}}),
    56  		newTestCase([]bool{true, false}, []types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 2}, {Expr: newExpression(1), Flag: 0}}),
    57  	}
    58  
    59  }
    60  
    61  func TestString(t *testing.T) {
    62  	buf := new(bytes.Buffer)
    63  	for _, tc := range tcs {
    64  		tc.arg.String(buf)
    65  	}
    66  }
    67  
    68  func TestPrepare(t *testing.T) {
    69  	for _, tc := range tcs {
    70  		err := tc.arg.Prepare(tc.proc)
    71  		require.NoError(t, err)
    72  	}
    73  }
    74  
    75  func TestTop(t *testing.T) {
    76  	for _, tc := range tcs {
    77  		err := tc.arg.Prepare(tc.proc)
    78  		require.NoError(t, err)
    79  		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows)
    80  		tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
    81  		tc.proc.Reg.MergeReceivers[0].Ch <- nil
    82  		tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, Rows)
    83  		tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
    84  		tc.proc.Reg.MergeReceivers[1].Ch <- nil
    85  		for {
    86  			ok, err := tc.arg.Call(tc.proc)
    87  			if ok.Status == vm.ExecStop || err != nil {
    88  				cleanResult(&ok, tc.proc)
    89  				break
    90  			}
    91  			cleanResult(&ok, tc.proc)
    92  		}
    93  		for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
    94  			for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
    95  				bat := <-tc.proc.Reg.MergeReceivers[i].Ch
    96  				if bat != nil {
    97  					bat.Clean(tc.proc.Mp())
    98  				}
    99  			}
   100  		}
   101  		tc.proc.FreeVectors()
   102  		require.Equal(t, tc.proc.Mp().CurrNB(), int64(0))
   103  	}
   104  }
   105  
   106  func BenchmarkTop(b *testing.B) {
   107  	for i := 0; i < b.N; i++ {
   108  		tcs = []topTestCase{
   109  			newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 0}}),
   110  			newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, 3, []*plan.OrderBySpec{{Expr: newExpression(0), Flag: 2}}),
   111  		}
   112  		t := new(testing.T)
   113  		for _, tc := range tcs {
   114  			err := tc.arg.Prepare(tc.proc)
   115  			require.NoError(t, err)
   116  			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, BenchmarkRows)
   117  			tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
   118  			tc.proc.Reg.MergeReceivers[0].Ch <- nil
   119  			tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, BenchmarkRows)
   120  			tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
   121  			tc.proc.Reg.MergeReceivers[1].Ch <- nil
   122  			for {
   123  				ok, err := tc.arg.Call(tc.proc)
   124  				if ok.Status == vm.ExecStop || err != nil {
   125  					cleanResult(&ok, tc.proc)
   126  					break
   127  				}
   128  				cleanResult(&ok, tc.proc)
   129  			}
   130  			for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   131  				for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   132  					bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   133  					if bat != nil {
   134  						bat.Clean(tc.proc.Mp())
   135  					}
   136  				}
   137  			}
   138  		}
   139  	}
   140  }
   141  
   142  func newTestCase(ds []bool, ts []types.Type, limit int64, fs []*plan.OrderBySpec) topTestCase {
   143  	proc := testutil.NewProcessWithMPool(mpool.MustNewZero())
   144  	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
   145  	ctx, cancel := context.WithCancel(context.Background())
   146  	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
   147  		Ctx: ctx,
   148  		Ch:  make(chan *batch.Batch, 3),
   149  	}
   150  	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
   151  		Ctx: ctx,
   152  		Ch:  make(chan *batch.Batch, 3),
   153  	}
   154  	return topTestCase{
   155  		ds:    ds,
   156  		types: ts,
   157  		proc:  proc,
   158  		arg: &Argument{
   159  			Fs:    fs,
   160  			Limit: limit,
   161  			OperatorBase: vm.OperatorBase{
   162  				OperatorInfo: vm.OperatorInfo{
   163  					Idx:     0,
   164  					IsFirst: false,
   165  					IsLast:  false,
   166  				},
   167  			},
   168  		},
   169  		cancel: cancel,
   170  	}
   171  }
   172  
   173  func newExpression(pos int32) *plan.Expr {
   174  	return &plan.Expr{
   175  		Expr: &plan.Expr_Col{
   176  			Col: &plan.ColRef{
   177  				ColPos: pos,
   178  			},
   179  		},
   180  		Typ: plan.Type{
   181  			Id: int32(types.T_int64),
   182  		},
   183  	}
   184  }
   185  
   186  // create a new block based on the type information, ds[i] == true: in descending order
   187  func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   188  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   189  }
   190  
   191  func cleanResult(result *vm.CallResult, proc *process.Process) {
   192  	if result.Batch != nil {
   193  		result.Batch.Clean(proc.Mp())
   194  	}
   195  }