openGauss-server/src/gausskernel/storage/access/redo/xact.cpp

504 lines
18 KiB
C++

/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* xact.cpp
* parse xact xlog
*
* IDENTIFICATION
*
* src/gausskernel/storage/access/redo/xact.cpp
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#ifdef PGXC
#include "pgxc/pgxc.h"
#endif
#include "access/clog.h"
#include "access/csnlog.h"
#include "access/multixact.h"
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "access/xlogproc.h"
#include "access/multi_redo_api.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/storage.h"
#include "commands/async.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/sequence.h"
#include "executor/spi.h"
#include "libpq/be-fsstubs.h"
#include "pgxc/groupmgr.h"
#include "replication/datasyncrep.h"
#include "replication/datasender.h"
#include "replication/dataqueue.h"
#include "replication/walsender.h"
#include "replication/syncrep.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/sinvaladt.h"
#include "storage/smgr.h"
#include "utils/combocid.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/plog.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
#include "utils/timestamp.h"
#include "access/redo_common.h"
/*
* *************Add for batchredo begin***************
* for these func ,they don't hold the lock and parse the record
* they only operator the page, and update page's LSN
* they are shared by Normal redo、ExtremRTO and DFV
* **************************************************
*/
XLogRecParseState* xact_redo_rmddl_parse_to_block(
XLogReaderState* record, XLogRecParseState* recordstatehead, uint32* blocknum, ColFileNodeRel* xnodes, int nrels)
{
XLogRecParseState* blockstate = NULL;
Assert(nrels > 0);
for (int i = 0; i < nrels; ++i) {
ColFileNodeRel* colFileNode = xnodes + i;
ColFileNode node;
ColFileNodeCopy(&node, colFileNode);
if (!IsValidColForkNum(node.forknum)) {
if (SUPPORT_DFS_BATCH && ((IS_PGXC_COORDINATOR && IsValidPaxDfsForkNum(node.forknum)) ||
(!IS_PGXC_COORDINATOR && IsTruncateDfsForkNum(node.forknum)))) {
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
ForkNumber fork = (ForkNumber)node.forknum;
XLogRecSetBlockCommonState(
record, BLOCK_DATA_DDL_TYPE, fork, InvalidBlockNumber, &node.filenode, blockstate);
XLogRecSetBlockDdlState(&(blockstate->blockparse.extra_rec.blockddlrec),
BLOCK_DDL_DROP_RELNODE,
false,
node.ownerid);
} else {
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
XLogRecSetBlockCommonState(
record, BLOCK_DATA_DDL_TYPE, MAX_FORKNUM, InvalidBlockNumber, &node.filenode, blockstate);
XLogRecSetBlockDdlState(&(blockstate->blockparse.extra_rec.blockddlrec),
BLOCK_DDL_DROP_RELNODE,
false,
node.ownerid);
}
} else {
if (SUPPORT_COLUMN_BATCH) {
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
Assert(IsValidColForkNum(node.forknum));
int fork = (ForkNumber)node.forknum;
XLogRecSetBlockCommonState(
record, BLOCK_DATA_DDL_TYPE, fork, InvalidBlockNumber, &node.filenode, blockstate);
XLogRecSetBlockDdlState(&(blockstate->blockparse.extra_rec.blockddlrec),
BLOCK_DDL_DROP_RELNODE,
true,
node.ownerid);
}
}
}
return recordstatehead;
}
static XLogRecParseState* xact_xlog_commit_internal_parse(XLogReaderState* record, uint32* blocknum)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
TransactionId xid = XLogRecGetXid(record);
CommitSeqNo commitseql = COMMITSEQNO_INPROGRESS;
TransactionId* sub_xids = NULL;
int nsubxacts;
uint64 csn;
TransactionId max_xid;
XLogRecParseState* recordstatehead = NULL;
*blocknum = 0;
if (info != XLOG_XACT_COMMIT_COMPACT) {
xl_xact_commit* xlrec = NULL;
if (info == XLOG_XACT_COMMIT) {
xlrec = (xl_xact_commit*)XLogRecGetData(record);
} else {
xl_xact_commit_prepared* xlrecpre = (xl_xact_commit_prepared*)XLogRecGetData(record);
xlrec = &(xlrecpre->crec);
xid = xlrecpre->xid; /* prepare for special */
}
sub_xids = (TransactionId*)&(xlrec->xnodes[xlrec->nrels]);
nsubxacts = xlrec->nsubxacts;
csn = xlrec->csn;
} else {
xl_xact_commit_compact* xlrec = (xl_xact_commit_compact*)XLogRecGetData(record);
sub_xids = xlrec->subxacts;
nsubxacts = xlrec->nsubxacts;
csn = xlrec->csn;
}
max_xid = TransactionIdLatest(xid, nsubxacts, sub_xids);
recordstatehead = xact_xlog_clog_parse_to_block(
record, recordstatehead, blocknum, xid, nsubxacts, sub_xids, CLOG_XID_STATUS_COMMITTED);
if (recordstatehead == NULL) {
return NULL;
}
if (csn >= COMMITSEQNO_FROZEN) {
commitseql = csn;
} else if (csn == COMMITSEQNO_INPROGRESS) {
commitseql = COMMITSEQNO_FROZEN;
}
recordstatehead =
xact_xlog_csnlog_parse_to_block(record, blocknum, xid, nsubxacts, sub_xids, commitseql, recordstatehead);
if (recordstatehead == NULL) {
return NULL;
}
recordstatehead = xact_xlog_commit_parse_to_block(record, recordstatehead, blocknum, max_xid, commitseql);
return recordstatehead;
}
static XLogRecParseState* xact_xlog_abort_internal_parse(XLogReaderState* record, uint32* blocknum)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
TransactionId xid = XLogRecGetXid(record);
TransactionId* sub_xids = NULL;
int nsubxacts;
TransactionId max_xid;
XLogRecParseState* recordstatehead = NULL;
*blocknum = 0;
xl_xact_abort* xlrec = NULL;
if (info == XLOG_XACT_ABORT) {
xlrec = (xl_xact_abort*)XLogRecGetData(record);
} else {
xl_xact_abort_prepared* xlrecpre = (xl_xact_abort_prepared*)XLogRecGetData(record);
xlrec = &(xlrecpre->arec);
xid = xlrecpre->xid; /* prepare for special */
}
sub_xids = (TransactionId*)&(xlrec->xnodes[xlrec->nrels]);
nsubxacts = xlrec->nsubxacts;
max_xid = TransactionIdLatest(xid, nsubxacts, sub_xids);
recordstatehead = xact_xlog_clog_parse_to_block(
record, recordstatehead, blocknum, xid, nsubxacts, sub_xids, CLOG_XID_STATUS_ABORTED);
if (recordstatehead == NULL) {
return NULL;
}
recordstatehead = xact_xlog_csnlog_parse_to_block(
record, blocknum, xid, nsubxacts, sub_xids, COMMITSEQNO_ABORTED, recordstatehead);
if (recordstatehead == NULL) {
return NULL;
}
recordstatehead = xact_xlog_abort_parse_to_block(record, recordstatehead, blocknum, max_xid, COMMITSEQNO_ABORTED);
return recordstatehead;
}
static XLogRecParseState* xact_xlog_prepare_internal_parse(XLogReaderState* record, uint32* blocknum)
{
TransactionId xid;
TransactionId* sub_xids = NULL;
int nsubxacts;
TransactionId max_xid;
XLogRecParseState* recordstatehead = NULL;
char* recorddata = XLogRecGetData(record);
TwoPhaseFileHeader* hdr = (TwoPhaseFileHeader*)recorddata;
*blocknum = 0;
if (TransactionIdIsNormal(hdr->xid)) {
sub_xids = (TransactionId*)(recorddata + MAXALIGN(sizeof(TwoPhaseFileHeader)));
nsubxacts = hdr->nsubxacts;
xid = hdr->xid;
recordstatehead = xact_xlog_csnlog_parse_to_block(
record, blocknum, xid, nsubxacts, sub_xids, COMMITSEQNO_COMMIT_INPROGRESS, recordstatehead);
if (recordstatehead == NULL) {
return NULL;
}
}
max_xid = XLogRecGetXid(record);
recordstatehead = xact_xlog_prepare_parse_to_block(record, recordstatehead, blocknum, max_xid);
return recordstatehead;
}
XLogRecParseState* xact_redo_parse_to_block(XLogReaderState* record, uint32* blocknum)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
XLogRecParseState* recordblockstate = NULL;
/* Backup blocks are not used in xact records */
Assert(!XLogRecHasAnyBlockRefs(record));
if ((info == XLOG_XACT_COMMIT_COMPACT) || (info == XLOG_XACT_COMMIT) || (info == XLOG_XACT_COMMIT_PREPARED)) {
recordblockstate = xact_xlog_commit_internal_parse(record, blocknum);
} else if ((info == XLOG_XACT_ABORT) || (info == XLOG_XACT_ABORT_PREPARED)) {
recordblockstate = xact_xlog_abort_internal_parse(record, blocknum);
} else if (info == XLOG_XACT_PREPARE) {
recordblockstate = xact_xlog_prepare_internal_parse(record, blocknum);
} else if (info == XLOG_XACT_ASSIGNMENT) {
/* don't process */
} else
ereport(PANIC,
(errcode(ERRCODE_INVALID_TRANSACTION_STATE), errmsg("xact_redo_parse_to_block: unknown op code %u", info)));
return recordblockstate;
}
/*
* *************Add for batchredo end****************
* for these func ,they don't hold the lock and parse the record
* they only operator the page, and update page's LSN
* they are shared by Normal redo、ExtremRTO and DFV
* **************************************************
*/
/*
* ************Add for batchredo begin****************
* for these func ,they don't hold the lock and parse the record
* they only operator the page, and update page's LSN
* they are shared by Normal redo、ExtremRTO and DFV
* ***************************************************
*/
XLogRecParseState* xact_xlog_commit_parse_to_block(XLogReaderState* record, XLogRecParseState* recordstatehead,
uint32* blocknum, TransactionId maxxid, CommitSeqNo maxseqnum)
{
XLogRecParseState* blockstate = NULL;
RelFileNode relnode;
XLogRecPtr globalDelayDDLLSN;
XLogRecPtr lsn = record->EndRecPtr;
bool delayddlflag = false;
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
uint64 xrecinfo = 0;
TimestampTz xact_time;
uint8 updateminrecovery = false;
ColFileNodeRel* xnodes = NULL;
int nrels = 0;
SharedInvalidationMessage* inval_msgs = NULL;
int invalidmsgnum = 0;
int nlibrary = 0;
char* libfilename = NULL;
relnode.dbNode = InvalidOid;
relnode.spcNode = InvalidOid;
relnode.relNode = InvalidOid;
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
if (info != XLOG_XACT_COMMIT_COMPACT) {
xl_xact_commit* xlrec = NULL;
TransactionId* subxacts = NULL;
int nsubxacts = 0;
if (info == XLOG_XACT_COMMIT) {
xlrec = (xl_xact_commit*)XLogRecGetData(record);
} else {
xl_xact_commit_prepared* xlrecpre = (xl_xact_commit_prepared*)XLogRecGetData(record);
xlrec = &(xlrecpre->crec);
}
xrecinfo = xlrec->xinfo;
xact_time = xlrec->xact_time;
xnodes = xlrec->xnodes;
nrels = xlrec->nrels;
if (nrels > 0) {
updateminrecovery = true;
globalDelayDDLLSN = GetDDLDelayStartPtr();
if (!XLogRecPtrIsInvalid(globalDelayDDLLSN) && XLByteLT(globalDelayDDLLSN, lsn))
delayddlflag = true;
else
delayddlflag = false;
}
/* subxid array follows relfilenodes */
subxacts = (TransactionId*)&(xlrec->xnodes[xlrec->nrels]);
nsubxacts = xlrec->nsubxacts;
/* invalidation messages array follows subxids */
inval_msgs = (SharedInvalidationMessage*)&(subxacts[xlrec->nsubxacts]);
invalidmsgnum = xlrec->nmsgs;
nlibrary = xlrec->nlibrary;
if (nlibrary > 0) {
libfilename = (char*)xnodes + (nrels * sizeof(ColFileNode)) + (nsubxacts * sizeof(TransactionId)) +
(invalidmsgnum * sizeof(SharedInvalidationMessage));
}
relnode.dbNode = xlrec->dbId;
relnode.spcNode = xlrec->tsId;
} else {
xl_xact_commit_compact* xlrec = (xl_xact_commit_compact*)XLogRecGetData(record);
xact_time = xlrec->xact_time;
}
XLogRecSetBlockCommonState(
record, BLOCK_DATA_XACTDATA_TYPE, InvalidForkNumber, InvalidBlockNumber, &relnode, blockstate, true);
XLogRecSetXactCommonState(&blockstate->blockparse.extra_rec.blockxact, info, xrecinfo, xact_time);
XLogRecSetXactRecoveryState(
&blockstate->blockparse.extra_rec.blockxact, maxxid, maxseqnum, delayddlflag, updateminrecovery);
XLogRecSetXactDdlState(&blockstate->blockparse.extra_rec.blockxact,
nrels,
(void*)xnodes,
invalidmsgnum,
(void*)inval_msgs,
nlibrary,
(void*)libfilename);
if (nrels > 0) {
recordstatehead = xact_redo_rmddl_parse_to_block(record, recordstatehead, blocknum, xnodes, nrels);
}
return recordstatehead;
}
XLogRecParseState* xact_xlog_abort_parse_to_block(XLogReaderState* record, XLogRecParseState* recordstatehead,
uint32* blocknum, TransactionId maxxid, CommitSeqNo maxseqnum)
{
XLogRecParseState* blockstate = NULL;
XLogRecPtr globalDelayDDLLSN;
XLogRecPtr lsn = record->EndRecPtr;
bool delayddlflag = false;
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
TimestampTz xact_time;
ColFileNodeRel* xnodes = NULL;
int nrels = 0;
int nlibrary = 0;
char* libfilename = NULL;
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
xl_xact_abort* xlrec = NULL;
int nsubxacts = 0;
if (info == XLOG_XACT_ABORT) {
xlrec = (xl_xact_abort*)XLogRecGetData(record);
} else {
xl_xact_abort_prepared* xlrecpre = (xl_xact_abort_prepared*)XLogRecGetData(record);
xlrec = &(xlrecpre->arec);
}
xact_time = xlrec->xact_time;
xnodes = xlrec->xnodes;
nrels = xlrec->nrels;
nsubxacts = xlrec->nsubxacts;
if (nrels > 0) {
globalDelayDDLLSN = GetDDLDelayStartPtr();
if (!XLogRecPtrIsInvalid(globalDelayDDLLSN) && XLByteLT(globalDelayDDLLSN, lsn))
delayddlflag = true;
else
delayddlflag = false;
}
nlibrary = xlrec->nlibrary;
if (nlibrary > 0) {
libfilename = (char*)xnodes + (nrels * sizeof(ColFileNode)) + (nsubxacts * sizeof(TransactionId));
}
XLogRecSetBlockCommonState(
record, BLOCK_DATA_XACTDATA_TYPE, InvalidForkNumber, InvalidBlockNumber, NULL, blockstate, true);
XLogRecSetXactCommonState(&blockstate->blockparse.extra_rec.blockxact, info, 0, xact_time);
XLogRecSetXactRecoveryState(&blockstate->blockparse.extra_rec.blockxact, maxxid, maxseqnum, delayddlflag, false);
XLogRecSetXactDdlState(
&blockstate->blockparse.extra_rec.blockxact, nrels, (void*)xnodes, 0, NULL, nlibrary, (void*)libfilename);
if (nrels > 0) {
recordstatehead = xact_redo_rmddl_parse_to_block(record, recordstatehead, blocknum, xnodes, nrels);
}
return recordstatehead;
}
void XLogRecSetPreparState(
XLogBlockPrepareParse* blockpreparestate, TransactionId maxxid, char* maindata, Size maindatalen)
{
blockpreparestate->maxxid = maxxid;
blockpreparestate->maindata = maindata;
blockpreparestate->maindatalen = maindatalen;
}
XLogRecParseState* xact_xlog_prepare_parse_to_block(
XLogReaderState* record, XLogRecParseState* recordstatehead, uint32* blocknum, TransactionId maxxid)
{
XLogRecParseState* blockstate = NULL;
(*blocknum)++;
XLogParseBufferAllocListStateFunc(record, &blockstate, &recordstatehead);
if (blockstate == NULL) {
return NULL;
}
XLogRecSetBlockCommonState(
record, BLOCK_DATA_PREPARE_TYPE, InvalidForkNumber, InvalidBlockNumber, NULL, blockstate, true);
char* maindata = XLogRecGetData(record);
Size maindatalen = XLogRecGetDataLen(record);
XLogRecSetPreparState(&blockstate->blockparse.extra_rec.blockprepare, maxxid, maindata, maindatalen);
return recordstatehead;
}
/*
* ************Add for batchredo end****************
* for these func ,they don't hold the lock and parse the record
* they only operator the page, and update page's LSN
* they are shared by Normal redo, ExtremRTO and DFV
* *************************************************
*/