Пример #1
0
/* ----------------------------------------------------------------
 *		ExecSort
 *
 *		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.
 *
 *		Conditions:
 *		  -- none.
 *
 *		Initial States:
 *		  -- the outer child is prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecSort(SortState *node)
{
	EState	   *estate;
	ScanDirection dir;
	Tuplesortstate *tuplesortstate;
	TupleTableSlot *slot;

	/*
	 * 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.
	 */

	if (!node->sort_Done)
	{
		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 (;;)
		{
			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");
	}

	SO1_printf("ExecSort: %s\n",
			   "retrieving tuple from tuplesort");

	/*
	 * Get the first or next tuple from tuplesort. Returns NULL if no more
	 * tuples.
	 */
	slot = node->ss.ps.ps_ResultTupleSlot;
	(void) tuplesort_gettupleslot(tuplesortstate,
								  ScanDirectionIsForward(dir),
								  slot);

	return slot;
}
Пример #2
0
/* ----------------------------------------------------------------
 *		ExecSort
 *
 *		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.
 *
 *		Conditions:
 *		  -- none.
 *
 *		Initial States:
 *		  -- the outer child is prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
static TupleTableSlot *
ExecSort(PlanState *pstate)
{
	SortState  *node = castNode(SortState, pstate);
	EState	   *estate;
	ScanDirection dir;
	Tuplesortstate *tuplesortstate;
	TupleTableSlot *slot;

	CHECK_FOR_INTERRUPTS();

	/*
	 * 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.
	 */

	if (!node->sort_Done)
	{
		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,
											  NULL, 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;
		if (node->shared_info && node->am_worker)
		{
			TuplesortInstrumentation *si;

			Assert(IsParallelWorker());
			Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
			si = &node->shared_info->sinstrument[ParallelWorkerNumber];
			tuplesort_get_stats(tuplesortstate, si);
		}
		SO1_printf("ExecSort: %s\n", "sorting done");
	}

	SO1_printf("ExecSort: %s\n",
			   "retrieving tuple from tuplesort");

	/*
	 * Get the first or next tuple from tuplesort. Returns NULL if no more
	 * tuples.  Note that we only rely on slot tuple remaining valid until the
	 * next fetch from the tuplesort.
	 */
	slot = node->ss.ps.ps_ResultTupleSlot;
	(void) tuplesort_gettupleslot(tuplesortstate,
								  ScanDirectionIsForward(dir),
								  false, slot, NULL);
	return slot;
}
Пример #3
0
/* ----------------------------------------------------------------
 *		ExecSort
 *
 *		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.
 *
 *		Conditions:
 *		  -- none.
 *
 *		Initial States:
 *		  -- the outer child is prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecSort(SortState *node)
{
	EState	   *estate;
	ScanDirection dir;
	Tuplesortstate *tuplesortstate;
	TupleTableSlot *slot;

	/*
	 * 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.
	 */

	if (!node->sort_Done)
	{
		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);

#ifdef PGXC
		if (plannode->srt_start_merge &&
			IsA(node->ss.ps.lefttree, RemoteQueryState))
		{
			RemoteQueryState	*rqs = (RemoteQueryState *)node->ss.ps.lefttree;

			rqs->rqs_for_sort = true;
			/*
			 * Start the queries on all the nodes. That way we get the number of
			 * connections and connection handlers set in RemoteQueryState.
			 * Those will be used to merge the data from the datanodes.
			 */
			if (!rqs->query_Done)
			{
				do_query(rqs);
				rqs->query_Done = true;
			}

			/*
			 * PGXCTODO: We don't handle bounded in this case, but see if it can
			 * be used.
			 */
			tuplesortstate = tuplesort_begin_merge(tupDesc,
													plannode->numCols,
													plannode->sortColIdx,
													plannode->sortOperators,
													plannode->collations,
													plannode->nullsFirst,
													rqs, work_mem);

		}
		else
		{
#endif /* PGXC */
		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);
