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