github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/ordered_synchronizer_test.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package colexec 12 13 import ( 14 "context" 15 "math/rand" 16 "sort" 17 "testing" 18 19 "github.com/cockroachdb/cockroach/pkg/col/coldata" 20 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase" 21 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 22 "github.com/cockroachdb/cockroach/pkg/sql/types" 23 "github.com/cockroachdb/cockroach/pkg/util/encoding" 24 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 25 "github.com/stretchr/testify/require" 26 ) 27 28 // Adapted from the same-named test in the rowflow package. 29 func TestOrderedSync(t *testing.T) { 30 defer leaktest.AfterTest(t)() 31 testCases := []struct { 32 sources []tuples 33 ordering sqlbase.ColumnOrdering 34 expected tuples 35 }{ 36 { 37 sources: []tuples{ 38 { 39 {0, 1, 4}, 40 {0, 1, 2}, 41 {0, 2, 3}, 42 {1, 1, 3}, 43 }, 44 { 45 {1, 0, 4}, 46 }, 47 { 48 {0, 0, 0}, 49 {4, 4, 4}, 50 }, 51 }, 52 ordering: sqlbase.ColumnOrdering{ 53 {ColIdx: 0, Direction: encoding.Ascending}, 54 {ColIdx: 1, Direction: encoding.Ascending}, 55 }, 56 expected: tuples{ 57 {0, 0, 0}, 58 {0, 1, 4}, 59 {0, 1, 2}, 60 {0, 2, 3}, 61 {1, 0, 4}, 62 {1, 1, 3}, 63 {4, 4, 4}, 64 }, 65 }, 66 { 67 sources: []tuples{ 68 { 69 {1, 0, 4}, 70 }, 71 { 72 {3, 4, 1}, 73 {4, 4, 4}, 74 {3, 2, 0}, 75 }, 76 { 77 {4, 4, 5}, 78 {3, 3, 0}, 79 {0, 0, 0}, 80 }, 81 }, 82 ordering: sqlbase.ColumnOrdering{ 83 {ColIdx: 1, Direction: encoding.Descending}, 84 {ColIdx: 0, Direction: encoding.Ascending}, 85 {ColIdx: 2, Direction: encoding.Ascending}, 86 }, 87 expected: tuples{ 88 {3, 4, 1}, 89 {4, 4, 4}, 90 {4, 4, 5}, 91 {3, 3, 0}, 92 {3, 2, 0}, 93 {0, 0, 0}, 94 {1, 0, 4}, 95 }, 96 }, 97 { 98 sources: []tuples{ 99 { 100 {-1}, 101 }, 102 { 103 {1}, 104 }, 105 { 106 {nil}, 107 }, 108 }, 109 ordering: sqlbase.ColumnOrdering{ 110 {ColIdx: 0, Direction: encoding.Ascending}, 111 }, 112 expected: tuples{ 113 {nil}, 114 {-1}, 115 {1}, 116 }, 117 }, 118 { 119 sources: []tuples{ 120 { 121 {-1}, 122 }, 123 { 124 {1}, 125 }, 126 { 127 {nil}, 128 }, 129 }, 130 ordering: sqlbase.ColumnOrdering{ 131 {ColIdx: 0, Direction: encoding.Descending}, 132 }, 133 expected: tuples{ 134 {1}, 135 {-1}, 136 {nil}, 137 }, 138 }, 139 } 140 for _, tc := range testCases { 141 numCols := len(tc.sources[0][0]) 142 typs := make([]*types.T, numCols) 143 for i := range typs { 144 typs[i] = types.Int 145 } 146 runTests(t, tc.sources, tc.expected, orderedVerifier, func(inputs []colexecbase.Operator) (colexecbase.Operator, error) { 147 return NewOrderedSynchronizer(testAllocator, inputs, typs, tc.ordering) 148 }) 149 } 150 } 151 152 func TestOrderedSyncRandomInput(t *testing.T) { 153 defer leaktest.AfterTest(t)() 154 numInputs := 3 155 inputLen := 1024 156 batchSize := 16 157 if batchSize > coldata.BatchSize() { 158 batchSize = coldata.BatchSize() 159 } 160 typs := []*types.T{types.Int} 161 162 // Generate a random slice of sorted ints. 163 randInts := make([]int, inputLen) 164 for i := range randInts { 165 randInts[i] = rand.Int() 166 } 167 sort.Ints(randInts) 168 169 // Randomly distribute them among the inputs. 170 expected := make(tuples, inputLen) 171 sources := make([]tuples, numInputs) 172 for i := range expected { 173 t := tuple{randInts[i]} 174 expected[i] = t 175 sourceIdx := rand.Int() % 3 176 if i < numInputs { 177 // Make sure each input has at least one row. 178 sourceIdx = i 179 } 180 sources[sourceIdx] = append(sources[sourceIdx], t) 181 } 182 inputs := make([]colexecbase.Operator, numInputs) 183 for i := range inputs { 184 inputs[i] = newOpTestInput(batchSize, sources[i], typs) 185 } 186 ordering := sqlbase.ColumnOrdering{{ColIdx: 0, Direction: encoding.Ascending}} 187 op, err := NewOrderedSynchronizer(testAllocator, inputs, typs, ordering) 188 require.NoError(t, err) 189 op.Init() 190 out := newOpTestOutput(op, expected) 191 if err := out.Verify(); err != nil { 192 t.Error(err) 193 } 194 } 195 196 func BenchmarkOrderedSynchronizer(b *testing.B) { 197 ctx := context.Background() 198 199 numInputs := int64(3) 200 typs := []*types.T{types.Int} 201 batches := make([]coldata.Batch, numInputs) 202 for i := range batches { 203 batches[i] = testAllocator.NewMemBatch(typs) 204 batches[i].SetLength(coldata.BatchSize()) 205 } 206 for i := int64(0); i < int64(coldata.BatchSize())*numInputs; i++ { 207 batch := batches[i%numInputs] 208 batch.ColVec(0).Int64()[i/numInputs] = i 209 } 210 211 inputs := make([]colexecbase.Operator, len(batches)) 212 for i := range batches { 213 inputs[i] = colexecbase.NewRepeatableBatchSource(testAllocator, batches[i], typs) 214 } 215 216 ordering := sqlbase.ColumnOrdering{{ColIdx: 0, Direction: encoding.Ascending}} 217 op, err := NewOrderedSynchronizer(testAllocator, inputs, typs, ordering) 218 require.NoError(b, err) 219 op.Init() 220 221 b.SetBytes(8 * int64(coldata.BatchSize()) * numInputs) 222 b.ResetTimer() 223 for i := 0; i < b.N; i++ { 224 op.Next(ctx) 225 } 226 }