github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/mergegroup/group_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 mergegroup 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/testutil" 26 "github.com/matrixorigin/matrixone/pkg/vm" 27 "github.com/matrixorigin/matrixone/pkg/vm/process" 28 "github.com/stretchr/testify/require" 29 ) 30 31 const ( 32 Rows = 10 // default rows 33 BenchmarkRows = 100000 // default rows for benchmark 34 ) 35 36 // add unit tests for cases 37 38 type groupTestCase struct { 39 arg *Argument 40 flgs []bool // flgs[i] == true: nullable 41 types []types.Type 42 proc *process.Process 43 cancel context.CancelFunc 44 } 45 46 var ( 47 tcs []groupTestCase 48 ) 49 50 func init() { 51 tcs = []groupTestCase{ 52 newTestCase([]bool{false}, false, []types.Type{types.T_int8.ToType()}), 53 newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}), 54 newTestCase([]bool{false, true}, false, []types.Type{ 55 types.T_int8.ToType(), 56 types.T_int16.ToType(), 57 }), 58 newTestCase([]bool{false, true}, true, []types.Type{ 59 types.T_int16.ToType(), 60 types.T_int64.ToType(), 61 }), 62 newTestCase([]bool{false, true}, false, []types.Type{ 63 types.T_int64.ToType(), 64 types.T_decimal128.ToType(), 65 }), 66 newTestCase([]bool{true, false, true}, false, []types.Type{ 67 types.T_int64.ToType(), 68 types.T_int64.ToType(), 69 types.T_decimal128.ToType(), 70 }), 71 newTestCase([]bool{true, false, true}, false, []types.Type{ 72 types.T_int64.ToType(), 73 types.New(types.T_varchar, 2, 0), 74 types.T_decimal128.ToType(), 75 }), 76 newTestCase([]bool{true, true, true}, false, []types.Type{ 77 types.T_int64.ToType(), 78 types.New(types.T_varchar, 2, 0), 79 types.T_decimal128.ToType(), 80 }), 81 newTestCase([]bool{true, true, true}, false, []types.Type{ 82 types.T_int64.ToType(), 83 types.T_varchar.ToType(), 84 types.T_decimal128.ToType(), 85 }), 86 newTestCase([]bool{false, false, false}, false, []types.Type{ 87 types.T_int64.ToType(), 88 types.T_varchar.ToType(), 89 types.T_decimal128.ToType(), 90 }), 91 } 92 } 93 94 func TestString(t *testing.T) { 95 buf := new(bytes.Buffer) 96 for _, tc := range tcs { 97 tc.arg.String(buf) 98 } 99 } 100 101 func TestGroup(t *testing.T) { 102 for _, tc := range tcs { 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 <- nil 108 tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, Rows) 109 tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch 110 tc.proc.Reg.MergeReceivers[1].Ch <- nil 111 for { 112 ok, err := tc.arg.Call(tc.proc) 113 if ok.Status == vm.ExecStop || err != nil { 114 cleanResult(&ok, tc.proc) 115 break 116 } 117 cleanResult(&ok, tc.proc) 118 } 119 for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline 120 for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 { 121 bat := <-tc.proc.Reg.MergeReceivers[i].Ch 122 if bat != nil { 123 bat.Clean(tc.proc.Mp()) 124 } 125 } 126 } 127 tc.proc.FreeVectors() 128 tc.arg.Free(tc.proc, false, nil) 129 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 130 } 131 } 132 133 func BenchmarkGroup(b *testing.B) { 134 for i := 0; i < b.N; i++ { 135 tcs = []groupTestCase{ 136 newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}), 137 newTestCase([]bool{false}, true, []types.Type{types.T_int8.ToType()}), 138 } 139 t := new(testing.T) 140 for _, tc := range tcs { 141 err := tc.arg.Prepare(tc.proc) 142 require.NoError(t, err) 143 tc.proc.Reg.MergeReceivers[0].Ch <- newBatch(tc.types, tc.proc, Rows) 144 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 145 tc.proc.Reg.MergeReceivers[0].Ch <- nil 146 tc.proc.Reg.MergeReceivers[1].Ch <- newBatch(tc.types, tc.proc, Rows) 147 tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch 148 tc.proc.Reg.MergeReceivers[1].Ch <- nil 149 for { 150 ok, err := tc.arg.Call(tc.proc) 151 if ok.Status == vm.ExecStop || err != nil { 152 break 153 } 154 cleanResult(&ok, tc.proc) 155 } 156 for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline 157 for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 { 158 bat := <-tc.proc.Reg.MergeReceivers[i].Ch 159 if bat != nil { 160 bat.Clean(tc.proc.Mp()) 161 } 162 } 163 } 164 } 165 } 166 } 167 168 func newTestCase(flgs []bool, needEval bool, ts []types.Type) groupTestCase { 169 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 170 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 171 ctx, cancel := context.WithCancel(context.Background()) 172 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 173 Ctx: ctx, 174 Ch: make(chan *batch.Batch, 3), 175 } 176 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 177 Ctx: ctx, 178 Ch: make(chan *batch.Batch, 3), 179 } 180 return groupTestCase{ 181 types: ts, 182 flgs: flgs, 183 proc: proc, 184 cancel: cancel, 185 arg: &Argument{ 186 NeedEval: needEval, 187 OperatorBase: vm.OperatorBase{ 188 OperatorInfo: vm.OperatorInfo{ 189 Idx: 0, 190 IsFirst: false, 191 IsLast: false, 192 }, 193 }, 194 }, 195 } 196 } 197 198 // create a new block based on the type information, flgs[i] == ture: has null 199 func newBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 200 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 201 } 202 203 func cleanResult(result *vm.CallResult, proc *process.Process) { 204 if result.Batch != nil { 205 result.Batch.Clean(proc.Mp()) 206 } 207 }