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