mirror of
https://github.com/postgres/postgres.git
synced 2025-07-20 05:03:10 +03:00
Add new wal_level, logical, sufficient for logical decoding.
When wal_level=logical, we'll log columns from the old tuple as
configured by the REPLICA IDENTITY facility added in commit
07cacba983
. This makes it possible
a properly-configured logical replication solution to correctly
follow table updates even if they change the chosen key columns,
or, with REPLICA IDENTITY FULL, even if the table has no key at
all. Note that updates which do not modify the replica identity
column won't log anything extra, making the choice of a good key
(i.e. one that will rarely be changed) important to performance
when wal_level=logical is configured.
Each insert, update, or delete to a catalog table will also log
the CMIN and/or CMAX values of stamped by the current transaction.
This is necessary because logical decoding will require access to
historical snapshots of the catalog in order to decode some data
types, and the CMIN/CMAX values that we may need in order to judge
row visibility may have been overwritten by the time we need them.
Andres Freund, reviewed in various versions by myself, Heikki
Linnakangas, KONDO Mitsumasa, and many others.
This commit is contained in:
@ -148,6 +148,7 @@ typedef struct TransactionStateData
|
||||
int prevSecContext; /* previous SecurityRestrictionContext */
|
||||
bool prevXactReadOnly; /* entry-time xact r/o state */
|
||||
bool startedInRecovery; /* did we start in recovery? */
|
||||
bool didLogXid; /* has xid been included in WAL record? */
|
||||
struct TransactionStateData *parent; /* back link to parent */
|
||||
} TransactionStateData;
|
||||
|
||||
@ -177,6 +178,7 @@ static TransactionStateData TopTransactionStateData = {
|
||||
0, /* previous SecurityRestrictionContext */
|
||||
false, /* entry-time xact r/o state */
|
||||
false, /* startedInRecovery */
|
||||
false, /* didLogXid */
|
||||
NULL /* link to parent state block */
|
||||
};
|
||||
|
||||
@ -394,6 +396,19 @@ GetCurrentTransactionIdIfAny(void)
|
||||
return CurrentTransactionState->transactionId;
|
||||
}
|
||||
|
||||
/*
|
||||
* MarkCurrentTransactionIdLoggedIfAny
|
||||
*
|
||||
* Remember that the current xid - if it is assigned - now has been wal logged.
|
||||
*/
|
||||
void
|
||||
MarkCurrentTransactionIdLoggedIfAny(void)
|
||||
{
|
||||
if (TransactionIdIsValid(CurrentTransactionState->transactionId))
|
||||
CurrentTransactionState->didLogXid = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GetStableLatestTransactionId
|
||||
*
|
||||
@ -435,6 +450,7 @@ AssignTransactionId(TransactionState s)
|
||||
{
|
||||
bool isSubXact = (s->parent != NULL);
|
||||
ResourceOwner currentOwner;
|
||||
bool log_unknown_top = false;
|
||||
|
||||
/* Assert that caller didn't screw up */
|
||||
Assert(!TransactionIdIsValid(s->transactionId));
|
||||
@ -469,6 +485,20 @@ AssignTransactionId(TransactionState s)
|
||||
pfree(parents);
|
||||
}
|
||||
|
||||
/*
|
||||
* When wal_level=logical, guarantee that a subtransaction's xid can only
|
||||
* be seen in the WAL stream if its toplevel xid has been logged
|
||||
* before. If necessary we log a xact_assignment record with fewer than
|
||||
* PGPROC_MAX_CACHED_SUBXIDS. Note that it is fine if didLogXid isn't set
|
||||
* for a transaction even though it appears in a WAL record, we just might
|
||||
* superfluously log something. That can happen when an xid is included
|
||||
* somewhere inside a wal record, but not in XLogRecord->xl_xid, like in
|
||||
* xl_standby_locks.
|
||||
*/
|
||||
if (isSubXact && XLogLogicalInfoActive() &&
|
||||
!TopTransactionStateData.didLogXid)
|
||||
log_unknown_top = true;
|
||||
|
||||
/*
|
||||
* Generate a new Xid and record it in PG_PROC and pg_subtrans.
|
||||
*
|
||||
@ -523,6 +553,9 @@ AssignTransactionId(TransactionState s)
|
||||
* top-level transaction that each subxact belongs to. This is correct in
|
||||
* recovery only because aborted subtransactions are separately WAL
|
||||
* logged.
|
||||
*
|
||||
* This is correct even for the case where several levels above us didn't
|
||||
* have an xid assigned as we recursed up to them beforehand.
|
||||
*/
|
||||
if (isSubXact && XLogStandbyInfoActive())
|
||||
{
|
||||
@ -533,7 +566,8 @@ AssignTransactionId(TransactionState s)
|
||||
* ensure this test matches similar one in
|
||||
* RecoverPreparedTransactions()
|
||||
*/
|
||||
if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS)
|
||||
if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS ||
|
||||
log_unknown_top)
|
||||
{
|
||||
XLogRecData rdata[2];
|
||||
xl_xact_assignment xlrec;
|
||||
@ -552,13 +586,15 @@ AssignTransactionId(TransactionState s)
|
||||
rdata[0].next = &rdata[1];
|
||||
|
||||
rdata[1].data = (char *) unreportedXids;
|
||||
rdata[1].len = PGPROC_MAX_CACHED_SUBXIDS * sizeof(TransactionId);
|
||||
rdata[1].len = nUnreportedXids * sizeof(TransactionId);
|
||||
rdata[1].buffer = InvalidBuffer;
|
||||
rdata[1].next = NULL;
|
||||
|
||||
(void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT, rdata);
|
||||
|
||||
nUnreportedXids = 0;
|
||||
/* mark top, not current xact as having been logged */
|
||||
TopTransactionStateData.didLogXid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1737,6 +1773,7 @@ StartTransaction(void)
|
||||
* initialize reported xid accounting
|
||||
*/
|
||||
nUnreportedXids = 0;
|
||||
s->didLogXid = false;
|
||||
|
||||
/*
|
||||
* must initialize resource-management stuff first
|
||||
|
Reference in New Issue
Block a user