github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/loopanti/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 loopanti 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 for _, tc := range tcs { 93 err := tc.arg.Prepare(tc.proc) 94 require.NoError(t, err) 95 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 96 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 97 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 98 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 99 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 100 tc.proc.Reg.MergeReceivers[0].Ch <- nil 101 tc.proc.Reg.MergeReceivers[1].Ch <- nil 102 tc.proc.Reg.MergeReceivers[0].Ch <- nil 103 tc.proc.Reg.MergeReceivers[1].Ch <- nil 104 for { 105 ok, err := tc.arg.Call(tc.proc) 106 if ok.Status == vm.ExecStop || err != nil { 107 break 108 } 109 } 110 tc.arg.Free(tc.proc, false, nil) 111 tc.proc.FreeVectors() 112 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 113 } 114 115 } 116 117 func BenchmarkJoin(b *testing.B) { 118 for i := 0; i < b.N; i++ { 119 tcs = []joinTestCase{ 120 newTestCase([]bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}), 121 newTestCase([]bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}), 122 } 123 t := new(testing.T) 124 for _, tc := range tcs { 125 bats := hashBuild(t, tc) 126 err := tc.arg.Prepare(tc.proc) 127 require.NoError(t, err) 128 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 129 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 130 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 131 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 132 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 133 tc.proc.Reg.MergeReceivers[0].Ch <- nil 134 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 135 for { 136 ok, err := tc.arg.Call(tc.proc) 137 if ok.Status == vm.ExecStop || err != nil { 138 break 139 } 140 } 141 } 142 } 143 } 144 145 func newTestCase(flgs []bool, ts []types.Type, rp []int32) joinTestCase { 146 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 147 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 148 ctx, cancel := context.WithCancel(context.Background()) 149 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 150 Ctx: ctx, 151 Ch: make(chan *batch.Batch, 10), 152 } 153 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 154 Ctx: ctx, 155 Ch: make(chan *batch.Batch, 10), 156 } 157 fr, _ := function.GetFunctionByName(ctx, "=", ts) 158 fid := fr.GetEncodedOverloadID() 159 args := make([]*plan.Expr, 0, 2) 160 args = append(args, &plan.Expr{ 161 Typ: plan.Type{ 162 Id: int32(ts[0].Oid), 163 }, 164 Expr: &plan.Expr_Col{ 165 Col: &plan.ColRef{ 166 RelPos: 0, 167 ColPos: 0, 168 }, 169 }, 170 }) 171 args = append(args, &plan.Expr{ 172 Typ: plan.Type{ 173 Id: int32(ts[0].Oid), 174 }, 175 Expr: &plan.Expr_Col{ 176 Col: &plan.ColRef{ 177 RelPos: 1, 178 ColPos: 0, 179 }, 180 }, 181 }) 182 cond := &plan.Expr{ 183 Typ: plan.Type{ 184 Id: int32(types.T_bool), 185 }, 186 Expr: &plan.Expr_F{ 187 F: &plan.Function{ 188 Args: args, 189 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 190 }, 191 }, 192 } 193 return joinTestCase{ 194 types: ts, 195 flgs: flgs, 196 proc: proc, 197 cancel: cancel, 198 arg: &Argument{ 199 Typs: ts, 200 Cond: cond, 201 Result: rp, 202 OperatorBase: vm.OperatorBase{ 203 OperatorInfo: vm.OperatorInfo{ 204 Idx: 1, 205 IsFirst: false, 206 IsLast: false, 207 }, 208 }, 209 }, 210 barg: &hashbuild.Argument{ 211 Typs: ts, 212 OperatorBase: vm.OperatorBase{ 213 OperatorInfo: vm.OperatorInfo{ 214 Idx: 0, 215 IsFirst: false, 216 IsLast: false, 217 }, 218 }, 219 }, 220 } 221 } 222 223 func hashBuild(t *testing.T, tc joinTestCase) []*batch.Batch { 224 err := tc.barg.Prepare(tc.proc) 225 require.NoError(t, err) 226 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 227 for _, r := range tc.proc.Reg.MergeReceivers { 228 r.Ch <- nil 229 } 230 ok1, err := tc.barg.Call(tc.proc) 231 require.NoError(t, err) 232 require.Equal(t, false, ok1.Status == vm.ExecStop) 233 ok2, err := tc.barg.Call(tc.proc) 234 require.NoError(t, err) 235 require.Equal(t, false, ok2.Status == vm.ExecStop) 236 return []*batch.Batch{ok1.Batch, ok2.Batch} 237 } 238 239 // create a new block based on the type information, flgs[i] == ture: has null 240 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 241 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 242 }