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