예제 #1
0
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
}
예제 #2
0
/********************************************************************************
 * 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);
}