Merge lp:~mmcm/akiban-server/lookahead-quantum-index-scan into lp:~akiban-technologies/akiban-server/trunk

Proposed by Mike McMahon
Status: Superseded
Proposed branch: lp:~mmcm/akiban-server/lookahead-quantum-index-scan
Merge into: lp:~akiban-technologies/akiban-server/trunk
Prerequisite: lp:~mmcm/akiban-server/map-query-bindings
Diff against target: 1229 lines (+641/-49)
23 files modified
src/main/java/com/akiban/qp/operator/API.java (+13/-2)
src/main/java/com/akiban/qp/operator/IndexScan_Default.java (+220/-10)
src/main/java/com/akiban/qp/operator/Map_NestedLoops.java (+14/-4)
src/main/java/com/akiban/server/explain/Label.java (+1/-0)
src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java (+7/-3)
src/main/java/com/akiban/sql/optimizer/rule/PipelineConfiguration.java (+67/-0)
src/main/java/com/akiban/sql/optimizer/rule/SchemaRulesContext.java (+11/-0)
src/main/java/com/akiban/sql/server/ServerOperatorCompiler.java (+1/-0)
src/main/java/com/akiban/sql/server/ServerSession.java (+4/-0)
src/main/java/com/akiban/sql/server/ServerSessionBase.java (+10/-0)
src/main/java/com/akiban/util/SparseArray.java (+2/-1)
src/main/resources/com/akiban/server/service/config/configuration-defaults.properties (+1/-0)
src/test/java/com/akiban/server/test/ApiTestBase.java (+4/-0)
src/test/java/com/akiban/server/test/costmodel/MapCT.java (+2/-1)
src/test/java/com/akiban/server/test/it/qp/AncestorLookup_NestedIT.java (+8/-8)
src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java (+8/-8)
src/test/java/com/akiban/server/test/it/qp/IndexScanLookaheadIT.java (+227/-0)
src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsIT.java (+10/-10)
src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsPipelineIT.java (+26/-0)
src/test/java/com/akiban/server/test/it/qp/Sort_InsertionLimitedIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/qp/UnionAll_DefaultIT.java (+1/-1)
src/test/java/com/akiban/sql/optimizer/OperatorCompilerTest.java (+2/-0)
src/test/java/com/akiban/sql/optimizer/rule/RulesTestContext.java (+1/-0)
To merge this branch: bzr merge lp:~mmcm/akiban-server/lookahead-quantum-index-scan
Reviewer Review Type Date Requested Status
Akiban Technologies Pending
Review via email: mp+174297@code.launchpad.net

This proposal has been superseded by a proposal from 2013-07-13.

Description of the change

Pipelining option for IndexScan_Default.

When quantum is set > 1, open() tries to keep this many Cursors in play. It does this by looking ahead in the bindings stream and opening new cursors for those that match the depth at which it is being opened. It queues these bindings (whether a cursor was opened or not) so that it can later honor nextBindings().

Most of the trickiness is in implementing the cursor lifecycle. For instance, although all these cursors are open ahead of where downstream is, and one of them gets associated when moving to its bindings, the IS cursor itself is not yet active until open().

To post a comment you must log in.
Revision history for this message
Nathan Williams (nwilliams) wrote :

The static Integer and config lookup in the cursor() call is a little unfortunate. What about moving them to named methods on the QueryContext, which could then be initialized more explicitly?

Otherwise looks pretty good.

2732. By Mike McMahon

Merge from origin.

2733. By Mike McMahon

Update test.

2734. By Mike McMahon

Merge from origin.

2735. By Mike McMahon

Use new configuration technique.

2736. By Mike McMahon

