Example #1
0
/*
 * executormgr_bind_executor_task
 *	For each task in slice, allocate an executor and bind it to task.
 */
bool
executormgr_bind_executor_task(struct DispatchData *data,
							QueryExecutor *executor,
							SegmentDatabaseDescriptor *desc,
							struct DispatchTask *task,
							struct DispatchSlice *slice)
{
  Assert(desc != NULL);

  executor->state = QES_UNINIT;
	executor->desc = desc;
	executor->state = QES_DISPATCHABLE;
	executor->health = QEH_NA;

	/* setup the owner of the executor */
	executor->takeovered = false;

	/* setup payload */
	executor->refSlice = slice;
	executor->refTask = task;

	/* TODO: set result slot */
	executor->refResult = cdbdisp_makeResult(dispatch_get_results(data),
											executor->desc,
											dispatch_get_task_identity(task)->slice_id);

	if (executor->refResult == NULL)
	  return false;

	/* Transfer any connection errors from segdbDesc. */
	executormgr_merge_error(executor);

	return true;
}
Example #2
0
/*
 * Dispatch command to gang.
 *
 * Throw out error to upper try-catch block if anything goes wrong.
 */
static void
cdbdisp_dispatchToGang_async(struct CdbDispatcherState *ds,
							 struct Gang *gp,
							 int sliceIndex,
							 CdbDispatchDirectDesc * dispDirect)
{
	int	i;
	CdbDispatchCmdAsync *pParms = (CdbDispatchCmdAsync*)ds->dispatchParams;

	/*
	 * Start the dispatching
	 */
	for (i = 0; i < gp->size; i++)
	{
		CdbDispatchResult* qeResult;

		SegmentDatabaseDescriptor *segdbDesc = &gp->db_descriptors[i];
		Assert(segdbDesc != NULL);

		if (dispDirect->directed_dispatch)
		{
			/* We can direct dispatch to one segment DB only */
			Assert(dispDirect->count == 1);
			if (dispDirect->content[0] != segdbDesc->segindex)
				continue;
		}

		/*
		 * Initialize the QE's CdbDispatchResult object.
		 */
		qeResult = cdbdisp_makeResult(ds->primaryResults, segdbDesc, sliceIndex);
		if (qeResult == NULL)
		{
			/*
			 * writer_gang could be NULL if this is an extended query.
			 */
			if (ds->primaryResults->writer_gang)
				ds->primaryResults->writer_gang->dispatcherActive = true;

			elog(FATAL, "could not allocate resources for segworker communication");
		}
		pParms->dispatchResultPtrArray[pParms->dispatchCount++] = qeResult;

		if (cdbconn_isBadConnection(segdbDesc))
		{
			char *msg = PQerrorMessage(qeResult->segdbDesc->conn);
			qeResult->stillRunning = false;

			ereport(ERROR,
					(errcode(ERRCODE_GP_INTERCONNECTION_ERROR),
					 errmsg("Connection lost before dispatch to %s: %s",
							 segdbDesc->whoami, msg ? msg : "unknown error")));
		}

		dispatchCommand(qeResult, pParms->query_text, pParms->query_text_len);
	}
}
Example #3
0
/*
 * Test cdbdisp_makeResult would return NULL if OOM happens
 */
