mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
Merge the various forms of transaction commit & abort records.
Since 465883b0a
two versions of commit records have existed. A compact
version that was used when no cache invalidations, smgr unlinks and
similar were needed, and a full version that could deal with all
that. Additionally the full version was embedded into twophase commit
records.
That resulted in a measurable reduction in the size of the logged WAL in
some workloads. But more recently additions like logical decoding, which
e.g. needs information about the database something was executed on,
made it applicable in fewer situations. The static split generally made
it hard to expand the commit record, because concerns over the size made
it hard to add anything to the compact version.
Additionally it's not particularly pretty to have twophase.c insert
RM_XACT records.
Rejigger things so that the commit and abort records only have one form
each, including the twophase equivalents. The presence of the various
optional (in the sense of not being in every record) pieces is indicated
by a bits in the 'xinfo' flag. That flag previously was not included in
compact commit records. To prevent an increase in size due to its
presence, it's only included if necessary; signalled by a bit in the
xl_info bits available for xact.c, similar to heapam.c's
XLOG_HEAP_OPMASK/XLOG_HEAP_INIT_PAGE.
Twophase commit/aborts are now the same as their normal
counterparts. The original transaction's xid is included in an optional
data field.
This means that commit records generally are smaller, except in the case
of a transaction with subtransactions, but no other special cases; the
increase there is four bytes, which seems acceptable given that the more
common case of not having subtransactions shrank. The savings are
especially measurable for twophase commits, which previously always used
the full version; but will in practice only infrequently have required
that.
The motivation for this work are not the space savings and and
deduplication though; it's that it makes it easier to extend commit
records with additional information. That's just a few lines of code
now; without impacting the common case where that information is not
needed.
Discussion: 20150220152150.GD4149@awork2.anarazel.de,
235610.92468.qm%40web29004.mail.ird.yahoo.com
Reviewed-By: Heikki Linnakangas, Simon Riggs
This commit is contained in:
@ -5168,39 +5168,27 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
|
||||
static bool
|
||||
getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
|
||||
{
|
||||
uint8 record_info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
uint8 xact_info = info & XLOG_XACT_OPMASK;
|
||||
uint8 rmid = XLogRecGetRmid(record);
|
||||
|
||||
if (rmid == RM_XLOG_ID && record_info == XLOG_RESTORE_POINT)
|
||||
if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
|
||||
{
|
||||
*recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
|
||||
return true;
|
||||
}
|
||||
if (rmid == RM_XACT_ID && record_info == XLOG_XACT_COMMIT_COMPACT)
|
||||
{
|
||||
*recordXtime = ((xl_xact_commit_compact *) XLogRecGetData(record))->xact_time;
|
||||
return true;
|
||||
}
|
||||
if (rmid == RM_XACT_ID && record_info == XLOG_XACT_COMMIT)
|
||||
if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
|
||||
xact_info == XLOG_XACT_COMMIT_PREPARED))
|
||||
{
|
||||
*recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
|
||||
return true;
|
||||
}
|
||||
if (rmid == RM_XACT_ID && record_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
{
|
||||
*recordXtime = ((xl_xact_commit_prepared *) XLogRecGetData(record))->crec.xact_time;
|
||||
return true;
|
||||
}
|
||||
if (rmid == RM_XACT_ID && record_info == XLOG_XACT_ABORT)
|
||||
if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
|
||||
xact_info == XLOG_XACT_ABORT_PREPARED))
|
||||
{
|
||||
*recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
|
||||
return true;
|
||||
}
|
||||
if (rmid == RM_XACT_ID && record_info == XLOG_XACT_ABORT_PREPARED)
|
||||
{
|
||||
*recordXtime = ((xl_xact_abort_prepared *) XLogRecGetData(record))->arec.xact_time;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5216,7 +5204,7 @@ static bool
|
||||
recoveryStopsBefore(XLogReaderState *record)
|
||||
{
|
||||
bool stopsHere = false;
|
||||
uint8 record_info;
|
||||
uint8 xact_info;
|
||||
bool isCommit;
|
||||
TimestampTz recordXtime = 0;
|
||||
TransactionId recordXid;
|
||||
@ -5237,27 +5225,40 @@ recoveryStopsBefore(XLogReaderState *record)
|
||||
/* Otherwise we only consider stopping before COMMIT or ABORT records. */
|
||||
if (XLogRecGetRmid(record) != RM_XACT_ID)
|
||||
return false;
|
||||
record_info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
|
||||
if (record_info == XLOG_XACT_COMMIT_COMPACT || record_info == XLOG_XACT_COMMIT)
|
||||
xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
|
||||
|
||||
if (xact_info == XLOG_XACT_COMMIT)
|
||||
{
|
||||
isCommit = true;
|
||||
recordXid = XLogRecGetXid(record);
|
||||
}
|
||||
else if (record_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
else if (xact_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
{
|
||||
xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
|
||||
xl_xact_parsed_commit parsed;
|
||||
|
||||
isCommit = true;
|
||||
recordXid = ((xl_xact_commit_prepared *) XLogRecGetData(record))->xid;
|
||||
ParseCommitRecord(XLogRecGetInfo(record),
|
||||
xlrec,
|
||||
&parsed);
|
||||
recordXid = parsed.twophase_xid;
|
||||
}
|
||||
else if (record_info == XLOG_XACT_ABORT)
|
||||
else if (xact_info == XLOG_XACT_ABORT)
|
||||
{
|
||||
isCommit = false;
|
||||
recordXid = XLogRecGetXid(record);
|
||||
}
|
||||
else if (record_info == XLOG_XACT_ABORT_PREPARED)
|
||||
else if (xact_info == XLOG_XACT_ABORT_PREPARED)
|
||||
{
|
||||
isCommit = false;
|
||||
recordXid = ((xl_xact_abort_prepared *) XLogRecGetData(record))->xid;
|
||||
xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
|
||||
xl_xact_parsed_abort parsed;
|
||||
|
||||
isCommit = true;
|
||||
ParseAbortRecord(XLogRecGetInfo(record),
|
||||
xlrec,
|
||||
&parsed);
|
||||
recordXid = parsed.twophase_xid;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
@ -5325,11 +5326,12 @@ recoveryStopsBefore(XLogReaderState *record)
|
||||
static bool
|
||||
recoveryStopsAfter(XLogReaderState *record)
|
||||
{
|
||||
uint8 record_info;
|
||||
uint8 info;
|
||||
uint8 xact_info;
|
||||
uint8 rmid;
|
||||
TimestampTz recordXtime;
|
||||
|
||||
record_info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
rmid = XLogRecGetRmid(record);
|
||||
|
||||
/*
|
||||
@ -5337,7 +5339,7 @@ recoveryStopsAfter(XLogReaderState *record)
|
||||
* the first one.
|
||||
*/
|
||||
if (recoveryTarget == RECOVERY_TARGET_NAME &&
|
||||
rmid == RM_XLOG_ID && record_info == XLOG_RESTORE_POINT)
|
||||
rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
|
||||
{
|
||||
xl_restore_point *recordRestorePointData;
|
||||
|
||||
@ -5358,12 +5360,15 @@ recoveryStopsAfter(XLogReaderState *record)
|
||||
}
|
||||
}
|
||||
|
||||
if (rmid == RM_XACT_ID &&
|
||||
(record_info == XLOG_XACT_COMMIT_COMPACT ||
|
||||
record_info == XLOG_XACT_COMMIT ||
|
||||
record_info == XLOG_XACT_COMMIT_PREPARED ||
|
||||
record_info == XLOG_XACT_ABORT ||
|
||||
record_info == XLOG_XACT_ABORT_PREPARED))
|
||||
if (rmid != RM_XACT_ID)
|
||||
return false;
|
||||
|
||||
xact_info = info & XLOG_XACT_OPMASK;
|
||||
|
||||
if (xact_info == XLOG_XACT_COMMIT ||
|
||||
xact_info == XLOG_XACT_COMMIT_PREPARED ||
|
||||
xact_info == XLOG_XACT_ABORT ||
|
||||
xact_info == XLOG_XACT_ABORT_PREPARED)
|
||||
{
|
||||
TransactionId recordXid;
|
||||
|
||||
@ -5372,10 +5377,26 @@ recoveryStopsAfter(XLogReaderState *record)
|
||||
SetLatestXTime(recordXtime);
|
||||
|
||||
/* Extract the XID of the committed/aborted transaction */
|
||||
if (record_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
recordXid = ((xl_xact_commit_prepared *) XLogRecGetData(record))->xid;
|
||||
else if (record_info == XLOG_XACT_ABORT_PREPARED)
|
||||
recordXid = ((xl_xact_abort_prepared *) XLogRecGetData(record))->xid;
|
||||
if (xact_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
{
|
||||
xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
|
||||
xl_xact_parsed_commit parsed;
|
||||
|
||||
ParseCommitRecord(XLogRecGetInfo(record),
|
||||
xlrec,
|
||||
&parsed);
|
||||
recordXid = parsed.twophase_xid;
|
||||
}
|
||||
else if (xact_info == XLOG_XACT_ABORT_PREPARED)
|
||||
{
|
||||
xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
|
||||
xl_xact_parsed_abort parsed;
|
||||
|
||||
ParseAbortRecord(XLogRecGetInfo(record),
|
||||
xlrec,
|
||||
&parsed);
|
||||
recordXid = parsed.twophase_xid;
|
||||
}
|
||||
else
|
||||
recordXid = XLogRecGetXid(record);
|
||||
|
||||
@ -5396,17 +5417,16 @@ recoveryStopsAfter(XLogReaderState *record)
|
||||
recoveryStopTime = recordXtime;
|
||||
recoveryStopName[0] = '\0';
|
||||
|
||||
if (record_info == XLOG_XACT_COMMIT_COMPACT ||
|
||||
record_info == XLOG_XACT_COMMIT ||
|
||||
record_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
if (xact_info == XLOG_XACT_COMMIT ||
|
||||
xact_info == XLOG_XACT_COMMIT_PREPARED)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("recovery stopping after commit of transaction %u, time %s",
|
||||
recoveryStopXid,
|
||||
timestamptz_to_str(recoveryStopTime))));
|
||||
}
|
||||
else if (record_info == XLOG_XACT_ABORT ||
|
||||
record_info == XLOG_XACT_ABORT_PREPARED)
|
||||
else if (xact_info == XLOG_XACT_ABORT ||
|
||||
xact_info == XLOG_XACT_ABORT_PREPARED)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("recovery stopping after abort of transaction %u, time %s",
|
||||
@ -5494,7 +5514,7 @@ SetRecoveryPause(bool recoveryPause)
|
||||
static bool
|
||||
recoveryApplyDelay(XLogReaderState *record)
|
||||
{
|
||||
uint8 record_info;
|
||||
uint8 xact_info;
|
||||
TimestampTz xtime;
|
||||
long secs;
|
||||
int microsecs;
|
||||
@ -5511,11 +5531,13 @@ recoveryApplyDelay(XLogReaderState *record)
|
||||
* so there is already opportunity for issues caused by early conflicts on
|
||||
* standbys.
|
||||
*/
|
||||
record_info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
|
||||
if (!(XLogRecGetRmid(record) == RM_XACT_ID &&
|
||||
(record_info == XLOG_XACT_COMMIT_COMPACT ||
|
||||
record_info == XLOG_XACT_COMMIT ||
|
||||
record_info == XLOG_XACT_COMMIT_PREPARED)))
|
||||
if (XLogRecGetRmid(record) != RM_XACT_ID)
|
||||
return false;
|
||||
|
||||
xact_info = XLogRecGetInfo(record) & XLOG_XACT_COMMIT;
|
||||
|
||||
if (xact_info != XLOG_XACT_COMMIT &&
|
||||
xact_info != XLOG_XACT_COMMIT_PREPARED)
|
||||
return false;
|
||||
|
||||
if (!getRecordTimestamp(record, &xtime))
|
||||
|
Reference in New Issue
Block a user