From 1bf26fc1eaa6103342639e24a71e90d515c9b7a8 Mon Sep 17 00:00:00 2001 From: Arseny Sher Date: Tue, 14 Mar 2017 20:03:41 +0300 Subject: [PATCH 8/8] Reversed in-memory Sort implementation. Only in-memory sort is supported for now. --- src/backend/executor/execProcnode.c | 15 ++++ src/backend/executor/nodeSort.c | 139 +++++++++++------------------------- src/backend/utils/sort/tuplesort.c | 33 +++++++++ src/include/executor/nodeSort.h | 6 +- src/include/utils/tuplesort.h | 3 + 5 files changed, 95 insertions(+), 101 deletions(-) diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index ab0312a4bf..aadfce7f9d 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -193,6 +193,11 @@ ExecInitNode(Plan *node, EState *estate, int eflags, PlanState *parent) /* * materialization nodes */ + case T_Sort: + result = (PlanState *) ExecInitSort((Sort *) node, + estate, eflags, parent); + break; + case T_Agg: result = (PlanState *) ExecInitAgg((Agg *) node, estate, eflags, parent); @@ -288,6 +293,9 @@ ExecPushTuple(TupleTableSlot *slot, PlanState *pusher) if (nodeTag(receiver) == T_LimitState) return ExecPushTupleToLimit(slot, (LimitState *) receiver); + else if (nodeTag(receiver) == T_SortState) + return ExecPushTupleToSort(slot, (SortState *) receiver); + else if (nodeTag(receiver) == T_AggState) return ExecPushTupleToAgg(slot, (AggState *) receiver); @@ -334,6 +342,9 @@ ExecPushNull(TupleTableSlot *slot, PlanState *pusher) if (nodeTag(receiver) == T_LimitState) return ExecPushNullToLimit(slot, (LimitState *) receiver); + else if (nodeTag(receiver) == T_SortState) + return ExecPushNullToSort(slot, (SortState *) receiver); + else if (nodeTag(receiver) == T_AggState) return ExecPushNullToAgg(slot, (AggState *) receiver); @@ -410,6 +421,10 @@ ExecEndNode(PlanState *node) /* * materialization nodes */ + case T_SortState: + ExecEndSort((SortState *) node); + break; + case T_AggState: ExecEndAgg((AggState *) node); break; diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 0028912509..946e0c5f84 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -22,11 +22,10 @@ /* ---------------------------------------------------------------- - * ExecSort + * ExecPushTupleToSort * - * Sorts tuples from the outer subtree of the node using tuplesort, - * which saves the results in a temporary file or memory. After the - * initial call, returns a tuple from the file with each call. + * Puts tuple from the outer subtree of the node to tuplesort, + * which saves the results in a temporary file or memory. * * Conditions: * -- none. @@ -35,110 +34,50 @@ * -- the outer child is prepared to return the first tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * -ExecSort(SortState *node) +bool +ExecPushTupleToSort(TupleTableSlot *slot, SortState *node) { - EState *estate; - ScanDirection dir; - Tuplesortstate *tuplesortstate; - TupleTableSlot *slot; + Sort *plannode = (Sort *) node->ss.ps.plan; + PlanState *outerNode; + TupleDesc tupDesc; - /* - * get state info from node - */ - SO1_printf("ExecSort: %s\n", - "entering routine"); - - estate = node->ss.ps.state; - dir = estate->es_direction; - tuplesortstate = (Tuplesortstate *) node->tuplesortstate; + /* bounded nodes not supported yet */ + Assert(!node->bounded); + /* only forward direction is supported for now */ + Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction)); + Assert(!node->sort_Done); - /* - * If first time through, read all tuples from outer plan and pass them to - * tuplesort.c. Subsequent calls just fetch tuples from tuplesort. - */ - - if (!node->sort_Done) + if (node->tuplesortstate == NULL) { - Sort *plannode = (Sort *) node->ss.ps.plan; - PlanState *outerNode; - TupleDesc tupDesc; - - SO1_printf("ExecSort: %s\n", - "sorting subplan"); - - /* - * Want to scan subplan in the forward direction while creating the - * sorted data. - */ - estate->es_direction = ForwardScanDirection; - - /* - * Initialize tuplesort module. - */ - SO1_printf("ExecSort: %s\n", - "calling tuplesort_begin"); - + /* first call, time to create tuplesort */ outerNode = outerPlanState(node); tupDesc = ExecGetResultType(outerNode); - tuplesortstate = tuplesort_begin_heap(tupDesc, - plannode->numCols, - plannode->sortColIdx, - plannode->sortOperators, - plannode->collations, - plannode->nullsFirst, - work_mem, - node->randomAccess); - if (node->bounded) - tuplesort_set_bound(tuplesortstate, node->bound); - node->tuplesortstate = (void *) tuplesortstate; - - /* - * Scan the subplan and feed all the tuples to tuplesort. - */ - - for (;;) - { - slot = ExecProcNode(outerNode); - - if (TupIsNull(slot)) - break; - - tuplesort_puttupleslot(tuplesortstate, slot); - } - - /* - * Complete the sort. - */ - tuplesort_performsort(tuplesortstate); - - /* - * restore to user specified direction - */ - estate->es_direction = dir; - - /* - * finally set the sorted flag to true - */ - node->sort_Done = true; - node->bounded_Done = node->bounded; - node->bound_Done = node->bound; - SO1_printf("ExecSort: %s\n", "sorting done"); + node->tuplesortstate = tuplesort_begin_heap(tupDesc, + plannode->numCols, + plannode->sortColIdx, + plannode->sortOperators, + plannode->collations, + plannode->nullsFirst, + work_mem, + node->randomAccess); } + /* feed the tuple to tuplesort */ + tuplesort_puttupleslot(node->tuplesortstate, slot); + return true; +} - SO1_printf("ExecSort: %s\n", - "retrieving tuple from tuplesort"); - +/* NULL tuple arrived, sort and push tuples */ +void +ExecPushNullToSort(TupleTableSlot *slot, SortState *node) +{ /* - * Get the first or next tuple from tuplesort. Returns NULL if no more - * tuples. + * Complete the sort. */ - slot = node->ss.ps.ps_ResultTupleSlot; - (void) tuplesort_gettupleslot(tuplesortstate, - ScanDirectionIsForward(dir), - slot, NULL); - return slot; + tuplesort_performsort(node->tuplesortstate); + node->sort_Done = true; + + tuplesort_pushtuples(node->tuplesortstate, node); } /* ---------------------------------------------------------------- @@ -149,7 +88,7 @@ ExecSort(SortState *node) * ---------------------------------------------------------------- */ SortState * -ExecInitSort(Sort *node, EState *estate, int eflags) +ExecInitSort(Sort *node, EState *estate, int eflags, PlanState *parent) { SortState *sortstate; @@ -162,6 +101,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags) sortstate = makeNode(SortState); sortstate->ss.ps.plan = (Plan *) node; sortstate->ss.ps.state = estate; + sortstate->ss.ps.parent = parent; /* * We must have random access to the sort output to do backward scan or @@ -199,7 +139,8 @@ ExecInitSort(Sort *node, EState *estate, int eflags) */ eflags &= ~(EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK); - outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate, eflags, NULL); + outerPlanState(sortstate) = ExecInitNode(outerPlan(node), estate, eflags, + (PlanState *) sortstate); /* * initialize tuple type. no need to initialize projection info because diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index e1e692d5f0..7e078c22a3 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -2080,6 +2080,39 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, } /* + * Push every tuple from tuplesort. Push null tuple after, + */ +void +tuplesort_pushtuples(Tuplesortstate *state, SortState *node) +{ + SortTuple stup; + MemoryContext oldcontext = CurrentMemoryContext; + TupleTableSlot *slot = node->ss.ps.ps_ResultTupleSlot; + + /* only in mem sort is supported for now */ + Assert(state->status == TSS_SORTEDINMEM); + Assert(!state->slabAllocatorUsed); + + while (state->current < state->memtupcount) + { + /* Imitating context switching as it was before */ + MemoryContextSwitchTo(state->sortcontext); + stup = state->memtuples[state->current++]; + MemoryContextSwitchTo(oldcontext); + + stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple); + ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, true); + if (!ExecPushTuple(slot, (PlanState *) node)) + return; + } + + /* If parent still waits for tuples, let it know we are done */ + state->eof_reached = true; + ExecClearTuple(slot); + return ExecPushNull(slot, (PlanState *) node); +} + +/* * Fetch the next tuple in either forward or back direction. * If successful, put tuple in slot and return TRUE; else, clear the slot * and return FALSE. diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h index 10d16b47b1..3a726b3500 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -16,8 +16,10 @@ #include "nodes/execnodes.h" -extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags); -extern TupleTableSlot *ExecSort(SortState *node); +extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags, + PlanState *parent); +extern bool ExecPushTupleToSort(TupleTableSlot *slot, SortState *node); +extern void ExecPushNullToSort(TupleTableSlot *slot, SortState *node); extern void ExecEndSort(SortState *node); extern void ExecSortMarkPos(SortState *node); extern void ExecSortRestrPos(SortState *node); diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h index 5b3f4752f4..45c6659bea 100644 --- a/src/include/utils/tuplesort.h +++ b/src/include/utils/tuplesort.h @@ -92,6 +92,9 @@ extern void tuplesort_putdatum(Tuplesortstate *state, Datum val, extern void tuplesort_performsort(Tuplesortstate *state); +/* forward decl, since now we need to know about SortState */ +typedef struct SortState SortState; +extern void tuplesort_pushtuples(Tuplesortstate *state, SortState *node); extern bool tuplesort_gettupleslot(Tuplesortstate *state, bool forward, TupleTableSlot *slot, Datum *abbrev); extern HeapTuple tuplesort_getheaptuple(Tuplesortstate *state, bool forward); -- 2.11.0