github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/windower_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 rowexec 12 13 import ( 14 "context" 15 "fmt" 16 "math" 17 "strings" 18 "testing" 19 20 "github.com/cockroachdb/cockroach/pkg/base" 21 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 22 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 23 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 25 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 26 "github.com/cockroachdb/cockroach/pkg/storage" 27 "github.com/cockroachdb/cockroach/pkg/testutils/distsqlutils" 28 "github.com/cockroachdb/cockroach/pkg/util/encoding" 29 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 30 "github.com/cockroachdb/cockroach/pkg/util/mon" 31 ) 32 33 const noFilterIdx = -1 34 35 func TestWindowerAccountingForResults(t *testing.T) { 36 defer leaktest.AfterTest(t)() 37 ctx := context.Background() 38 st := cluster.MakeTestingClusterSettings() 39 monitor := mon.MakeMonitorWithLimit( 40 "test-monitor", 41 mon.MemoryResource, 42 100000, /* limit */ 43 nil, /* curCount */ 44 nil, /* maxHist */ 45 5000, /* increment */ 46 math.MaxInt64, /* noteworthy */ 47 st, 48 ) 49 evalCtx := tree.MakeTestingEvalContextWithMon(st, &monitor) 50 defer evalCtx.Stop(ctx) 51 diskMonitor := execinfra.NewTestDiskMonitor(ctx, st) 52 defer diskMonitor.Stop(ctx) 53 tempEngine, _, err := storage.NewTempEngine(ctx, storage.DefaultStorageEngine, base.DefaultTestTempStorageConfig(st), base.DefaultTestStoreSpec) 54 if err != nil { 55 t.Fatal(err) 56 } 57 defer tempEngine.Close() 58 59 flowCtx := &execinfra.FlowCtx{ 60 EvalCtx: &evalCtx, 61 Cfg: &execinfra.ServerConfig{ 62 Settings: st, 63 TempStorage: tempEngine, 64 DiskMonitor: diskMonitor, 65 }, 66 } 67 68 post := &execinfrapb.PostProcessSpec{} 69 input := execinfra.NewRepeatableRowSource(sqlbase.OneIntCol, sqlbase.MakeIntRows(1000, 1)) 70 aggSpec := execinfrapb.AggregatorSpec_ARRAY_AGG 71 spec := execinfrapb.WindowerSpec{ 72 PartitionBy: []uint32{}, 73 WindowFns: []execinfrapb.WindowerSpec_WindowFn{{ 74 Func: execinfrapb.WindowerSpec_Func{AggregateFunc: &aggSpec}, 75 ArgsIdxs: []uint32{0}, 76 Ordering: execinfrapb.Ordering{Columns: []execinfrapb.Ordering_Column{{ColIdx: 0}}}, 77 OutputColIdx: 1, 78 FilterColIdx: noFilterIdx, 79 Frame: &execinfrapb.WindowerSpec_Frame{ 80 Mode: execinfrapb.WindowerSpec_Frame_ROWS, 81 Bounds: execinfrapb.WindowerSpec_Frame_Bounds{ 82 Start: execinfrapb.WindowerSpec_Frame_Bound{ 83 BoundType: execinfrapb.WindowerSpec_Frame_OFFSET_PRECEDING, 84 IntOffset: 100, 85 }, 86 }, 87 }, 88 }}, 89 } 90 output := distsqlutils.NewRowBuffer( 91 sqlbase.OneIntCol, nil, distsqlutils.RowBufferArgs{}, 92 ) 93 94 d, err := newWindower(flowCtx, 0 /* processorID */, &spec, input, post, output) 95 if err != nil { 96 t.Fatal(err) 97 } 98 d.Run(ctx) 99 for { 100 row, meta := output.Next() 101 if row != nil { 102 t.Fatalf("unexpectedly received row %+v", row) 103 } 104 if meta == nil { 105 t.Fatalf("unexpectedly didn't receive an OOM error") 106 } 107 if meta.Err != nil { 108 if !strings.Contains(meta.Err.Error(), "memory budget exceeded") { 109 t.Fatalf("unexpectedly received an error other than OOM") 110 } 111 break 112 } 113 } 114 } 115 116 type windowTestSpec struct { 117 // The column indices of PARTITION BY clause. 118 partitionBy []uint32 119 // Window function to be computed. 120 windowFn windowFnTestSpec 121 } 122 123 type windowFnTestSpec struct { 124 funcName string 125 argsIdxs []uint32 126 columnOrdering sqlbase.ColumnOrdering 127 } 128 129 func windows(windowTestSpecs []windowTestSpec) ([]execinfrapb.WindowerSpec, error) { 130 windows := make([]execinfrapb.WindowerSpec, len(windowTestSpecs)) 131 for i, spec := range windowTestSpecs { 132 windows[i].PartitionBy = spec.partitionBy 133 windows[i].WindowFns = make([]execinfrapb.WindowerSpec_WindowFn, 1) 134 windowFnSpec := execinfrapb.WindowerSpec_WindowFn{} 135 fnSpec, err := CreateWindowerSpecFunc(spec.windowFn.funcName) 136 if err != nil { 137 return nil, err 138 } 139 windowFnSpec.Func = fnSpec 140 windowFnSpec.ArgsIdxs = spec.windowFn.argsIdxs 141 if spec.windowFn.columnOrdering != nil { 142 ordCols := make([]execinfrapb.Ordering_Column, 0, len(spec.windowFn.columnOrdering)) 143 for _, column := range spec.windowFn.columnOrdering { 144 ordCols = append(ordCols, execinfrapb.Ordering_Column{ 145 ColIdx: uint32(column.ColIdx), 146 // We need this -1 because encoding.Direction has extra value "_" 147 // as zeroth "entry" which its proto equivalent doesn't have. 148 Direction: execinfrapb.Ordering_Column_Direction(column.Direction - 1), 149 }) 150 } 151 windowFnSpec.Ordering = execinfrapb.Ordering{Columns: ordCols} 152 } 153 windowFnSpec.FilterColIdx = noFilterIdx 154 windows[i].WindowFns[0] = windowFnSpec 155 } 156 return windows, nil 157 } 158 159 func BenchmarkWindower(b *testing.B) { 160 const numCols = 3 161 const numRows = 100000 162 163 specs, err := windows([]windowTestSpec{ 164 { // sum(@1) OVER () 165 partitionBy: []uint32{}, 166 windowFn: windowFnTestSpec{ 167 funcName: "SUM", 168 argsIdxs: []uint32{0}, 169 }, 170 }, 171 { // sum(@1) OVER (ORDER BY @3) 172 windowFn: windowFnTestSpec{ 173 funcName: "SUM", 174 argsIdxs: []uint32{0}, 175 columnOrdering: sqlbase.ColumnOrdering{{ColIdx: 2, Direction: encoding.Ascending}}, 176 }, 177 }, 178 { // sum(@1) OVER (PARTITION BY @2) 179 partitionBy: []uint32{1}, 180 windowFn: windowFnTestSpec{ 181 funcName: "SUM", 182 argsIdxs: []uint32{0}, 183 }, 184 }, 185 { // sum(@1) OVER (PARTITION BY @2 ORDER BY @3) 186 partitionBy: []uint32{1}, 187 windowFn: windowFnTestSpec{ 188 funcName: "SUM", 189 argsIdxs: []uint32{0}, 190 columnOrdering: sqlbase.ColumnOrdering{{ColIdx: 2, Direction: encoding.Ascending}}, 191 }, 192 }, 193 }) 194 if err != nil { 195 b.Fatal(err) 196 } 197 198 ctx := context.Background() 199 st := cluster.MakeTestingClusterSettings() 200 evalCtx := tree.MakeTestingEvalContext(st) 201 defer evalCtx.Stop(ctx) 202 diskMonitor := execinfra.NewTestDiskMonitor(ctx, st) 203 defer diskMonitor.Stop(ctx) 204 205 flowCtx := &execinfra.FlowCtx{ 206 EvalCtx: &evalCtx, 207 Cfg: &execinfra.ServerConfig{ 208 Settings: st, 209 DiskMonitor: diskMonitor, 210 }, 211 } 212 213 rowsGenerators := []func(int, int) sqlbase.EncDatumRows{ 214 sqlbase.MakeIntRows, 215 func(numRows, numCols int) sqlbase.EncDatumRows { 216 return sqlbase.MakeRepeatedIntRows(numRows/100, numRows, numCols) 217 }, 218 } 219 skipRepeatedSpecs := map[int]bool{0: true, 1: true} 220 221 for j, rowsGenerator := range rowsGenerators { 222 for i, spec := range specs { 223 if skipRepeatedSpecs[i] && j == 1 { 224 continue 225 } 226 runName := fmt.Sprintf("%s() OVER (", spec.WindowFns[0].Func.AggregateFunc.String()) 227 if len(spec.PartitionBy) > 0 { 228 runName = runName + "PARTITION BY" 229 if j == 0 { 230 runName = runName + "/* SINGLE ROW PARTITIONS */" 231 } else { 232 runName = runName + "/* MULTIPLE ROWS PARTITIONS */" 233 } 234 } 235 if len(spec.PartitionBy) > 0 && spec.WindowFns[0].Ordering.Columns != nil { 236 runName = runName + " " 237 } 238 if spec.WindowFns[0].Ordering.Columns != nil { 239 runName = runName + "ORDER BY" 240 } 241 runName = runName + ")" 242 spec.WindowFns[0].OutputColIdx = 3 243 244 b.Run(runName, func(b *testing.B) { 245 post := &execinfrapb.PostProcessSpec{} 246 disposer := &rowDisposer{} 247 input := execinfra.NewRepeatableRowSource(sqlbase.ThreeIntCols, rowsGenerator(numRows, numCols)) 248 249 b.SetBytes(int64(8 * numRows * numCols)) 250 b.ResetTimer() 251 for i := 0; i < b.N; i++ { 252 d, err := newWindower(flowCtx, 0 /* processorID */, &spec, input, post, disposer) 253 if err != nil { 254 b.Fatal(err) 255 } 256 d.Run(context.Background()) 257 input.Reset() 258 } 259 b.StopTimer() 260 }) 261 } 262 } 263 }