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 }