github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/mergeorder/order_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 mergeorder 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "testing" 22 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/container/vector" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 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 orderTestCase struct { 41 arg *Argument 42 types []types.Type 43 proc *process.Process 44 cancel context.CancelFunc 45 } 46 47 func TestString(t *testing.T) { 48 tcs := []orderTestCase{ 49 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}), 50 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 51 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}), 52 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 53 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}), 54 } 55 buf := new(bytes.Buffer) 56 for _, tc := range tcs { 57 tc.arg.String(buf) 58 } 59 } 60 61 func TestPrepare(t *testing.T) { 62 tcs := []orderTestCase{ 63 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}), 64 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 65 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}), 66 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 67 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}), 68 } 69 for _, tc := range tcs { 70 err := tc.arg.Prepare(tc.proc) 71 require.NoError(t, err) 72 } 73 } 74 75 func TestOrder(t *testing.T) { 76 tcs := []orderTestCase{ 77 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}), 78 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 79 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(1, types.T_int64), Flag: 0}}), 80 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 81 newTestCase([]types.Type{types.T_int8.ToType(), types.T_int64.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}, {Expr: newExpression(1, types.T_int64), Flag: 0}}), 82 } 83 84 for tci, tc := range tcs { 85 err := tc.arg.Prepare(tc.proc) 86 require.NoError(t, err) 87 tc.proc.Reg.MergeReceivers[0].Ch <- newIntBatch(tc.types, tc.proc, Rows, tc.arg.OrderBySpecs) 88 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 89 tc.proc.Reg.MergeReceivers[0].Ch <- nil 90 tc.proc.Reg.MergeReceivers[1].Ch <- newIntBatch(tc.types, tc.proc, Rows, tc.arg.OrderBySpecs) 91 tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch 92 tc.proc.Reg.MergeReceivers[1].Ch <- nil 93 for { 94 if ok, err := tc.arg.Call(tc.proc); ok.Status == vm.ExecStop || err != nil { 95 require.NoError(t, err) 96 // do the result check 97 if len(tc.arg.OrderBySpecs) > 0 { 98 desc := tc.arg.OrderBySpecs[0].Flag&plan.OrderBySpec_DESC != 0 99 index := tc.arg.OrderBySpecs[0].Expr.Expr.(*plan.Expr_Col).Col.ColPos 100 bat := ok.Batch 101 vec := bat.Vecs[index] 102 if vec.GetType().Oid == types.T_int8 { 103 i8c := vector.MustFixedCol[int8](vec) 104 if desc { 105 for j := range i8c { 106 if j > 0 { 107 require.True(t, i8c[j] <= i8c[j-1], fmt.Sprintf("tc %d require desc, but get %v", tci, i8c)) 108 } 109 } 110 } else { 111 for j := range i8c { 112 if j > 0 { 113 require.True(t, i8c[j] >= i8c[j-1]) 114 } 115 } 116 } 117 } else if vec.GetType().Oid == types.T_int64 { 118 i64c := vector.MustFixedCol[int64](vec) 119 if desc { 120 for j := range i64c { 121 if j > 0 { 122 require.True(t, i64c[j] <= i64c[j-1]) 123 } 124 } 125 } else { 126 for j := range i64c { 127 if j > 0 { 128 require.True(t, i64c[j] >= i64c[j-1]) 129 } 130 } 131 } 132 } 133 } 134 135 break 136 } 137 } 138 for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline 139 for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 { 140 bat := <-tc.proc.Reg.MergeReceivers[i].Ch 141 if bat != nil { 142 bat.Clean(tc.proc.Mp()) 143 } 144 } 145 } 146 tc.proc.FreeVectors() 147 tc.arg.Free(tc.proc, false, nil) 148 require.Equal(t, int64(0), tc.proc.Mp().CurrNB()) 149 } 150 } 151 152 func BenchmarkOrder(b *testing.B) { 153 for i := 0; i < b.N; i++ { 154 tcs := []orderTestCase{ 155 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 0}}), 156 newTestCase([]types.Type{types.T_int8.ToType()}, []*plan.OrderBySpec{{Expr: newExpression(0, types.T_int8), Flag: 2}}), 157 } 158 t := new(testing.T) 159 for _, tc := range tcs { 160 err := tc.arg.Prepare(tc.proc) 161 require.NoError(t, err) 162 tc.proc.Reg.MergeReceivers[0].Ch <- newRandomBatch(tc.types, tc.proc, BenchmarkRows) 163 tc.proc.Reg.MergeReceivers[0].Ch <- batch.EmptyBatch 164 tc.proc.Reg.MergeReceivers[0].Ch <- nil 165 tc.proc.Reg.MergeReceivers[1].Ch <- newRandomBatch(tc.types, tc.proc, BenchmarkRows) 166 tc.proc.Reg.MergeReceivers[1].Ch <- batch.EmptyBatch 167 tc.proc.Reg.MergeReceivers[1].Ch <- nil 168 for { 169 ok, err := tc.arg.Call(tc.proc) 170 if ok.Status == vm.ExecStop || err != nil { 171 break 172 } 173 } 174 for i := 0; i < len(tc.proc.Reg.MergeReceivers); i++ { // simulating the end of a pipeline 175 for len(tc.proc.Reg.MergeReceivers[i].Ch) > 0 { 176 bat := <-tc.proc.Reg.MergeReceivers[i].Ch 177 if bat != nil { 178 bat.Clean(tc.proc.Mp()) 179 } 180 } 181 } 182 } 183 } 184 } 185 186 func newTestCase(ts []types.Type, fs []*plan.OrderBySpec) orderTestCase { 187 proc := testutil.NewProcessWithMPool(mpool.MustNewZero()) 188 proc.Reg.MergeReceivers = make([]*process.WaitRegister, 2) 189 ctx, cancel := context.WithCancel(context.Background()) 190 proc.Reg.MergeReceivers[0] = &process.WaitRegister{ 191 Ctx: ctx, 192 Ch: make(chan *batch.Batch, 3), 193 } 194 proc.Reg.MergeReceivers[1] = &process.WaitRegister{ 195 Ctx: ctx, 196 Ch: make(chan *batch.Batch, 3), 197 } 198 return orderTestCase{ 199 types: ts, 200 proc: proc, 201 arg: &Argument{ 202 OrderBySpecs: fs, 203 OperatorBase: vm.OperatorBase{ 204 OperatorInfo: vm.OperatorInfo{ 205 Idx: 0, 206 IsFirst: false, 207 IsLast: false, 208 }, 209 }, 210 }, 211 cancel: cancel, 212 } 213 } 214 215 func newExpression(pos int32, typeID types.T) *plan.Expr { 216 return &plan.Expr{ 217 Expr: &plan.Expr_Col{ 218 Col: &plan.ColRef{ 219 ColPos: pos, 220 }, 221 }, 222 Typ: plan.Type{ 223 Id: int32(typeID), 224 }, 225 } 226 } 227 228 func newIntBatch(ts []types.Type, proc *process.Process, rows int64, fs []*plan.OrderBySpec) *batch.Batch { 229 vs := make([]*vector.Vector, len(ts)) 230 for i, t := range ts { 231 generateDescData := false 232 for _, f := range fs { 233 if f.Flag == plan.OrderBySpec_DESC { 234 index := f.Expr.Expr.(*plan.Expr_Col).Col.ColPos 235 if int(index) == i { 236 generateDescData = true 237 } 238 } 239 } 240 241 if t.Oid == types.T_int8 { 242 values := make([]int8, rows) 243 if generateDescData { 244 for j := range values { 245 values[j] = int8(-j) 246 } 247 } else { 248 for j := range values { 249 values[j] = int8(j + 1) 250 } 251 } 252 vs[i] = testutil.NewVector(int(rows), t, proc.Mp(), false, values) 253 } else if t.Oid == types.T_int64 { 254 values := make([]int64, rows) 255 if generateDescData { 256 for j := range values { 257 values[j] = int64(-j) 258 } 259 } else { 260 for j := range values { 261 values[j] = int64(j + 1) 262 } 263 } 264 vs[i] = testutil.NewVector(int(rows), t, proc.Mp(), false, values) 265 } 266 } 267 zs := make([]int64, rows) 268 for i := range zs { 269 zs[i] = 1 270 } 271 return testutil.NewBatchWithVectors(vs, zs) 272 } 273 274 func newRandomBatch(ts []types.Type, proc *process.Process, rows int64) *batch.Batch { 275 return testutil.NewBatch(ts, false, int(rows), proc.Mp()) 276 }