Coverage Report

Created: 2026-10-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/storage/ipc/standby.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * standby.c
4
 *    Misc functions used in Hot Standby mode.
5
 *
6
 *  All functions for handling RM_STANDBY_ID, which relate to
7
 *  AccessExclusiveLocks and starting snapshots for Hot Standby mode.
8
 *  Plus conflict recovery processing.
9
 *
10
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11
 * Portions Copyright (c) 1994, Regents of the University of California
12
 *
13
 * IDENTIFICATION
14
 *    src/backend/storage/ipc/standby.c
15
 *
16
 *-------------------------------------------------------------------------
17
 */
18
#include "postgres.h"
19
#include "access/transam.h"
20
#include "access/twophase.h"
21
#include "access/xact.h"
22
#include "access/xloginsert.h"
23
#include "access/xlogrecovery.h"
24
#include "access/xlogutils.h"
25
#include "miscadmin.h"
26
#include "pgstat.h"
27
#include "replication/slot.h"
28
#include "storage/bufmgr.h"
29
#include "storage/proc.h"
30
#include "storage/procarray.h"
31
#include "storage/sinvaladt.h"
32
#include "storage/standby.h"
33
#include "utils/hsearch.h"
34
#include "utils/injection_point.h"
35
#include "utils/ps_status.h"
36
#include "utils/timeout.h"
37
#include "utils/timestamp.h"
38
#include "utils/wait_event.h"
39
40
/* User-settable GUC parameters */
41
int     max_standby_archive_delay = 30 * 1000;
42
int     max_standby_streaming_delay = 30 * 1000;
43
bool    log_recovery_conflict_waits = false;
44
45
/*
46
 * Keep track of all the exclusive locks owned by original transactions.
47
 * For each known exclusive lock, there is a RecoveryLockEntry in the
48
 * RecoveryLockHash hash table.  All RecoveryLockEntrys belonging to a
49
 * given XID are chained together so that we can find them easily.
50
 * For each original transaction that is known to have any such locks,
51
 * there is a RecoveryLockXidEntry in the RecoveryLockXidHash hash table,
52
 * which stores the head of the chain of its locks.
53
 */
54
typedef struct RecoveryLockEntry
55
{
56
  xl_standby_lock key;    /* hash key: xid, dbOid, relOid */
57
  struct RecoveryLockEntry *next; /* chain link */
58
} RecoveryLockEntry;
59
60
typedef struct RecoveryLockXidEntry
61
{
62
  TransactionId xid;      /* hash key -- must be first */
63
  struct RecoveryLockEntry *head; /* chain head */
64
} RecoveryLockXidEntry;
65
66
static HTAB *RecoveryLockHash = NULL;
67
static HTAB *RecoveryLockXidHash = NULL;
68
69
/* Flags set by timeout handlers */
70
static volatile sig_atomic_t got_standby_deadlock_timeout = false;
71
static volatile sig_atomic_t got_standby_delay_timeout = false;
72
static volatile sig_atomic_t got_standby_lock_timeout = false;
73
74
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
75
                           RecoveryConflictReason reason,
76
                           uint32 wait_event_info,
77
                           bool report_waiting);
78
static void SendRecoveryConflictWithBufferPin(RecoveryConflictReason reason);
79
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
80
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
81
static const char *get_recovery_conflict_desc(RecoveryConflictReason reason);
82
83
/*
84
 * InitRecoveryTransactionEnvironment
85
 *    Initialize tracking of our primary's in-progress transactions.
86
 *
87
 * We need to issue shared invalidations and hold locks. Holding locks
88
 * means others may want to wait on us, so we need to make a lock table
89
 * vxact entry like a real transaction. We could create and delete
90
 * lock table entries for each transaction but its simpler just to create
91
 * one permanent entry and leave it there all the time. Locks are then
92
 * acquired and released as needed. Yes, this means you can see the
93
 * Startup process in pg_locks once we have run this.
94
 */
95
void
96
InitRecoveryTransactionEnvironment(void)
97
0
{
98
0
  VirtualTransactionId vxid;
99
0
  HASHCTL   hash_ctl;
100
101
0
  Assert(RecoveryLockHash == NULL); /* don't run this twice */
102
103
  /*
104
   * Initialize the hash tables for tracking the locks held by each
105
   * transaction.
106
   */
107
0
  hash_ctl.keysize = sizeof(xl_standby_lock);
108
0
  hash_ctl.entrysize = sizeof(RecoveryLockEntry);
109
0
  RecoveryLockHash = hash_create("RecoveryLockHash",
110
0
                   64,
111
0
                   &hash_ctl,
112
0
                   HASH_ELEM | HASH_BLOBS);
113
0
  hash_ctl.keysize = sizeof(TransactionId);
114
0
  hash_ctl.entrysize = sizeof(RecoveryLockXidEntry);
115
0
  RecoveryLockXidHash = hash_create("RecoveryLockXidHash",
116
0
                    64,
117
0
                    &hash_ctl,
118
0
                    HASH_ELEM | HASH_BLOBS);
119
120
  /*
121
   * Initialize shared invalidation management for Startup process, being
122
   * careful to register ourselves as a sendOnly process so we don't need to
123
   * read messages, nor will we get signaled when the queue starts filling
124
   * up.
125
   */
126
0
  SharedInvalBackendInit(true);
127
128
  /*
129
   * Lock a virtual transaction id for Startup process.
130
   *
131
   * We need to do GetNextLocalTransactionId() because
132
   * SharedInvalBackendInit() leaves localTransactionId invalid and the lock
133
   * manager doesn't like that at all.
134
   *
135
   * Note that we don't need to run XactLockTableInsert() because nobody
136
   * needs to wait on xids. That sounds a little strange, but table locks
137
   * are held by vxids and row level locks are held by xids. All queries
138
   * hold AccessShareLocks so never block while we write or lock new rows.
139
   */
140
0
  MyProc->vxid.procNumber = MyProcNumber;
141
0
  vxid.procNumber = MyProcNumber;
142
0
  vxid.localTransactionId = GetNextLocalTransactionId();
143
0
  VirtualXactLockTableInsert(vxid);
144
145
0
  standbyState = STANDBY_INITIALIZED;
146
0
}
147
148
/*
149
 * ShutdownRecoveryTransactionEnvironment
150
 *    Shut down transaction tracking
151
 *
152
 * Prepare to switch from hot standby mode to normal operation. Shut down
153
 * recovery-time transaction tracking.
154
 *
155
 * This must be called even in shutdown of startup process if transaction
156
 * tracking has been initialized. Otherwise some locks the tracked
157
 * transactions were holding will not be released and may interfere with
158
 * the processes still running (but will exit soon later) at the exit of
159
 * startup process.
160
 */
161
void
162
ShutdownRecoveryTransactionEnvironment(void)
163
0
{
164
  /*
165
   * Do nothing if RecoveryLockHash is NULL because that means that
166
   * transaction tracking has not yet been initialized or has already been
167
   * shut down.  This makes it safe to have possibly-redundant calls of this
168
   * function during process exit.
169
   */
170
0
  if (RecoveryLockHash == NULL)
171
0
    return;
172
173
  /* Mark all tracked in-progress transactions as finished. */
174
0
  ExpireAllKnownAssignedTransactionIds();
175
176
  /* Release all locks the tracked transactions were holding */
177
0
  StandbyReleaseAllLocks();
178
179
  /* Destroy the lock hash tables. */
180
0
  hash_destroy(RecoveryLockHash);
181
0
  hash_destroy(RecoveryLockXidHash);
182
0
  RecoveryLockHash = NULL;
183
0
  RecoveryLockXidHash = NULL;
184
185
  /* Cleanup our VirtualTransaction */
186
0
  VirtualXactLockTableCleanup();
187
0
}
188
189
190
/*
191
 * -----------------------------------------------------
192
 *    Standby wait timers and backend cancel logic
193
 * -----------------------------------------------------
194
 */
