/* * NonThread version of cdbdisp_appendMessage. * * It's safe to use palloc/pfree or elog/ereport. */ void cdbdisp_appendMessageNonThread(CdbDispatchResult * dispatchResult, int elevel, const char *fmt, ...) { va_list args; int msgoff; /* * Remember first error. */ cdbdisp_seterrcode(ERRCODE_GP_INTERCONNECTION_ERROR, -1, dispatchResult); /* * Allocate buffer if first message. * Insert newline between previous message and new one. */ Assert(dispatchResult->error_message != NULL); oneTrailingNewlinePQ(dispatchResult->error_message); msgoff = dispatchResult->error_message->len; /* * Format the message and append it to the buffer. */ va_start(args, fmt); appendPQExpBufferVA(dispatchResult->error_message, fmt, args); va_end(args); /* * Display the message on stderr for debugging, if requested. * This helps to clarify the actual timing of threaded events. */ if (elevel >= log_min_messages) { oneTrailingNewlinePQ(dispatchResult->error_message); elog(LOG, "%s", dispatchResult->error_message->data + msgoff); } /* * In case the caller wants to hand the buffer to ereport(), * follow the ereport() convention of not ending with a newline. */ noTrailingNewlinePQ(dispatchResult->error_message); }
static bool processResults(CdbDispatchResult * dispatchResult) { SegmentDatabaseDescriptor *segdbDesc = dispatchResult->segdbDesc; char *msg; int rc; /* * PQisBusy() has side-effects */ if (DEBUG5 >= log_min_messages) { write_log("processResults. isBusy = %d", PQisBusy(segdbDesc->conn)); if (PQstatus(segdbDesc->conn) == CONNECTION_BAD) goto connection_error; } /* * Receive input from QE. */ rc = PQconsumeInput(segdbDesc->conn); /* * If PQconsumeInput fails, we're hosed. */ if (rc == 0) { /* handle PQconsumeInput error */ goto connection_error; } /* * PQisBusy() has side-effects */ if (DEBUG4 >= log_min_messages && PQisBusy(segdbDesc->conn)) write_log("PQisBusy"); /* * If we have received one or more complete messages, process them. */ while (!PQisBusy(segdbDesc->conn)) { /* loop to call PQgetResult; won't block */ PGresult *pRes; ExecStatusType resultStatus; int resultIndex; /* * PQisBusy() does some error handling, which can * cause the connection to die -- we can't just continue on as * if the connection is happy without checking first. * * For example, cdbdisp_numPGresult() will return a completely * bogus value! */ if (PQstatus(segdbDesc->conn) == CONNECTION_BAD || segdbDesc->conn->sock == -1) { goto connection_error; } resultIndex = cdbdisp_numPGresult(dispatchResult); if (DEBUG4 >= log_min_messages) write_log("PQgetResult"); /* * Get one message. */ pRes = PQgetResult(segdbDesc->conn); CollectQEWriterTransactionInformation(segdbDesc, dispatchResult); /* * Command is complete when PGgetResult() returns NULL. It is critical * that for any connection that had an asynchronous command sent thru * it, we call PQgetResult until it returns NULL. Otherwise, the next * time a command is sent to that connection, it will return an error * that there's a command pending. */ if (!pRes) { if (DEBUG4 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ write_log("%s -> idle", segdbDesc->whoami); } /* this is normal end of command */ return true; } /* end of results */ /* * Attach the PGresult object to the CdbDispatchResult object. */ cdbdisp_appendResult(dispatchResult, pRes); /* * Did a command complete successfully? */ resultStatus = PQresultStatus(pRes); if (resultStatus == PGRES_COMMAND_OK || resultStatus == PGRES_TUPLES_OK || resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT) { /* * Save the index of the last successful PGresult. Can be given to * cdbdisp_getPGresult() to get tuple count, etc. */ dispatchResult->okindex = resultIndex; if (DEBUG3 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ char *cmdStatus = PQcmdStatus(pRes); write_log("%s -> ok %s", segdbDesc->whoami, cmdStatus ? cmdStatus : "(no cmdStatus)"); } /* * SREH - get number of rows rejected from QE if any */ if (pRes->numRejected > 0) dispatchResult->numrowsrejected += pRes->numRejected; if (resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT) return true; } /* * Note QE error. Cancel the whole statement if requested. */ else { /* QE reported an error */ char *sqlstate = PQresultErrorField(pRes, PG_DIAG_SQLSTATE); int errcode = 0; msg = PQresultErrorMessage(pRes); if (DEBUG2 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ write_log("%s -> %s %s %s", segdbDesc->whoami, PQresStatus(resultStatus), sqlstate ? sqlstate : "(no SQLSTATE)", msg ? msg : ""); } /* * Convert SQLSTATE to an error code (ERRCODE_xxx). Use a generic * nonzero error code if no SQLSTATE. */ if (sqlstate && strlen(sqlstate) == 5) errcode = sqlstate_to_errcode(sqlstate); /* * Save first error code and the index of its PGresult buffer * entry. */ cdbdisp_seterrcode(errcode, resultIndex, dispatchResult); } } return false; /* we must keep on monitoring this socket */ connection_error: msg = PQerrorMessage(segdbDesc->conn); if (msg) write_log("Dispatcher encountered connection error on %s: %s", segdbDesc->whoami, msg); /* * Save error info for later. */ cdbdisp_appendMessage(dispatchResult, LOG, ERRCODE_GP_INTERCONNECTION_ERROR, "Error on receive from %s: %s", segdbDesc->whoami, msg ? msg : "unknown error"); /* * Can't recover, so drop the connection. */ PQfinish(segdbDesc->conn); segdbDesc->conn = NULL; dispatchResult->stillRunning = false; return true; /* connection is gone! */ }
static void thread_DispatchWaitSingle(DispatchCommandParms * pParms) { SegmentDatabaseDescriptor *segdbDesc; CdbDispatchResult *dispatchResult; char *msg = NULL; /* * Assert() cannot be used in threads */ if (pParms->db_count != 1) write_log("Bug... thread_dispatchWaitSingle called with db_count %d", pParms->db_count); dispatchResult = pParms->dispatchResultPtrArray[0]; segdbDesc = dispatchResult->segdbDesc; if (PQstatus(segdbDesc->conn) == CONNECTION_BAD) { msg = PQerrorMessage(segdbDesc->conn); /* * Save error info for later. */ cdbdisp_appendMessage(dispatchResult, DEBUG1, ERRCODE_GP_INTERCONNECTION_ERROR, "Lost connection to %s. %s", segdbDesc->whoami, msg ? msg : ""); /* * Free the PGconn object. */ PQfinish(segdbDesc->conn); segdbDesc->conn = NULL; dispatchResult->stillRunning = false; } else { PQsetnonblocking(segdbDesc->conn, FALSE); for (;;) { PGresult *pRes; ExecStatusType resultStatus; int resultIndex = cdbdisp_numPGresult(dispatchResult); if (DEBUG4 >= log_min_messages) write_log("PQgetResult, resultIndex = %d", resultIndex); /* * Get one message. */ pRes = PQgetResult(segdbDesc->conn); CollectQEWriterTransactionInformation(segdbDesc, dispatchResult); /* * Command is complete when PGgetResult() returns NULL. It is critical * that for any connection that had an asynchronous command sent thru * it, we call PQgetResult until it returns NULL. Otherwise, the next * time a command is sent to that connection, it will return an error * that there's a command pending. */ if (!pRes) { if (DEBUG4 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ write_log("%s -> idle", segdbDesc->whoami); } break; } /* * Attach the PGresult object to the CdbDispatchResult object. */ cdbdisp_appendResult(dispatchResult, pRes); /* * Did a command complete successfully? */ resultStatus = PQresultStatus(pRes); if (resultStatus == PGRES_COMMAND_OK || resultStatus == PGRES_TUPLES_OK || resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT) { /* * Save the index of the last successful PGresult. Can be given to * cdbdisp_getPGresult() to get tuple count, etc. */ dispatchResult->okindex = resultIndex; if (DEBUG3 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ char *cmdStatus = PQcmdStatus(pRes); write_log("%s -> ok %s", segdbDesc->whoami, cmdStatus ? cmdStatus : "(no cmdStatus)"); } if (resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT) return; } /* * Note QE error. Cancel the whole statement if requested. */ else { char *sqlstate = PQresultErrorField(pRes, PG_DIAG_SQLSTATE); int errcode = 0; msg = PQresultErrorMessage(pRes); if (DEBUG2 >= log_min_messages) { /* * Don't use elog, it's not thread-safe */ write_log("%s -> %s %s %s", segdbDesc->whoami, PQresStatus(resultStatus), sqlstate ? sqlstate : "(no SQLSTATE)", msg ? msg : ""); } /* * Convert SQLSTATE to an error code (ERRCODE_xxx). Use a generic * nonzero error code if no SQLSTATE. */ if (sqlstate && strlen(sqlstate) == 5) errcode = sqlstate_to_errcode(sqlstate); /* * Save first error code and the index of its PGresult buffer * entry. */ cdbdisp_seterrcode(errcode, resultIndex, dispatchResult); } } if (DEBUG4 >= log_min_messages) write_log("processResultsSingle says we are finished with : %s", segdbDesc->whoami); dispatchResult->stillRunning = false; if (DEBUG1 >= log_min_messages) { char msec_str[32]; switch (check_log_duration(msec_str, false)) { case 1: case 2: write_log ("duration to dispatch result received from thread (seg %d): %s ms", dispatchResult->segdbDesc->segindex, msec_str); break; } } if (PQisBusy(dispatchResult->segdbDesc->conn)) write_log ("We thought we were done, because finished==true, but libpq says we are still busy"); } }
/* * Receive and process input from one QE. * * Return true if all input are consumed or the connection went wrong. * Return false if there'er still more data expected. */ static bool processResults(CdbDispatchResult * dispatchResult) { SegmentDatabaseDescriptor *segdbDesc = dispatchResult->segdbDesc; char *msg; /* * Receive input from QE. */ if (PQconsumeInput(segdbDesc->conn) == 0) { msg = PQerrorMessage(segdbDesc->conn); cdbdisp_appendMessageNonThread(dispatchResult, LOG, "Error on receive from %s: %s", segdbDesc->whoami, msg ? msg : "unknown error"); return true; } /* * If we have received one or more complete messages, process them. */ while (!PQisBusy(segdbDesc->conn)) { /* loop to call PQgetResult; won't block */ PGresult *pRes; ExecStatusType resultStatus; int resultIndex; /* * PQisBusy() does some error handling, which can * cause the connection to die -- we can't just continue on as * if the connection is happy without checking first. * * For example, cdbdisp_numPGresult() will return a completely * bogus value! */ if (cdbconn_isBadConnection(segdbDesc)) { msg = PQerrorMessage(segdbDesc->conn); cdbdisp_appendMessageNonThread(dispatchResult, LOG, "Connection lost when receiving from %s: %s", segdbDesc->whoami, msg ? msg : "unknown error"); return true; } /* * Get one message. */ ELOG_DISPATCHER_DEBUG("PQgetResult"); pRes = PQgetResult(segdbDesc->conn); /* * Command is complete when PGgetResult() returns NULL. It is critical * that for any connection that had an asynchronous command sent thru * it, we call PQgetResult until it returns NULL. Otherwise, the next * time a command is sent to that connection, it will return an error * that there's a command pending. */ if (!pRes) { ELOG_DISPATCHER_DEBUG("%s -> idle", segdbDesc->whoami); /* this is normal end of command */ return true; } /* * Attach the PGresult object to the CdbDispatchResult object. */ resultIndex = cdbdisp_numPGresult(dispatchResult); cdbdisp_appendResult(dispatchResult, pRes); /* * Did a command complete successfully? */ resultStatus = PQresultStatus(pRes); if (resultStatus == PGRES_COMMAND_OK || resultStatus == PGRES_TUPLES_OK || resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT || resultStatus == PGRES_EMPTY_QUERY) { ELOG_DISPATCHER_DEBUG("%s -> ok %s", segdbDesc->whoami, PQcmdStatus(pRes) ? PQcmdStatus(pRes) : "(no cmdStatus)"); if (resultStatus == PGRES_EMPTY_QUERY) ELOG_DISPATCHER_DEBUG("QE received empty query."); /* * Save the index of the last successful PGresult. Can be given to * cdbdisp_getPGresult() to get tuple count, etc. */ dispatchResult->okindex = resultIndex; /* * SREH - get number of rows rejected from QE if any */ if (pRes->numRejected > 0) dispatchResult->numrowsrejected += pRes->numRejected; if (resultStatus == PGRES_COPY_IN || resultStatus == PGRES_COPY_OUT) return true; } /* * Note QE error. Cancel the whole statement if requested. */ else { /* QE reported an error */ char *sqlstate = PQresultErrorField(pRes, PG_DIAG_SQLSTATE); int errcode = 0; msg = PQresultErrorMessage(pRes); ELOG_DISPATCHER_DEBUG("%s -> %s %s %s", segdbDesc->whoami, PQresStatus(resultStatus), sqlstate ? sqlstate : "(no SQLSTATE)", msg); /* * Convert SQLSTATE to an error code (ERRCODE_xxx). Use a generic * nonzero error code if no SQLSTATE. */ if (sqlstate && strlen(sqlstate) == 5) errcode = sqlstate_to_errcode(sqlstate); /* * Save first error code and the index of its PGresult buffer * entry. */ cdbdisp_seterrcode(errcode, resultIndex, dispatchResult); } } return false; /* we must keep on monitoring this socket */ }