github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/mergeorder/order_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 mergeorder
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    24  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    25  	"github.com/matrixorigin/matrixone/pkg/container/types"
    26  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    28  	"github.com/matrixorigin/matrixone/pkg/testutil"
    29  	"github.com/matrixorigin/matrixone/pkg/vm"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  const (
    35  	Rows          = 10     // default rows
    36  	BenchmarkRows = 100000 // default rows for benchmark
    37  )
    38  
    39  // add unit tests for cases
    40  type orderTestCase struct {
    41  	arg    *Argument
    42  	types  []types.Type
    43  	proc   *process.Process
    44  	cancel context.CancelFunc
    45  }
    46  
    47  func TestString(t *testing.T) {
    48  	tcs := []orderTestCase{
    49  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}),
    50  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    51  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}),
    52  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    53  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}),
    54  	}
    55  	buf := new(bytes.Buffer)
    56  	for _, tc := range tcs {
    57  		tc.arg.String(buf)
    58  	}
    59  }
    60  
    61  func TestPrepare(t *testing.T) {
    62  	tcs := []orderTestCase{
    63  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}),
    64  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    65  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}),
    66  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    67  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}),
    68  	}
    69  	for _, tc := range tcs {
    70  		err := tc.arg.Prepare(tc.proc)
    71  		require.NoError(t, err)
    72  	}
    73  }
    74  
    75  func TestOrder(t *testing.T) {
    76  	tcs := []orderTestCase{
    77  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}),
    78  		newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    79  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}),
    80  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
    81  		newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}),
    82  	}
    83  
    84  	for tci, tc := range tcs {
    85  		err := tc.arg.Prepare(tc.proc)
    86  		require.NoError(t, err)
    87  		tc.proc.Reg.MergeReceivers[0].Ch <- newIntBatch(tc.types, tc.proc, Rows, tc.arg.OrderBySpecs)
    88  		tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
    89  		tc.proc.Reg.MergeReceivers[0].Ch <- nil
    90  		tc.proc.Reg.MergeReceivers[1].Ch <- newIntBatch(tc.types, tc.proc, Rows, tc.arg.OrderBySpecs)
    91  		tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
    92  		tc.proc.Reg.MergeReceivers[1].Ch <- nil
    93  		for {
    94  			if ok, err := tc.arg.Call(tc.proc); ok.Status == vm.ExecStop || err != nil {
    95  				require.NoError(t, err)
    96  				// do the result check
    97  				if len(tc.arg.OrderBySpecs) > 0 {
    98  					desc := tc.arg.OrderBySpecs[0].Flag&plan.OrderBySpec_DESC != 0
    99  					index := tc.arg.OrderBySpecs[0].Expr.Expr.(*plan.Expr_Col).Col.ColPos
   100  					bat := ok.Batch
   101  					vec := bat.Vecs[index]
   102  					if vec.GetType().Oid == types.T_int8 {
   103  						i8c := vector.MustFixedCol[int8](vec)
   104  						if desc {
   105  							for j := range i8c {
   106  								if j > 0 {
   107  									require.True(t, i8c[j] <= i8c[j-1], fmt.Sprintf("tc %d require desc, but get %v", tci, i8c))
   108  								}
   109  							}
   110  						} else {
   111  							for j := range i8c {
   112  								if j > 0 {
   113  									require.True(t, i8c[j] >= i8c[j-1])
   114  								}
   115  							}
   116  						}
   117  					} else if vec.GetType().Oid == types.T_int64 {
   118  						i64c := vector.MustFixedCol[int64](vec)
   119  						if desc {
   120  							for j := range i64c {
   121  								if j > 0 {
   122  									require.True(t, i64c[j] <= i64c[j-1])
   123  								}
   124  							}
   125  						} else {
   126  							for j := range i64c {
   127  								if j > 0 {
   128  									require.True(t, i64c[j] >= i64c[j-1])
   129  								}
   130  							}
   131  						}
   132  					}
   133  				}
   134  
   135  				break
   136  			}
   137  		}
   138  		for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   139  			for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   140  				bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   141  				if bat != nil {
   142  					bat.Clean(tc.proc.Mp())
   143  				}
   144  			}
   145  		}
   146  		tc.proc.FreeVectors()
   147  		tc.arg.Free(tc.proc, false, nil)
   148  		require.Equal(t, int64(0), tc.proc.Mp().CurrNB())
   149  	}
   150  }
   151  
   152  func BenchmarkOrder(b *testing.B) {
   153  	for i := 0; i < b.N; i++ {
   154  		tcs := []orderTestCase{
   155  			newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}),
   156  			newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}),
   157  		}
   158  		t := new(testing.T)
   159  		for _, tc := range tcs {
   160  			err := tc.arg.Prepare(tc.proc)
   161  			require.NoError(t, err)
   162  			tc.proc.Reg.MergeReceivers[0].Ch <- newRandomBatch(tc.types, tc.proc, BenchmarkRows)
   163  			tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch
   164  			tc.proc.Reg.MergeReceivers[0].Ch <- nil
   165  			tc.proc.Reg.MergeReceivers[1].Ch <- newRandomBatch(tc.types, tc.proc, BenchmarkRows)
   166  			tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch
   167  			tc.proc.Reg.MergeReceivers[1].Ch <- nil
   168  			for {
   169  				ok, err := tc.arg.Call(tc.proc)
   170  				if ok.Status == vm.ExecStop || err != nil {
   171  					break
   172  				}
   173  			}
   174  			for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline
   175  				for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 {
   176  					bat := <-tc.proc.Reg.MergeReceivers[i].Ch
   177  					if bat != nil {
   178  						bat.Clean(tc.proc.Mp())
   179  					}
   180  				}
   181  			}
   182  		}
   183  	}
   184  }
   185  
   186  func newTestCase(ts []types.Type, fs []*plan.OrderBySpec) orderTestCase {
   187  	proc := testutil.NewProcessWithMPool(mpool.MustNewZero())
   188  	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2)
   189  	ctx, cancel := context.WithCancel(context.Background())
   190  	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
   191  		Ctx: ctx,
   192  		Ch:  make(chan *batch.Batch, 3),
   193  	}
   194  	proc.Reg.MergeReceivers[1] = &process.WaitRegister{
   195  		Ctx: ctx,
   196  		Ch:  make(chan *batch.Batch, 3),
   197  	}
   198  	return orderTestCase{
   199  		types: ts,
   200  		proc:  proc,
   201  		arg: &Argument{
   202  			OrderBySpecs: fs,
   203  			OperatorBase: vm.OperatorBase{
   204  				OperatorInfo: vm.OperatorInfo{
   205  					Idx:     0,
   206  					IsFirst: false,
   207  					IsLast:  false,
   208  				},
   209  			},
   210  		},
   211  		cancel: cancel,
   212  	}
   213  }
   214  
   215  func newExpression(pos int32, typeID types.T) *plan.Expr {
   216  	return &plan.Expr{
   217  		Expr: &plan.Expr_Col{
   218  			Col: &plan.ColRef{
   219  				ColPos: pos,
   220  			},
   221  		},
   222  		Typ: plan.Type{
   223  			Id: int32(typeID),
   224  		},
   225  	}
   226  }
   227  
   228  func newIntBatch(ts []types.Type, proc *process.Process, rows int64, fs []*plan.OrderBySpec) *batch.Batch {
   229  	vs := make([]*vector.Vector, len(ts))
   230  	for i, t := range ts {
   231  		generateDescData := false
   232  		for _, f := range fs {
   233  			if f.Flag == plan.OrderBySpec_DESC {
   234  				index := f.Expr.Expr.(*plan.Expr_Col).Col.ColPos
   235  				if int(index) == i {
   236  					generateDescData = true
   237  				}
   238  			}
   239  		}
   240  
   241  		if t.Oid == types.T_int8 {
   242  			values := make([]int8, rows)
   243  			if generateDescData {
   244  				for j := range values {
   245  					values[j] = int8(-j)
   246  				}
   247  			} else {
   248  				for j := range values {
   249  					values[j] = int8(j + 1)
   250  				}
   251  			}
   252  			vs[i] = testutil.NewVector(int(rows), t, proc.Mp(), false, values)
   253  		} else if t.Oid == types.T_int64 {
   254  			values := make([]int64, rows)
   255  			if generateDescData {
   256  				for j := range values {
   257  					values[j] = int64(-j)
   258  				}
   259  			} else {
   260  				for j := range values {
   261  					values[j] = int64(j + 1)
   262  				}
   263  			}
   264  			vs[i] = testutil.NewVector(int(rows), t, proc.Mp(), false, values)
   265  		}
   266  	}
   267  	zs := make([]int64, rows)
   268  	for i := range zs {
   269  		zs[i] = 1
   270  	}
   271  	return testutil.NewBatchWithVectors(vs, zs)
   272  }
   273  
   274  func newRandomBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   275  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   276  }