mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Logging running transactions every 15 seconds.
Previously, we did this just once per checkpoint, but that could make Hot Standby take a long time to initialize. To avoid busying an otherwise-idle system, we don't do this if no WAL has been written since we did it last. Andres Freund
This commit is contained in:
parent
d02c0ddb15
commit
ed46758381
@ -54,9 +54,11 @@
|
|||||||
#include "storage/shmem.h"
|
#include "storage/shmem.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "storage/spin.h"
|
#include "storage/spin.h"
|
||||||
|
#include "storage/standby.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/resowner.h"
|
#include "utils/resowner.h"
|
||||||
|
#include "utils/timestamp.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -70,6 +72,20 @@ int BgWriterDelay = 200;
|
|||||||
*/
|
*/
|
||||||
#define HIBERNATE_FACTOR 50
|
#define HIBERNATE_FACTOR 50
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interval in which standby snapshots are logged into the WAL stream, in
|
||||||
|
* milliseconds.
|
||||||
|
*/
|
||||||
|
#define LOG_SNAPSHOT_INTERVAL_MS 15000
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LSN and timestamp at which we last issued a LogStandbySnapshot(), to avoid
|
||||||
|
* doing so too often or repeatedly if there has been no other write activity
|
||||||
|
* in the system.
|
||||||
|
*/
|
||||||
|
static TimestampTz last_snapshot_ts;
|
||||||
|
static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags set by interrupt handlers for later service in the main loop.
|
* Flags set by interrupt handlers for later service in the main loop.
|
||||||
*/
|
*/
|
||||||
@ -141,6 +157,12 @@ BackgroundWriterMain(void)
|
|||||||
*/
|
*/
|
||||||
CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Writer");
|
CurrentResourceOwner = ResourceOwnerCreate(NULL, "Background Writer");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We just started, assume there has been either a shutdown or
|
||||||
|
* end-of-recovery snapshot.
|
||||||
|
*/
|
||||||
|
last_snapshot_ts = GetCurrentTimestamp();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a memory context that we will do all our work in. We do this so
|
* Create a memory context that we will do all our work in. We do this so
|
||||||
* that we can reset the context during error recovery and thereby avoid
|
* that we can reset the context during error recovery and thereby avoid
|
||||||
@ -275,6 +297,46 @@ BackgroundWriterMain(void)
|
|||||||
smgrcloseall();
|
smgrcloseall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log a new xl_running_xacts every now and then so replication can get
|
||||||
|
* into a consistent state faster (think of suboverflowed snapshots)
|
||||||
|
* and clean up resources (locks, KnownXids*) more frequently. The
|
||||||
|
* costs of this are relatively low, so doing it 4 times
|
||||||
|
* (LOG_SNAPSHOT_INTERVAL_MS) a minute seems fine.
|
||||||
|
*
|
||||||
|
* We assume the interval for writing xl_running_xacts is
|
||||||
|
* significantly bigger than BgWriterDelay, so we don't complicate the
|
||||||
|
* overall timeout handling but just assume we're going to get called
|
||||||
|
* often enough even if hibernation mode is active. It's not that
|
||||||
|
* important that log_snap_interval_ms is met strictly. To make sure
|
||||||
|
* we're not waking the disk up unneccesarily on an idle system we
|
||||||
|
* check whether there has been any WAL inserted since the last time
|
||||||
|
* we've logged a running xacts.
|
||||||
|
*
|
||||||
|
* We do this logging in the bgwriter as its the only process thats
|
||||||
|
* run regularly and returns to its mainloop all the
|
||||||
|
* time. E.g. Checkpointer, when active, is barely ever in its
|
||||||
|
* mainloop and thus makes it hard to log regularly.
|
||||||
|
*/
|
||||||
|
if (XLogStandbyInfoActive() && !RecoveryInProgress())
|
||||||
|
{
|
||||||
|
TimestampTz timeout = 0;
|
||||||
|
TimestampTz now = GetCurrentTimestamp();
|
||||||
|
timeout = TimestampTzPlusMilliseconds(last_snapshot_ts,
|
||||||
|
LOG_SNAPSHOT_INTERVAL_MS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* only log if enough time has passed and some xlog record has been
|
||||||
|
* inserted.
|
||||||
|
*/
|
||||||
|
if (now >= timeout &&
|
||||||
|
last_snapshot_lsn != GetXLogInsertRecPtr())
|
||||||
|
{
|
||||||
|
last_snapshot_lsn = LogStandbySnapshot();
|
||||||
|
last_snapshot_ts = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sleep until we are signaled or BgWriterDelay has elapsed.
|
* Sleep until we are signaled or BgWriterDelay has elapsed.
|
||||||
*
|
*
|
||||||
|
@ -42,7 +42,7 @@ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlis
|
|||||||
ProcSignalReason reason);
|
ProcSignalReason reason);
|
||||||
static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid);
|
static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid);
|
||||||
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
|
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
|
||||||
static void LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
|
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
|
||||||
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
|
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
|
||||||
|
|
||||||
|
|
||||||
@ -853,10 +853,13 @@ standby_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
* currently running xids, performed by StandbyReleaseOldLocks().
|
* currently running xids, performed by StandbyReleaseOldLocks().
|
||||||
* Zero xids should no longer be possible, but we may be replaying WAL
|
* Zero xids should no longer be possible, but we may be replaying WAL
|
||||||
* from a time when they were possible.
|
* from a time when they were possible.
|
||||||
|
*
|
||||||
|
* Returns the RecPtr of the last inserted record.
|
||||||
*/
|
*/
|
||||||
void
|
XLogRecPtr
|
||||||
LogStandbySnapshot(void)
|
LogStandbySnapshot(void)
|
||||||
{
|
{
|
||||||
|
XLogRecPtr recptr;
|
||||||
RunningTransactions running;
|
RunningTransactions running;
|
||||||
xl_standby_lock *locks;
|
xl_standby_lock *locks;
|
||||||
int nlocks;
|
int nlocks;
|
||||||
@ -876,9 +879,12 @@ LogStandbySnapshot(void)
|
|||||||
* record we write, because standby will open up when it sees this.
|
* record we write, because standby will open up when it sees this.
|
||||||
*/
|
*/
|
||||||
running = GetRunningTransactionData();
|
running = GetRunningTransactionData();
|
||||||
LogCurrentRunningXacts(running);
|
recptr = LogCurrentRunningXacts(running);
|
||||||
|
|
||||||
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
|
/* GetRunningTransactionData() acquired XidGenLock, we must release it */
|
||||||
LWLockRelease(XidGenLock);
|
LWLockRelease(XidGenLock);
|
||||||
|
|
||||||
|
return recptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -889,7 +895,7 @@ LogStandbySnapshot(void)
|
|||||||
* is a contiguous chunk of memory and never exists fully until it is
|
* is a contiguous chunk of memory and never exists fully until it is
|
||||||
* assembled in WAL.
|
* assembled in WAL.
|
||||||
*/
|
*/
|
||||||
static void
|
static XLogRecPtr
|
||||||
LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
|
LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
|
||||||
{
|
{
|
||||||
xl_running_xacts xlrec;
|
xl_running_xacts xlrec;
|
||||||
@ -939,6 +945,19 @@ LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
|
|||||||
CurrRunningXacts->oldestRunningXid,
|
CurrRunningXacts->oldestRunningXid,
|
||||||
CurrRunningXacts->latestCompletedXid,
|
CurrRunningXacts->latestCompletedXid,
|
||||||
CurrRunningXacts->nextXid);
|
CurrRunningXacts->nextXid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure running_xacts information is synced to disk not too far in the
|
||||||
|
* future. We don't want to stall anything though (i.e. use XLogFlush()),
|
||||||
|
* so we let the wal writer do it during normal
|
||||||
|
* operation. XLogSetAsyncXactLSN() conveniently will mark the LSN as
|
||||||
|
* to-be-synced and nudge the WALWriter into action if sleeping. Check
|
||||||
|
* XLogBackgroundFlush() for details why a record might not be flushed
|
||||||
|
* without it.
|
||||||
|
*/
|
||||||
|
XLogSetAsyncXactLSN(recptr);
|
||||||
|
|
||||||
|
return recptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -113,6 +113,6 @@ typedef RunningTransactionsData *RunningTransactions;
|
|||||||
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
|
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
|
||||||
extern void LogAccessExclusiveLockPrepare(void);
|
extern void LogAccessExclusiveLockPrepare(void);
|
||||||
|
|
||||||
extern void LogStandbySnapshot(void);
|
extern XLogRecPtr LogStandbySnapshot(void);
|
||||||
|
|
||||||
#endif /* STANDBY_H */
|
#endif /* STANDBY_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user