github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/loopsemi/join_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 loopsemi 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/sql/colexec/hashbuild" 27 "github.com/matrixorigin/matrixone/pkg/sql/plan/function" 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 joinTestCase struct { 41 arg *Argument 42 flgs []bool // flgs[i] == true: nullable 43 types []types.Type 44 proc *process.Process 45 cancel context.CancelFunc 46 barg *hashbuild.Argument 47 } 48 49 var ( 50 tcs []joinTestCase 51 ) 52 53 func init() { 54 tcs = []joinTestCase{ 55 newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}), 56 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}), 57 } 58 } 59 60 func TestString(t *testing.T) { 61 buf := new(bytes.Buffer) 62 for _, tc := range tcs { 63 tc.arg.String(buf) 64 } 65 } 66 67 func TestJoin(t *testing.T) { 68 for _, tc := range tcs { 69 bats := hashBuild(t, tc) 70 err := tc.arg.Prepare(tc.proc) 71 require.NoError(t, err) 72 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 73 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 74 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 75 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 76 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 77 tc.proc.Reg.MergeReceivers[0].Ch <- nil 78 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 79 tc.proc.Reg.MergeReceivers[0].Ch <- nil 80 tc.proc.Reg.MergeReceivers[1].Ch <- nil 81 for { 82 ok, err := tc.arg.Call(tc.proc) 83 if ok.Status == vm.ExecStop || err != nil { 84 break 85 } 86 } 87 tc.arg.Free(tc.proc, false, nil) 88 tc.proc.FreeVectors() 89 tc.arg.Free(tc.proc, false, nil) 90 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 91 } 92 } 93 94 func BenchmarkJoin(b *testing.B) { 95 for i := 0; i < b.N; i++ { 96 tcs = []joinTestCase{ 97 newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}), 98 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}), 99 } 100 t := new(testing.T) 101 for _, tc := range tcs { 102 bats := hashBuild(t, tc) 103 err := tc.arg.Prepare(tc.proc) 104 require.NoError(t, err) 105 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 106 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 107 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 108 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 109 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 110 tc.proc.Reg.MergeReceivers[0].Ch <- nil 111 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 112 for { 113 ok, err := tc.arg.Call(tc.proc) 114 if ok.Status == vm.ExecStop || err != nil { 115 break 116 } 117 } 118 } 119 } 120 } 121 122 func newTestCase(flgs []bool, ts []types.Type, rp []int32) joinTestCase { 123 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 124 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 125 ctx, cancel := context.WithCancel(context.Background()) 126 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 127 Ctx: ctx, 128 Ch: make(chan *batch.Batch, 10), 129 } 130 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 131 Ctx: ctx, 132 Ch: make(chan *batch.Batch, 4), 133 } 134 fr, _ := function.GetFunctionByName(ctx, "=", ts) 135 fid := fr.GetEncodedOverloadID() 136 args := make([]*plan.Expr, 0, 2) 137 args = append(args, &plan.Expr{ 138 Typ: plan.Type{ 139 Id: int32(ts[0].Oid), 140 }, 141 Expr: &plan.Expr_Col{ 142 Col: &plan.ColRef{ 143 RelPos: 0, 144 ColPos: 0, 145 }, 146 }, 147 }) 148 args = append(args, &plan.Expr{ 149 Typ: plan.Type{ 150 Id: int32(ts[0].Oid), 151 }, 152 Expr: &plan.Expr_Col{ 153 Col: &plan.ColRef{ 154 RelPos: 1, 155 ColPos: 0, 156 }, 157 }, 158 }) 159 cond := &plan.Expr{ 160 Typ: plan.Type{ 161 Id: int32(types.T_bool), 162 }, 163 Expr: &plan.Expr_F{ 164 F: &plan.Function{ 165 Args: args, 166 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 167 }, 168 }, 169 } 170 return joinTestCase{ 171 types: ts, 172 flgs: flgs, 173 proc: proc, 174 cancel: cancel, 175 arg: &Argument{ 176 Typs: ts, 177 Cond: cond, 178 Result: rp, 179 OperatorBase: vm.OperatorBase{ 180 OperatorInfo: vm.OperatorInfo{ 181 Idx: 0, 182 IsFirst: false, 183 IsLast: false, 184 }, 185 }, 186 }, 187 barg: &hashbuild.Argument{ 188 Typs: ts, 189 OperatorBase: vm.OperatorBase{ 190 OperatorInfo: vm.OperatorInfo{ 191 Idx: 0, 192 IsFirst: false, 193 IsLast: false, 194 }, 195 }, 196 }, 197 } 198 } 199 200 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 201 err := tc.barg.Prepare(tc.proc) 202 require.NoError(t, err) 203 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 204 for _, r := range tc.proc.Reg.MergeReceivers { 205 r.Ch <- nil 206 } 207 ok1, err := tc.barg.Call(tc.proc) 208 require.NoError(t, err) 209 require.Equal(t, false, ok1.Status == vm.ExecStop) 210 ok2, err := tc.barg.Call(tc.proc) 211 require.NoError(t, err) 212 require.Equal(t, false, ok2.Status == vm.ExecStop) 213 return []*batch.Batch{ok1.Batch, ok2.Batch} 214 } 215 216 // create a new block based on the type information, flgs[i] == ture: has null 217 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 218 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 219 }