195
196
/*
197
 * Determine the cutoff time at which we want to start canceling conflicting
198
 * transactions.  Returns zero (a time safely in the past) if we are willing
199
 * to wait forever.
200
 */
201
static TimestampTz
202
GetStandbyLimitTime(void)
203
0
{
204
0
  TimestampTz rtime;
205
0
  bool    fromStream;
206
207
  /*
208
   * The cutoff time is the last WAL data receipt time plus the appropriate
209
   * delay variable.  Delay of -1 means wait forever.
210
   */
211
0
  GetXLogReceiptTime(&rtime, &fromStream);
212
0
  if (fromStream)
213
0
  {
214
0
    if (max_standby_streaming_delay < 0)
215
0
      return 0;     /* wait forever */
216
0
    return TimestampTzPlusMilliseconds(rtime, max_standby_streaming_delay);
217
0
  }
218
0
  else
219
0
  {
220
0
    if (max_standby_archive_delay < 0)
221
0
      return 0;     /* wait forever */
222
0
    return TimestampTzPlusMilliseconds(rtime, max_standby_archive_delay);
223
0
  }
224
0
}
225
226
0
#define STANDBY_INITIAL_WAIT_US  1000
227
static int  standbyWait_us = STANDBY_INITIAL_WAIT_US;
228
229
/*
230
 * Standby wait logic for ResolveRecoveryConflictWithVirtualXIDs.
231
 * We wait here for a while then return. If we decide we can't wait any
232
 * more then we return true, if we can wait some more return false.
233
 */
234
static bool
235
WaitExceedsMaxStandbyDelay(uint32 wait_event_info)
236
0
{
237
0
  TimestampTz ltime;
238
239
0
  CHECK_FOR_INTERRUPTS();
240
241
  /* Are we past the limit time? */
242
0
  ltime = GetStandbyLimitTime();
243
0
  if (ltime && GetCurrentTimestamp() >= ltime)
244
0
    return true;
245
246
  /*
247
   * Sleep a bit (this is essential to avoid busy-waiting).
248
   */
249
0
  pgstat_report_wait_start(wait_event_info);
250
0
  pg_usleep(standbyWait_us);
251
0
  pgstat_report_wait_end();
252
253
  /*
254
   * Progressively increase the sleep times, but not to more than 1s, since
255
   * pg_usleep isn't interruptible on some platforms.
256
   */
257
0
  standbyWait_us *= 2;
258
0
  if (standbyWait_us > 1000000)
259
0
    standbyWait_us = 1000000;
260
261
0
  return false;
262
0
}
263
264
/*
265
 * Log the recovery conflict.
266
 *
267
 * wait_start is the timestamp when the caller started to wait.
268
 * now is the timestamp when this function has been called.
269
 * wait_list is the list of virtual transaction ids assigned to
270
 * conflicting processes. still_waiting indicates whether
271
 * the startup process is still waiting for the recovery conflict
272
 * to be resolved or not.
273
 */
274
void
275
LogRecoveryConflict(RecoveryConflictReason reason, TimestampTz wait_start,
276
          TimestampTz now, VirtualTransactionId *wait_list,
277
          bool still_waiting)
278
0
{
279
0
  long    secs;
280
0
  int     usecs;
281
0
  long    msecs;
282
0
  StringInfoData buf;
283
0
  int     nprocs = 0;
284
285
  /*
286
   * There must be no conflicting processes when the recovery conflict has
287
   * already been resolved.
288
   */
289
0
  Assert(still_waiting || wait_list == NULL);
290
291
0
  TimestampDifference(wait_start, now, &secs, &usecs);
292
0
  msecs = secs * 1000 + usecs / 1000;
293
0
  usecs = usecs % 1000;
294
295
0
  if (wait_list)
296
0
  {
297
0
    VirtualTransactionId *vxids;
298
299
    /* Construct a string of list of the conflicting processes */
300
0
    vxids = wait_list;
301
0
    while (VirtualTransactionIdIsValid(*vxids))
302
0
    {
303
0
      PGPROC     *proc = ProcNumberGetProc(vxids->procNumber);
304
305
      /* proc can be NULL if the target backend is not active */
306
0
      if (proc)
307
0
      {
308
0
        if (nprocs == 0)
309
0
        {
310
0
          initStringInfo(&buf);
311
0
          appendStringInfo(&buf, "%d", proc->pid);
312
0
        }
313
0
        else
314
0
          appendStringInfo(&buf, ", %d", proc->pid);
315
316
0
        nprocs++;
317
0
      }
318
319
0
      vxids++;
320
0
    }
321
0
  }
322
323
  /*
324
   * If wait_list is specified, report the list of PIDs of active
325
   * conflicting backends in a detail message. Note that if all the backends
326
   * in the list are not active, no detail message is logged.
327
   */
328
0
  if (still_waiting)
329
0
  {
330
0
    ereport(LOG,
331
0
        errmsg("recovery still waiting after %ld.%03d ms: %s",
332
0
             msecs, usecs, get_recovery_conflict_desc(reason)),
333
0
        nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.",
334
0
                          "Conflicting processes: %s.",
335
0
                          nprocs, buf.data) : 0);
336
0
  }
337
0
  else
338
0
  {
339
0
    ereport(LOG,
340
0
        errmsg("recovery finished waiting after %ld.%03d ms: %s",
341
0
             msecs, usecs, get_recovery_conflict_desc(reason)));
342
0
  }
343
344
0
  if (nprocs > 0)
345
0
    pfree(buf.data);
346
0
}
347
348
/*
349
 * This is the main executioner for any query backend that conflicts with
350
 * recovery processing. Judgement has already been passed on it within
351
 * a specific rmgr. Here we just issue the orders to the procs. The procs
352
 * then throw the required error as instructed.
353
 *
354
 * If report_waiting is true, "waiting" is reported in PS display and the
355
 * wait for recovery conflict is reported in the log, if necessary. If
356
 * the caller is responsible for reporting them, report_waiting should be
357
 * false. Otherwise, both the caller and this function report the same
358
 * thing unexpectedly.
359
 */
360
static void
361
ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
362
                     RecoveryConflictReason reason,
363
                     uint32 wait_event_info,
364
                     bool report_waiting)
