From 54f81da3169d488afee133053897a52f65481809 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 | 12 +++ src/backend/executor/nodeSort.c | 143 ++++++++++++------------------------ src/backend/utils/sort/tuplesort.c | 35 +++++++++ src/include/executor/nodeSort.h | 5 +- src/include/utils/tuplesort.h | 3 + 5 files changed, 98 insertions(+), 100 deletions(-) diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 1aca5f0d75..a7e29a126b 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -168,6 +168,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); @@ -261,6 +266,9 @@ pushTuple(TupleTableSlot *slot, PlanState *node, PlanState *pusher) if (nodeTag(node) == T_LimitState) return pushTupleToLimit(slot, (LimitState *) node); + else if (nodeTag(node) == T_SortState) + return pushTupleToSort(slot, (SortState *) node); + else if (nodeTag(node) == T_AggState) return pushTupleToAgg(slot, (AggState *) node); @@ -332,6 +340,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..8ba501e9ac 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -22,11 +22,11 @@ /* ---------------------------------------------------------------- - * ExecSort + * pushTupleToSort * * 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. + * which saves the results in a temporary file or memory. After receiving + * NULL slot, pushes all tuples. * * Conditions: * -- none. @@ -35,110 +35,55 @@ * -- the outer child is prepared to return the first tuple. * ---------------------------------------------------------------- */ -TupleTableSlot * -ExecSort(SortState *node) +bool +pushTupleToSort(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; - - /* - * If first time through, read all tuples from outer plan and pass them to - * tuplesort.c. Subsequent calls just fetch tuples from tuplesort. - */ + /* 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 (!node->sort_Done) + if (!TupIsNull(slot)) { - 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"); - - 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 (;;) + if (node->tuplesortstate == NULL) { - slot = ExecProcNode(outerNode); - - if (TupIsNull(slot)) - break; - - tuplesort_puttupleslot(tuplesortstate, slot); + /* first call, time to create tuplesort */ + outerNode = outerPlanState(node); + tupDesc = ExecGetResultType(outerNode); + + node->tuplesortstate = tuplesort_begin_heap(tupDesc, + plannode->numCols, + plannode->sortColIdx, + plannode->sortOperators, + plannode->collations, + plannode->nullsFirst, + work_mem, + node->randomAccess); } - - /* - * 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"); + /* 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 */ /* - * 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; + + if (tuplesort_pushtuples(node->tuplesortstate, node)) + /* If parent still waits for tuples, let it know we are done */ + pushTuple(NULL, node->ss.ps.parent, (PlanState *) node); + + /* doesn't matter */ + return false; } /* ---------------------------------------------------------------- @@ -149,7 +94,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 +107,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 +145,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..96ffadafc5 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -2080,6 +2080,41 @@ tuplesort_gettuple_common(Tuplesortstate *state, bool forward, } /* + * Push every tuple from tuplesort. Returns last pushTuple() result. + */ +bool +tuplesort_pushtuples(Tuplesortstate *state, SortState *node) +{ + SortTuple stup; + MemoryContext oldcontext = CurrentMemoryContext; + TupleTableSlot *slot = node->ss.ps.ps_ResultTupleSlot; + bool parent_accepts_tuples = true; + + /* 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); + parent_accepts_tuples = + pushTuple(slot, node->ss.ps.parent, (PlanState *) node); + if (!parent_accepts_tuples) + return false; + } + + state->eof_reached = true; + ExecClearTuple(slot); + return parent_accepts_tuples; +} + +/* * 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..27a7fb02d5 100644 --- a/src/include/executor/nodeSort.h +++ b/src/include/executor/nodeSort.h @@ -16,8 +16,9 @@ #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 pushTupleToSort(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..a3770c3af8 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 bool 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