static void thread_DispatchOut(DispatchCommandParms * pParms) { CdbDispatchResult *dispatchResult; int i, db_count = pParms->db_count; /* * The pParms contains an array of SegmentDatabaseDescriptors * to send commands through to. */ for (i = 0; i < db_count; i++) { dispatchResult = pParms->dispatchResultPtrArray[i]; /* * Don't use elog, it's not thread-safe */ if (DEBUG5 >= log_min_messages) { if (dispatchResult->segdbDesc->conn) { write_log ("thread_DispatchCommand working on %d of %d commands. asyncStatus %d", i + 1, db_count, dispatchResult->segdbDesc->conn->asyncStatus); } } dispatchResult->hasDispatched = false; dispatchResult->sentSignal = DISPATCH_WAIT_NONE; dispatchResult->wasCanceled = false; if (!shouldStillDispatchCommand(pParms, dispatchResult)) { /* * Don't dispatch if cancellation pending or no connection. */ dispatchResult->stillRunning = false; if (PQisBusy(dispatchResult->segdbDesc->conn)) write_log (" We thought we were done, because !shouldStillDispatchCommand(), but libpq says we are still busy"); if (PQstatus(dispatchResult->segdbDesc->conn) == CONNECTION_BAD) write_log (" We thought we were done, because !shouldStillDispatchCommand(), but libpq says the connection died?"); } else { /* * Kick off the command over the libpq connection. * * If unsuccessful, proceed anyway, and check for lost connection below. */ if (PQisBusy(dispatchResult->segdbDesc->conn)) { write_log ("Trying to send to busy connection %s %d %d asyncStatus %d", dispatchResult->segdbDesc->whoami, i, db_count, dispatchResult->segdbDesc->conn->asyncStatus); } if (PQstatus(dispatchResult->segdbDesc->conn) == CONNECTION_BAD) { char *msg; msg = PQerrorMessage(dispatchResult->segdbDesc->conn); write_log ("Dispatcher noticed a problem before query transmit: %s (%s)", msg ? msg : "unknown error", dispatchResult->segdbDesc->whoami); /* * Save error info for later. */ cdbdisp_appendMessage(dispatchResult, LOG, ERRCODE_GP_INTERCONNECTION_ERROR, "Error before transmit from %s: %s", dispatchResult->segdbDesc->whoami, msg ? msg : "unknown error"); PQfinish(dispatchResult->segdbDesc->conn); dispatchResult->segdbDesc->conn = NULL; dispatchResult->stillRunning = false; continue; } #ifdef USE_NONBLOCKING /* * In 2000, Tom Lane said: * "I believe that the nonblocking-mode code is pretty buggy, and don't * recommend using it unless you really need it and want to help debug * it.." * * Reading through the code, I'm not convinced the situation has * improved in 2007... I still see some very questionable things * about nonblocking mode, so for now, I'm disabling it. */ PQsetnonblocking(dispatchResult->segdbDesc->conn, TRUE); #endif dispatchCommand(dispatchResult, pParms->query_text, pParms->query_text_len); } } #ifdef USE_NONBLOCKING /* * Is everything sent? Well, if the network stack was too busy, and we are using * nonblocking mode, some of the sends * might not have completed. We can't use SELECT to wait unless they have * received their work, or we will wait forever. Make sure they do. */ { bool allsent = true; /* * debug loop to check to see if this really is needed */ for (i = 0; i < db_count; i++) { dispatchResult = pParms->dispatchResultPtrArray[i]; if (!dispatchResult->stillRunning || !dispatchResult->hasDispatched) continue; if (PQstatus(dispatchResult->segdbDesc->conn) == CONNECTION_BAD) continue; if (dispatchResult->segdbDesc->conn->outCount > 0) { write_log("Yes, extra flushing is necessary %d", i); break; } } /* * Check to see if any needed extra flushing. */ for (i = 0; i < db_count; i++) { int flushResult; dispatchResult = pParms->dispatchResultPtrArray[i]; if (!dispatchResult->stillRunning || !dispatchResult->hasDispatched) continue; if (PQstatus(dispatchResult->segdbDesc->conn) == CONNECTION_BAD) continue; /* * If data remains unsent, send it. Else we might be waiting for the * result of a command the backend hasn't even got yet. */ flushResult = PQflush(dispatchResult->segdbDesc->conn); /* * First time, go through the loop without waiting if we can't * flush, in case we are using multiple network adapters, and * other connections might be able to flush */ if (flushResult > 0) { allsent = false; write_log("flushing didn't finish the work %d", i); } } /* * our first attempt at doing more flushes didn't get everything out, * so we need to continue to try. */ for (i = 0; i < db_count; i++) { dispatchResult = pParms->dispatchResultPtrArray[i]; while (PQisnonblocking(dispatchResult->segdbDesc->conn)) { PQflush(dispatchResult->segdbDesc->conn); PQsetnonblocking(dispatchResult->segdbDesc->conn, FALSE); } } } #endif }
/******************************************************************************** * Returns the blocking status of the database connection int PQisnonblocking(const PGconn *conn) Returns TRUE if the connection is set to non-blocking mode, FALSE if blocking. ********************************************************************************/ int dbi_isnonblocking(const DBI_conn *conn) { return PQisnonblocking(conn); }