github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/anti/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 anti 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/types" 26 "github.com/matrixorigin/matrixone/pkg/pb/plan" 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 antiTestCase 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 []antiTestCase 52 ) 53 54 func init() { 55 tcs = []antiTestCase{ 56 newTestCase(mpool.MustNewZero(), []bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}, 57 [][]*plan.Expr{ 58 { 59 newExpr(0, types.T_int8.ToType()), 60 }, 61 { 62 newExpr(0, types.T_int8.ToType()), 63 }, 64 }), 65 newTestCase(mpool.MustNewZero(), []bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}, 66 [][]*plan.Expr{ 67 { 68 newExpr(0, types.T_int8.ToType()), 69 }, 70 { 71 newExpr(0, types.T_int8.ToType()), 72 }, 73 }), 74 } 75 } 76 77 func TestString(t *testing.T) { 78 buf := new(bytes.Buffer) 79 for _, tc := range tcs { 80 tc.arg.String(buf) 81 } 82 } 83 84 func TestAnti(t *testing.T) { 85 for _, tc := range tcs { 86 bats := hashBuild(t, tc) 87 if jm, ok := bats[0].AuxData.(*hashmap.JoinMap); ok { 88 jm.SetDupCount(int64(1)) 89 } 90 err := tc.arg.Prepare(tc.proc) 91 require.NoError(t, err) 92 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 93 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 94 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 95 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 96 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 97 tc.proc.Reg.MergeReceivers[0].Ch <- nil 98 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 99 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 100 tc.proc.Reg.MergeReceivers[1].Ch <- nil 101 for { 102 ok, err := tc.arg.Call(tc.proc) 103 if ok.Status == vm.ExecStop || err != nil { 104 break 105 } 106 } 107 tc.proc.Reg.MergeReceivers[0].Ch <- nil 108 tc.proc.Reg.MergeReceivers[1].Ch <- nil 109 tc.arg.Free(tc.proc, false, nil) 110 tc.proc.FreeVectors() 111 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 112 } 113 for _, tc := range tcs { 114 err := tc.arg.Prepare(tc.proc) 115 require.NoError(t, err) 116 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 117 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 118 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 119 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 120 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 121 tc.proc.Reg.MergeReceivers[0].Ch <- nil 122 tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch 123 tc.proc.Reg.MergeReceivers[1].Ch <- nil 124 for { 125 ok, err := tc.arg.Call(tc.proc) 126 if ok.Status == vm.ExecStop || err != nil { 127 break 128 } 129 } 130 tc.proc.Reg.MergeReceivers[0].Ch <- nil 131 tc.proc.Reg.MergeReceivers[1].Ch <- nil 132 tc.arg.Free(tc.proc, false, nil) 133 tc.proc.FreeVectors() 134 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 135 } 136 } 137 138 func BenchmarkAnti(b *testing.B) { 139 for i := 0; i < b.N; i++ { 140 tcs = []antiTestCase{ 141 newTestCase(mpool.MustNewZero(), []bool{false}, []types.Type{types.T_int8.ToType()}, []int32{0}, 142 [][]*plan.Expr{ 143 { 144 newExpr(0, types.T_int8.ToType()), 145 }, 146 { 147 newExpr(0, types.T_int8.ToType()), 148 }, 149 }), 150 newTestCase(mpool.MustNewZero(), []bool{true}, []types.Type{types.T_int8.ToType()}, []int32{0}, 151 [][]*plan.Expr{ 152 { 153 newExpr(0, types.T_int8.ToType()), 154 }, 155 { 156 newExpr(0, types.T_int8.ToType()), 157 }, 158 }), 159 } 160 t := new(testing.T) 161 for _, tc := range tcs { 162 bats := hashBuild(t, tc) 163 err := tc.arg.Prepare(tc.proc) 164 require.NoError(t, err) 165 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 166 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 167 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 168 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 169 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 170 tc.proc.Reg.MergeReceivers[0].Ch <- nil 171 tc.proc.Reg.MergeReceivers[1].Ch <- bats[0] 172 tc.proc.Reg.MergeReceivers[1].Ch <- bats[1] 173 for { 174 ok, err := tc.arg.Call(tc.proc) 175 if ok.Status == vm.ExecStop || err != nil { 176 break 177 } 178 } 179 } 180 } 181 } 182 183 func newExpr(pos int32, typ types.Type) *plan.Expr { 184 return &plan.Expr{ 185 Typ: plan.Type{ 186 Scale: typ.Scale, 187 Width: typ.Width, 188 Id: int32(typ.Oid), 189 }, 190 Expr: &plan.Expr_Col{ 191 Col: &plan.ColRef{ 192 ColPos: pos, 193 }, 194 }, 195 } 196 } 197 198 func newTestCase(m *mpool.MPool, flgs []bool, ts []types.Type, rp []int32, cs [][]*plan.Expr) antiTestCase { 199 proc := testutil.NewProcessWithMPool(m) 200 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 201 ctx, cancel := context.WithCancel(context.Background()) 202 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 203 Ctx: ctx, 204 Ch: make(chan *batch.Batch, 10), 205 } 206 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 207 Ctx: ctx, 208 Ch: make(chan *batch.Batch, 3), 209 } 210 fr, _ := function.GetFunctionByName(ctx, "=", ts) 211 fid := fr.GetEncodedOverloadID() 212 args := make([]*plan.Expr, 0, 2) 213 args = append(args, &plan.Expr{ 214 Typ: plan.Type{ 215 Id: int32(ts[0].Oid), 216 }, 217 Expr: &plan.Expr_Col{ 218 Col: &plan.ColRef{ 219 RelPos: 0, 220 ColPos: 0, 221 }, 222 }, 223 }) 224 args = append(args, &plan.Expr{ 225 Typ: plan.Type{ 226 Id: int32(ts[0].Oid), 227 }, 228 Expr: &plan.Expr_Col{ 229 Col: &plan.ColRef{ 230 RelPos: 1, 231 ColPos: 0, 232 }, 233 }, 234 }) 235 cond := &plan.Expr{ 236 Typ: plan.Type{ 237 Id: int32(types.T_bool), 238 }, 239 Expr: &plan.Expr_F{ 240 F: &plan.Function{ 241 Args: args, 242 Func: &plan.ObjectRef{Obj: fid, ObjName: "="}, 243 }, 244 }, 245 } 246 return antiTestCase{ 247 types: ts, 248 flgs: flgs, 249 proc: proc, 250 cancel: cancel, 251 arg: &Argument{ 252 Typs: ts, 253 Result: rp, 254 Conditions: cs, 255 Cond: cond, 256 OperatorBase: vm.OperatorBase{ 257 OperatorInfo: vm.OperatorInfo{ 258 Idx: 1, 259 IsFirst: false, 260 IsLast: false, 261 }, 262 }, 263 }, 264 barg: &hashbuild.Argument{ 265 Typs: ts, 266 NeedHashMap: true, 267 Conditions: cs[1], 268 OperatorBase: vm.OperatorBase{ 269 OperatorInfo: vm.OperatorInfo{ 270 Idx: 0, 271 IsFirst: false, 272 IsLast: false, 273 }, 274 }, 275 NeedAllocateSels: true, 276 NeedMergedBatch: true, 277 }, 278 } 279 } 280 281 func hashBuild(t *testing.T, tc antiTestCase) []*batch.Batch { 282 err := tc.barg.Prepare(tc.proc) 283 require.NoError(t, err) 284 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 285 for _, r := range tc.proc.Reg.MergeReceivers { 286 r.Ch <- nil 287 } 288 ok1, err := tc.barg.Call(tc.proc) 289 require.NoError(t, err) 290 require.Equal(t, false, ok1.Status == vm.ExecStop) 291 ok2, err := tc.barg.Call(tc.proc) 292 require.NoError(t, err) 293 require.Equal(t, false, ok2.Status == vm.ExecStop) 294 return []*batch.Batch{ok1.Batch, ok2.Batch} 295 } 296 297 // create a new block based on the type information, flgs[i] == ture: has null 298 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 299 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 300 }