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