*
* xactdesc.cpp
* rmgr descriptor routines for access/transam/xact.cpp
*
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/gausskernel/storage/access/rmgrdesc/xactdesc.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/xact.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "catalog/catalog.h"
#include "storage/sinval.h"
#include "utils/timestamp.h"
#include "securec.h"
* @Description: Desc library file.
* @out buf: String data.
* @in filename: Library file start ptr.
* @in library_path: Library path include head info.
*/
static void desc_library(StringInfo buf, char *filename, int nlibrary)
{
int len = 0;
char *library_path = NULL;
int nlib = nlibrary;
char *ptr = filename;
errno_t rc = 0;
while (nlib > 0) {
rc = memcpy_s(&len, sizeof(int), ptr, sizeof(int));
securec_check_c(rc, "\0", "\0");
ptr += sizeof(int);
if (len + 1 <= 0) {
return;
}
library_path = (char *)malloc((size_t)len + 1);
if (library_path == NULL) {
return;
}
rc = memcpy_s(library_path, (size_t)len + 1, ptr, (size_t)len);
securec_check_c(rc, "\0", "\0");
library_path[len] = '\0';
ptr += len;
appendStringInfo(buf, "; library: %s", library_path);
free(library_path);
library_path = NULL;
nlib--;
}
}
static void xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec, RepOriginId origin_id, bool compress)
{
int i;
int nsubxacts = xlrec->nsubxacts;
TransactionId *subxacts = NULL;
subxacts = GET_SUB_XACTS(xlrec->xnodes, xlrec->nrels, compress);
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
appendStringInfo(buf, "; csn:%lu", xlrec->csn);
if (xlrec->nrels > 0) {
appendStringInfo(buf, "; rels:");
for (i = 0; i < xlrec->nrels; i++) {
ColFileNode colFileNode;
if (compress) {
ColFileNode *colFileNodeRel = ((ColFileNode *)(void *)xlrec->xnodes) + i;
ColFileNodeFullCopy(&colFileNode, colFileNodeRel);
} else {
ColFileNodeRel *colFileNodeRel = xlrec->xnodes + i;
ColFileNodeCopy(&colFileNode, colFileNodeRel);
}
char *path = relpathperm(colFileNode.filenode, MAIN_FORKNUM);
* because *relpathperm()* cannot handle column table now,
* so we have to append Cxxxxx.0 to filename buffer.
*/
if (IsValidColForkNum(colFileNode.forknum))
appendStringInfo(buf, " %s_C%d", path, ColForkNum2ColumnId(colFileNode.forknum));
else
appendStringInfo(buf, " %s", path);
#ifdef FRONTEND
free(path);
#else
pfree(path);
#endif
path = NULL;
}
}
if (xlrec->nsubxacts > 0) {
appendStringInfo(buf, "; subxacts:");
for (i = 0; i < xlrec->nsubxacts; i++)
appendStringInfo(buf, " " XID_FMT, subxacts[i]);
}
if (xlrec->nmsgs > 0) {
SharedInvalidationMessage *msgs = NULL;
msgs = (SharedInvalidationMessage *)&subxacts[xlrec->nsubxacts];
if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u", xlrec->dbId, xlrec->tsId);
appendStringInfo(buf, "; inval msgs:");
for (i = 0; i < xlrec->nmsgs; i++) {
SharedInvalidationMessage *msg = &msgs[i];
if (msg->id >= 0)
appendStringInfo(buf, " catcache %d", msg->id);
else if (msg->id == SHAREDINVALCATALOG_ID)
appendStringInfo(buf, " catalog %u", msg->cat.catId);
else if (msg->id == SHAREDINVALRELCACHE_ID)
appendStringInfo(buf, " relcache %u", msg->rc.relId);
else if (msg->id == SHAREDINVALSMGR_ID)
appendStringInfo(buf, " smgr");
else if (msg->id == SHAREDINVALRELMAP_ID)
appendStringInfo(buf, " relmap");
else
appendStringInfo(buf, " unknown id %d", msg->id);
}
}
#ifndef ENABLE_MULTIPLE_NODES
SharedInvalidationMessage* msgs = (SharedInvalidationMessage*)&subxacts[xlrec->nsubxacts];
TransactionId* recentXmin = (TransactionId *)&(msgs[xlrec->nmsgs]);
appendStringInfo(buf, "; RecentXmin:%lu", *recentXmin);
nsubxacts++;
#endif
if (xlrec->nlibrary > 0) {
char *filename = NULL;
filename = (char *)xlrec->xnodes + (xlrec->nrels * SIZE_OF_COLFILENODE(compress)) +
(nsubxacts * sizeof(TransactionId)) + (xlrec->nmsgs * sizeof(SharedInvalidationMessage));
desc_library(buf, filename, xlrec->nlibrary);
}
if (xlrec->xinfo & XACT_HAS_ORIGIN) {
xl_xact_origin *origin = (xl_xact_origin *)GetRepOriginPtr((char *)xlrec->xnodes, xlrec->xinfo,
xlrec->nsubxacts, xlrec->nmsgs, xlrec->nrels, xlrec->nlibrary, compress);
appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s", origin_id,
(uint32)(origin->origin_lsn >> BITS_PER_INT),
(uint32)origin->origin_lsn, timestamptz_to_str(origin->origin_timestamp));
}
}
static void xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
{
int i;
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
appendStringInfo(buf, "; csn:%lu", xlrec->csn);
if (xlrec->nsubxacts > 0) {
appendStringInfo(buf, "; subxacts:");
for (i = 0; i < xlrec->nsubxacts; i++)
appendStringInfo(buf, " " XID_FMT, xlrec->subxacts[i]);
}
#ifndef ENABLE_MULTIPLE_NODES
appendStringInfo(buf, "; RecentXmin:%lu", xlrec->subxacts[xlrec->nsubxacts]);
#endif
}
static void xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec, bool abortXlogNewVersion, bool compress)
{
int i;
appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
if (xlrec->nrels > 0) {
appendStringInfo(buf, "; rels:");
for (i = 0; i < xlrec->nrels; i++) {
ColFileNode colFileNode;
if (compress) {
ColFileNode *colFileNodeRel = ((ColFileNode *)(void *)xlrec->xnodes) + i;
ColFileNodeFullCopy(&colFileNode, colFileNodeRel);
} else {
ColFileNodeRel *colFileNodeRel = xlrec->xnodes + i;
ColFileNodeCopy(&colFileNode, colFileNodeRel);
}
char *path = relpathperm(colFileNode.filenode, MAIN_FORKNUM);
* because *relpathperm()* cannot handle column table now,
* so we append Cxxxxx.0 to filename buffer.
*/
if (IsValidColForkNum(colFileNode.forknum))
appendStringInfo(buf, " %s_C%d", path, ColForkNum2ColumnId(colFileNode.forknum));
else
appendStringInfo(buf, " %s", path);
#ifdef FRONTEND
free(path);
#else
pfree(path);
#endif
path = NULL;
}
}
if (xlrec->nsubxacts > 0) {
TransactionId *xacts = GET_SUB_XACTS(xlrec->xnodes, xlrec->nrels, compress);
appendStringInfo(buf, "; subxacts:");
for (i = 0; i < xlrec->nsubxacts; i++)
appendStringInfo(buf, " " XID_FMT, xacts[i]);
}
if (xlrec->nlibrary > 0) {
char *filename = NULL;
filename = (char *)xlrec->xnodes + (xlrec->nrels * SIZE_OF_COLFILENODE(compress)) +
(xlrec->nsubxacts * sizeof(TransactionId));
if (abortXlogNewVersion) {
appendStringInfo(buf, "; current xact: %lu", *(TransactionId*)(filename));
filename += sizeof(TransactionId);
}
desc_library(buf, filename, xlrec->nlibrary);
} else if (abortXlogNewVersion) {
appendStringInfo(buf, "; current xact: %lu",
*(TransactionId *)(void *)((char *)xlrec->xnodes +
(xlrec->nrels * SIZE_OF_COLFILENODE(compress)) +
((uint32)xlrec->nsubxacts * sizeof(TransactionId))));
}
}
const char *xact_type_name(uint8 subtype)
{
uint8 info = subtype & ~XLR_INFO_MASK;
if (info == XLOG_XACT_COMMIT_COMPACT) {
return "commit_compact";
} else if (info == XLOG_XACT_COMMIT) {
return "commit";
} else if (info == XLOG_XACT_ABORT) {
return "abort";
} else if (info == XLOG_XACT_ABORT_WITH_XID) {
return "abort_with_xid";
} else if (info == XLOG_XACT_PREPARE) {
return "prepare";
} else if (info == XLOG_XACT_COMMIT_PREPARED) {
return "commit_prepared";
} else if (info == XLOG_XACT_ABORT_PREPARED) {
return "abort_prepared";
} else if (info == XLOG_XACT_ASSIGNMENT) {
return "assignment";
} else {
return "unkown_type";
}
}
void xact_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
bool compress = (bool)(XLogRecGetInfo(record) & XLR_REL_COMPRESS);
if (info == XLOG_XACT_COMMIT_COMPACT) {
xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *)rec;
appendStringInfo(buf, "XLOG_XACT_COMMIT_COMPACT commit: ");
xact_desc_commit_compact(buf, xlrec);
} else if (info == XLOG_XACT_COMMIT) {
xl_xact_commit *xlrec = (xl_xact_commit *)rec;
appendStringInfo(buf, "XLOG_XACT_COMMIT commit: ");
xact_desc_commit(buf, xlrec, XLogRecGetOrigin(record), compress);
} else if (info == XLOG_XACT_ABORT) {
xl_xact_abort *xlrec = (xl_xact_abort *)rec;
appendStringInfo(buf, "abort: ");
xact_desc_abort(buf, xlrec, false, compress);
} else if (info == XLOG_XACT_ABORT_WITH_XID) {
xl_xact_abort *xlrec = (xl_xact_abort *)rec;
appendStringInfo(buf, "abort_with_xid: ");
xact_desc_abort(buf, xlrec, true, compress);
} else if (info == XLOG_XACT_PREPARE) {
TwoPhaseFileHeader *hdr = (TwoPhaseFileHeader *)rec;
appendStringInfo(buf, "prepare transaction, gid: %s", hdr->gid);
} else if (info == XLOG_XACT_COMMIT_PREPARED) {
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *)rec;
appendStringInfo(buf, "commit prepared " XID_FMT ": ", xlrec->xid);
xact_desc_commit(buf, &xlrec->crec, XLogRecGetOrigin(record), compress);
} else if (info == XLOG_XACT_ABORT_PREPARED) {
xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *)rec;
appendStringInfo(buf, "abort prepared " XID_FMT ": ", xlrec->xid);
xact_desc_abort(buf, &xlrec->arec, false, compress);
} else if (info == XLOG_XACT_ASSIGNMENT) {
xl_xact_assignment *xlrec = (xl_xact_assignment *)rec;
* Note that we ignore the WAL record's xid, since we're more
* interested in the top-level xid that issued the record and which
* xids are being reported here.
*/
appendStringInfo(buf, "xid assignment xtop " XID_FMT ": ", xlrec->xtop);
} else
appendStringInfo(buf, "UNKNOWN");
}