365
0
{
366
0
  TimestampTz waitStart = 0;
367
0
  bool    waiting = false;
368
0
  bool    logged_recovery_conflict = false;
369
370
  /* Fast exit, to avoid a kernel call if there's no work to be done. */
371
0
  if (!VirtualTransactionIdIsValid(*waitlist))
372
0
    return;
373
374
  /* Set the wait start timestamp for reporting */
375
0
  if (report_waiting && (log_recovery_conflict_waits || update_process_title))
376
0
    waitStart = GetCurrentTimestamp();
377
378
0
  while (VirtualTransactionIdIsValid(*waitlist))
379
0
  {
380
    /* reset standbyWait_us for each xact we wait for */
381
0
    standbyWait_us = STANDBY_INITIAL_WAIT_US;
382
383
    /* wait until the virtual xid is gone */
384
0
    while (!VirtualXactLock(*waitlist, false))
385
0
    {
386
      /* Is it time to kill it? */
387
0
      if (WaitExceedsMaxStandbyDelay(wait_event_info))
388
0
      {
389
0
        bool    signaled;
390
391
        /*
392
         * Now find out who to throw out of the balloon.
393
         */
394
0
        Assert(VirtualTransactionIdIsValid(*waitlist));
395
0
        signaled = SignalRecoveryConflictWithVirtualXID(*waitlist, reason);
396
397
        /*
398
         * Wait a little bit for it to die so that we avoid flooding
399
         * an unresponsive backend when system is heavily loaded.
400
         */
401
0
        if (signaled)
402
0
          pg_usleep(5000L);
403
0
      }
404
405
0
      if (waitStart != 0 && (!logged_recovery_conflict || !waiting))
406
0
      {
407
0
        TimestampTz now = 0;
408
0
        bool    maybe_log_conflict;
409
0
        bool    maybe_update_title;
410
411
0
        maybe_log_conflict = (log_recovery_conflict_waits && !logged_recovery_conflict);
412
0
        maybe_update_title = (update_process_title && !waiting);
413
414
        /* Get the current timestamp if not report yet */
415
0
        if (maybe_log_conflict || maybe_update_title)
416
0
          now = GetCurrentTimestamp();
417
418
        /*
419
         * Report via ps if we have been waiting for more than 500
420
         * msec (should that be configurable?)
421
         */
422
0
        if (maybe_update_title &&
423
0
          TimestampDifferenceExceeds(waitStart, now, 500))
424
0
        {
425
0
          set_ps_display_suffix("waiting");
426
0
          waiting = true;
427
0
        }
428
429
        /*
430
         * Emit the log message if the startup process is waiting
431
         * longer than deadlock_timeout for recovery conflict.
432
         */
433
0
        if (maybe_log_conflict &&
434
0
          TimestampDifferenceExceeds(waitStart, now, DeadlockTimeout))
435
0
        {
436
0
          LogRecoveryConflict(reason, waitStart, now, waitlist, true);
437
0
          logged_recovery_conflict = true;
438
0
        }
439
0
      }
440
0
    }
441
442
    /* The virtual transaction is gone now, wait for the next one */
443
0
    waitlist++;
444
0
  }
445
446
  /*
447
   * Emit the log message if recovery conflict was resolved but the startup
448
   * process waited longer than deadlock_timeout for it.
449
   */
450
0
  if (logged_recovery_conflict)
451
0
    LogRecoveryConflict(reason, waitStart, GetCurrentTimestamp(),
452
0
              NULL, false);
453
454
  /* reset ps display to remove the suffix if we added one */
455
0
  if (waiting)
456
0
    set_ps_display_remove_suffix();
457
458
0
}
459
460
/*
461
 * Generate whatever recovery conflicts are needed to eliminate snapshots that
462
 * might see XIDs <= snapshotConflictHorizon as still running.
463
 *
464
 * snapshotConflictHorizon cutoffs are our standard approach to generating
465
 * granular recovery conflicts.  Note that InvalidTransactionId values are
466
 * interpreted as "definitely don't need any conflicts" here, which is a
467
 * general convention that WAL records can (and often do) depend on.
468
 */
469
void
470
ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon,
471
                  bool isCatalogRel,
472
                  RelFileLocator locator)
473
0
{
474
0
  VirtualTransactionId *backends;
475
476
  /*
477
   * If we get passed InvalidTransactionId then we do nothing (no conflict).
478
   *
479
   * This can happen whenever the changes in the WAL record do not affect
480
   * visibility on a standby. For example: a record that only freezes an
481
   * xmax from a locker.
482
   *
483
   * It's also quite common with records generated during index deletion
484
   * (original execution of the deletion can reason that a recovery conflict
485
   * which is sufficient for the deletion operation must take place before
486
   * replay of the deletion record itself).
487
   */
488
0
  if (!TransactionIdIsValid(snapshotConflictHorizon))
489
0
    return;
490
491
0
  Assert(TransactionIdIsNormal(snapshotConflictHorizon));
492
0
  backends = GetConflictingVirtualXIDs(snapshotConflictHorizon,
493
0
                     locator.dbOid);
494
0
  ResolveRecoveryConflictWithVirtualXIDs(backends,
495
0
                       RECOVERY_CONFLICT_SNAPSHOT,
496
0
                       WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
497
0
                       true);
498
499
  /*
500
   * Note that WaitExceedsMaxStandbyDelay() is not taken into account here
501
   * (as opposed to ResolveRecoveryConflictWithVirtualXIDs() above). That
502
   * seems OK, given that this kind of conflict should not normally be
503
   * reached, e.g. due to using a physical replication slot.
504
   */
505
0
  if (IsLogicalDecodingEnabled() && isCatalogRel)
506
0
    InvalidateObsoleteReplicationSlots(RS_INVAL_HORIZON, 0, locator.dbOid,
507
0
                       snapshotConflictHorizon);
508
0
}
509
510
/*
511
 * Variant of ResolveRecoveryConflictWithSnapshot that works with
512
 * FullTransactionId values
513
 */
514
void
515
ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon,
516
                       bool isCatalogRel,
517
                       RelFileLocator locator)
518
0
{
519
  /*
520
   * ResolveRecoveryConflictWithSnapshot operates on 32-bit TransactionIds,
521
   * so truncate the logged FullTransactionId.  If the logged value is very
522
   * old, so that XID wrap-around already happened on it, there can't be any
523
   * snapshots that still see it.
524
   */
525
0
  FullTransactionId nextXid = ReadNextFullTransactionId();
526
0
  uint64    diff;
527
528
0
  diff = U64FromFullTransactionId(nextXid) -
529
0
    U64FromFullTransactionId(snapshotConflictHorizon);
530
0
  if (diff < MaxTransactionId / 2)
531
0
  {
532
0
    TransactionId truncated;
533
534
0
    truncated = XidFromFullTransactionId(snapshotConflictHorizon);
535
0
    ResolveRecoveryConflictWithSnapshot(truncated,
536
0
                      isCatalogRel,
537
0
                      locator);
538
0
  }
539
0
}
540
541
void
542
ResolveRecoveryConflictWithTablespace(Oid tsid)
543
0
{
544
0
  VirtualTransactionId *temp_file_users;
545
546
  /*
547
   * Standby users may be currently using this tablespace for their
548
   * temporary files. We only care about current users because
549
   * temp_tablespace parameter will just ignore tablespaces that no longer
550
   * exist.
551
   *
552
   * Ask everybody to cancel their queries immediately so we can ensure no
553
   * temp files remain and we can remove the tablespace. Nuke the entire
554
   * site from orbit, it's the only way to be sure.
555
   *
556
   * XXX: We could work out the pids of active backends using this
557
   * tablespace by examining the temp filenames in the directory. We would
558
   * then convert the pids into VirtualXIDs before attempting to cancel
559
   * them.
560
   *
561
   * We don't wait for commit because drop tablespace is non-transactional.
562
   */
563
0
  temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
564
0
                        InvalidOid);
565
0
  ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
566
0
                       RECOVERY_CONFLICT_TABLESPACE,
567
0
                       WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE,
568
0
                       true);
569
0
}
570
571
void
572
ResolveRecoveryConflictWithDatabase(Oid dbid)
573
0
{
574
  /*
575
   * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
576
   * only waits for transactions and completely idle sessions would block
577
   * us. This is rare enough that we do this as simply as possible: no wait,
578
   * just force them off immediately.
579
   *
580
   * No locking is required here because we already acquired
581
   * AccessExclusiveLock. Anybody trying to connect while we do this will
582
   * block during InitPostgres() and then disconnect when they see the
583
   * database has been removed.
584
   */
585
0
  while (CountDBBackends(dbid) > 0)
586
0
  {
587
0
    SignalRecoveryConflictWithDatabase(dbid, RECOVERY_CONFLICT_DATABASE);
588
589
    /*
590
     * Wait awhile for them to die so that we avoid flooding an
591
     * unresponsive backend when system is heavily loaded.
592
     */
593
0
    pg_usleep(10000);
594
0
  }
595
0
}
596
597
/*
598
 * ResolveRecoveryConflictWithLock is called from ProcSleep()
599
 * to resolve conflicts with other backends holding relation locks.
600
 *
601
 * The WaitLatch sleep normally done in ProcSleep()
602
 * (when not InHotStandby) is performed here, for code clarity.
603
 *
604
 * We either resolve conflicts immediately or set a timeout to wake us at
605
 * the limit of our patience.
606
 *
607
 * Resolve conflicts by canceling to all backends holding a conflicting
608
 * lock.  As we are already queued to be granted the lock, no new lock
609
 * requests conflicting with ours will be granted in the meantime.
610
 *
611
 * We also must check for deadlocks involving the Startup process and
612
 * hot-standby backend processes. If deadlock_timeout is reached in
613
 * this function, all the backends holding the conflicting locks are
614
 * requested to check themselves for deadlocks.
615
 *
616
 * logging_conflict should be true if the recovery conflict has not been
617
 * logged yet even though logging is enabled. After deadlock_timeout is
618
 * reached and the request for deadlock check is sent, we wait again to
619
 * be signaled by the release of the lock if logging_conflict is false.
620
 * Otherwise we return without waiting again so that the caller can report
621
 * the recovery conflict. In this case, then, this function is called again
622
 * with logging_conflict=false (because the recovery conflict has already
623
 * been logged) and we will wait again for the lock to be released.
624
 */
