static PyObject * spt_getproctitle(PyObject *self /* Not used */, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; int tlen; const char *title; title = get_ps_display(&tlen); return Py_BuildValue("s#", title, tlen); }
/* * Wait for synchronous replication, if requested by user. * * Initially backends start in state SYNC_REP_NOT_WAITING and then * change that state to SYNC_REP_WAITING before adding ourselves * to the wait queue. During SyncRepWakeQueue() a WALSender changes * the state to SYNC_REP_WAIT_COMPLETE once replication is confirmed. * This backend then resets its state to SYNC_REP_NOT_WAITING. */ void SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) { char *new_status = NULL; const char *old_status; /* * Fast exit if user has not requested sync replication, or * there are no sync replication standby names defined. * Note that those standbys don't need to be connected. */ if (!SyncRepRequested() || !SyncStandbysDefined()) return; Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks))); Assert(WalSndCtl != NULL); /* Reset the latch before adding ourselves to the queue. */ ResetLatch(&MyProc->waitLatch); /* * Set our waitLSN so WALSender will know when to wake us, and add * ourselves to the queue. */ LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); Assert(MyProc->syncRepState == SYNC_REP_NOT_WAITING); if (!WalSndCtl->sync_standbys_defined) { /* * We don't wait for sync rep if WalSndCtl->sync_standbys_defined is * not set. See SyncRepUpdateSyncStandbysDefined. */ LWLockRelease(SyncRepLock); return; } MyProc->waitLSN = XactCommitLSN; MyProc->syncRepState = SYNC_REP_WAITING; SyncRepQueueInsert(); Assert(SyncRepQueueIsOrderedByLSN()); LWLockRelease(SyncRepLock); /* Alter ps display to show waiting for sync rep. */ if (update_process_title) { int len; old_status = get_ps_display(&len); new_status = (char *) palloc(len + 32 + 1); memcpy(new_status, old_status, len); sprintf(new_status + len, " waiting for %X/%X", XactCommitLSN.xlogid, XactCommitLSN.xrecoff); set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting ..." */ } /* * Wait for specified LSN to be confirmed. * * Each proc has its own wait latch, so we perform a normal latch * check/wait loop here. */ for (;;) { int syncRepState; /* * Wait on latch for up to 60 seconds. This allows us to * check for postmaster death regularly while waiting. * Note that timeout here does not necessarily release from loop. */ WaitLatch(&MyProc->waitLatch, 60000000L); /* Must reset the latch before testing state. */ ResetLatch(&MyProc->waitLatch); /* * Try checking the state without the lock first. There's no guarantee * that we'll read the most up-to-date value, so if it looks like we're * still waiting, recheck while holding the lock. But if it looks like * we're done, we must really be done, because once walsender changes * the state to SYNC_REP_WAIT_COMPLETE, it will never update it again, * so we can't be seeing a stale value in that case. */ syncRepState = MyProc->syncRepState; if (syncRepState == SYNC_REP_WAITING) { LWLockAcquire(SyncRepLock, LW_SHARED); syncRepState = MyProc->syncRepState; LWLockRelease(SyncRepLock); } if (syncRepState == SYNC_REP_WAIT_COMPLETE) break; /* * If a wait for synchronous replication is pending, we can neither * acknowledge the commit nor raise ERROR or FATAL. The latter * would lead the client to believe that that the transaction * aborted, which is not true: it's already committed locally. * The former is no good either: the client has requested * synchronous replication, and is entitled to assume that an * acknowledged commit is also replicated, which may not be true. * So in this case we issue a WARNING (which some clients may * be able to interpret) and shut off further output. We do NOT * reset ProcDiePending, so that the process will die after the * commit is cleaned up. */ if (ProcDiePending) { ereport(WARNING, (errcode(ERRCODE_ADMIN_SHUTDOWN), errmsg("canceling the wait for synchronous replication and terminating connection due to administrator command"), errdetail("The transaction has already committed locally, but may not have been replicated to the standby."))); whereToSendOutput = DestNone; SyncRepCancelWait(); break; } /* * It's unclear what to do if a query cancel interrupt arrives. We * can't actually abort at this point, but ignoring the interrupt * altogether is not helpful, so we just terminate the wait with * a suitable warning. */ if (QueryCancelPending) { QueryCancelPending = false; ereport(WARNING, (errmsg("canceling wait for synchronous replication due to user request"), errdetail("The transaction has already committed locally, but may not have been replicated to the standby."))); SyncRepCancelWait(); break; } /* * If the postmaster dies, we'll probably never get an acknowledgement, * because all the wal sender processes will exit. So just bail out. */ if (!PostmasterIsAlive(true)) { ProcDiePending = true; whereToSendOutput = DestNone; SyncRepCancelWait(); break; } } /* * WalSender has checked our LSN and has removed us from queue. Clean up * state and leave. It's OK to reset these shared memory fields without * holding SyncRepLock, because any walsenders will ignore us anyway when * we're not on the queue. */ 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); } }
/* * This is the main executioner for any query backend that conflicts with * recovery processing. Judgement has already been passed on it within * a specific rmgr. Here we just issue the orders to the procs. The procs * then throw the required error as instructed. */ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason) { TimestampTz waitStart; char *new_status; /* Fast exit, to avoid a kernel call if there's no work to be done. */ if (!VirtualTransactionIdIsValid(*waitlist)) return; waitStart = GetCurrentTimestamp(); new_status = NULL; /* we haven't changed the ps display */ while (VirtualTransactionIdIsValid(*waitlist)) { /* reset standbyWait_us for each xact we wait for */ standbyWait_us = STANDBY_INITIAL_WAIT_US; /* wait until the virtual xid is gone */ while (!ConditionalVirtualXactLockTableWait(*waitlist)) { /* * Report via ps if we have been waiting for more than 500 msec * (should that be configurable?) */ if (update_process_title && new_status == NULL && TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(), 500)) { const char *old_status; int len; old_status = get_ps_display(&len); new_status = (char *) palloc(len + 8 + 1); memcpy(new_status, old_status, len); strcpy(new_status + len, " waiting"); set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting" */ } /* Is it time to kill it? */ if (WaitExceedsMaxStandbyDelay()) { pid_t pid; /* * Now find out who to throw out of the balloon. */ Assert(VirtualTransactionIdIsValid(*waitlist)); pid = CancelVirtualTransaction(*waitlist, reason); /* * Wait a little bit for it to die so that we avoid flooding * an unresponsive backend when system is heavily loaded. */ if (pid != 0) pg_usleep(5000L); } } /* The virtual transaction is gone now, wait for the next one */ waitlist++; } /* Reset ps display if we changed it */ if (new_status) { set_ps_display(new_status, false); pfree(new_status); } }
/* * redis_log_hook * Hook for shipping log events to Redis * (based on jsonlog.c) */ static void redis_log_hook(ErrorData *edata) { StringInfoData buf; TransactionId txid = GetTopTransactionIdIfAny(); bool print_stmt = false; bool send_status = false; /* static counter for line numbers */ static long log_line_number = 0; /* * This is one of the few places where we'd rather not inherit a static * variable's value from the postmaster. But since we will, reset it when * MyProcPid changes. */ if (lastPid != MyProcPid) { log_line_number = 0; lastPid = MyProcPid; formatted_start_time[0] = '\0'; redis_close_connection(); } /* * Check if the log has to be written, if not just exit. */ if (!is_log_level_output(edata->elevel, Redislog_min_messages)) { goto quickExit; } log_line_number++; initStringInfo(&buf); /* Initialize string */ appendStringInfoChar(&buf, '{'); /* Timestamp */ setup_formatted_log_time(); append_json_literal(&buf, "@timestamp", formatted_log_time, true); /* Username */ if (MyProcPort) append_json_literal(&buf, "user_name", MyProcPort->user_name, true); /* Database name */ if (MyProcPort) append_json_literal(&buf, "database_name", MyProcPort->database_name, true); /* Process ID */ if (MyProcPid != 0) appendStringInfo(&buf, "\"process_id\":%d,", MyProcPid); /* Remote host and port */ if (MyProcPort && MyProcPort->remote_host) { append_json_literal(&buf, "remote_host", MyProcPort->remote_host, true); if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0') append_json_literal(&buf, "remote_port", MyProcPort->remote_port, true); } /* Session id */ if (MyProcPid != 0) appendStringInfo(&buf, "\"session_id\":\"%lx.%x\",", (long) MyStartTime, MyProcPid); /* Process ID */ if (MyProcPid != 0) appendStringInfo(&buf, "\"session_line_num\":%ld,", log_line_number); /* PS display */ if (MyProcPort) { StringInfoData msgbuf; const char *psdisp; int displen; initStringInfo(&msgbuf); psdisp = get_ps_display(&displen); appendBinaryStringInfo(&msgbuf, psdisp, displen); append_json_literal(&buf, "command_tag", msgbuf.data, true); pfree(msgbuf.data); } /* session start timestamp */ if (formatted_start_time[0] == '\0') setup_formatted_start_time(); append_json_literal(&buf, "session_start_time", formatted_start_time, true); /* Virtual transaction id */ /* keep VXID format in sync with lockfuncs.c */ if (MyProc != NULL && MyProc->backendId != InvalidBackendId) appendStringInfo(&buf, "\"virtual_transaction_id\":\"%d/%u\",", MyProc->backendId, MyProc->lxid); /* Transaction id */ if (txid != InvalidTransactionId) appendStringInfo(&buf, "\"transaction_id\":%u,", GetTopTransactionIdIfAny()); /* Error severity */ append_json_literal(&buf, "error_severity", (char *) error_severity(edata->elevel), true); /* SQL state code */ if (edata->sqlerrcode != ERRCODE_SUCCESSFUL_COMPLETION) append_json_literal(&buf, "sql_state_code", unpack_sql_state(edata->sqlerrcode), true); /* Error detail or Error detail log */ if (edata->detail_log) append_json_literal(&buf, "detail_log", edata->detail_log, true); else if (edata->detail) append_json_literal(&buf, "detail", edata->detail, true); /* Error hint */ if (edata->hint) append_json_literal(&buf, "hint", edata->hint, true); /* Internal query */ if (edata->internalquery) append_json_literal(&buf, "internal_query", edata->internalquery, true); /* if printed internal query, print internal pos too */ if (edata->internalpos > 0 && edata->internalquery != NULL) appendStringInfo(&buf, "\"internal_query_pos\":%d,", edata->internalpos); /* Error context */ if (edata->context) append_json_literal(&buf, "context", edata->context, true); /* user query --- only reported if not disabled by the caller */ if (is_log_level_output(edata->elevel, Redislog_min_error_statement) && debug_query_string != NULL && !edata->hide_stmt) print_stmt = true; if (print_stmt) append_json_literal(&buf, "query", debug_query_string, true); /* user query position -- only reposted if not disabled by the caller */ if (print_stmt && edata->cursorpos > 0) appendStringInfo(&buf, "\"query_pos\":%d,", edata->cursorpos); /* File error location */ if (Log_error_verbosity >= PGERROR_VERBOSE) { StringInfoData msgbuf; initStringInfo(&msgbuf); if (edata->funcname && edata->filename) appendStringInfo(&msgbuf, "%s, %s:%d", edata->funcname, edata->filename, edata->lineno); else if (edata->filename) appendStringInfo(&msgbuf, "%s:%d", edata->filename, edata->lineno); append_json_literal(&buf, "file_location", msgbuf.data, true); pfree(msgbuf.data); } /* Application name */ if (application_name && application_name[0] != '\0') append_json_literal(&buf, "application_name", application_name, true); /* Error message */ append_json_literal(&buf, "message", edata->message, false); /* Finish string */ appendStringInfoChar(&buf, '}'); appendStringInfoChar(&buf, '\n'); /* Send the data to Redis */ send_status = redis_log_shipper(buf.data, buf.len); /* Skip sending the event to the server, if it was correctly * shipped to Redis and if 'ship_to_redis_only' is set to true */ if (Redislog_ship_to_redis_only && send_status) { edata->output_to_server = false; } /* Cleanup */ pfree(buf.data); quickExit: /* Continue chain to previous hook */ if (prev_log_hook) (*prev_log_hook) (edata); }
/* * Wait for synchronous replication, if requested by user. * * Initially backends start in state SYNC_REP_NOT_WAITING and then * change that state to SYNC_REP_WAITING before adding ourselves * to the wait queue. During SyncRepWakeQueue() a WALSender changes * the state to SYNC_REP_WAIT_COMPLETE once replication is confirmed. * This backend then resets its state to SYNC_REP_NOT_WAITING. */ void SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) { char *new_status = NULL; const char *old_status; int mode = SyncRepWaitMode; /* * Fast exit if user has not requested sync replication, or there are no * sync replication standby names defined. Note that those standbys don't * need to be connected. */ if (!SyncRepRequested() || !SyncStandbysDefined()) return; Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks))); Assert(WalSndCtl != NULL); LWLockAcquire(SyncRepLock, LW_EXCLUSIVE); Assert(MyProc->syncRepState == SYNC_REP_NOT_WAITING); /* * We don't wait for sync rep if WalSndCtl->sync_standbys_defined is not * set. See SyncRepUpdateSyncStandbysDefined. * * Also check that the standby hasn't already replied. Unlikely race * condition but we'll be fetching that cache line anyway so its likely to * be a low cost check. */ if (!WalSndCtl->sync_standbys_defined || XLByteLE(XactCommitLSN, WalSndCtl->lsn[mode])) { LWLockRelease(SyncRepLock); return; } /* * Set our waitLSN so WALSender will know when to wake us, and add * ourselves to the queue. */ MyProc->waitLSN = XactCommitLSN; MyProc->syncRepState = SYNC_REP_WAITING; SyncRepQueueInsert(mode); Assert(SyncRepQueueIsOrderedByLSN(mode)); LWLockRelease(SyncRepLock); /* Alter ps display to show waiting for sync rep. */ if (update_process_title) { int len; old_status = get_ps_display(&len); new_status = (char *) palloc(len + 32 + 1); memcpy(new_status, old_status, len); sprintf(new_status + len, " waiting for %X/%X", XactCommitLSN.xlogid, XactCommitLSN.xrecoff); set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting ..." */ } /* * Wait for specified LSN to be confirmed. * * Each proc has its own wait latch, so we perform a normal latch * check/wait loop here. */ for (;;) { int syncRepState; /* Must reset the latch before testing state. */ ResetLatch(&MyProc->procLatch); /* * Try checking the state without the lock first. There's no * guarantee that we'll read the most up-to-date value, so if it looks * like we're still waiting, recheck while holding the lock. But if * it looks like we're done, we must really be done, because once * walsender changes the state to SYNC_REP_WAIT_COMPLETE, it will * never update it again, so we can't be seeing a stale value in that * case. * * Note: on machines with weak memory ordering, the acquisition of the * lock is essential to avoid race conditions: we cannot be sure the * sender's state update has reached main memory until we acquire the * lock. We could get rid of this dance if SetLatch/ResetLatch * contained memory barriers. */ syncRepState = MyProc->syncRepState; if (syncRepState == SYNC_REP_WAITING) { LWLockAcquire(SyncRepLock, LW_SHARED); syncRepState = MyProc->syncRepState; LWLockRelease(SyncRepLock); } if (syncRepState == SYNC_REP_WAIT_COMPLETE) break; /* * If a wait for synchronous replication is pending, we can neither * acknowledge the commit nor raise ERROR or FATAL. The latter would * lead the client to believe that that the transaction aborted, which * is not true: it's already committed locally. The former is no good * either: the client has requested synchronous replication, and is * entitled to assume that an acknowledged commit is also replicated, * which might not be true. So in this case we issue a WARNING (which * some clients may be able to interpret) and shut off further output. * We do NOT reset ProcDiePending, so that the process will die after * the commit is cleaned up. */ if (ProcDiePending) { ereport(WARNING, (errcode(ERRCODE_ADMIN_SHUTDOWN), errmsg("canceling the wait for synchronous replication and terminating connection due to administrator command"), errdetail("The transaction has already committed locally, but might not have been replicated to the standby."))); whereToSendOutput = DestNone; SyncRepCancelWait(); break; } /* * It's unclear what to do if a query cancel interrupt arrives. We * can't actually abort at this point, but ignoring the interrupt * altogether is not helpful, so we just terminate the wait with a * suitable warning. */ if (QueryCancelPending) { QueryCancelPending = false; ereport(WARNING, (errmsg("canceling wait for synchronous replication due to user request"), errdetail("The transaction has already committed locally, but might not have been replicated to the standby."))); SyncRepCancelWait(); break; } /* * If the postmaster dies, we'll probably never get an * acknowledgement, because all the wal sender processes will exit. So * just bail out. */ if (!PostmasterIsAlive()) { ProcDiePending = true; whereToSendOutput = DestNone; SyncRepCancelWait(); break; } /* * Wait on latch. Any condition that should wake us up will set the * latch, so no need for timeout. */ WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1); } /* * WalSender has checked our LSN and has removed us from queue. Clean up * state and leave. It's OK to reset these shared memory fields without * holding SyncRepLock, because any walsenders will ignore us anyway when * we're not on the queue. */ 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); } }
static void fmtLogMsg(StringInfo dst, ErrorData *edata) { { char formattedLogTime[FORMATTED_TS_LEN]; /* timestamp with milliseconds */ formatNow(formattedLogTime, sizeof formattedLogTime); /* * Always present, non-nullable; don't need to write the N/P * header. */ appendStringInfoString(dst, formattedLogTime); appendStringInfoChar(dst, '\0'); } /* username */ if (MyProcPort) appendStringInfoPtr(dst, MyProcPort->user_name); else appendStringInfoPtr(dst, NULL); /* database name */ if (MyProcPort) appendStringInfoPtr(dst, MyProcPort->database_name); else appendStringInfoPtr(dst, NULL); /* Process id */ { uint32_t nPid = htobe32(savedPid); appendBinaryStringInfo(dst, (void *) &nPid, sizeof nPid); } /* Remote host and port */ if (MyProcPort && MyProcPort->remote_host) { /* 'present' string header, since this string is nullable */ appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, MyProcPort->remote_host); if (MyProcPort->remote_port && MyProcPort->remote_port[0] != '\0') { appendStringInfoChar(dst, ':'); appendStringInfoString(dst, MyProcPort->remote_port); } appendStringInfoChar(dst, '\0'); } else appendStringInfoPtr(dst, NULL); /* session id; non-nullable */ appendStringInfo(dst, "%lx.%x", (long) MyStartTime, MyProcPid); appendStringInfoChar(dst, '\0'); /* Line number */ { uint64_t nSeqNum = htobe64(seqNum); appendBinaryStringInfo(dst, (void *) &nSeqNum, sizeof nSeqNum); } /* PS display */ if (MyProcPort) { StringInfoData msgbuf; const char *psdisp; int displen; initStringInfo(&msgbuf); psdisp = get_ps_display(&displen); appendBinaryStringInfo(&msgbuf, psdisp, displen); appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, msgbuf.data); appendStringInfoChar(dst, '\0'); pfree(msgbuf.data); } else appendStringInfoPtr(dst, NULL); /* session start timestamp */ if (cachedBackendStartTime[0] == '\0') { /* Rebuild the cache if it was blown */ reCacheBackendStartTime(); } /* backend start time; non-nullable string */ appendStringInfoString(dst, cachedBackendStartTime); appendStringInfoChar(dst, '\0'); /* * Virtual transaction id * * keep VXID format in sync with lockfuncs.c */ if (MyProc != NULL && MyProc->backendId != InvalidBackendId) { appendStringInfoChar(dst, 'P'); appendStringInfo(dst, "%d/%u", MyProc->backendId, MyProc->lxid); appendStringInfoChar(dst, '\0'); } else appendStringInfoPtr(dst, NULL); /* * Transaction id * * This seems to be a mistake both here and in elog.c; in particular, it's * not clear how the epoch would get added here. However, leave room in * the protocol to fix this later by upcasting. */ { uint64_t nTxid = htobe64((uint64) GetTopTransactionIdIfAny()); appendBinaryStringInfo(dst, (void *) &nTxid, sizeof nTxid); } /* Error severity */ { uint32_t nelevel = htobe32(edata->elevel); appendBinaryStringInfo(dst, (void *) &nelevel, sizeof nelevel); } /* SQL state code */ appendStringInfoPtr(dst, unpack_sql_state(edata->sqlerrcode)); /* errmessage */ appendStringInfoPtr(dst, edata->message); /* errdetail or errdetail_log */ if (edata->detail_log) appendStringInfoPtr(dst, edata->detail_log); else appendStringInfoPtr(dst, edata->detail); /* errhint */ appendStringInfoPtr(dst, edata->hint); /* internal query */ appendStringInfoPtr(dst, edata->internalquery); /* if printed internal query, print internal pos too */ if (edata->internalpos > 0 && edata->internalquery != NULL) { uint32_t ninternalpos = htobe32(edata->internalpos); appendBinaryStringInfo(dst, (void *) &ninternalpos, sizeof ninternalpos); } else { uint32_t ninternalpos = htobe32(-1); appendBinaryStringInfo(dst, (void *) &ninternalpos, sizeof ninternalpos); } /* errcontext */ appendStringInfoPtr(dst, edata->context); /* * user query --- only reported if not disabled by the caller. * * Also include query position. */ if (isLogLevelOutput(edata->elevel, log_min_error_statement) && debug_query_string != NULL && !edata->hide_stmt) { uint32_t nCursorPos = htobe32(edata->cursorpos); appendStringInfoPtr(dst, debug_query_string); appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos); } else { uint32_t nCursorPos = htobe32(-1); appendStringInfoPtr(dst, NULL); appendBinaryStringInfo(dst, (void *) &nCursorPos, sizeof nCursorPos); } /* file error location */ if (Log_error_verbosity >= PGERROR_VERBOSE) { StringInfoData msgbuf; initStringInfo(&msgbuf); if (edata->funcname && edata->filename) appendStringInfo(&msgbuf, "%s, %s:%d", edata->funcname, edata->filename, edata->lineno); else if (edata->filename) appendStringInfo(&msgbuf, "%s:%d", edata->filename, edata->lineno); appendStringInfoChar(dst, 'P'); appendStringInfoString(dst, msgbuf.data); appendStringInfoChar(dst, '\0'); pfree(msgbuf.data); } else appendStringInfoPtr(dst, NULL); /* application name */ appendStringInfoPtr(dst, application_name); }