Javadoc.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/main/java/com/akiban/qp/operator/API.java'
2--- src/main/java/com/akiban/qp/operator/API.java 2013-07-10 18:42:14 +0000
3+++ src/main/java/com/akiban/qp/operator/API.java 2013-07-13 21:10:31 +0000
4@@ -385,7 +385,16 @@
5 Ordering ordering,
6 IndexScanSelector indexScanSelector)
7 {
8- return new IndexScan_Default(indexType, indexKeyRange, ordering, indexScanSelector, USE_PVALUES);
9+ return indexScan_Default(indexType, indexKeyRange, ordering, indexScanSelector, 1);
10+ }
11+
12+ public static Operator indexScan_Default(IndexRowType indexType,
13+ IndexKeyRange indexKeyRange,
14+ Ordering ordering,
15+ IndexScanSelector indexScanSelector,
16+ int lookaheadQuantum)
17+ {
18+ return new IndexScan_Default(indexType, indexKeyRange, ordering, indexScanSelector, lookaheadQuantum, USE_PVALUES);
19 }
20
21 // Select
22@@ -497,9 +506,11 @@
23 public static Operator map_NestedLoops(Operator outerInput,
24 Operator innerInput,
25 int inputBindingPosition,
26+ boolean pipeline,
27 int depth)
28 {
29- return new Map_NestedLoops(outerInput, innerInput, inputBindingPosition, depth);
30+ return new Map_NestedLoops(outerInput, innerInput, inputBindingPosition,
31+ pipeline, depth);
32 }
33
34 // IfEmpty
35
36=== modified file 'src/main/java/com/akiban/qp/operator/IndexScan_Default.java'
37--- src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-09 17:26:33 +0000
38+++ src/main/java/com/akiban/qp/operator/IndexScan_Default.java 2013-07-13 21:10:31 +0000
39@@ -31,7 +31,9 @@
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43+import java.util.ArrayDeque;
44 import java.util.List;
45+import java.util.Queue;
46
47 /**
48
49@@ -47,20 +49,19 @@
50
51 <li><b>IndexRowType indexType:</b> The index's type.
52
53- <li><b>boolean reverse:</b> Indicates whether keys should be visited
54- in ascending order (reverse = false) or descending order (reverse =
55- true).
56-
57 <li><b>IndexKeyRange indexKeyRange:</b> Describes the range of keys
58 to be visited. The values specified by the indexKeyRange should
59 restrict one or more of the leading fields of the index. If null,
60 then the entire index will be scanned.
61
62- <li><b>UserTableRowType innerJoinUntilRowType</b>: On a table index,
63- this must be the UserTableRowType of the Index's table (but it's
64- ignored). On a group index, this is the table until which the group
65- index is interpreted with INNER JOIN semantics. The specified row
66- type must be within the group index's branch segment.
67+ <li><b>Ordering ordering:</b> Indicates whether keys should be visited
68+ in ascending order or descending order.
69+
70+ <li><b>IndexScanSelector scanSelector:</b> On a group index, specify which
71+ tables must be present for OUTER JOIN semantics.
72+
73+ <li><b>int lookaheadQuantum:</b> Number of cursors to try to keep open by looking
74+ ahead in bindings stream.
75
76 </ul>
77
78@@ -165,7 +166,12 @@
79 @Override
80 protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
81 {
82- return new Execution(context, bindingsCursor);
83+ if (lookaheadQuantum <= 1) {
84+ return new Execution(context, bindingsCursor);
85+ }
86+ else {
87+ return new LookaheadExecution(context, bindingsCursor, lookaheadQuantum);
88+ }
89 }
90
91 // IndexScan_Default interface
92@@ -174,6 +180,7 @@
93 IndexKeyRange indexKeyRange,
94 API.Ordering ordering,
95 IndexScanSelector scanSelector,
96+ int lookaheadQuantum,
97 boolean usePValues)
98 {
99 ArgumentValidation.notNull("indexType", indexType);
100@@ -182,6 +189,7 @@
101 this.ordering = ordering;
102 this.indexKeyRange = indexKeyRange;
103 this.scanSelector = scanSelector;
104+ this.lookaheadQuantum = lookaheadQuantum;
105 this.usePValues = usePValues;
106 }
107
108@@ -198,6 +206,7 @@
109 private final API.Ordering ordering;
110 private final IndexKeyRange indexKeyRange;
111 private final IndexScanSelector scanSelector;
112+ private final int lookaheadQuantum;
113 private final boolean usePValues;
114
115 @Override
116@@ -372,4 +381,205 @@
117
118 private final RowCursor cursor;
119 }
120+
121+ static final class BindingsAndCursor {
122+ QueryBindings bindings;
123+ RowCursor cursor;
124+
125+ BindingsAndCursor(QueryBindings bindings, RowCursor cursor) {
126+ this.bindings = bindings;
127+ this.cursor = cursor;
128+ }
129+ }
130+
131+ private class LookaheadExecution extends OperatorCursor
132+ {
133+ // Cursor interface
134+
135+ @Override
136+ public void open() {
137+ TAP_OPEN.in();
138+ try {
139+ CursorLifecycle.checkIdle(this);
140+ if (currentCursor != null) {
141+ currentCursor.open();
142+ }
143+ else if (pendingCursor != null) {
144+ currentCursor = pendingCursor;
145+ pendingCursor = null;
146+ }
147+ else {
148+ // At the very beginning, the pipeline isn't started.
149+ currentCursor = openACursor(currentBindings);
150+ }
151+ while (!cursorPool.isEmpty() && !bindingsExhausted) {
152+ QueryBindings bindings = bindingsCursor.nextBindings();
153+ if (bindings == null) {
154+ bindingsExhausted = true;
155+ break;
156+ }
157+ RowCursor cursor = null;
158+ if (bindings.getDepth() == currentBindings.getDepth()) {
159+ cursor = openACursor(bindings);
160+ LOG.debug("IndexScan: lookahead {}", bindings);
161+ }
162+ pendingBindings.add(new BindingsAndCursor(bindings, cursor));
163+ }
164+ } finally {
165+ TAP_OPEN.out();
166+ }
167+ }
168+
169+ @Override
170+ public Row next() {
171+ if (TAP_NEXT_ENABLED) {
172+ TAP_NEXT.in();
173+ }
174+ try {
175+ checkQueryCancelation();
176+ Row row = currentCursor.next();
177+ if (row == null) {
178+ currentCursor.close();
179+ }
180+ if (LOG_EXECUTION) {
181+ LOG.debug("IndexScan: yield {}", row);
182+ }
183+ return row;
184+ } finally {
185+ if (TAP_NEXT_ENABLED) {
186+ TAP_NEXT.out();
187+ }
188+ }
189+ }
190+
191+ @Override
192+ public void jump(Row row, ColumnSelector columnSelector) {
193+ currentCursor.jump(row, columnSelector);
194+ }
195+
196+ @Override
197+ public void close() {
198+ if (currentCursor != null) {
199+ currentCursor.close();
200+ }
201+ }
202+
203+ @Override
204+ public void destroy() {
205+ CursorLifecycle.checkIdleOrActive(this);
206+ if (currentCursor != null) {
207+ currentCursor.destroy();
208+ currentCursor = null;
209+ }
210+ if (pendingCursor != null) {
211+ pendingCursor.destroy();
212+ pendingCursor = null;
213+ }
214+ recyclePending();
215+ while (true) {
216+ RowCursor cursor = cursorPool.poll();
217+ if (cursor == null) break;
218+ cursor.destroy();
219+ }
220+ destroyed = true;
221+ }
222+
223+ @Override
224+ public boolean isIdle() {
225+ return (currentCursor != null) ? currentCursor.isIdle() : !destroyed;
226+ }
227+
228+ @Override
229+ public boolean isActive() {
230+ return ((currentCursor != null) && currentCursor.isActive());
231+ }
232+
233+ @Override
234+ public boolean isDestroyed() {
235+ return destroyed;
236+ }
237+
238+ @Override
239+ public void openBindings() {
240+ recyclePending();
241+ bindingsCursor.openBindings();
242+ bindingsExhausted = false;
243+ currentCursor = pendingCursor = null;
244+ }
245+
246+ @Override
247+ public QueryBindings nextBindings() {
248+ if (currentCursor != null) {
249+ cursorPool.add(currentCursor);
250+ currentCursor = null;
251+ }
252+ if (pendingCursor != null) {
253+ pendingCursor.close(); // Abandoning lookahead.
254+ cursorPool.add(pendingCursor);
255+ pendingCursor = null;
256+ }
257+ BindingsAndCursor bandc = pendingBindings.poll();
258+ if (bandc != null) {
259+ currentBindings = bandc.bindings;
260+ pendingCursor = bandc.cursor;
261+ return currentBindings;
262+ }
263+ currentBindings = bindingsCursor.nextBindings();
264+ if (currentBindings == null) {
265+ bindingsExhausted = true;
266+ }
267+ return currentBindings;
268+ }
269+
270+ @Override
271+ public void closeBindings() {
272+ bindingsCursor.closeBindings();
273+ recyclePending();
274+ }
275+
276+ // LookaheadExecution interface
277+
278+ LookaheadExecution(QueryContext context, QueryBindingsCursor bindingsCursor,
279+ int quantum) {
280+ super(context);
281+ this.bindingsCursor = bindingsCursor;
282+ this.pendingBindings = new ArrayDeque<>(quantum+1);
283+ this.cursorPool = new ArrayDeque<>(quantum);
284+ UserTable table = (UserTable)index.rootMostTable();
285+ StoreAdapter adapter = adapter(table);
286+ for (int i = 0; i < quantum; i++) {
287+ RowCursor cursor = adapter.newIndexCursor(context, index, indexKeyRange, ordering, scanSelector, usePValues);
288+ cursorPool.add(cursor);
289+ }
290+ }
291+
292+ // For use by this class
293+
294+ private void recyclePending() {
295+ while (true) {
296+ BindingsAndCursor bandc = pendingBindings.poll();
297+ if (bandc == null) break;
298+ if (bandc.cursor != null) {
299+ bandc.cursor.close();
300+ cursorPool.add(bandc.cursor);
301+ }
302+ }
303+ }
304+
305+ private RowCursor openACursor(QueryBindings bindings) {
306+ RowCursor cursor = cursorPool.remove();
307+ ((BindingsAwareCursor)cursor).rebind(bindings);
308+ cursor.open();
309+ return cursor;
310+ }
311+
312+ // Object state
313+
314+ private final QueryBindingsCursor bindingsCursor;
315+ private final Queue<BindingsAndCursor> pendingBindings;
316+ private final Queue<RowCursor> cursorPool;
317+ private QueryBindings currentBindings;
318+ private RowCursor pendingCursor, currentCursor;
319+ private boolean bindingsExhausted, destroyed;
320+ }
321 }
322
323=== modified file 'src/main/java/com/akiban/qp/operator/Map_NestedLoops.java'
324--- src/main/java/com/akiban/qp/operator/Map_NestedLoops.java 2013-07-10 21:30:34 +0000
325+++ src/main/java/com/akiban/qp/operator/Map_NestedLoops.java 2013-07-13 21:10:31 +0000
326@@ -51,6 +51,8 @@
327
328 <li><b>int inputBindingPosition:</b> Position of inner loop row in query context.
329
330+ <li><b>boolean pipeline:</b> Whether to use bracketing cursors instead of rebinding.
331+
332 <li><b>int depth:</b> Number of nested Maps, including this one.
333
334 </ul>
335@@ -90,7 +92,7 @@
336 @Override
337 protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
338 {
339- if (false)
340+ if (!pipeline)
341 return new Execution(context, bindingsCursor); // Old-style
342 else {
343 Cursor outerCursor = outerInputOperator.cursor(context, bindingsCursor);
344@@ -127,6 +129,7 @@
345 public Map_NestedLoops(Operator outerInputOperator,
346 Operator innerInputOperator,
347 int inputBindingPosition,
348+ boolean pipeline,
349 int depth)
350 {
351 ArgumentValidation.notNull("outerInputOperator", outerInputOperator);
352@@ -136,6 +139,7 @@
353 this.outerInputOperator = outerInputOperator;
354 this.innerInputOperator = innerInputOperator;
355 this.inputBindingPosition = inputBindingPosition;
356+ this.pipeline = pipeline;
357 this.depth = depth;
358 }
359
360@@ -150,12 +154,14 @@
361 private final Operator outerInputOperator;
362 private final Operator innerInputOperator;
363 private final int inputBindingPosition, depth;
364+ private final boolean pipeline;
365
366 @Override
367 public CompoundExplainer getExplainer(ExplainContext context)
368 {
369 CompoundExplainer ex = new NestedLoopsExplainer(getName(), innerInputOperator, outerInputOperator, null, null, context);
370 ex.addAttribute(Label.BINDING_POSITION, PrimitiveExplainer.getInstance(inputBindingPosition));
371+ ex.addAttribute(Label.PIPELINE, PrimitiveExplainer.getInstance(pipeline));
372 ex.addAttribute(Label.DEPTH, PrimitiveExplainer.getInstance(depth));
373 if (context.hasExtraInfo(this))
374 ex.get().putAll(context.getExtraInfo(this).get());
375@@ -346,9 +352,13 @@
376 pendingBindings = null;
377 return bindings;
378 }
379- bindings = input.nextBindings();
380- assert ((bindings == null) || (bindings.getDepth() < depth));
381- return bindings;
382+ while (true) {
383+ // Skip over any that we would elide.
384+ bindings = input.nextBindings();
385+ if ((bindings == null) || (bindings.getDepth() < depth))
386+ return bindings;
387+ assert (bindings.getDepth() == depth);
388+ }
389 }
390
391 @Override
392
393=== modified file 'src/main/java/com/akiban/server/explain/Label.java'
394--- src/main/java/com/akiban/server/explain/Label.java 2013-07-10 18:42:14 +0000
395+++ src/main/java/com/akiban/server/explain/Label.java 2013-07-13 21:10:31 +0000
396@@ -48,6 +48,7 @@
397 INFIX_REPRESENTATION(Category.DESCRIPTION),
398 ASSOCIATIVE(Category.DESCRIPTION),
399 INDEX(Category.DESCRIPTION),
400+ PIPELINE(Category.DESCRIPTION),
401 DEPTH(Category.DESCRIPTION),
402
403 // IDENTIFIER
404
405=== modified file 'src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java'
406--- src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-10 18:42:14 +0000
407+++ src/main/java/com/akiban/sql/optimizer/rule/OperatorAssembler.java 2013-07-13 21:10:31 +0000
408@@ -1182,7 +1182,8 @@
409 stream.operator = API.indexScan_Default(indexRowType,
410 assembleSpatialIndexKeyRange(indexScan, null),
411 API.ordering(), // TODO: what ordering?
412- selector);
413+ selector,
414+ rulesContext.getPipelineConfiguration().getIndexScanLookaheadQuantum());
415 indexRowType = indexRowType.physicalRowType();
416 stream.rowType = indexRowType;
417 }
418@@ -1190,7 +1191,8 @@
419 stream.operator = API.indexScan_Default(indexRowType,
420 assembleIndexKeyRange(indexScan, null),
421 assembleIndexOrdering(indexScan, indexRowType),
422- selector);
423+ selector,
424+ rulesContext.getPipelineConfiguration().getIndexScanLookaheadQuantum());
425 stream.rowType = indexRowType;
426 }
427 else {
428@@ -1221,7 +1223,8 @@
429 Operator scan = API.indexScan_Default(indexRowType,
430 assembleIndexKeyRange(indexScan, null, rangeSegment),
431 assembleIndexOrdering(indexScan, indexRowType),
432- selector);
433+ selector,
434+ rulesContext.getPipelineConfiguration().getIndexScanLookaheadQuantum());
435 if (stream.operator == null) {
436 stream.operator = scan;
437 stream.rowType = indexRowType;
438@@ -1529,6 +1532,7 @@
439 stream.operator = API.map_NestedLoops(ostream.operator,
440 stream.operator,
441 currentBindingPosition(),
442+ rulesContext.getPipelineConfiguration().isMapEnabled(),
443 nestedBindingsDepth);
444 nestedBindingsDepth--;
445 popBoundRow();
446
447=== added file 'src/main/java/com/akiban/sql/optimizer/rule/PipelineConfiguration.java'
448--- src/main/java/com/akiban/sql/optimizer/rule/PipelineConfiguration.java 1970-01-01 00:00:00 +0000
449+++ src/main/java/com/akiban/sql/optimizer/rule/PipelineConfiguration.java 2013-07-13 21:10:31 +0000
450@@ -0,0 +1,67 @@
451+/**
452+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
453+ *
454+ * This program is free software: you can redistribute it and/or modify
455+ * it under the terms of the GNU Affero General Public License as published by
456+ * the Free Software Foundation, either version 3 of the License, or
457+ * (at your option) any later version.
458+ *
459+ * This program is distributed in the hope that it will be useful,
460+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
461+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
462+ * GNU Affero General Public License for more details.
463+ *
464+ * You should have received a copy of the GNU Affero General Public License
465+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
466+ */
467+
468+package com.akiban.sql.optimizer.rule;
469+
470+import java.util.Properties;
471+
472+public class PipelineConfiguration
473+{
474+ private boolean mapEnabled = false;
475+ private int indexScanLookaheadQuantum = 1;
476+ private int groupLookupLookaheadQuantum = 1;
477+ private boolean unionAllOpenBoth = false;
478+
479+ public PipelineConfiguration() {
480+ }
481+
482+ public PipelineConfiguration(Properties properties) {
483+ load(properties);
484+ }
485+
486+ public boolean isMapEnabled() {
487+ return mapEnabled;
488+ }
489+
490+ public int getIndexScanLookaheadQuantum() {
491+ return indexScanLookaheadQuantum;
492+ }
493+
494+ public int getGroupLookupLookaheadQuantum() {
495+ return groupLookupLookaheadQuantum;
496+ }
497+
498+ public boolean isUnionAllOpenBoth() {
499+ return unionAllOpenBoth;
500+ }
501+
502+ public void load(Properties properties) {
503+ for (String prop : properties.stringPropertyNames()) {
504+ String val = properties.getProperty(prop);
505+ if ("map.enabled".equals(prop))
506+ mapEnabled = Boolean.parseBoolean(val);
507+ else if ("indexScan.lookaheadQuantum".equals(prop))
508+ indexScanLookaheadQuantum = Integer.parseInt(val);
509+ else if ("groupLookup.lookaheadQuantum".equals(prop))
510+ groupLookupLookaheadQuantum = Integer.parseInt(val);
511+ else if ("unionAll.openBoth".equals(prop))
512+ unionAllOpenBoth = Boolean.parseBoolean(val);
513+ else
514+ throw new IllegalArgumentException("Unknown property " + prop);
515+ }
516+ }
517+}
518
519=== modified file 'src/main/java/com/akiban/sql/optimizer/rule/SchemaRulesContext.java'
520--- src/main/java/com/akiban/sql/optimizer/rule/SchemaRulesContext.java 2013-03-22 20:05:57 +0000
521+++ src/main/java/com/akiban/sql/optimizer/rule/SchemaRulesContext.java 2013-07-13 21:10:31 +0000
522@@ -36,6 +36,8 @@
523 private FunctionsRegistry functionsRegistry;
524 private CostEstimator costEstimator;
525 private T3RegistryService t3Registry;
526+ private PipelineConfiguration pipelineConfiguration;
527+
528 protected SchemaRulesContext() {
529 }
530
531@@ -55,12 +57,17 @@
532 this.costEstimator = costEstimator;
533 }
534
535+ protected void initPipelineConfiguration(PipelineConfiguration pipelineConfiguration) {
536+ this.pipelineConfiguration = pipelineConfiguration;
537+ }
538+
539 @Override
540 protected void initDone() {
541 super.initDone();
542 assert (schema != null) : "initSchema() not called";
543 assert (functionsRegistry != null) : "initFunctionsRegistry() not called";
544 assert (costEstimator != null) : "initCostEstimator() not called";
545+ assert (pipelineConfiguration != null) : "initPipelineConfiguration() not called";
546 }
547
548 public Schema getSchema() {
549@@ -89,4 +96,8 @@
550
551 public abstract String getDefaultSchemaName();
552
553+ public PipelineConfiguration getPipelineConfiguration() {
554+ return pipelineConfiguration;
555+ }
556+
557 }
558
559=== modified file 'src/main/java/com/akiban/sql/server/ServerOperatorCompiler.java'
560--- src/main/java/com/akiban/sql/server/ServerOperatorCompiler.java 2013-06-11 16:30:17 +0000
561+++ src/main/java/com/akiban/sql/server/ServerOperatorCompiler.java 2013-07-13 21:10:31 +0000
562@@ -36,6 +36,7 @@
563 initParser(server.getParser());
564 initFunctionsRegistry(server.functionsRegistry());
565 initCostEstimator(server.costEstimator(this, keyCreator), usePValues);
566+ initPipelineConfiguration(server.getPipelineConfiguration());
567 if (usePValues)
568 initT3Registry(server.t3RegistryService());
569
570
571=== modified file 'src/main/java/com/akiban/sql/server/ServerSession.java'
572--- src/main/java/com/akiban/sql/server/ServerSession.java 2013-06-11 16:32:59 +0000
573+++ src/main/java/com/akiban/sql/server/ServerSession.java 2013-07-13 21:10:31 +0000
574@@ -23,6 +23,7 @@
575 import com.akiban.sql.parser.SQLParser;
576
577 import com.akiban.sql.optimizer.AISBinderContext;
578+import com.akiban.sql.optimizer.rule.PipelineConfiguration;
579 import com.akiban.sql.optimizer.rule.cost.CostEstimator;
580
581 import com.akiban.ais.model.AkibanInformationSchema;
582@@ -165,4 +166,7 @@
583
584 /** Check access to given schema */
585 public boolean isSchemaAccessible(String schemaName);
586+
587+ /** Get the pipeline configuration. */
588+ public PipelineConfiguration getPipelineConfiguration();
589 }
590
591=== modified file 'src/main/java/com/akiban/sql/server/ServerSessionBase.java'
592--- src/main/java/com/akiban/sql/server/ServerSessionBase.java 2013-06-12 21:51:17 +0000
593+++ src/main/java/com/akiban/sql/server/ServerSessionBase.java 2013-07-13 21:10:31 +0000
594@@ -40,6 +40,7 @@
595 import com.akiban.server.service.tree.KeyCreator;
596 import com.akiban.server.t3expressions.T3RegistryService;
597 import com.akiban.sql.optimizer.AISBinderContext;
598+import com.akiban.sql.optimizer.rule.PipelineConfiguration;
599 import com.akiban.sql.optimizer.rule.cost.CostEstimator;
600
601 import java.util.*;
602@@ -47,10 +48,12 @@
603 public abstract class ServerSessionBase extends AISBinderContext implements ServerSession
604 {
605 public static final String COMPILER_PROPERTIES_PREFIX = "optimizer.";
606+ public static final String PIPELINE_PROPERTIES_PREFIX = "akserver.pipeline.";
607
608 protected final ServerServiceRequirements reqs;
609 protected Properties compilerProperties;
610 protected Map<String,Object> attributes = new HashMap<>();
611+ protected PipelineConfiguration pipelineConfiguration;
612
613 protected Session session;
614 protected Map<StoreAdapter.AdapterType, StoreAdapter> adapters =
615@@ -401,4 +404,11 @@
616 return reqs.securityService().isAccessible(session, schemaName);
617 }
618
619+ @Override
620+ public PipelineConfiguration getPipelineConfiguration() {
621+ if (pipelineConfiguration == null)
622+ pipelineConfiguration = new PipelineConfiguration(reqs.config().deriveProperties(PIPELINE_PROPERTIES_PREFIX));
623+ return pipelineConfiguration;
624+ }
625+
626 }
627
628=== modified file 'src/main/java/com/akiban/util/SparseArray.java'
629--- src/main/java/com/akiban/util/SparseArray.java 2013-07-10 17:31:42 +0000
630+++ src/main/java/com/akiban/util/SparseArray.java 2013-07-13 21:10:31 +0000
631@@ -118,13 +118,14 @@
632
633 public StringBuilder describeElements(StringBuilder sb) {
634 sb.append('[');
635+ int ilen = sb.length();
636
637 int size = definedElements.size();
638 for (int i = 0; i < size; ++i) {
639 if (isDefined(i))
640 sb.append(internalGet(i)).append(", ");
641 }
642- if (sb.length() > 1) // sb is not just the initial '['
643+ if (sb.length() > ilen) // sb is not just the initial '['
644 sb.setLength(sb.length() - 2); // snip off the trailing ", "
645 sb.append(']');
646
647
648=== modified file 'src/main/resources/com/akiban/server/service/config/configuration-defaults.properties'
649--- src/main/resources/com/akiban/server/service/config/configuration-defaults.properties 2013-06-11 21:35:24 +0000
650+++ src/main/resources/com/akiban/server/service/config/configuration-defaults.properties 2013-07-13 21:10:31 +0000
651@@ -43,6 +43,7 @@
652 akserver.gc_monitor.interval=1000
653 akserver.gc_monitor.log_threshold_ms=100
654 akserver.write_lock_enabled=true
655+akserver.lookaheadQuantum.indexScan=1
656
657 persistit.buffersize=16384
658
659
660=== modified file 'src/test/java/com/akiban/server/test/ApiTestBase.java'
661--- src/test/java/com/akiban/server/test/ApiTestBase.java 2013-07-03 15:32:40 +0000
662+++ src/test/java/com/akiban/server/test/ApiTestBase.java 2013-07-13 21:10:31 +0000
663@@ -1353,6 +1353,10 @@
664 return true;
665 }
666
667+ protected boolean pipelineMap() {
668+ return false;
669+ }
670+
671 protected DDLFunctions ddlForAlter() {
672 return ddl();
673 }
674
675=== modified file 'src/test/java/com/akiban/server/test/costmodel/MapCT.java'
676--- src/test/java/com/akiban/server/test/costmodel/MapCT.java 2013-07-10 18:42:14 +0000
677+++ src/test/java/com/akiban/server/test/costmodel/MapCT.java 2013-07-13 21:10:31 +0000
678@@ -83,7 +83,8 @@
679 TimeOperator timeSetupOuter = new TimeOperator(setupOuter);
680 Operator setupInner = limit_Default(groupScan_Default(group), innerRows);
681 TimeOperator timeSetupInner = new TimeOperator(setupInner);
682- Operator plan = map_NestedLoops(timeSetupOuter, timeSetupInner, 0, 1);
683+ Operator plan = map_NestedLoops(timeSetupOuter, timeSetupInner,
684+ 0, pipelineMap(), 1);
685 long start = System.nanoTime();
686 for (int r = 0; r < runs; r++) {
687 Cursor cursor = cursor(plan, queryContext, queryBindings);
688
689=== modified file 'src/test/java/com/akiban/server/test/it/qp/AncestorLookup_NestedIT.java'
690--- src/test/java/com/akiban/server/test/it/qp/AncestorLookup_NestedIT.java 2013-07-10 21:30:34 +0000
691+++ src/test/java/com/akiban/server/test/it/qp/AncestorLookup_NestedIT.java 2013-07-13 21:10:31 +0000
692@@ -141,7 +141,7 @@
693 map_NestedLoops(
694 indexScan_Default(aValueIndexRowType),
695 ancestorLookup_Nested(rabc, aValueIndexRowType, Collections.singleton(aRowType), 0),
696- 0, 1);
697+ 0, pipelineMap(), 1);
698 Cursor cursor = cursor(plan, queryContext, queryBindings);
699 RowBase[] expected = new RowBase[]{
700 row(aRowType, 13L, 1L, "a13"),
701@@ -159,7 +159,7 @@
702 map_NestedLoops(
703 indexScan_Default(aValueIndexRowType),
704 ancestorLookup_Nested(rabc, aValueIndexRowType, Arrays.asList(aRowType, rRowType), 0),
705- 0, 1);
706+ 0, pipelineMap(), 1);
707 Cursor cursor = cursor(plan, queryContext, queryBindings);
708 RowBase[] expected = new RowBase[]{
709 row(rRowType, 1L, "r1"),
710@@ -181,7 +181,7 @@
711 map_NestedLoops(
712 indexScan_Default(aValueIndexRowType),
713 ancestorLookup_Nested(rabc, aValueIndexRowType, Arrays.asList(rRowType, aRowType), 0),
714- 0, 1);
715+ 0, pipelineMap(), 1);
716 Cursor cursor = cursor(plan, queryContext, queryBindings);
717 RowBase[] expected = new RowBase[]{
718 row(rRowType, 1L, "r1"),
719@@ -204,9 +204,9 @@
720 map_NestedLoops(
721 indexScan_Default(aValueIndexRowType),
722 ancestorLookup_Nested(rabc, aValueIndexRowType, Arrays.asList(aRowType), 0),
723- 0, 1),
724+ 0, pipelineMap(), 1),
725 ancestorLookup_Nested(rabc, aRowType, Arrays.asList(rRowType), 1),
726- 1, 1);
727+ 1, pipelineMap(), 1);
728 Cursor cursor = cursor(plan, queryContext, queryBindings);
729 RowBase[] expected = new RowBase[]{
730 row(rRowType, 1L, "r1"),
731@@ -236,7 +236,7 @@
732 map_NestedLoops(
733 abIndexScan,
734 ancestorLookup_Nested(rabc, abIndexScan.rowType(), Collections.singleton(rRowType), 0),
735- 0, 1);
736+ 0, pipelineMap(), 1);
737 Cursor cursor = cursor(plan, queryContext, queryBindings);
738 RowBase[] expected = new RowBase[]{
739 row(rRowType, 1L, "r1"),
740@@ -272,7 +272,7 @@
741 map_NestedLoops(
742 abcIndexScan,
743 ancestorLookup_Nested(rabc, abcIndexScan.rowType(), Collections.singleton(rRowType), 0),
744- 0, 1);
745+ 0, pipelineMap(), 1);
746 Cursor cursor = cursor(plan, queryContext, queryBindings);
747 RowBase[] expected = new RowBase[]{
748 row(rRowType, 1L, "r1"),
749@@ -287,7 +287,7 @@
750 map_NestedLoops(
751 indexScan_Default(aValueIndexRowType),
752 ancestorLookup_Nested(rabc, aValueIndexRowType, Collections.singleton(aRowType), 0),
753- 0, 1);
754+ 0, pipelineMap(), 1);
755 CursorLifecycleTestCase testCase = new CursorLifecycleTestCase()
756 {
757 @Override
758
759=== modified file 'src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java'
760--- src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-10 21:30:34 +0000
761+++ src/test/java/com/akiban/server/test/it/qp/BranchLookup_NestedIT.java 2013-07-13 21:10:31 +0000
762@@ -154,7 +154,7 @@
763 map_NestedLoops(
764 indexScan_Default(aValueIndexRowType),
765 branchLookup_Nested(rabc, aValueIndexRowType, rRowType, InputPreservationOption.DISCARD_INPUT, 0),
766- 0, 1);
767+ 0, pipelineMap(), 1);
768 Cursor cursor = cursor(plan, queryContext, queryBindings);
769 RowBase[] expected = new RowBase[]{
770 // Each r row, and everything below it, is duplicated, because the A index refers to each r value twice.
771@@ -202,7 +202,7 @@
772 Collections.singleton(aRowType),
773 InputPreservationOption.DISCARD_INPUT),
774 branchLookup_Nested(rabc, aRowType, rRowType, InputPreservationOption.DISCARD_INPUT, 0),
775- 0, 1);
776+ 0, pipelineMap(), 1);
777 Cursor cursor = cursor(plan, queryContext, queryBindings);
778 RowBase[] expected = new RowBase[]{
779 // Each r row, and everything below it, is duplicated, because the A index refers to each r value twice.
780@@ -247,7 +247,7 @@
781 groupScan_Default(rabc),
782 Collections.singleton(aRowType)),
783 branchLookup_Nested(rabc, aRowType, bRowType, InputPreservationOption.DISCARD_INPUT, 0),
784- 0, 1);
785+ 0, pipelineMap(), 1);
786 Cursor cursor = cursor(plan, queryContext, queryBindings);
787 RowBase[] expected = new RowBase[]{
788 row(bRowType, 15L, 1L, "b15"),
789@@ -272,9 +272,9 @@
790 groupScan_Default(rabc),
791 Collections.singleton(aRowType)),
792 branchLookup_Nested(rabc, aRowType, bRowType, InputPreservationOption.DISCARD_INPUT, 0),
793- 0, 1),
794+ 0, pipelineMap(), 1),
795 branchLookup_Nested(rabc, bRowType, cRowType, InputPreservationOption.KEEP_INPUT, 1),
796- 1, 1);
797+ 1, pipelineMap(), 1);
798 Cursor cursor = cursor(plan, queryContext, queryBindings);
799 RowBase[] expected = new RowBase[]{
800 row(bRowType, 15L, 1L, "b15"),
801@@ -324,7 +324,7 @@
802 map_NestedLoops(
803 abIndexScan,
804 branchLookup_Nested(rabc, abIndexScan.rowType(), cRowType, InputPreservationOption.DISCARD_INPUT, 0),
805- 0, 1);
806+ 0, pipelineMap(), 1);
807 Cursor cursor = cursor(plan, queryContext, queryBindings);
808 RowBase[] expected = new RowBase[]{
809 row(cRowType, 17L, 1L, "c17"),
810@@ -342,7 +342,7 @@
811 groupScan_Default(rabc),
812 Collections.singleton(aRowType)),
813 branchLookup_Nested(rabc, aRowType, rRowType, aRowType, InputPreservationOption.DISCARD_INPUT, 0),
814- 0, 1);
815+ 0, pipelineMap(), 1);
816 Cursor cursor = cursor(plan, queryContext, queryBindings);
817 RowBase[] expected = new RowBase[]{
818 row(aRowType, 13L, 1L, "a13"),
819@@ -366,7 +366,7 @@
820 groupScan_Default(rabc),
821 Collections.singleton(aRowType)),
822 branchLookup_Nested(rabc, aRowType, rRowType, aRowType, InputPreservationOption.DISCARD_INPUT, 0),
823- 0, 1);
824+ 0, pipelineMap(), 1);
825 CursorLifecycleTestCase testCase = new CursorLifecycleTestCase()
826 {
827 @Override
828
829=== added file 'src/test/java/com/akiban/server/test/it/qp/IndexScanLookaheadIT.java'
830--- src/test/java/com/akiban/server/test/it/qp/IndexScanLookaheadIT.java 1970-01-01 00:00:00 +0000
831+++ src/test/java/com/akiban/server/test/it/qp/IndexScanLookaheadIT.java 2013-07-13 21:10:31 +0000
832@@ -0,0 +1,227 @@
833+/**
834+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
835+ *
836+ * This program is free software: you can redistribute it and/or modify
837+ * it under the terms of the GNU Affero General Public License as published by
838+ * the Free Software Foundation, either version 3 of the License, or
839+ * (at your option) any later version.
840+ *
841+ * This program is distributed in the hope that it will be useful,
842+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
843+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
844+ * GNU Affero General Public License for more details.
845+ *
846+ * You should have received a copy of the GNU Affero General Public License
847+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
848+ */
849+
850+package com.akiban.server.test.it.qp;
851+
852+import com.akiban.qp.expression.ExpressionRow;
853+import com.akiban.qp.expression.IndexBound;
854+import com.akiban.qp.expression.IndexKeyRange;
855+import com.akiban.qp.expression.RowBasedUnboundExpressions;
856+import com.akiban.qp.operator.Cursor;
857+import com.akiban.qp.operator.ExpressionGenerator;
858+import com.akiban.qp.operator.IndexScanSelector;
859+import com.akiban.qp.operator.Operator;
860+import com.akiban.qp.row.BindableRow;
861+import com.akiban.qp.row.Row;
862+import com.akiban.qp.rowtype.IndexRowType;
863+import com.akiban.qp.rowtype.RowType;
864+import com.akiban.server.api.dml.SetColumnSelector;
865+import com.akiban.server.api.dml.scan.NewRow;
866+import com.akiban.server.types.AkType;
867+import com.akiban.server.types3.mcompat.mtypes.MNumeric;
868+import com.akiban.server.types3.pvalue.PValue;
869+import com.akiban.server.types3.texpressions.TPreparedExpression;
870+import com.akiban.server.types3.texpressions.TPreparedLiteral;
871+
872+import static com.akiban.qp.operator.API.*;
873+import static com.akiban.server.test.ExpressionGenerators.*;
874+
875+import org.junit.Test;
876+import static junit.framework.Assert.assertEquals;
877+
878+import java.util.ArrayList;
879+import java.util.Arrays;
880+import java.util.Collection;
881+import java.util.HashMap;
882+import java.util.List;
883+import java.util.Map;
884+
885+public class IndexScanLookaheadIT extends OperatorITBase
886+{
887+ @Override
888+ protected boolean pipelineMap() {
889+ return true;
890+ }
891+
892+ protected int lookaheadQuantum() {
893+ return 4;
894+ }
895+
896+ @Override
897+ protected void setupPostCreateSchema() {
898+ super.setupPostCreateSchema();
899+ // Like super, but with a whole lot more cid=2 orders.
900+ db = new NewRow[]{createNewRow(customer, 1L, "xyz"),
901+ createNewRow(customer, 2L, "abc"),
902+ createNewRow(customer, 4L, "qqq"),
903+ createNewRow(order, 11L, 1L, "ori"),
904+ createNewRow(order, 12L, 1L, "david"),
905+ createNewRow(order, 21L, 2L, "tom"),
906+ createNewRow(order, 22L, 2L, "jack"),
907+ createNewRow(order, 23L, 2L, "dave"),
908+ createNewRow(order, 24L, 2L, "dave"),
909+ createNewRow(order, 25L, 2L, "dave"),
910+ createNewRow(order, 26L, 2L, "dave"),
911+ createNewRow(order, 27L, 2L, "dave"),
912+ createNewRow(order, 28L, 2L, "dave"),
913+ createNewRow(order, 29L, 2L, "dave"),
914+ createNewRow(order, 41L, 4L, "nathan"),
915+ createNewRow(item, 111L, 11L),
916+ createNewRow(item, 112L, 11L),
917+ createNewRow(item, 121L, 12L),
918+ createNewRow(item, 122L, 12L),
919+ createNewRow(item, 211L, 21L),
920+ createNewRow(item, 212L, 21L),
921+ createNewRow(item, 221L, 22L),
922+ createNewRow(item, 222L, 22L),
923+ createNewRow(item, 241L, 24L),
924+ createNewRow(item, 251L, 25L)};
925+ use(db);
926+ }
927+
928+ @Test
929+ public void testCursor()
930+ {
931+ Operator indexScan = indexScan_Default(itemIidIndexRowType, iidKeyRange(100, false, 125, false), ordering(itemIidIndexRowType), IndexScanSelector.leftJoinAfter(itemIidIndexRowType.index(), itemRowType.userTable()), lookaheadQuantum());
932+ CursorLifecycleTestCase testCase = new CursorLifecycleTestCase()
933+ {
934+ @Override
935+ public boolean hKeyComparison()
936+ {
937+ return true;
938+ }
939+
940+ @Override
941+ public String[] firstExpectedHKeys()
942+ {
943+ return new String[]{hkey(1, 11, 111), hkey(1, 11, 112), hkey(1, 12, 121), hkey(1, 12, 122)};
944+ }
945+ };
946+ testCursorLifecycle(indexScan, testCase);
947+ }
948+
949+ @Test
950+ public void testSingle()
951+ {
952+ Operator indexScan = indexScan_Default(itemIidIndexRowType, iidKeyRange(212, true, 212, true), ordering(itemIidIndexRowType), IndexScanSelector.leftJoinAfter(itemIidIndexRowType.index(), itemRowType.userTable()), lookaheadQuantum());
953+ Cursor cursor = cursor(indexScan, queryContext, queryBindings);
954+ String[] expected = new String[]{hkey(2, 21, 212)};
955+ compareRenderedHKeys(expected, cursor);
956+ }
957+
958+ @Test
959+ public void testMap()
960+ {
961+ RowType cidValueRowType = schema.newValuesType(AkType.INT);
962+ List<ExpressionGenerator> cidExprs = Arrays.asList(boundField(cidValueRowType, 1, 0));
963+ IndexBound cidBound =
964+ new IndexBound(
965+ new RowBasedUnboundExpressions(orderCidIndexRowType, cidExprs),
966+ new SetColumnSelector(0));
967+ IndexKeyRange cidRange = IndexKeyRange.bounded(orderCidIndexRowType, cidBound, true, cidBound, true);
968+ Operator plan =
969+ map_NestedLoops(
970+ valuesScan_Default(
971+ bindableExpressions(intRow(cidValueRowType, 2),
972+ intRow(cidValueRowType, 4),
973+ intRow(cidValueRowType, 6)),
974+ cidValueRowType),
975+ indexScan_Default(orderCidIndexRowType, cidRange, ordering(orderCidIndexRowType), IndexScanSelector.leftJoinAfter(orderCidIndexRowType.index(), orderRowType.userTable()), lookaheadQuantum()),
976+ 1, pipelineMap(), 1);
977+ Cursor cursor = cursor(plan, queryContext, queryBindings);
978+ String[] expected = new String[]{hkey(2, 21),hkey(2, 22),hkey(2, 23),hkey(2, 24),hkey(2, 25),hkey(2, 26),hkey(2, 27),hkey(2, 28),hkey(2, 29),hkey(4, 41)};
979+ compareRenderedHKeys(expected, cursor);
980+ }
981+
982+ @Test
983+ public void testNested()
984+ {
985+ RowType cidValueRowType = schema.newValuesType(AkType.INT);
986+ List<ExpressionGenerator> cidExprs = Arrays.asList(boundField(cidValueRowType, 1, 0));
987+ IndexBound cidBound =
988+ new IndexBound(
989+ new RowBasedUnboundExpressions(orderCidIndexRowType, cidExprs),
990+ new SetColumnSelector(0));
991+ IndexKeyRange cidRange = IndexKeyRange.bounded(orderCidIndexRowType, cidBound, true, cidBound, true);
992+ List<ExpressionGenerator> oidExprs = Arrays.asList(boundField(orderCidIndexRowType, 2, 1));
993+ IndexBound oidBound =
994+ new IndexBound(
995+ new RowBasedUnboundExpressions(itemOidIndexRowType, oidExprs),
996+ new SetColumnSelector(0));
997+ IndexKeyRange oidRange = IndexKeyRange.bounded(itemOidIndexRowType, oidBound, true, oidBound, true);
998+ Operator plan =
999+ map_NestedLoops(
1000+ valuesScan_Default(
1001+ bindableExpressions(intRow(cidValueRowType, 2),
1002+ intRow(cidValueRowType, 4),
1003+ intRow(cidValueRowType, 6)),
1004+ cidValueRowType),
1005+ map_NestedLoops(
1006+ indexScan_Default(orderCidIndexRowType, cidRange, ordering(orderCidIndexRowType), IndexScanSelector.leftJoinAfter(orderCidIndexRowType.index(), orderRowType.userTable()), lookaheadQuantum()),
1007+ indexScan_Default(itemOidIndexRowType, oidRange, ordering(itemOidIndexRowType), IndexScanSelector.leftJoinAfter(itemOidIndexRowType.index(), itemRowType.userTable()), lookaheadQuantum()),
1008+ 2, pipelineMap(), 2),
1009+ 1, pipelineMap(), 1);
1010+ Cursor cursor = cursor(plan, queryContext, queryBindings);
1011+ String[] expected = new String[]{hkey(2, 21, 211),hkey(2, 21, 212),hkey(2, 22, 221),hkey(2, 22, 222),hkey(2, 24, 241),hkey(2, 25, 251)};
1012+ compareRenderedHKeys(expected, cursor);
1013+ }
1014+
1015+ // For use by this class
1016+
1017+ private IndexKeyRange iidKeyRange(int lo, boolean loInclusive, int hi, boolean hiInclusive)
1018+ {
1019+ return IndexKeyRange.bounded(itemIidIndexRowType, iidBound(lo), loInclusive, iidBound(hi), hiInclusive);
1020+ }
1021+
1022+ private IndexBound iidBound(int iid)
1023+ {
1024+ return new IndexBound(row(itemIidIndexRowType, iid), new SetColumnSelector(0));
1025+ }
1026+
1027+ private Row intRow(RowType rowType, int x)
1028+ {
1029+ List<TPreparedExpression> pExpressions = Arrays.<TPreparedExpression>asList(new TPreparedLiteral(MNumeric.INT.instance(false), new PValue(MNumeric.INT.instance(false), x)));
1030+ return new ExpressionRow(rowType, queryContext, queryBindings, null, pExpressions);
1031+ }
1032+
1033+ private Collection<? extends BindableRow> bindableExpressions(Row... rows) {
1034+ List<BindableRow> result = new ArrayList<>();
1035+ for (Row row : rows) {
1036+ result.add(BindableRow.of(row, true));
1037+ }
1038+ return result;
1039+ }
1040+
1041+ private String hkey(int cid, int oid)
1042+ {
1043+ return String.format("{1,(long)%s,2,(long)%s}", cid, oid);
1044+ }
1045+
1046+ private String hkey(int cid, int oid, int iid)
1047+ {
1048+ return String.format("{1,(long)%s,2,(long)%s,3,(long)%s}", cid, oid, iid);
1049+ }
1050+
1051+ private Ordering ordering(IndexRowType indexRowType) {
1052+ Ordering ordering = new Ordering();
1053+ for (int i = 0; i < indexRowType.nFields(); i++) {
1054+ ordering.append(field(indexRowType, i), true);
1055+ }
1056+ return ordering;
1057+ }
1058+
1059+}
1060
1061=== modified file 'src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsIT.java'
1062--- src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsIT.java 2013-07-10 21:30:34 +0000
1063+++ src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsIT.java 2013-07-13 21:10:31 +0000
1064@@ -102,25 +102,25 @@
1065 @Test(expected = IllegalArgumentException.class)
1066 public void testLeftInputNull()
1067 {
1068- map_NestedLoops(null, groupScan_Default(coi), 0, 1);
1069+ map_NestedLoops(null, groupScan_Default(coi), 0, pipelineMap(), 1);
1070 }
1071
1072 @Test(expected = IllegalArgumentException.class)
1073 public void testRightInputNull()
1074 {
1075- map_NestedLoops(groupScan_Default(coi), null, 0, 1);
1076+ map_NestedLoops(groupScan_Default(coi), null, 0, pipelineMap(), 1);
1077 }
1078
1079 @Test(expected = IllegalArgumentException.class)
1080 public void testNegativeInputBindingPosition()
1081 {
1082- map_NestedLoops(groupScan_Default(coi), groupScan_Default(coi), -1, 1);
1083+ map_NestedLoops(groupScan_Default(coi), groupScan_Default(coi), -1, pipelineMap(), 1);
1084 }
1085
1086 @Test(expected = IllegalArgumentException.class)
1087 public void testNonPositiveDepth()
1088 {
1089- map_NestedLoops(groupScan_Default(coi), groupScan_Default(coi), 0, 0);
1090+ map_NestedLoops(groupScan_Default(coi), groupScan_Default(coi), 0, pipelineMap(),0);
1091 }
1092
1093 // Test operator execution
1094@@ -132,7 +132,7 @@
1095 map_NestedLoops(
1096 indexScan_Default(itemOidIndexRowType, false),
1097 ancestorLookup_Nested(coi, itemOidIndexRowType, Collections.singleton(itemRowType), 0),
1098- 0, 1);
1099+ 0, pipelineMap(), 1);
1100 RowBase[] expected = new RowBase[]{
1101 row(itemRowType, 1000L, 100L),
1102 row(itemRowType, 1001L, 100L),
1103@@ -175,7 +175,7 @@
1104 groupScan_Default(coi),
1105 Collections.singleton(customerRowType)),
1106 project,
1107- 0, 1);
1108+ 0, pipelineMap(), 1);
1109 RowType projectRowType = project.rowType();
1110 RowBase[] expected = new RowBase[]{
1111 row(projectRowType, 1L, 100L),
1112@@ -212,7 +212,7 @@
1113 groupScan_Default(coi),
1114 Collections.singleton(customerRowType)),
1115 ifEmpty_Default(project, projectRowType, Arrays.asList(boundField(customerRowType, 0, 0), literal(null)), InputPreservationOption.KEEP_INPUT),
1116- 0, 1);
1117+ 0, pipelineMap(), 1);
1118 RowBase[] expected = new RowBase[]{
1119 row(projectRowType, 1L, 100L),
1120 row(projectRowType, 1L, 101L),
1121@@ -234,7 +234,7 @@
1122 map_NestedLoops(
1123 indexScan_Default(itemOidIndexRowType, false),
1124 ancestorLookup_Nested(coi, itemOidIndexRowType, Collections.singleton(itemRowType), 0),
1125- 0, 1);
1126+ 0, pipelineMap(), 1);
1127 CursorLifecycleTestCase testCase = new CursorLifecycleTestCase()
1128 {
1129 @Override
1130@@ -291,8 +291,8 @@
1131 map_NestedLoops(
1132 indexScan_Default(customerCidIndexRowType, false, cidRange),
1133 ancestorLookup_Nested(coi, customerCidIndexRowType, Collections.singleton(customerRowType), 0),
1134- 0, 2),
1135- 1, 1);
1136+ 0, pipelineMap(), 2),
1137+ 1, pipelineMap(), 1);
1138 RowBase[] expected = new RowBase[]{
1139 row(customerRowType, 1L, "northbridge"),
1140 row(customerRowType, 2L, "foundation"),
1141
1142=== added file 'src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsPipelineIT.java'
1143--- src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsPipelineIT.java 1970-01-01 00:00:00 +0000
1144+++ src/test/java/com/akiban/server/test/it/qp/Map_NestedLoopsPipelineIT.java 2013-07-13 21:10:31 +0000
1145@@ -0,0 +1,26 @@
1146+/**
1147+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
1148+ *
1149+ * This program is free software: you can redistribute it and/or modify
1150+ * it under the terms of the GNU Affero General Public License as published by
1151+ * the Free Software Foundation, either version 3 of the License, or
1152+ * (at your option) any later version.
1153+ *
1154+ * This program is distributed in the hope that it will be useful,
1155+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1156+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1157+ * GNU Affero General Public License for more details.
1158+ *
1159+ * You should have received a copy of the GNU Affero General Public License
1160+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1161+ */
1162+
1163+package com.akiban.server.test.it.qp;
1164+
1165+public class Map_NestedLoopsPipelineIT extends Map_NestedLoopsIT
1166+{
1167+ @Override
1168+ protected boolean pipelineMap() {
1169+ return true;
1170+ }
1171+}
1172
1173=== modified file 'src/test/java/com/akiban/server/test/it/qp/Sort_InsertionLimitedIT.java'
1174--- src/test/java/com/akiban/server/test/it/qp/Sort_InsertionLimitedIT.java 2013-07-10 18:42:14 +0000
1175+++ src/test/java/com/akiban/server/test/it/qp/Sort_InsertionLimitedIT.java 2013-07-13 21:10:31 +0000
1176@@ -540,7 +540,7 @@
1177 map_NestedLoops(
1178 filter_Default(groupScan_Default(coi),
1179 Collections.singleton(customerRowType)),
1180- project, 0, 1),
1181+ project, 0, pipelineMap(), 1),
1182 projectType,
1183 ordering(field(projectType, 0), true),
1184 SortOption.PRESERVE_DUPLICATES,
1185
1186=== modified file 'src/test/java/com/akiban/server/test/it/qp/UnionAll_DefaultIT.java'
1187--- src/test/java/com/akiban/server/test/it/qp/UnionAll_DefaultIT.java 2013-07-10 18:42:14 +0000
1188+++ src/test/java/com/akiban/server/test/it/qp/UnionAll_DefaultIT.java 2013-07-13 21:10:31 +0000
1189@@ -270,7 +270,7 @@
1190 xEQ9Range,
1191 ordering),
1192 txIndexRowType),
1193- 0, 1);
1194+ 0, pipelineMap(), 1);
1195 String[] expected = new String[]{
1196 hKey(1000),
1197 hKey(1002),
1198
1199=== modified file 'src/test/java/com/akiban/sql/optimizer/OperatorCompilerTest.java'
1200--- src/test/java/com/akiban/sql/optimizer/OperatorCompilerTest.java 2013-03-22 20:05:57 +0000
1201+++ src/test/java/com/akiban/sql/optimizer/OperatorCompilerTest.java 2013-07-13 21:10:31 +0000
1202@@ -33,6 +33,7 @@
1203 import com.akiban.sql.optimizer.plan.ResultSet.ResultField;
1204 import com.akiban.sql.optimizer.rule.ExplainPlanContext;
1205 import com.akiban.sql.optimizer.rule.RulesTestHelper;
1206+import com.akiban.sql.optimizer.rule.PipelineConfiguration;
1207 import com.akiban.sql.optimizer.rule.cost.TestCostEstimator;
1208
1209 import com.akiban.junit.NamedParameterizedRunner;
1210@@ -122,6 +123,7 @@
1211 compiler.initT3Registry(t3Registry);
1212 }
1213 compiler.initCostEstimator(new TestCostEstimator(ais, compiler.getSchema(), statsFile, false, properties), usePValues);
1214+ compiler.initPipelineConfiguration(new PipelineConfiguration());
1215 compiler.initDone();
1216 return compiler;
1217 }
1218
1219=== modified file 'src/test/java/com/akiban/sql/optimizer/rule/RulesTestContext.java'
1220--- src/test/java/com/akiban/sql/optimizer/rule/RulesTestContext.java 2013-03-22 20:05:57 +0000
1221+++ src/test/java/com/akiban/sql/optimizer/rule/RulesTestContext.java 2013-07-13 21:10:31 +0000
1222@@ -50,6 +50,7 @@
1223 context.initCostEstimator(new TestCostEstimator(ais, context.getSchema(),
1224 statsFile, statsIgnoreMissingIndexes,
1225 properties), false);
1226+ context.initPipelineConfiguration(new PipelineConfiguration());
1227 context.initDone();
1228 return context;
1229 }

Subscribers

People subscribed via source and target branches