625
void
626
ResolveRecoveryConflictWithLock(LOCKTAG locktag, bool logging_conflict)
627
0
{
628
0
  TimestampTz ltime;
629
0
  TimestampTz now;
630
631
0
  Assert(InHotStandby);
632
633
0
  ltime = GetStandbyLimitTime();
634
0
  now = GetCurrentTimestamp();
635
636
  /*
637
   * Update waitStart if first time through after the startup process
638
   * started waiting for the lock. It should not be updated every time
639
   * ResolveRecoveryConflictWithLock() is called during the wait.
640
   *
641
   * Use the current time obtained for comparison with ltime as waitStart
642
   * (i.e., the time when this process started waiting for the lock). Since
643
   * getting the current time newly can cause overhead, we reuse the
644
   * already-obtained time to avoid that overhead.
645
   *
646
   * Note that waitStart is updated without holding the lock table's
647
   * partition lock, to avoid the overhead by additional lock acquisition.
648
   * This can cause "waitstart" in pg_locks to become NULL for a very short
649
   * period of time after the wait started even though "granted" is false.
650
   * This is OK in practice because we can assume that users are likely to
651
   * look at "waitstart" when waiting for the lock for a long time.
652
   */
653
0
  if (pg_atomic_read_u64(&MyProc->waitStart) == 0)
654
0
    pg_atomic_write_u64(&MyProc->waitStart, now);
655
656
0
  if (now >= ltime && ltime != 0)
657
0
  {
658
    /*
659
     * We're already behind, so clear a path as quickly as possible.
660
     */
661
0
    VirtualTransactionId *backends;
662
663
0
    backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL);
664
665
    /*
666
     * Prevent ResolveRecoveryConflictWithVirtualXIDs() from reporting
667
     * "waiting" in PS display by disabling its argument report_waiting
668
     * because the caller, WaitOnLock(), has already reported that.
669
     */
670
0
    ResolveRecoveryConflictWithVirtualXIDs(backends,
671
0
                         RECOVERY_CONFLICT_LOCK,
672
0
                         PG_WAIT_LOCK | locktag.locktag_type,
673
0
                         false);
674
0
  }
675
0
  else
676
0
  {
677
    /*
678
     * Wait (or wait again) until ltime, and check for deadlocks as well
679
     * if we will be waiting longer than deadlock_timeout
680
     */
681
0
    EnableTimeoutParams timeouts[2];
682
0
    int     cnt = 0;
683
684
0
    if (ltime != 0)
685
0
    {
686
0
      got_standby_lock_timeout = false;
687
0
      timeouts[cnt].id = STANDBY_LOCK_TIMEOUT;
688
0
      timeouts[cnt].type = TMPARAM_AT;
689
0
      timeouts[cnt].fin_time = ltime;
690
0
      cnt++;
691
0
    }
692
693
0
    got_standby_deadlock_timeout = false;
694
0
    timeouts[cnt].id = STANDBY_DEADLOCK_TIMEOUT;
695
0
    timeouts[cnt].type = TMPARAM_AFTER;
696
0
    timeouts[cnt].delay_ms = DeadlockTimeout;
697
0
    cnt++;
698
699
0
    enable_timeouts(timeouts, cnt);
700
0
  }
701
702
  /* Wait to be signaled by the release of the Relation Lock */
703
0
  ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type);
704
705
  /*
706
   * Exit if ltime is reached. Then all the backends holding conflicting
707
   * locks will be canceled in the next ResolveRecoveryConflictWithLock()
708
   * call.
709
   */
710
0
  if (got_standby_lock_timeout)
711
0
    goto cleanup;
712
713
0
  if (got_standby_deadlock_timeout)
714
0
  {
715
0
    VirtualTransactionId *backends;
716
717
0
    backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL);
718
719
    /* Quick exit if there's no work to be done */
720
0
    if (!VirtualTransactionIdIsValid(*backends))
721
0
      goto cleanup;
722
723
    /*
724
     * Send signals to all the backends holding the conflicting locks, to
725
     * ask them to check themselves for deadlocks.
726
     */
727
0
    while (VirtualTransactionIdIsValid(*backends))
728
0
    {
729
0
      (void) SignalRecoveryConflictWithVirtualXID(*backends,
730
0
                            RECOVERY_CONFLICT_STARTUP_DEADLOCK);
731
0
      backends++;
732
0
    }
733
734
    /*
735
     * Exit if the recovery conflict has not been logged yet even though
736
     * logging is enabled, so that the caller can log that. Then
737
     * RecoveryConflictWithLock() is called again and we will wait again
738
     * for the lock to be released.
739
     */
740
0
    if (logging_conflict)
741
0
      goto cleanup;
742
743
    /*
744
     * Wait again here to be signaled by the release of the Relation Lock,
745
     * to prevent the subsequent RecoveryConflictWithLock() from causing
746
     * deadlock_timeout and sending a request for deadlocks check again.
747
     * Otherwise the request continues to be sent every deadlock_timeout
748
     * until the relation locks are released or ltime is reached.
749
     */
750
0
    got_standby_deadlock_timeout = false;
751
0
    ProcWaitForSignal(PG_WAIT_LOCK | locktag.locktag_type);
752
0
  }
753
754
0
cleanup:
755
756
  /*
757
   * Clear any timeout requests established above.  We assume here that the
758
   * Startup process doesn't have any other outstanding timeouts than those
759
   * used by this function. If that stops being true, we could cancel the
760
   * timeouts individually, but that'd be slower.
761
   */
762
0
  disable_all_timeouts(false);
763
0
  got_standby_lock_timeout = false;
764
0
  got_standby_deadlock_timeout = false;
765
0
}
766
767
/*
768
 * ResolveRecoveryConflictWithBufferPin is called from LockBufferForCleanup()
769
 * to resolve conflicts with other backends holding buffer pins.
770
 *
771
 * The ProcWaitForSignal() sleep normally done in LockBufferForCleanup()
772
 * (when not InHotStandby) is performed here, for code clarity.
773
 *
774
 * We either resolve conflicts immediately or set a timeout to wake us at
775
 * the limit of our patience.
776
 *
777
 * Resolve conflicts by sending a PROCSIG signal to all backends to check if
778
 * they hold one of the buffer pins that is blocking Startup process. If so,
779
 * those backends will take an appropriate error action, ERROR or FATAL.
780
 *
781
 * We also must check for deadlocks.  Deadlocks occur because if queries
782
 * wait on a lock, that must be behind an AccessExclusiveLock, which can only
783
 * be cleared if the Startup process replays a transaction completion record.
784
 * If Startup process is also waiting then that is a deadlock. The deadlock
785
 * can occur if the query is waiting and then the Startup sleeps, or if
786
 * Startup is sleeping and the query waits on a lock. We protect against
787
 * only the former sequence here, the latter sequence is checked prior to
788
 * the query sleeping, in CheckRecoveryConflictDeadlock().
789
 *
790
 * Deadlocks are extremely rare, and relatively expensive to check for,
791
 * so we don't do a deadlock check right away ... only if we have had to wait
792
 * at least deadlock_timeout.
793
 */
