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