Example #1
0
File: fe-misc.c Project: LJoNe/gpdb
/*
 * pqPutMsgEnd: finish constructing a message and possibly send it
 *
 * Returns 0 on success, EOF on error
 *
 * We don't actually send anything here unless we've accumulated at least
 * 8K worth of data (the typical size of a pipe buffer on Unix systems).
 * This avoids sending small partial packets.  The caller must use pqFlush
 * when it's important to flush all the data out to the server.
 */
int
pqPutMsgEnd(PGconn *conn)
{
	pqPutMsgEndNoAutoFlush(conn);

	if (conn->outCount >= 8192)
	{
		int			toSend = conn->outCount - (conn->outCount % 8192);

		if (pqSendSome(conn, toSend) < 0)
			return EOF;
		/* in nonblock mode, don't complain if unable to send it all */
	}

	return 0;
}
/*
 *
 *
 * Control Message has msg_type='C'.
 * Control Message is consumed by Receiver thread on mirror side.
 *
 * Data Message has msg_type='M'.
 * Data Message is inserted in Shared memory and consumed by Consumer
 * thread on mirror side.
 */
bool
FileRepConnClient_SendMessage(
							  FileRepConsumerProcIndex_e messageType,
							  bool messageSynchronous,
							  char *message,
							  uint32 messageLength)
{
	char		msgType = 0;
	int			status = STATUS_OK;

#ifdef USE_ASSERT_CHECKING
	int			prevOutCount = filerep_conn->outCount;
#endif							/* // USE_ASSERT_CHECKING */

	switch (messageType)
	{
		case FileRepMessageTypeXLog:
			msgType = '1';
			break;
		case FileRepMessageTypeAO01:
			msgType = '2';
			break;
		case FileRepMessageTypeWriter:
			msgType = '3';
			break;
		case FileRepMessageTypeShutdown:
			msgType = 'S';
			break;
		default:
			return false;
	}

	/**
	 * Note that pqPutMsgStart and pqPutnchar both may grow the connection's internal buffer, and do not
	 *   flush data
	 */
	if (pqPutMsgStart(msgType, true, filerep_conn) < 0)
	{
		return false;
	}

	if (pqPutnchar(message, messageLength, filerep_conn) < 0)
	{
		return false;
	}

	/*
	 * Server side needs complete messages for mode-transitions so disable
	 * auto-flush since it flushes partial messages
	 */
	pqPutMsgEndNoAutoFlush(filerep_conn);

	/* assert that a flush did not occur */
	Assert(prevOutCount + messageLength + 5 == filerep_conn->outCount); /* the +5 is the amount
																		 * added by
																		 * pgPutMsgStart */

	/*
	 * note also that we could do a flush beforehand to avoid having
	 * pqPutMsgStart and pqPutnchar growing the buffer
	 */
	if (messageSynchronous || filerep_conn->outCount >= file_rep_min_data_before_flush)
	{
		int			result = 0;

		/* wait and timeout will be handled by pqWaitTimeout */
		while ((status = pqFlushNonBlocking(filerep_conn)) > 0)
		{
			/* retry on timeout */
			while (!(result = pqWaitTimeout(FALSE, TRUE, filerep_conn, time(NULL) + file_rep_socket_timeout)))
			{
				if (FileRepSubProcess_IsStateTransitionRequested())
				{
					elog(WARNING, "segment state transition requested while waiting to write data to socket");
					status = -1;
					break;
				}
			}

			if (result < 0)
			{
				ereport(WARNING,
						(errcode_for_socket_access(),
						 errmsg("could not write data to socket, failure detected : %m")));
				status = -1;
				break;
			}

			if (status == -1)
			{
				break;
			}
		}

		if (status < 0)
		{
			return false;
		}
		Assert(status == 0);
		return true;
	}

	return true;
}