794
void
795
ResolveRecoveryConflictWithBufferPin(void)
796
0
{
797
0
  TimestampTz ltime;
798
799
0
  Assert(InHotStandby);
800
801
0
  ltime = GetStandbyLimitTime();
802
803
0
  if (GetCurrentTimestamp() >= ltime && ltime != 0)
804
0
  {
805
    /*
806
     * We're already behind, so clear a path as quickly as possible.
807
     */
808
0
    SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_BUFFERPIN);
809
0
  }
810
0
  else
811
0
  {
812
    /*
813
     * Wake up at ltime, and check for deadlocks as well if we will be
814
     * waiting longer than deadlock_timeout
815
     */
816
0
    EnableTimeoutParams timeouts[2];
817
0
    int     cnt = 0;
818
819
0
    if (ltime != 0)
820
0
    {
821
0
      timeouts[cnt].id = STANDBY_TIMEOUT;
822
0
      timeouts[cnt].type = TMPARAM_AT;
823
0
      timeouts[cnt].fin_time = ltime;
824
0
      cnt++;
825
0
    }
826
827
0
    got_standby_deadlock_timeout = false;
828
0
    timeouts[cnt].id = STANDBY_DEADLOCK_TIMEOUT;
829
0
    timeouts[cnt].type = TMPARAM_AFTER;
830
0
    timeouts[cnt].delay_ms = DeadlockTimeout;
831
0
    cnt++;
832
833
0
    enable_timeouts(timeouts, cnt);
834
0
  }
835
836
  /*
837
   * Wait to be signaled by UnpinBuffer() or for the wait to be interrupted
838
   * by one of the timeouts established above.
839
   *
840
   * We assume that only UnpinBuffer() and the timeout requests established
841
   * above can wake us up here. WakeupRecovery() called by walreceiver or
842
   * SIGHUP signal handler, etc cannot do that because it uses the different
843
   * latch from that ProcWaitForSignal() waits on.
844
   */
845
0
  ProcWaitForSignal(WAIT_EVENT_BUFFER_CLEANUP);
846
847
0
  if (got_standby_delay_timeout)
848
0
    SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_BUFFERPIN);
849
0
  else if (got_standby_deadlock_timeout)
850
0
  {
851
    /*
852
     * Send out a request for hot-standby backends to check themselves for
853
     * deadlocks.
854
     *
855
     * XXX The subsequent ResolveRecoveryConflictWithBufferPin() will wait
856
     * to be signaled by UnpinBuffer() again and send a request for
857
     * deadlocks check if deadlock_timeout happens. This causes the
858
     * request to continue to be sent every deadlock_timeout until the
859
     * buffer is unpinned or ltime is reached. This would increase the
860
     * workload in the startup process and backends. In practice it may
861
     * not be so harmful because the period that the buffer is kept pinned
862
     * is basically no so long. But we should fix this?
863
     */
864
0
    SendRecoveryConflictWithBufferPin(RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK);
865
0
  }
866
867
  /*
868
   * Clear any timeout requests established above.  We assume here that the
869
   * Startup process doesn't have any other timeouts than what this function
870
   * uses.  If that stops being true, we could cancel the timeouts
871
   * individually, but that'd be slower.
872
   */
873
0
  disable_all_timeouts(false);
874
0
  got_standby_delay_timeout = false;
875
0
  got_standby_deadlock_timeout = false;
876
0
}
877
878
static void
879
SendRecoveryConflictWithBufferPin(RecoveryConflictReason reason)
880
0
{
881
0
  Assert(reason == RECOVERY_CONFLICT_BUFFERPIN ||
882
0
       reason == RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK);
883
884
  /*
885
   * We send signal to all backends to ask them if they are holding the
886
   * buffer pin which is delaying the Startup process. Most of them will be
887
   * innocent, but we let the SIGUSR1 handling in each backend decide their
888
   * own fate.
889
   */
890
0
  SignalRecoveryConflictWithDatabase(InvalidOid, reason);
891
0
}
892
893
/*
894
 * In Hot Standby perform early deadlock detection.  We abort the lock
895
 * wait if we are about to sleep while holding the buffer pin that Startup
896
 * process is waiting for.
897
 *
898
 * Note: this code is pessimistic, because there is no way for it to
899
 * determine whether an actual deadlock condition is present: the lock we
900
 * need to wait for might be unrelated to any held by the Startup process.
901
 * Sooner or later, this mechanism should get ripped out in favor of somehow
902
 * accounting for buffer locks in DeadLockCheck().  However, errors here
903
 * seem to be very low-probability in practice, so for now it's not worth
904
 * the trouble.
905
 */
906
void
907
CheckRecoveryConflictDeadlock(void)
908
0
{
909
0
  Assert(!InRecovery);    /* do not call in Startup process */
910
911
0
  if (!HoldingBufferPinThatDelaysRecovery())
912
0
    return;
913
914
  /*
915
   * Error message should match ProcessInterrupts() but we avoid calling
916
   * that because we aren't handling an interrupt at this point. Note that
917
   * we only cancel the current transaction here, so if we are in a
918
   * subtransaction and the pin is held by a parent, then the Startup
919
   * process will continue to wait even though we have avoided deadlock.
920
   */
921
0
  ereport(ERROR,
922
0
      (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
923
0
       errmsg("canceling statement due to conflict with recovery"),
924
0
       errdetail("User transaction caused buffer deadlock with recovery.")));
925
0
}
926
927
928
/* --------------------------------
929
 *    timeout handler routines
930
 * --------------------------------
931
 */
932
933
/*
934
 * StandbyDeadLockHandler() will be called if STANDBY_DEADLOCK_TIMEOUT is
935
 * exceeded.
936
 */
937
void
938
StandbyDeadLockHandler(void)
939
0
{
940
0
  got_standby_deadlock_timeout = true;
941
0
}
942
943
/*
944
 * StandbyTimeoutHandler() will be called if STANDBY_TIMEOUT is exceeded.
945
 */
946
void
947
StandbyTimeoutHandler(void)
948
0
{
949
0
  got_standby_delay_timeout = true;
950
0
}
951
952
/*
953
 * StandbyLockTimeoutHandler() will be called if STANDBY_LOCK_TIMEOUT is exceeded.
954
 */
955
void
956
StandbyLockTimeoutHandler(void)
957
0
{
958
0
  got_standby_lock_timeout = true;
959
0
}
960
961
/*
962
 * -----------------------------------------------------
963
 * Locking in Recovery Mode
964
 * -----------------------------------------------------
965
 *
966
 * All locks are held by the Startup process using a single virtual
967
 * transaction. This implementation is both simpler and in some senses,
968
 * more correct. The locks held mean "some original transaction held
969
 * this lock, so query access is not allowed at this time". So the Startup
970
 * process is the proxy by which the original locks are implemented.
971
 *
972
 * We only keep track of AccessExclusiveLocks, which are only ever held by
973
 * one transaction on one relation.
974
 *
975
 * We keep a table of known locks in the RecoveryLockHash hash table.
976
 * The point of that table is to let us efficiently de-duplicate locks,
977
 * which is important because checkpoints will re-report the same locks
978
 * already held.  There is also a RecoveryLockXidHash table with one entry
979
 * per xid, which allows us to efficiently find all the locks held by a
980
 * given original transaction.
981
 *
982
 * We use session locks rather than normal locks so we don't need
983
 * ResourceOwners.
984
 */
