54
54
#include "storage/shmem.h"
55
55
#include "storage/smgr.h"
56
56
#include "storage/spin.h"
57
+ #include "storage/standby.h"
57
58
#include "utils/guc.h"
58
59
#include "utils/memutils.h"
59
60
#include "utils/resowner.h"
61
+ #include "utils/timestamp.h"
60
62
61
63
62
64
/*
@@ -70,6 +72,20 @@ int BgWriterDelay = 200;
70
72
*/
71
73
#define HIBERNATE_FACTOR 50
72
74
75
+ /*
76
+ * Interval in which standby snapshots are logged into the WAL stream, in
77
+ * milliseconds.
78
+ */
79
+ #define LOG_SNAPSHOT_INTERVAL_MS 15000
80
+
81
+ /*
82
+ * LSN and timestamp at which we last issued a LogStandbySnapshot(), to avoid
83
+ * doing so too often or repeatedly if there has been no other write activity
84
+ * in the system.
85
+ */
86
+ static TimestampTz last_snapshot_ts ;
87
+ static XLogRecPtr last_snapshot_lsn = InvalidXLogRecPtr ;
88
+
73
89
/*
74
90
* Flags set by interrupt handlers for later service in the main loop.
75
91
*/
@@ -141,6 +157,12 @@ BackgroundWriterMain(void)
141
157
*/
142
158
CurrentResourceOwner = ResourceOwnerCreate (NULL , "Background Writer" );
143
159
160
+ /*
161
+ * We just started, assume there has been either a shutdown or
162
+ * end-of-recovery snapshot.
163
+ */
164
+ last_snapshot_ts = GetCurrentTimestamp ();
165
+
144
166
/*
145
167
* Create a memory context that we will do all our work in. We do this so
146
168
* that we can reset the context during error recovery and thereby avoid
@@ -275,6 +297,46 @@ BackgroundWriterMain(void)
275
297
smgrcloseall ();
276
298
}
277
299
300
+ /*
301
+ * Log a new xl_running_xacts every now and then so replication can get
302
+ * into a consistent state faster (think of suboverflowed snapshots)
303
+ * and clean up resources (locks, KnownXids*) more frequently. The
304
+ * costs of this are relatively low, so doing it 4 times
305
+ * (LOG_SNAPSHOT_INTERVAL_MS) a minute seems fine.
306
+ *
307
+ * We assume the interval for writing xl_running_xacts is
308
+ * significantly bigger than BgWriterDelay, so we don't complicate the
309
+ * overall timeout handling but just assume we're going to get called
310
+ * often enough even if hibernation mode is active. It's not that
311
+ * important that log_snap_interval_ms is met strictly. To make sure
312
+ * we're not waking the disk up unneccesarily on an idle system we
313
+ * check whether there has been any WAL inserted since the last time
314
+ * we've logged a running xacts.
315
+ *
316
+ * We do this logging in the bgwriter as its the only process thats
317
+ * run regularly and returns to its mainloop all the
318
+ * time. E.g. Checkpointer, when active, is barely ever in its
319
+ * mainloop and thus makes it hard to log regularly.
320
+ */
321
+ if (XLogStandbyInfoActive () && !RecoveryInProgress ())
322
+ {
323
+ TimestampTz timeout = 0 ;
324
+ TimestampTz now = GetCurrentTimestamp ();
325
+ timeout = TimestampTzPlusMilliseconds (last_snapshot_ts ,
326
+ LOG_SNAPSHOT_INTERVAL_MS );
327
+
328
+ /*
329
+ * only log if enough time has passed and some xlog record has been
330
+ * inserted.
331
+ */
332
+ if (now >= timeout &&
333
+ last_snapshot_lsn != GetXLogInsertRecPtr ())
334
+ {
335
+ last_snapshot_lsn = LogStandbySnapshot ();
336
+ last_snapshot_ts = now ;
337
+ }
338
+ }
339
+
278
340
/*
279
341
* Sleep until we are signaled or BgWriterDelay has elapsed.
280
342
*
0 commit comments