github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/colexec/hashbuild/build_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 hashbuild
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"testing"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/hashmap"
    23  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    24  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    25  	"github.com/matrixorigin/matrixone/pkg/container/index"
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    29  	"github.com/matrixorigin/matrixone/pkg/testutil"
    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 buildTestCase struct {
    41  	arg    *Argument
    42  	flgs   []bool // flgs[i] == true: nullable
    43  	types  []types.Type
    44  	proc   *process.Process
    45  	cancel context.CancelFunc
    46  }
    47  
    48  var (
    49  	tcs []buildTestCase
    50  )
    51  
    52  func init() {
    53  	tcs = []buildTestCase{
    54  		newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}},
    55  			[]*plan.Expr{
    56  				newExpr(0, types.Type{Oid: types.T_int8}),
    57  			}),
    58  		newTestCase([]bool{true}, []types.Type{{Oid: types.T_int8}},
    59  			[]*plan.Expr{
    60  				newExpr(0, types.Type{Oid: types.T_int8}),
    61  			}),
    62  	}
    63  }
    64  
    65  func TestString(t *testing.T) {
    66  	buf := new(bytes.Buffer)
    67  	for _, tc := range tcs {
    68  		String(tc.arg, buf)
    69  	}
    70  }
    71  
    72  func TestBuild(t *testing.T) {
    73  	for _, tc := range tcs[:1] {
    74  		err := Prepare(tc.proc, tc.arg)
    75  		require.NoError(t, err)
    76  		tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
    77  		tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
    78  		tc.proc.Reg.MergeReceivers[0].Ch <- nil
    79  		for {
    80  			ok, err := Call(0, tc.proc, tc.arg, false, false)
    81  			require.NoError(t, err)
    82  			require.Equal(t, true, ok)
    83  			mp := tc.proc.Reg.InputBatch.Ht.(*hashmap.JoinMap)
    84  			mp.Free()
    85  			tc.proc.Reg.InputBatch.Clean(tc.proc.Mp())
    86  			break
    87  		}
    88  		tc.arg.Free(tc.proc, false)
    89  		require.Equal(t, int64(0), tc.proc.Mp().CurrNB())
    90  	}
    91  }
    92  
    93  func TestLowCardinalityBuild(t *testing.T) {
    94  	tc := newTestCase([]bool{false}, []types.Type{types.T_varchar.ToType()},
    95  		[]*plan.Expr{
    96  			newExpr(0, types.T_varchar.ToType()),
    97  		},
    98  	)
    99  	err := Prepare(tc.proc, tc.arg)
   100  	require.NoError(t, err)
   101  
   102  	values := []string{"a", "b", "a", "c", "b", "c", "a", "a"}
   103  	v := testutil.NewVector(len(values), types.T_varchar.ToType(), tc.proc.Mp(), false, values)
   104  	constructIndex(t, v, tc.proc.Mp())
   105  
   106  	tc.proc.Reg.MergeReceivers[0].Ch <- testutil.NewBatchWithVectors([]*vector.Vector{v}, nil)
   107  	tc.proc.Reg.MergeReceivers[0].Ch <- nil
   108  
   109  	ok, err := Call(0, tc.proc, tc.arg, false, false)
   110  	require.NoError(t, err)
   111  	require.Equal(t, true, ok)
   112  	mp := tc.proc.Reg.InputBatch.Ht.(*hashmap.JoinMap)
   113  	require.NotNil(t, mp.Index())
   114  
   115  	sels := mp.Sels()
   116  	require.Equal(t, []int32{0, 2, 6, 7}, sels[0])
   117  	require.Equal(t, []int32{1, 4}, sels[1])
   118  	require.Equal(t, []int32{3, 5}, sels[2])
   119  
   120  	mp.Free()
   121  	tc.proc.Reg.InputBatch.Clean(tc.proc.Mp())
   122  }
   123  
   124  func BenchmarkBuild(b *testing.B) {
   125  	for i := 0; i < b.N; i++ {
   126  		tcs = []buildTestCase{
   127  			newTestCase([]bool{false}, []types.Type{{Oid: types.T_int8}},
   128  				[]*plan.Expr{
   129  					newExpr(0, types.Type{Oid: types.T_int8}),
   130  				}),
   131  		}
   132  		t := new(testing.T)
   133  		for _, tc := range tcs {
   134  			err := Prepare(tc.proc, tc.arg)
   135  			require.NoError(t, err)
   136  			tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(t, tc.flgs, tc.types, tc.proc, Rows)
   137  			tc.proc.Reg.MergeReceivers[0].Ch <- &batch.Batch{}
   138  			tc.proc.Reg.MergeReceivers[0].Ch <- nil
   139  			for {
   140  				ok, err := Call(0, tc.proc, tc.arg, false, false)
   141  				require.NoError(t, err)
   142  				require.Equal(t, true, ok)
   143  				mp := tc.proc.Reg.InputBatch.Ht.(*hashmap.JoinMap)
   144  				mp.Free()
   145  				tc.proc.Reg.InputBatch.Clean(tc.proc.Mp())
   146  				break
   147  			}
   148  		}
   149  	}
   150  }
   151  
   152  func newExpr(pos int32, typ types.Type) *plan.Expr {
   153  	return &plan.Expr{
   154  		Typ: &plan.Type{
   155  			Size:  typ.Size,
   156  			Scale: typ.Scale,
   157  			Width: typ.Width,
   158  			Id:    int32(typ.Oid),
   159  		},
   160  		Expr: &plan.Expr_Col{
   161  			Col: &plan.ColRef{
   162  				ColPos: pos,
   163  			},
   164  		},
   165  	}
   166  }
   167  
   168  func newTestCase(flgs []bool, ts []types.Type, cs []*plan.Expr) buildTestCase {
   169  	proc := testutil.NewProcessWithMPool(mpool.MustNewZero())
   170  	proc.Reg.MergeReceivers = make([]*process.WaitRegister, 1)
   171  	ctx, cancel := context.WithCancel(context.Background())
   172  	proc.Reg.MergeReceivers[0] = &process.WaitRegister{
   173  		Ctx: ctx,
   174  		Ch:  make(chan *batch.Batch, 10),
   175  	}
   176  	return buildTestCase{
   177  		types:  ts,
   178  		flgs:   flgs,
   179  		proc:   proc,
   180  		cancel: cancel,
   181  		arg: &Argument{
   182  			Typs:        ts,
   183  			Conditions:  cs,
   184  			NeedHashMap: true,
   185  		},
   186  	}
   187  }
   188  
   189  // create a new block based on the type information, flgs[i] == ture: has null
   190  func newBatch(t *testing.T, flgs []bool, ts []types.Type, proc *process.Process, rows int64) *batch.Batch {
   191  	return testutil.NewBatch(ts, false, int(rows), proc.Mp())
   192  }
   193  
   194  func constructIndex(t *testing.T, v *vector.Vector, m *mpool.MPool) {
   195  	idx, err := index.New(v.Typ, m)
   196  	require.NoError(t, err)
   197  
   198  	err = idx.InsertBatch(v)
   199  	require.NoError(t, err)
   200  
   201  	v.SetIndex(idx)
   202  }