985
986
987
void
988
StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
989
0
{
990
0
  RecoveryLockXidEntry *xidentry;
991
0
  RecoveryLockEntry *lockentry;
992
0
  xl_standby_lock key;
993
0
  LOCKTAG   locktag;
994
0
  bool    found;
995
996
  /* Already processed? */
997
0
  if (!TransactionIdIsValid(xid) ||
998
0
    TransactionIdDidCommit(xid) ||
999
0
    TransactionIdDidAbort(xid))
1000
0
    return;
1001
1002
0
  elog(DEBUG4, "adding recovery lock: db %u rel %u", dbOid, relOid);
1003
1004
  /* dbOid is InvalidOid when we are locking a shared relation. */
1005
0
  Assert(OidIsValid(relOid));
1006
1007
  /* Create a hash entry for this xid, if we don't have one already. */
1008
0
  xidentry = hash_search(RecoveryLockXidHash, &xid, HASH_ENTER, &found);
1009
0
  if (!found)
1010
0
  {
1011
0
    Assert(xidentry->xid == xid); /* dynahash should have set this */
1012
0
    xidentry->head = NULL;
1013
0
  }
1014
1015
  /* Create a hash entry for this lock, unless we have one already. */
1016
0
  key.xid = xid;
1017
0
  key.dbOid = dbOid;
1018
0
  key.relOid = relOid;
1019
0
  lockentry = hash_search(RecoveryLockHash, &key, HASH_ENTER, &found);
1020
0
  if (!found)
1021
0
  {
1022
    /* First, acquire the lock ... */
1023
0
    SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
1024
1025
0
    (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
1026
1027
    /* ... and then, as it is new, link it into the XID's list. */
1028
0
    lockentry->next = xidentry->head;
1029
0
    xidentry->head = lockentry;
1030
0
  }
1031
0
}
1032
1033
/*
1034
 * Release all the locks associated with this RecoveryLockXidEntry.
1035
 */
1036
static void
1037
StandbyReleaseXidEntryLocks(RecoveryLockXidEntry *xidentry)
1038
{
1039
  RecoveryLockEntry *entry;
1040
  RecoveryLockEntry *next;
1041
1042
  for (entry = xidentry->head; entry != NULL; entry = next)
1043
  {
1044
    LOCKTAG   locktag;
1045
1046
    elog(DEBUG4,
1047
       "releasing recovery lock: xid %u db %u rel %u",
1048
       entry->key.xid, entry->key.dbOid, entry->key.relOid);
1049
    /* Release the lock ... */
1050
    SET_LOCKTAG_RELATION(locktag, entry->key.dbOid, entry->key.relOid);
1051
    if (!LockRelease(&locktag, AccessExclusiveLock, true))
1052
    {
1053
      elog(LOG,
1054
         "RecoveryLockHash contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
1055
         entry->key.xid, entry->key.dbOid, entry->key.relOid);
1056
      Assert(false);
1057
    }
1058
    /* ... and remove the per-lock hash entry */
1059
    next = entry->next;
1060
    hash_search(RecoveryLockHash, entry, HASH_REMOVE, NULL);
1061
  }
1062
1063
  xidentry->head = NULL;    /* just for paranoia */
1064
}
1065
1066
/*
1067
 * Release locks for specific XID, or all locks if it's InvalidXid.
1068
 */
1069
static void
1070
StandbyReleaseLocks(TransactionId xid)
1071
0
{
1072
0
  RecoveryLockXidEntry *entry;
1073
1074
0
  if (TransactionIdIsValid(xid))
1075
0
  {
1076
0
    if ((entry = hash_search(RecoveryLockXidHash, &xid, HASH_FIND, NULL)))
1077
0
    {
1078
0
      StandbyReleaseXidEntryLocks(entry);
1079
0
      hash_search(RecoveryLockXidHash, entry, HASH_REMOVE, NULL);
1080
0
    }
1081
0
  }
1082
0
  else
1083
0
    StandbyReleaseAllLocks();
1084
0
}
1085
1086
/*
1087
 * Release locks for a transaction tree, starting at xid down, from
1088
 * RecoveryLockXidHash.
1089
 *
1090
 * Called during WAL replay of COMMIT/ROLLBACK when in hot standby mode,
1091
 * to remove any AccessExclusiveLocks requested by a transaction.
1092
 */
1093
void
1094
StandbyReleaseLockTree(TransactionId xid, int nsubxids, TransactionId *subxids)
1095
0
{
1096
0
  int     i;
1097
1098
0
  StandbyReleaseLocks(xid);
1099
1100
0
  for (i = 0; i < nsubxids; i++)
1101
0
    StandbyReleaseLocks(subxids[i]);
1102
0
}
1103
1104
/*
1105
 * Called at end of recovery and when we see a shutdown checkpoint.
1106
 */
1107
void
1108
StandbyReleaseAllLocks(void)
1109
0
{
1110
0
  HASH_SEQ_STATUS status;
1111
0
  RecoveryLockXidEntry *entry;
1112
1113
0
  elog(DEBUG2, "release all standby locks");
1114
1115
0
  hash_seq_init(&status, RecoveryLockXidHash);
1116
0
  while ((entry = hash_seq_search(&status)))
1117
0
  {
1118
0
    StandbyReleaseXidEntryLocks(entry);
1119
0
    hash_search(RecoveryLockXidHash, entry, HASH_REMOVE, NULL);
1120
0
  }
1121
0
}
1122
1123
/*
1124
 * StandbyReleaseOldLocks
1125
 *    Release standby locks held by top-level XIDs that aren't running,
1126
 *    as long as they're not prepared transactions.
1127
 *
1128
 * This is needed to prune the locks of crashed transactions, which didn't
1129
 * write an ABORT/COMMIT record.
1130
 */
1131
void
1132
StandbyReleaseOldLocks(TransactionId oldxid)
1133
0
{
1134
0
  HASH_SEQ_STATUS status;
1135
0
  RecoveryLockXidEntry *entry;
1136
1137
0
  hash_seq_init(&status, RecoveryLockXidHash);
1138
0
  while ((entry = hash_seq_search(&status)))
1139
0
  {
1140
0
    Assert(TransactionIdIsValid(entry->xid));
1141
1142
    /* Skip if prepared transaction. */
1143
0
    if (StandbyTransactionIdIsPrepared(entry->xid))
1144
0
      continue;
1145
1146
    /* Skip if >= oldxid. */
1147
0
    if (!TransactionIdPrecedes(entry->xid, oldxid))
1148
0
      continue;
1149
1150
    /* Remove all locks and hash table entry. */
1151
0
    StandbyReleaseXidEntryLocks(entry);
1152
0
    hash_search(RecoveryLockXidHash, entry, HASH_REMOVE, NULL);
1153
0
  }
1154
0
}
1155
1156
/*
1157
 * --------------------------------------------------------------------
1158
 *    Recovery handling for Rmgr RM_STANDBY_ID
1159
 *
1160
 * These record types will only be created if XLogStandbyInfoActive()
1161
 * --------------------------------------------------------------------
1162
 */
1163
1164
void
1165
standby_redo(XLogReaderState *record)
1166
0
{
1167
0
  uint8   info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
1168
1169
  /* Backup blocks are not used in standby records */
1170
0
  Assert(!XLogRecHasAnyBlockRefs(record));
1171
1172
  /* Do nothing if we're not in hot standby mode */
1173
0
  if (standbyState == STANDBY_DISABLED)
1174
0
    return;
1175
1176
0
  if (info == XLOG_STANDBY_LOCK)
1177
0
  {
1178
0
    xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
1179
0
    int     i;
1180
1181
0
    for (i = 0; i < xlrec->nlocks; i++)
1182
0
      StandbyAcquireAccessExclusiveLock(xlrec->locks[i].xid,
1183
0
                        xlrec->locks[i].dbOid,
1184
0
                        xlrec->locks[i].relOid);
1185
0
  }
1186
0
  else if (info == XLOG_RUNNING_XACTS)
1187
0
  {
1188
0
    xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
1189
0
    RunningTransactionsData running;
1190
1191
0
    running.xcnt = xlrec->xcnt;
1192
0
    running.subxcnt = xlrec->subxcnt;
1193
0
    running.subxid_status = xlrec->subxid_overflow ? SUBXIDS_MISSING : SUBXIDS_IN_ARRAY;
1194
0
    running.nextXid = xlrec->nextXid;
1195
0
    running.latestCompletedXid = xlrec->latestCompletedXid;
1196
0
    running.oldestRunningXid = xlrec->oldestRunningXid;
1197
0
    running.xids = xlrec->xids;
1198
1199
0
    ProcArrayApplyRecoveryInfo(&running);
1200
1201
    /*
1202
     * The startup process currently has no convenient way to schedule
1203
     * stats to be reported. XLOG_RUNNING_XACTS records issued at a
1204
     * regular cadence, making this a convenient location to report stats.
1205
     * While these records aren't generated with wal_level=minimal, stats
1206
     * also cannot be accessed during WAL replay.
1207
     */
1208
0
    pgstat_report_stat(true);
1209
0
  }
1210
0
  else if (info == XLOG_INVALIDATIONS)
1211
0
  {
1212
0
    xl_invalidations *xlrec = (xl_invalidations *) XLogRecGetData(record);
1213
1214
0
    ProcessCommittedInvalidationMessages(xlrec->msgs,
1215
0
                       xlrec->nmsgs,
1216
0
                       xlrec->relcacheInitFileInval,
1217
0
                       xlrec->dbId,
1218
0
                       xlrec->tsId);
1219
0
  }
1220
0
  else
1221
0
    elog(PANIC, "standby_redo: unknown op code %u", info);
1222
0
}
1223
1224
/*
1225
 * Log details of the current snapshot to WAL. This allows the snapshot state
1226
 * to be reconstructed on the standby and for logical decoding.
1227
 *
1228
 * This is used for Hot Standby as follows:
1229
 *
1230
 * We can move directly to STANDBY_SNAPSHOT_READY at startup if we
1231
 * start from a shutdown checkpoint because we know nothing was running
1232
 * at that time and our recovery snapshot is known empty. In the more
1233
 * typical case of an online checkpoint we need to jump through a few
1234
 * hoops to get a correct recovery snapshot and this requires a two or
1235
 * sometimes a three stage process.
1236
 *
1237
 * The initial snapshot must contain all running xids and all current
1238
 * AccessExclusiveLocks at a point in time on the standby. Assembling
1239
 * that information while the server is running requires many and
1240
 * various LWLocks, so we choose to derive that information piece by
1241
 * piece and then re-assemble that info on the standby. When that
1242
 * information is fully assembled we move to STANDBY_SNAPSHOT_READY.
1243
 *
1244
 * Since locking on the primary when we derive the information is not
1245
 * strict, we note that there is a time window between the derivation and
1246
 * writing to WAL of the derived information. That allows race conditions
1247
 * that we must resolve, since xids and locks may enter or leave the
1248
 * snapshot during that window. This creates the issue that an xid or
1249
 * lock may start *after* the snapshot has been derived yet *before* the
1250
 * snapshot is logged in the running xacts WAL record. We resolve this by
1251
 * starting to accumulate changes at a point just prior to when we derive
1252
 * the snapshot on the primary, then ignore duplicates when we later apply
1253
 * the snapshot from the running xacts record. This is implemented during
1254
 * CreateCheckPoint() where we use the logical checkpoint location as
1255
 * our starting point and then write the running xacts record immediately
1256
 * before writing the main checkpoint WAL record. Since we always start
1257
 * up from a checkpoint and are immediately at our starting point, we
1258
 * unconditionally move to STANDBY_INITIALIZED. After this point we
1259
 * must do 4 things:
1260
 *  * move shared nextXid forwards as we see new xids
1261
 *  * extend the clog and subtrans with each new xid
1262
 *  * keep track of uncommitted known assigned xids
1263
 *  * keep track of uncommitted AccessExclusiveLocks
1264
 *
1265
 * When we see a commit/abort we must remove known assigned xids and locks
1266
 * from the completing transaction. Attempted removals that cannot locate
1267
 * an entry are expected and must not cause an error when we are in state
1268
 * STANDBY_INITIALIZED. This is implemented in StandbyReleaseLocks() and
1269
 * KnownAssignedXidsRemove().
1270
 *
1271
 * Later, when we apply the running xact data we must be careful to ignore
1272
 * transactions already committed, since those commits raced ahead when
1273
 * making WAL entries.
1274
 *
1275
 * For logical decoding only the running xacts information is needed;
1276
 * there's no need to look at the locking information, but it's logged anyway,
1277
 * as there's no independent knob to just enable logical decoding. For
1278
 * details of how this is used, check snapbuild.c's introductory comment.
1279
 *
1280
 *
1281
 * Returns the RecPtr of the last inserted record.
1282
 */
1283
XLogRecPtr
1284
LogStandbySnapshot(void)
1285
0
{
1286
0
  XLogRecPtr  recptr;
1287
0
  RunningTransactions running;
1288
0
  xl_standby_lock *locks;
1289
0
  int     nlocks;
1290
0
  bool    logical_decoding_enabled = IsLogicalDecodingEnabled();
1291
1292
0
  Assert(XLogStandbyInfoActive());
1293
1294
#ifdef USE_INJECTION_POINTS
1295
  if (IS_INJECTION_POINT_ATTACHED("skip-log-running-xacts"))
1296
  {
1297
    /*
1298
     * This record could move slot's xmin forward during decoding, leading
1299
     * to unpredictable results, so skip it when requested by the test.
1300
     */
1301
    return GetInsertRecPtr();
1302
  }
1303
#endif
1304
1305
  /*
1306
   * Get details of any AccessExclusiveLocks being held at the moment.
1307
   */
1308
0
  locks = GetRunningTransactionLocks(&nlocks);
1309
0
  if (nlocks > 0)
1310
0
    LogAccessExclusiveLocks(nlocks, locks);
1311
0
  pfree(locks);
1312
1313
  /*
1314
   * Log details of all in-progress transactions. This should be the last
1315
   * record we write, because standby will open up when it sees this.
1316
   */
1317
0
  running = GetRunningTransactionData();
1318
1319
  /*
1320
   * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
1321
   * For Hot Standby this can be done before inserting the WAL record
1322
   * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
1323
   * the clog. For logical decoding, though, the lock can't be released
1324
   * early because the clog might be "in the future" from the POV of the
1325
   * historic snapshot. This would allow for situations where we're waiting
1326
   * for the end of a transaction listed in the xl_running_xacts record
1327
   * which, according to the WAL, has committed before the xl_running_xacts
1328
   * record. Fortunately this routine isn't executed frequently, and it's
1329
   * only a shared lock.
1330
   */
1331
0
  if (!logical_decoding_enabled)
1332
0
    LWLockRelease(ProcArrayLock);
1333
1334
0
  recptr = LogCurrentRunningXacts(running);
1335
1336
  /* Release lock if we kept it longer ... */
1337
0
  if (logical_decoding_enabled)
1338
0
    LWLockRelease(ProcArrayLock);
1339
1340
  /* GetRunningTransactionData() acquired XidGenLock, we must release it */
1341
0
  LWLockRelease(XidGenLock);
1342
1343
0
  return recptr;
1344
0
}
1345
1346
/*
1347
 * Record an enhanced snapshot of running transactions into WAL.
1348
 *
1349
 * The definitions of RunningTransactionsData and xl_running_xacts are
1350
 * similar. We keep them separate because xl_running_xacts is a contiguous
1351
 * chunk of memory and never exists fully until it is assembled in WAL.
1352
 * The inserted records are marked as not being important for durability,
1353
 * to avoid triggering superfluous checkpoint / archiving activity.
1354
 */
1355
static XLogRecPtr
1356
LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
1357
{
1358
  xl_running_xacts xlrec;
1359
  XLogRecPtr  recptr;
1360
1361
  xlrec.xcnt = CurrRunningXacts->xcnt;
1362
  xlrec.subxcnt = CurrRunningXacts->subxcnt;
1363
  xlrec.subxid_overflow = (CurrRunningXacts->subxid_status != SUBXIDS_IN_ARRAY);
1364
  xlrec.nextXid = CurrRunningXacts->nextXid;
1365
  xlrec.oldestRunningXid = CurrRunningXacts->oldestRunningXid;
1366
  xlrec.latestCompletedXid = CurrRunningXacts->latestCompletedXid;
1367
1368
  /* Header */
1369
  XLogBeginInsert();
1370
  XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
1371
  XLogRegisterData(&xlrec, MinSizeOfXactRunningXacts);
1372
1373
  /* array of TransactionIds */
1374
  if (xlrec.xcnt > 0)
1375
    XLogRegisterData(CurrRunningXacts->xids,
1376
             (xlrec.xcnt + xlrec.subxcnt) * sizeof(TransactionId));
1377
1378
  recptr = XLogInsert(RM_STANDBY_ID, XLOG_RUNNING_XACTS);
1379
1380
  if (xlrec.subxid_overflow)
1381
    elog(DEBUG2,
1382
       "snapshot of %d running transactions overflowed (lsn %X/%08X oldest xid %u latest complete %u next xid %u)",
1383
       CurrRunningXacts->xcnt,
1384
       LSN_FORMAT_ARGS(recptr),
1385
       CurrRunningXacts->oldestRunningXid,
1386
       CurrRunningXacts->latestCompletedXid,
1387
       CurrRunningXacts->nextXid);
1388
  else
1389
    elog(DEBUG2,
1390
       "snapshot of %d+%d running transaction ids (lsn %X/%08X oldest xid %u latest complete %u next xid %u)",
1391
       CurrRunningXacts->xcnt, CurrRunningXacts->subxcnt,
1392
       LSN_FORMAT_ARGS(recptr),
1393
       CurrRunningXacts->oldestRunningXid,
1394
       CurrRunningXacts->latestCompletedXid,
1395
       CurrRunningXacts->nextXid);
1396
1397
  /*
1398
   * Ensure running_xacts information is synced to disk not too far in the
1399
   * future. We don't want to stall anything though (i.e. use XLogFlush()),
1400
   * so we let the wal writer do it during normal operation.
1401
   * XLogSetAsyncXactLSN() conveniently will mark the LSN as to-be-synced
1402
   * and nudge the WALWriter into action if sleeping. Check
1403
   * XLogBackgroundFlush() for details why a record might not be flushed
1404
   * without it.
1405
   */
1406
  XLogSetAsyncXactLSN(recptr);
1407
1408
  return recptr;
1409
}
1410
1411
/*
1412
 * Wholesale logging of AccessExclusiveLocks. Other lock types need not be
1413
 * logged, as described in backend/storage/lmgr/README.
1414
 */
1415
static void
1416
LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
1417
0
{
1418
0
  xl_standby_locks xlrec;
1419
1420
0
  xlrec.nlocks = nlocks;
1421
1422
0
  XLogBeginInsert();
1423
0
  XLogRegisterData(&xlrec, offsetof(xl_standby_locks, locks));
1424
0
  XLogRegisterData(locks, nlocks * sizeof(xl_standby_lock));
1425
0
  XLogSetRecordFlags(XLOG_MARK_UNIMPORTANT);
1426
1427
0
  (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK);
1428
0
}
1429
1430
/*
1431
 * Individual logging of AccessExclusiveLocks for use during LockAcquire()
1432
 */
1433
void
1434
LogAccessExclusiveLock(Oid dbOid, Oid relOid)
1435
0
{
1436
0
  xl_standby_lock xlrec;
1437
1438
0
  xlrec.xid = GetCurrentTransactionId();
1439
1440
0
  xlrec.dbOid = dbOid;
1441
0
  xlrec.relOid = relOid;
1442
1443
0
  LogAccessExclusiveLocks(1, &xlrec);
1444
0
  MyXactFlags |= XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK;
1445
0
}
1446
1447
/*
1448
 * Prepare to log an AccessExclusiveLock, for use during LockAcquire()
1449
 */
1450
void
1451
LogAccessExclusiveLockPrepare(void)
1452
0
{
1453
  /*
1454
   * Ensure that a TransactionId has been assigned to this transaction, for
1455
   * two reasons, both related to lock release on the standby. First, we
1456
   * must assign an xid so that RecordTransactionCommit() and
1457
   * RecordTransactionAbort() do not optimise away the transaction
1458
   * completion record which recovery relies upon to release locks. It's a
1459
   * hack, but for a corner case not worth adding code for into the main
1460
   * commit path. Second, we must assign an xid before the lock is recorded
1461
   * in shared memory, otherwise a concurrently executing
1462
   * GetRunningTransactionLocks() might see a lock associated with an
1463
   * InvalidTransactionId which we later assert cannot happen.
1464
   */
1465
0
  (void) GetCurrentTransactionId();
1466
0
}
1467
1468
/*
1469
 * Emit WAL for invalidations. This currently is only used for commits without
1470
 * an xid but which contain invalidations.
1471
 */
1472
void
1473
LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
1474
            bool relcacheInitFileInval)
