mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Add basic infrastructure for 64 bit transaction IDs.
Instead of inferring epoch progress from xids and checkpoints, introduce a 64 bit FullTransactionId type and use it to track xid generation. This fixes an unlikely bug where the epoch is reported incorrectly if the range of active xids wraps around more than once between checkpoints. The only user-visible effect of this commit is to correct the epoch used by txid_current() and txid_status(), also visible with pg_controldata, in those rare circumstances. It also creates some basic infrastructure so that later patches can use 64 bit transaction IDs in more places. The new type is a struct that we pass by value, as a form of strong typedef. This prevents the sort of accidental confusion between TransactionId and FullTransactionId that would be possible if we were to use a plain old uint64. Author: Thomas Munro Reported-by: Amit Kapila Reviewed-by: Andres Freund, Tom Lane, Heikki Linnakangas Discussion: https://postgr.es/m/CAA4eK1%2BMv%2Bmb0HFfWM9Srtc6MVe160WFurXV68iAFMcagRZ0dQ%40mail.gmail.com
This commit is contained in:
@@ -44,6 +44,32 @@
|
||||
#define TransactionIdStore(xid, dest) (*(dest) = (xid))
|
||||
#define StoreInvalidTransactionId(dest) (*(dest) = InvalidTransactionId)
|
||||
|
||||
#define EpochFromFullTransactionId(x) ((uint32) ((x).value >> 32))
|
||||
#define XidFromFullTransactionId(x) ((uint32) (x).value)
|
||||
#define U64FromFullTransactionId(x) ((x).value)
|
||||
#define FullTransactionIdPrecedes(a, b) ((a).value < (b).value)
|
||||
#define FullTransactionIdIsValid(x) TransactionIdIsValid(XidFromFullTransactionId(x))
|
||||
|
||||
/*
|
||||
* A 64 bit value that contains an epoch and a TransactionId. This is
|
||||
* wrapped in a struct to prevent implicit conversion to/from TransactionId.
|
||||
* Not all values represent valid normal XIDs.
|
||||
*/
|
||||
typedef struct FullTransactionId
|
||||
{
|
||||
uint64 value;
|
||||
} FullTransactionId;
|
||||
|
||||
static inline FullTransactionId
|
||||
FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
|
||||
{
|
||||
FullTransactionId result;
|
||||
|
||||
result.value = ((uint64) epoch) << 32 | xid;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* advance a transaction ID variable, handling wraparound correctly */
|
||||
#define TransactionIdAdvance(dest) \
|
||||
do { \
|
||||
@@ -52,6 +78,15 @@
|
||||
(dest) = FirstNormalTransactionId; \
|
||||
} while(0)
|
||||
|
||||
/* advance a FullTransactionId variable, stepping over special XIDs */
|
||||
static inline void
|
||||
FullTransactionIdAdvance(FullTransactionId *dest)
|
||||
{
|
||||
dest->value++;
|
||||
while (XidFromFullTransactionId(*dest) < FirstNormalTransactionId)
|
||||
dest->value++;
|
||||
}
|
||||
|
||||
/* back up a transaction ID variable, handling wraparound correctly */
|
||||
#define TransactionIdRetreat(dest) \
|
||||
do { \
|
||||
@@ -125,12 +160,12 @@ typedef struct VariableCacheData
|
||||
/*
|
||||
* These fields are protected by XidGenLock.
|
||||
*/
|
||||
TransactionId nextXid; /* next XID to assign */
|
||||
FullTransactionId nextFullXid; /* next full XID to assign */
|
||||
|
||||
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
|
||||
TransactionId xidVacLimit; /* start forcing autovacuums here */
|
||||
TransactionId xidWarnLimit; /* start complaining here */
|
||||
TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */
|
||||
TransactionId xidStopLimit; /* refuse to advance nextFullXid beyond here */
|
||||
TransactionId xidWrapLimit; /* where the world ends */
|
||||
Oid oldestXidDB; /* database with minimum datfrozenxid */
|
||||
|
||||
@@ -187,11 +222,21 @@ extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid);
|
||||
|
||||
/* in transam/varsup.c */
|
||||
extern TransactionId GetNewTransactionId(bool isSubXact);
|
||||
extern TransactionId ReadNewTransactionId(void);
|
||||
extern void AdvanceNextFullTransactionIdPastXid(TransactionId xid);
|
||||
extern FullTransactionId ReadNextFullTransactionId(void);
|
||||
extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
|
||||
Oid oldest_datoid);
|
||||
extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid);
|
||||
extern bool ForceTransactionIdLimitUpdate(void);
|
||||
extern Oid GetNewObjectId(void);
|
||||
|
||||
/*
|
||||
* For callers that just need the XID part of the next transaction ID.
|
||||
*/
|
||||
static inline TransactionId
|
||||
ReadNewTransactionId(void)
|
||||
{
|
||||
return XidFromFullTransactionId(ReadNextFullTransactionId());
|
||||
}
|
||||
|
||||
#endif /* TRAMSAM_H */
|
||||
|
@@ -310,7 +310,6 @@ extern XLogRecPtr GetRedoRecPtr(void);
|
||||
extern XLogRecPtr GetInsertRecPtr(void);
|
||||
extern XLogRecPtr GetFlushRecPtr(void);
|
||||
extern XLogRecPtr GetLastImportantRecPtr(void);
|
||||
extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch);
|
||||
extern void RemovePromoteSignalFiles(void);
|
||||
|
||||
extern bool CheckPromoteSignal(void);
|
||||
|
@@ -15,13 +15,14 @@
|
||||
#ifndef PG_CONTROL_H
|
||||
#define PG_CONTROL_H
|
||||
|
||||
#include "access/transam.h"
|
||||
#include "access/xlogdefs.h"
|
||||
#include "pgtime.h" /* for pg_time_t */
|
||||
#include "port/pg_crc32c.h"
|
||||
|
||||
|
||||
/* Version identifier for this pg_control format */
|
||||
#define PG_CONTROL_VERSION 1200
|
||||
#define PG_CONTROL_VERSION 1201
|
||||
|
||||
/* Nonce key length, see below */
|
||||
#define MOCK_AUTH_NONCE_LEN 32
|
||||
@@ -39,8 +40,7 @@ typedef struct CheckPoint
|
||||
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
|
||||
* timeline (equals ThisTimeLineID otherwise) */
|
||||
bool fullPageWrites; /* current full_page_writes */
|
||||
uint32 nextXidEpoch; /* higher-order bits of nextXid */
|
||||
TransactionId nextXid; /* next free XID */
|
||||
FullTransactionId nextFullXid; /* next free full transaction ID */
|
||||
Oid nextOid; /* next free OID */
|
||||
MultiXactId nextMulti; /* next free MultiXactId */
|
||||
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
|
||||
|
@@ -72,7 +72,7 @@ typedef struct RunningTransactionsData
|
||||
int xcnt; /* # of xact ids in xids[] */
|
||||
int subxcnt; /* # of subxact ids in xids[] */
|
||||
bool subxid_overflow; /* snapshot overflowed, subxids missing */
|
||||
TransactionId nextXid; /* copy of ShmemVariableCache->nextXid */
|
||||
TransactionId nextXid; /* xid from ShmemVariableCache->nextFullXid */
|
||||
TransactionId oldestRunningXid; /* *not* oldestXmin */
|
||||
TransactionId latestCompletedXid; /* so we can set xmax */
|
||||
|
||||
|
@@ -49,7 +49,7 @@ typedef struct xl_running_xacts
|
||||
int xcnt; /* # of xact ids in xids[] */
|
||||
int subxcnt; /* # of subxact ids in xids[] */
|
||||
bool subxid_overflow; /* snapshot overflowed, subxids missing */
|
||||
TransactionId nextXid; /* copy of ShmemVariableCache->nextXid */
|
||||
TransactionId nextXid; /* xid from ShmemVariableCache->nextFullXid */
|
||||
TransactionId oldestRunningXid; /* *not* oldestXmin */
|
||||
TransactionId latestCompletedXid; /* so we can set xmax */
|
||||
|
||||
|
Reference in New Issue
Block a user