mirror of
https://github.com/postgres/postgres.git
synced 2026-04-15 22:10:45 -04:00
removing an infrequently occurring race condition in Hot Standby. An xid must be assigned before a lock appears in shared memory, rather than immediately after, else GetRunningTransactionLocks() may see InvalidTransactionId, causing assertion failures during lock processing on standby. Bug report and diagnosis by Fujii Masao, fix by me.
116 lines
4.2 KiB
C
116 lines
4.2 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* standby.h
|
|
* Definitions for hot standby mode.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.11 2010/07/03 20:43:58 tgl Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#ifndef STANDBY_H
|
|
#define STANDBY_H
|
|
|
|
#include "access/xlog.h"
|
|
#include "storage/lock.h"
|
|
#include "storage/procsignal.h"
|
|
#include "storage/relfilenode.h"
|
|
|
|
/* User-settable GUC parameters */
|
|
extern int vacuum_defer_cleanup_age;
|
|
extern int max_standby_archive_delay;
|
|
extern int max_standby_streaming_delay;
|
|
|
|
extern void InitRecoveryTransactionEnvironment(void);
|
|
extern void ShutdownRecoveryTransactionEnvironment(void);
|
|
|
|
extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid,
|
|
RelFileNode node);
|
|
extern void ResolveRecoveryConflictWithRemovedTransactionId(void);
|
|
extern void ResolveRecoveryConflictWithTablespace(Oid tsid);
|
|
extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
|
|
|
|
extern void ResolveRecoveryConflictWithBufferPin(void);
|
|
extern void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
|
|
extern void CheckRecoveryConflictDeadlock(LWLockId partitionLock);
|
|
|
|
/*
|
|
* Standby Rmgr (RM_STANDBY_ID)
|
|
*
|
|
* Standby recovery manager exists to perform actions that are required
|
|
* to make hot standby work. That includes logging AccessExclusiveLocks taken
|
|
* by transactions and running-xacts snapshots.
|
|
*/
|
|
extern void StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid);
|
|
extern void StandbyReleaseLockTree(TransactionId xid,
|
|
int nsubxids, TransactionId *subxids);
|
|
extern void StandbyReleaseAllLocks(void);
|
|
extern void StandbyReleaseOldLocks(TransactionId removeXid);
|
|
|
|
/*
|
|
* XLOG message types
|
|
*/
|
|
#define XLOG_STANDBY_LOCK 0x00
|
|
#define XLOG_RUNNING_XACTS 0x10
|
|
|
|
typedef struct xl_standby_locks
|
|
{
|
|
int nlocks; /* number of entries in locks array */
|
|
xl_standby_lock locks[1]; /* VARIABLE LENGTH ARRAY */
|
|
} xl_standby_locks;
|
|
|
|
/*
|
|
* When we write running xact data to WAL, we use this structure.
|
|
*/
|
|
typedef struct xl_running_xacts
|
|
{
|
|
int xcnt; /* # of xact ids in xids[] */
|
|
bool subxid_overflow; /* snapshot overflowed, subxids missing */
|
|
TransactionId nextXid; /* copy of ShmemVariableCache->nextXid */
|
|
TransactionId oldestRunningXid; /* *not* oldestXmin */
|
|
TransactionId latestCompletedXid; /* so we can set xmax */
|
|
|
|
TransactionId xids[1]; /* VARIABLE LENGTH ARRAY */
|
|
} xl_running_xacts;
|
|
|
|
#define MinSizeOfXactRunningXacts offsetof(xl_running_xacts, xids)
|
|
|
|
|
|
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
|
|
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
|
|
extern void standby_desc(StringInfo buf, uint8 xl_info, char *rec);
|
|
|
|
/*
|
|
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
|
|
* not quite. This has nothing at all to do with visibility on this server,
|
|
* so this is completely separate from snapmgr.c and snapmgr.h.
|
|
* This data is important for creating the initial snapshot state on a
|
|
* standby server. We need lots more information than a normal snapshot,
|
|
* hence we use a specific data structure for our needs. This data
|
|
* is written to WAL as a separate record immediately after each
|
|
* checkpoint. That means that wherever we start a standby from we will
|
|
* almost immediately see the data we need to begin executing queries.
|
|
*/
|
|
|
|
typedef struct RunningTransactionsData
|
|
{
|
|
int xcnt; /* # of xact ids in xids[] */
|
|
bool subxid_overflow; /* snapshot overflowed, subxids missing */
|
|
TransactionId nextXid; /* copy of ShmemVariableCache->nextXid */
|
|
TransactionId oldestRunningXid; /* *not* oldestXmin */
|
|
TransactionId latestCompletedXid; /* so we can set xmax */
|
|
|
|
TransactionId *xids; /* array of (sub)xids still running */
|
|
} RunningTransactionsData;
|
|
|
|
typedef RunningTransactionsData *RunningTransactions;
|
|
|
|
extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
|
|
extern void LogAccessExclusiveLockPrepare(void);
|
|
|
|
extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid);
|
|
|
|
#endif /* STANDBY_H */
|