1475
0
{
1476
0
  xl_invalidations xlrec;
1477
1478
  /* prepare record */
1479
0
  memset(&xlrec, 0, sizeof(xlrec));
1480
0
  xlrec.dbId = MyDatabaseId;
1481
0
  xlrec.tsId = MyDatabaseTableSpace;
1482
0
  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1483
0
  xlrec.nmsgs = nmsgs;
1484
1485
  /* perform insertion */
1486
0
  XLogBeginInsert();
1487
0
  XLogRegisterData(&xlrec, MinSizeOfInvalidations);
1488
0
  XLogRegisterData(msgs,
1489
0
           nmsgs * sizeof(SharedInvalidationMessage));
1490
0
  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1491
0
}
1492
1493
/* Return the description of recovery conflict */
1494
static const char *
1495
get_recovery_conflict_desc(RecoveryConflictReason reason)
1496
0
{
1497
0
  const char *reasonDesc = _("unknown reason");
1498
1499
0
  switch (reason)
1500
0
  {
1501
0
    case RECOVERY_CONFLICT_BUFFERPIN:
1502
0
      reasonDesc = _("recovery conflict on buffer pin");
1503
0
      break;
1504
0
    case RECOVERY_CONFLICT_LOCK:
1505
0
      reasonDesc = _("recovery conflict on lock");
1506
0
      break;
1507
0
    case RECOVERY_CONFLICT_TABLESPACE:
1508
0
      reasonDesc = _("recovery conflict on tablespace");
1509
0
      break;
1510
0
    case RECOVERY_CONFLICT_SNAPSHOT:
1511
0
      reasonDesc = _("recovery conflict on snapshot");
1512
0
      break;
1513
0
    case RECOVERY_CONFLICT_LOGICALSLOT:
1514
0
      reasonDesc = _("recovery conflict on replication slot");
1515
0
      break;
1516
0
    case RECOVERY_CONFLICT_STARTUP_DEADLOCK:
1517
0
      reasonDesc = _("recovery conflict on deadlock");
1518
0
      break;
1519
0
    case RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK:
1520
0
      reasonDesc = _("recovery conflict on buffer deadlock");
1521
0
      break;
1522
0
    case RECOVERY_CONFLICT_DATABASE:
1523
0
      reasonDesc = _("recovery conflict on database");
1524
0
      break;
1525
0
  }
1526
1527
0
  return reasonDesc;
1528
0
}