*** a/src/backend/replication/syncrep.c --- b/src/backend/replication/syncrep.c *************** *** 164,183 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) case SYNC_REP_WAITING: /* - * Check for conditions that would cause us to leave the - * wait state before the LSN has been reached. - */ - if (!PostmasterIsAlive(true)) - { - LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); - SHMQueueDelete(&(MyProc->syncRepLinks)); - LWLockRelease(SyncRepLock); - - MyProc->syncRepState = SYNC_REP_MUST_DISCONNECT; - return; - } - - /* * We don't receive SIGHUPs at this point, so resetting * synchronous_standby_names has no effect on waiters. */ --- 164,169 ---- *************** *** 191,216 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) * WalSender has checked our LSN and has removed us from * queue. Cleanup local state and leave. */ - Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks))); - MyProc->syncRepState = SYNC_REP_NOT_WAITING; ! MyProc->waitLSN.xlogid = 0; ! MyProc->waitLSN.xrecoff = 0; ! ! if (new_status) ! { ! /* Reset ps display */ ! set_ps_display(new_status, false); ! pfree(new_status); ! } ! ! return; case SYNC_REP_MUST_DISCONNECT: return; default: ! elog(FATAL, "invalid syncRepState"); } /* --- 177,212 ---- * WalSender has checked our LSN and has removed us from * queue. Cleanup local state and leave. */ MyProc->syncRepState = SYNC_REP_NOT_WAITING; ! goto cleanup; case SYNC_REP_MUST_DISCONNECT: return; default: ! /* ! * Just close the connection without returning anything ! * to the client instead of throwing ERROR/FATAL error ! * since it's not allowed while in COMMIT state. ! */ ! elog(WARNING, "invalid syncRepState"); ! goto disconnect; ! } ! ! /* ! * Check for conditions that would cause us to leave the ! * wait state before the LSN has been reached. ! */ ! if (!PostmasterIsAlive(true) || ProcDiePending) ! { ! if (ProcDiePending) ! ereport(LOG, ! (errcode(ERRCODE_ADMIN_SHUTDOWN), ! errmsg("canceling the wait for replication and terminating " ! "connection due to administrator command"), ! errdetail("The transaction has already been committed locally " ! "but might have not been replicated to the standby."))); ! goto disconnect; } /* *************** *** 220,225 **** SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) --- 216,241 ---- */ WaitLatch(&MyProc->waitLatch, 60000000L); } + + disconnect: + LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); + SHMQueueDelete(&(MyProc->syncRepLinks)); + LWLockRelease(SyncRepLock); + + MyProc->syncRepState = SYNC_REP_MUST_DISCONNECT; + + cleanup: + Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks))); + + MyProc->waitLSN.xlogid = 0; + MyProc->waitLSN.xrecoff = 0; + + if (new_status) + { + /* Reset ps display */ + set_ps_display(new_status, false); + pfree(new_status); + } } /* *** a/src/backend/tcop/dest.c --- b/src/backend/tcop/dest.c *************** *** 36,41 **** --- 36,45 ---- #include "executor/tstoreReceiver.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" + #include "miscadmin.h" + #include "replication/syncrep.h" + #include "storage/ipc.h" + #include "tcop/tcopprot.h" #include "utils/portal.h" *************** *** 144,149 **** EndCommand(const char *commandTag, CommandDest dest) --- 148,171 ---- case DestRemoteExecute: /* + * If we receive SIGTERM while we are waiting for synchronous + * replication, we close the connection before returning the + * "success" indication to the client. This prevents the client + * from thinking that the transaction which might have not been + * replicated yet has been committed and visible in the standby. + */ + if (MyProc->syncRepState == SYNC_REP_MUST_DISCONNECT) + { + /* + * Reset whereToSendOutput to prevent ereport from + * attempting to send any more messages to client. + */ + whereToSendOutput = DestNone; + + proc_exit(0); + } + + /* * We assume the commandTag is plain ASCII and therefore requires * no encoding conversion. */ *** a/src/backend/tcop/postgres.c --- b/src/backend/tcop/postgres.c *************** *** 2643,2648 **** die(SIGNAL_ARGS) --- 2643,2651 ---- InterruptHoldoffCount--; ProcessInterrupts(); } + + /* Wake up myself waiting on the latch */ + SetLatch(&(MyProc->waitLatch)); } errno = save_errno;