void
test__cdbdisp_makeResult__oom(void **state)
{
	CdbDispatchResult *result = NULL;

	struct CdbDispatchResults *results = _init_cdbdisp_makeResult();
	struct SegmentDatabaseDescriptor *segdbDesc =
		(struct SegmentDatabaseDescriptor *) palloc0(sizeof(struct SegmentDatabaseDescriptor));

	/*
	 * createPQExpBuffer is supposed to return NULL in OOM cases
	 */
	will_return_count(createPQExpBuffer, NULL, -1);
	expect_any_count(destroyPQExpBuffer, str, -1);
	will_be_called_count(destroyPQExpBuffer, -1);
	result = cdbdisp_makeResult(results, segdbDesc, 0);
	assert_true(result == NULL);
}
Example #4
0
void
cdbdisp_dispatchToGang_internal(struct CdbDispatcherState *ds,
								struct Gang *gp,
								int sliceIndex,
								CdbDispatchDirectDesc * disp_direct)
{
	struct CdbDispatchResults *dispatchResults = ds->primaryResults;
	SegmentDatabaseDescriptor *segdbDesc;
	int	i,
		max_threads,
		segdbs_in_thread_pool = 0,
		newThreads = 0;
	int	gangSize = 0;
	SegmentDatabaseDescriptor *db_descriptors;
	char *newQueryText = NULL;
	DispatchCommandParms *pParms = NULL;

	gangSize = gp->size;
	Assert(gangSize <= largestGangsize());
	db_descriptors = gp->db_descriptors;

	/*
	 * The most threads we could have is segdb_count / gp_connections_per_thread, rounded up.
	 * This is equivalent to 1 + (segdb_count-1) / gp_connections_per_thread.
	 * We allocate enough memory for this many DispatchCommandParms structures,
	 * even though we may not use them all.
	 *
	 * We can only use gp->size here if we're not dealing with a
	 * singleton gang. It is safer to always use the max number of segments we are
	 * controlling (largestGangsize).
	 */
	Assert(gp_connections_per_thread >= 0);
	Assert(ds->dispatchThreads != NULL);
	/*
	 * If we attempt to reallocate, there is a race here: we
	 * know that we have threads running using the
	 * dispatchCommandParamsAr! If we reallocate we
	 * potentially yank it out from under them! Don't do
	 * it!
	 */
	max_threads = getMaxThreadsPerGang();
	if (ds->dispatchThreads->dispatchCommandParmsArSize <
		(ds->dispatchThreads->threadCount + max_threads))
	{
		elog(ERROR,
			 "Attempted to reallocate dispatchCommandParmsAr while other threads still running size %d new threadcount %d",
			 ds->dispatchThreads->dispatchCommandParmsArSize,
			 ds->dispatchThreads->threadCount + max_threads);
	}

	pParms = &ds->dispatchThreads->dispatchCommandParmsAr[0];
	newQueryText =
		dupQueryTextAndSetSliceId(ds->dispatchStateContext, pParms->query_text,
								  pParms->query_text_len, sliceIndex);
	/*
	 * Create the thread parms structures based targetSet parameter.
	 * This will add the segdbDesc pointers appropriate to the
	 * targetSet into the thread Parms structures, making sure that each thread
	 * handles gp_connections_per_thread segdbs.
	 */
	for (i = 0; i < gangSize; i++)
	{
		CdbDispatchResult *qeResult;

		segdbDesc = &db_descriptors[i];
		int	parmsIndex = 0;

		Assert(segdbDesc != NULL);

		if (disp_direct->directed_dispatch)
		{
			Assert(disp_direct->count == 1);	/* currently we allow direct-to-one dispatch, only */

			if (disp_direct->content[0] !=
				segdbDesc->segment_database_info->segindex)
				continue;
		}

		/*
		 * Initialize the QE's CdbDispatchResult object. 
		 */
		qeResult = cdbdisp_makeResult(dispatchResults, segdbDesc, sliceIndex);

		if (qeResult == NULL)
		{
			/*
			 * writer_gang could be NULL if this is an extended query.
			 */
			if (dispatchResults->writer_gang)
				dispatchResults->writer_gang->dispatcherActive = true;
			elog(FATAL, "could not allocate resources for segworker communication");
		}

		/*
		 * Transfer any connection errors from segdbDesc.
		 */
		if (segdbDesc->errcode || segdbDesc->error_message.len)
			cdbdisp_mergeConnectionErrors(qeResult, segdbDesc);

		parmsIndex = gp_connections_per_thread == 0 ? 0 : segdbs_in_thread_pool / gp_connections_per_thread;
		pParms =
			ds->dispatchThreads->dispatchCommandParmsAr +
			ds->dispatchThreads->threadCount + parmsIndex;
		pParms->dispatchResultPtrArray[pParms->db_count++] = qeResult;
		if (newQueryText != NULL)
			pParms->query_text = newQueryText;

		/*
		 * This CdbDispatchResult/SegmentDatabaseDescriptor pair will be
		 * dispatched and monitored by a thread to be started below. Only that
		 * thread should touch them until the thread is finished with them and
		 * resets the stillRunning flag. Caller must CdbCheckDispatchResult()
		 * to wait for completion.
		 */
		qeResult->stillRunning = true;

		segdbs_in_thread_pool++;
	}

	/*
	 * Compute the thread count based on how many segdbs were added into the
	 * thread pool, knowing that each thread handles gp_connections_per_thread
	 * segdbs.
	 */
	if (segdbs_in_thread_pool == 0)
		newThreads = 0;
	else if (gp_connections_per_thread == 0)
		newThreads = 1;
	else
		newThreads = 1
			+ (segdbs_in_thread_pool - 1) / gp_connections_per_thread;

	/*
	 * Create the threads. (which also starts the dispatching).
	 */
	for (i = 0; i < newThreads; i++)
	{
		DispatchCommandParms *pParms =
			&(ds->dispatchThreads->dispatchCommandParmsAr +
			  ds->dispatchThreads->threadCount)[i];

		Assert(pParms != NULL);

		if (gp_connections_per_thread == 0)
		{
			Assert(newThreads <= 1);
			thread_DispatchOut(pParms);
		}
		else
		{
			int	pthread_err = 0;

			pParms->thread_valid = true;
			pthread_err =
				gp_pthread_create(&pParms->thread, thread_DispatchCommand,
								  pParms, "dispatchToGang");

			if (pthread_err != 0)
			{
				int	j;

				pParms->thread_valid = false;

				/*
				 * Error during thread create (this should be caused by
				 * resource constraints). If we leave the threads running,
				 * they'll immediately have some problems -- so we need to
				 * join them, and *then* we can issue our FATAL error
				 */
				pParms->waitMode = DISPATCH_WAIT_CANCEL;

				for (j = 0; j < ds->dispatchThreads->threadCount + (i - 1); j++)
				{
					DispatchCommandParms *pParms;

					pParms = &ds->dispatchThreads->dispatchCommandParmsAr[j];

					pParms->waitMode = DISPATCH_WAIT_CANCEL;
					pParms->thread_valid = false;
					pthread_join(pParms->thread, NULL);
				}

				ereport(FATAL,
						(errcode(ERRCODE_INTERNAL_ERROR),
						 errmsg("could not create thread %d of %d", i + 1, newThreads),
						 errdetail ("pthread_create() failed with err %d", pthread_err)));
			}
		}

	}

	ds->dispatchThreads->threadCount += newThreads;
	elog(DEBUG4, "dispatchToGang: Total threads now %d",
		 ds->dispatchThreads->threadCount);
}