#ifdef PGXC
		}
#endif /* PGXC */
		node->tuplesortstate = (void *) tuplesortstate;

#ifdef PGXC
		if (!plannode->srt_start_merge)
		{
#endif /* PGXC */
		/*
		 * 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);
#ifdef PGXC
		}
		else
			Assert(IsA(node->ss.ps.lefttree, RemoteQueryState));
#endif /* PGXC */

		/*
		 * 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");
	}

	SO1_printf("ExecSort: %s\n",
			   "retrieving tuple from tuplesort");

	/*
	 * Get the first or next tuple from tuplesort. Returns NULL if no more
	 * tuples.
	 */
	slot = node->ss.ps.ps_ResultTupleSlot;
	(void) tuplesort_gettupleslot(tuplesortstate,
								  ScanDirectionIsForward(dir),
								  slot);
	return slot;
}
Пример #4
0
/* ----------------------------------------------------------------
 *		ExecSort
 *
 *		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.
 *
 *		Conditions:
 *		  -- none.
 *
 *		Initial States:
 *		  -- the outer child is prepared to return the first tuple.
 * ----------------------------------------------------------------
 */
TupleTableSlot *
ExecSort(SortState *node)
{
	EState	   *estate;
	ScanDirection dir;
	Tuplesortstate *tuplesortstate = NULL;
	Tuplesortstate_mk *tuplesortstate_mk = NULL;
	TupleTableSlot *slot = NULL;
	Sort 		*plannode = NULL;
	PlanState  *outerNode = NULL;
	TupleDesc	tupDesc = NULL;
	workfile_set *work_set = NULL;

	/*
	 * get state info from node
	 */
	SO1_printf("ExecSort: %s\n",
			   "entering routine");

	estate = node->ss.ps.state;
	dir = estate->es_direction;

	if(gp_enable_mk_sort)
	{
		tuplesortstate_mk = node->tuplesortstate->sortstore_mk;
	}
	else
	{
		tuplesortstate = node->tuplesortstate->sortstore;
	}

	/*
	 * In Window node, we might need to call ExecSort again even when
	 * the last tuple in the Sort has been retrieved. Since we might
	 * eager free the tuplestore, the tuplestorestate could be NULL.
	 * We simply return NULL in this case.
	 */
	if (node->sort_Done &&
		((gp_enable_mk_sort && tuplesortstate_mk == NULL) ||
		 (!gp_enable_mk_sort && tuplesortstate == NULL)))
	{
		return NULL;
	}

	plannode = (Sort *) node->ss.ps.plan;


	/*
	 * If called for the first time, initialize tuplesort_state
	 */

	if (!node->sort_Done)
	{
		SO1_printf("ExecSort: %s\n",
				   "sorting subplan");

		if (gp_workfile_caching)
		{
			/* Look for cached workfile set. Mark here if found */
			work_set = workfile_mgr_find_set(&node->ss.ps);
			if (work_set != NULL)
			{
				elog(gp_workfile_caching_loglevel, "Sort found matching cached workfile set");
				node->cached_workfiles_found = true;
			}
		}

		/*
		 * 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);

		if(plannode->share_type == SHARE_SORT_XSLICE)
		{
			char rwfile_prefix[100];
			if(plannode->driver_slice != currentSliceId)
			{
				elog(LOG, "Sort exec on CrossSlice, current slice %d", currentSliceId);
				return NULL;
			}

			shareinput_create_bufname_prefix(rwfile_prefix, sizeof(rwfile_prefix), plannode->share_id);
			elog(LOG, "Sort node create shareinput rwfile %s", rwfile_prefix);

			if(gp_enable_mk_sort)
				tuplesortstate_mk = tuplesort_begin_heap_file_readerwriter_mk(
					& node->ss,
					rwfile_prefix, true,
					tupDesc,
					plannode->numCols,
					plannode->sortOperators,
					plannode->sortColIdx,
					PlanStateOperatorMemKB((PlanState *) node),
					true
					); 
			else
				tuplesortstate = tuplesort_begin_heap_file_readerwriter(
					rwfile_prefix, true,
					tupDesc,
					plannode->numCols,
					plannode->sortOperators,
					plannode->sortColIdx,
					PlanStateOperatorMemKB((PlanState *) node),
					true
					); 
		}
		else
		{
			if(gp_enable_mk_sort)
				tuplesortstate_mk = tuplesort_begin_heap_mk(& node->ss,
						tupDesc,
						plannode->numCols,
						plannode->sortOperators,
						plannode->sortColIdx,
						PlanStateOperatorMemKB((PlanState *) node),
						node->randomAccess);
			else
				tuplesortstate = tuplesort_begin_heap(tupDesc,
						plannode->numCols,
						plannode->sortOperators,
						plannode->sortColIdx,
						PlanStateOperatorMemKB((PlanState *) node),
						node->randomAccess);
		}

		if(gp_enable_mk_sort)
		{
			node->tuplesortstate->sortstore_mk = tuplesortstate_mk;
		}
		else
		{
			node->tuplesortstate->sortstore = tuplesortstate;
		}

		/* CDB */
		{
			ExprContext *econtext = node->ss.ps.ps_ExprContext;
			bool 		isNull;
			int64 		limit = 0;
			int64 		offset = 0;
			int 		unique = 0;
			int 		sort_flags = gp_sort_flags; /* get the guc */
			int         maxdistinct = gp_sort_max_distinct; /* get the guc */

			if (node->limitCount)
			{
				limit =
						DatumGetInt64(
								ExecEvalExprSwitchContext(node->limitCount,
														  econtext,
														  &isNull,
														  NULL));
				/* Interpret NULL limit as no limit */
				if (isNull)
					limit = 0;
				else if (limit < 0)
					limit = 0;

			}
			if (node->limitOffset)
			{
				offset =
						DatumGetInt64(
								ExecEvalExprSwitchContext(node->limitOffset,
														  econtext,
														  &isNull,
														  NULL));
				/* Interpret NULL offset as no offset */
				if (isNull)
					offset = 0;
				else if (offset < 0)
					offset = 0;

			}

			if (node->noduplicates)
				unique = 1;
			
			if(gp_enable_mk_sort)
				cdb_tuplesort_init_mk(tuplesortstate_mk, offset, limit, unique, sort_flags, maxdistinct);
			else
				cdb_tuplesort_init(tuplesortstate, offset, limit, unique, sort_flags, maxdistinct);
		}

		/* If EXPLAIN ANALYZE, share our Instrumentation object with sort. */
		if(gp_enable_mk_sort)
		{
			if (node->ss.ps.instrument)
				tuplesort_set_instrument_mk(tuplesortstate_mk,
						node->ss.ps.instrument,
						node->ss.ps.cdbexplainbuf);

			tuplesort_set_gpmon_mk(tuplesortstate_mk, &node->ss.ps.gpmon_pkt, 
					&node->ss.ps.gpmon_plan_tick);
		}
		else
		{
			if (node->ss.ps.instrument)
				tuplesort_set_instrument(tuplesortstate,
						node->ss.ps.instrument,
						node->ss.ps.cdbexplainbuf);

			tuplesort_set_gpmon(tuplesortstate, &node->ss.ps.gpmon_pkt, 
					&node->ss.ps.gpmon_plan_tick);
		}


	}

	/*
	 * Before reading any tuples from below, check if we can re-use
	 * existing spill files.
	 * Only mk_sort supports spill file caching.
	 */
	if (!node->sort_Done && gp_enable_mk_sort && gp_workfile_caching)
	{
		Assert(tuplesortstate_mk != NULL);

		if (node->cached_workfiles_found && !node->cached_workfiles_loaded)
		{
			Assert(work_set != NULL);
			elog(gp_workfile_caching_loglevel, "nodeSort: loading cached workfile metadata");

			tuplesort_set_spillfile_set_mk(tuplesortstate_mk, work_set);
			tuplesort_read_spill_metadata_mk(tuplesortstate_mk);
			node->cached_workfiles_loaded = true;

			if (node->ss.ps.instrument)
			{
				node->ss.ps.instrument->workfileReused = true;
			}

			/* Loaded sorted data from cached workfile, therefore
			 * no need to sort anymore!
			 */
			node->sort_Done = true;

			elog(gp_workfile_caching_loglevel, "Sort reusing cached workfiles, initiating Squelch walker");
			ExecSquelchNode(outerNode);
		}
	}



	/*
	 * If first time through and no cached workfiles can be used,
	 * read all tuples from outer plan and pass them to
	 * tuplesort.c. Subsequent calls just fetch tuples from tuplesort.
	 */
	if (!node->sort_Done)
	{

		Assert(outerNode != NULL);

		/*
		 * Scan the subplan and feed all the tuples to tuplesort.
		 */

		for (;;)
		{
			slot = ExecProcNode(outerNode);

			if (TupIsNull(slot))
			{
				break;
			}

			CheckSendPlanStateGpmonPkt(&node->ss.ps);
			if(gp_enable_mk_sort)
				tuplesort_puttupleslot_mk(tuplesortstate_mk, slot);
			else
				tuplesort_puttupleslot(tuplesortstate, slot);
		}

#ifdef FAULT_INJECTOR
		FaultInjector_InjectFaultIfSet(
				ExecSortBeforeSorting,
				DDLNotSpecified,
				"" /* databaseName */,
				"" /* tableName */
				);
#endif

		/*
		 * Complete the sort.
		 */
		if(gp_enable_mk_sort)
		{
			tuplesort_performsort_mk(tuplesortstate_mk);
		}
		else
		{
			tuplesort_performsort(tuplesortstate);
		}

		CheckSendPlanStateGpmonPkt(&node->ss.ps);
		/*
		 * restore to user specified direction
		 */
		estate->es_direction = dir;

		/*
		 * finally set the sorted flag to true
		 */
		node->sort_Done = true;
		SO1_printf("ExecSort: %s\n", "sorting done");

		/* for share input, do not need to return any tuple */
		if(plannode->share_type != SHARE_NOTSHARED) 
		{
			Assert(plannode->share_type == SHARE_SORT || plannode->share_type == SHARE_SORT_XSLICE);

			if(plannode->share_type == SHARE_SORT_XSLICE)
			{
				if(plannode->driver_slice == currentSliceId)
				{
					if(gp_enable_mk_sort)
						tuplesort_flush_mk(tuplesortstate_mk);
					else
						tuplesort_flush(tuplesortstate);

					node->share_lk_ctxt = shareinput_writer_notifyready(plannode->share_id, plannode->nsharer_xslice,
							estate->es_plannedstmt->planGen);
				}
			}

			return NULL;
		}

	} /* if (!node->sort_Done) */

	if(plannode->share_type != SHARE_NOTSHARED)
		return NULL;
				
	SO1_printf("ExecSort: %s\n",
			   "retrieving tuple from tuplesort");

	/*
	 * Get the first or next tuple from tuplesort. Returns NULL if no more
	 * tuples.
	 */
	slot = node->ss.ps.ps_ResultTupleSlot;
	if(gp_enable_mk_sort)
		(void) tuplesort_gettupleslot_mk(tuplesortstate_mk,
				ScanDirectionIsForward(dir),
				slot);
	else
		(void) tuplesort_gettupleslot(tuplesortstate,
				ScanDirectionIsForward(dir),
				slot);

	if (TupIsNull(slot) && !node->ss.ps.delayEagerFree)
	{
		ExecEagerFreeSort(node);
	}

	return slot;
}