*
* heapdesc.cpp
* rmgr descriptor routines for access/heap/heapam.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/heapdesc.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/htup.h"
#include "access/xlog.h"
void heap_add_lock_info(StringInfo buf, xl_heap_lock *xlrec)
{
if (xlrec->shared_lock) {
appendStringInfo(buf, "shared_lock: ");
} else {
appendStringInfo(buf, "exclusive_lock: ");
}
if (xlrec->xid_is_mxact) {
appendStringInfo(buf, "mxid ");
} else {
appendStringInfo(buf, "xid ");
}
appendStringInfo(buf, "%lu ", xlrec->locking_xid);
appendStringInfo(buf, "off %u XLOG_HEAP_LOCK", (uint32)xlrec->offnum);
}
static void OutInfobits(StringInfo buf, uint8 infobits)
{
if (infobits & XLHL_XMAX_IS_MULTI) {
appendStringInfo(buf, "IS_MULTI ");
}
if (infobits & XLHL_XMAX_LOCK_ONLY) {
appendStringInfo(buf, "LOCK_ONLY ");
}
if (infobits & XLHL_XMAX_EXCL_LOCK) {
appendStringInfo(buf, "EXCL_LOCK ");
}
if (infobits & XLHL_XMAX_KEYSHR_LOCK) {
appendStringInfo(buf, "KEYSHR_LOCK ");
}
if (infobits & XLHL_KEYS_UPDATED) {
appendStringInfo(buf, "KEYS_UPDATED ");
}
}
void heap3_new_cid(StringInfo buf, int bucket_id, xl_heap_new_cid *xlrec)
{
if (bucket_id == -1) {
appendStringInfo(buf, "rel %u/%u/%u; tid %u/%hu", xlrec->target_node.spcNode, xlrec->target_node.dbNode,
xlrec->target_node.relNode, ItemPointerGetBlockNumber(&(xlrec->target_tid)),
ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
} else {
appendStringInfo(buf, "rel %u/%u/%u/%d; tid %u/%hu", xlrec->target_node.spcNode, xlrec->target_node.dbNode,
xlrec->target_node.relNode, bucket_id, ItemPointerGetBlockNumber(&(xlrec->target_tid)),
ItemPointerGetOffsetNumber(&(xlrec->target_tid)));
}
appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u", xlrec->cmin, xlrec->cmax, xlrec->combocid);
}
const char* heap_type_name(uint8 subtype)
{
uint8 info = subtype & ~XLR_INFO_MASK;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP_INSERT) {
return "heap_insert";
} else if (info == XLOG_HEAP_DELETE) {
return "heap_delete";
} else if (info == XLOG_HEAP_UPDATE) {
return "heap_update";
} else if (info == XLOG_HEAP_HOT_UPDATE) {
return "heap_hot_update";
} else if (info == XLOG_HEAP_NEWPAGE) {
return "heap_newpage";
} else if (info == XLOG_HEAP_LOCK) {
return "heap_lock";
} else if (info == XLOG_HEAP_INPLACE) {
return "heap_inplace";
} else if (info == XLOG_HEAP_BASE_SHIFT) {
return "base_shift";
}
return "unkown_type";
}
void heap_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
bool isTupleLockUPgrade = (XLogRecGetInfo(record) & XLOG_TUPLE_LOCK_UPGRADE_FLAG) != 0;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP_INSERT) {
xl_heap_insert *xlrec = (xl_heap_insert *)rec;
if (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "XLOG_HEAP_INSERT insert(init): ");
else
appendStringInfo(buf, "XLOG_HEAP_INSERT insert: ");
appendStringInfo(buf, "off %u", (uint32)xlrec->offnum);
} else if (info == XLOG_HEAP_DELETE) {
xl_heap_delete *xlrec = (xl_heap_delete *)rec;
appendStringInfo(buf, "delete: ");
appendStringInfo(buf, "off %u", (uint32)xlrec->offnum);
if (isTupleLockUPgrade) {
appendStringInfoChar(buf, ' ');
OutInfobits(buf, xlrec->infobits_set);
}
} else if (info == XLOG_HEAP_UPDATE) {
xl_heap_update *xlrec = (xl_heap_update *)rec;
if (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "XLOG_HEAP_UPDATE update(init): ");
else
appendStringInfo(buf, "XLOG_HEAP_UPDATE update: ");
appendStringInfo(buf, "off %u new off %u", (uint32)xlrec->old_offnum, (uint32)xlrec->new_offnum);
if (isTupleLockUPgrade) {
appendStringInfoChar(buf, ' ');
OutInfobits(buf, xlrec->old_infobits_set);
}
} else if (info == XLOG_HEAP_HOT_UPDATE) {
xl_heap_update *xlrec = (xl_heap_update *)rec;
if (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE)
appendStringInfo(buf, "XLOG_HEAP_HOT_UPDATE hot_update(init): ");
else
appendStringInfo(buf, "XLOG_HEAP_HOT_UPDATE hot_update: ");
appendStringInfo(buf, "off %u new off %u", (uint32)xlrec->old_offnum, (uint32)xlrec->new_offnum);
if (isTupleLockUPgrade) {
appendStringInfoChar(buf, ' ');
OutInfobits(buf, xlrec->old_infobits_set);
}
} else if (info == XLOG_HEAP_NEWPAGE) {
appendStringInfo(buf, "new page");
} else if (info == XLOG_HEAP_LOCK) {
xl_heap_lock *xlrec = (xl_heap_lock *)rec;
heap_add_lock_info(buf, xlrec);
if (isTupleLockUPgrade) {
appendStringInfoChar(buf, ' ');
OutInfobits(buf, xlrec->infobits_set);
}
} else if (info == XLOG_HEAP_INPLACE) {
xl_heap_inplace *xlrec = (xl_heap_inplace *)rec;
appendStringInfo(buf, "inplace: ");
appendStringInfo(buf, "off %u", (uint32)xlrec->offnum);
} else if (info == XLOG_HEAP3_NEW_CID) {
xl_heap_new_cid *xlrec = (xl_heap_new_cid *)rec;
int bucket_id = XLogRecGetBucketId(record);
heap3_new_cid(buf, bucket_id, xlrec);
} else if (info == XLOG_HEAP_BASE_SHIFT) {
xl_heap_base_shift *xlrec = (xl_heap_base_shift *)rec;
appendStringInfo(buf, "base_shift delta %ld multi %d", xlrec->delta, xlrec->multi);
} else if (info == XLOG_HEAP3_TRUNCATE) {
xl_heap_truncate *xlrec = (xl_heap_truncate *) rec;
int i;
if (xlrec->flags & XLH_TRUNCATE_CASCADE)
appendStringInfo(buf, "cascade ");
if (xlrec->flags & XLH_TRUNCATE_RESTART_SEQS)
appendStringInfo(buf, "restart_seqs ");
appendStringInfo(buf, "nrelids %u relids", xlrec->nrelids);
for (i = 0; i < (int)xlrec->nrelids; i++)
appendStringInfo(buf, " %u", xlrec->relids[i]);
} else
appendStringInfo(buf, "UNKNOWN");
}
const char* heap2_type_name(uint8 subtype)
{
uint8 info = subtype & ~XLR_INFO_MASK;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP2_FREEZE) {
return "heap2_freeze";
} else if (info == XLOG_HEAP2_CLEAN) {
return "heap2_clean";
} else if (info == XLOG_HEAP2_PAGE_UPGRADE) {
return "heap2_page_udpate";
} else if (info == XLOG_HEAP2_CLEANUP_INFO) {
return "heap2_cleanup_info";
} else if (info == XLOG_HEAP2_VISIBLE) {
return "heap2_visible";
} else if (info == XLOG_HEAP2_BCM) {
return "heap2_bcm";
} else if (info == XLOG_HEAP2_MULTI_INSERT) {
return "heap2_multi_insert";
} else if (info == XLOG_HEAP2_LOGICAL_NEWPAGE) {
return "heap2_logical_newpage";
} else {
return "unkown_type";
}
}
void heap2_desc(StringInfo buf, XLogReaderState *record)
{
char *rec = XLogRecGetData(record);
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP2_FREEZE) {
xl_heap_freeze *xlrec = (xl_heap_freeze *)rec;
appendStringInfo(buf, "freeze: cutoff xid %lu", xlrec->cutoff_xid);
if (!XLogRecHasBlockImage(record, 0)) {
Size datalen;
OffsetNumber *offsets = NULL;
OffsetNumber *offsets_end = NULL;
offsets = (OffsetNumber *)XLogRecGetBlockData(record, 0, &datalen);
if (datalen > 0) {
offsets_end = (OffsetNumber *)((char *)offsets + datalen);
appendStringInfo(buf, " offsets: [");
while (offsets < offsets_end) {
appendStringInfo(buf, " %d ", *offsets);
offsets++;
}
appendStringInfo(buf, "]");
}
}
} else if (info == XLOG_HEAP2_CLEAN) {
xl_heap_clean *xlrec = (xl_heap_clean *)rec;
appendStringInfo(buf, "clean: remxid %lu", xlrec->latestRemovedXid);
if (!XLogRecHasBlockImage(record, 0)) {
OffsetNumber *end = NULL;
OffsetNumber *redirected = NULL;
OffsetNumber *nowdead = NULL;
OffsetNumber *nowunused = NULL;
int nredirected;
int ndead;
int nunused;
Size datalen;
int i = 0;
redirected = (OffsetNumber *)XLogRecGetBlockData(record, 0, &datalen);
nredirected = xlrec->nredirected;
ndead = xlrec->ndead;
end = (OffsetNumber *)((char *)redirected + datalen);
nowdead = redirected + (nredirected * 2);
nowunused = nowdead + ndead;
nunused = (end - nowunused);
if ((XLogRecGetInfo(record) & XLOG_HEAP2_NO_REPAIR_PAGE) != 0) {
appendStringInfo(buf, "don't need PageRepairFragmentation;");
}
if (nredirected > 0) {
appendStringInfo(buf, " redirected: [");
while (i < nredirected) {
appendStringInfo(buf, " %d ", redirected[i]);
i++;
}
appendStringInfo(buf, "]");
}
if (ndead > 0) {
i = 0;
appendStringInfo(buf, " dead: [");
while (i < ndead) {
appendStringInfo(buf, " %d ", nowdead[i]);
i++;
}
appendStringInfo(buf, "]");
}
if (nunused > 0) {
i = 0;
appendStringInfo(buf, " unused: [");
while (i < nunused) {
appendStringInfo(buf, " %d ", nowunused[i]);
i++;
}
appendStringInfo(buf, "]");
}
}
} else if (info == XLOG_HEAP3_REWRITE) {
appendStringInfoString(buf, "heap rewrite:");
} else if (info == XLOG_HEAP2_CLEANUP_INFO) {
xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *)rec;
appendStringInfo(buf, "cleanup info: remxid %lu", xlrec->latestRemovedXid);
} else if (info == XLOG_HEAP2_VISIBLE) {
xl_heap_visible *xlrec = (xl_heap_visible *)rec;
appendStringInfo(buf, "visible: cutoff xid %lu", xlrec->cutoff_xid);
} else if (info == XLOG_HEAP2_BCM) {
xl_heap_bcm *xlrec = (xl_heap_bcm *)rec;
int bucket_id = XLogRecGetBucketId(record);
if (bucket_id == -1) {
appendStringInfo(buf, "bcm: rel %u/%u/%u; blk %lu status: %d, count: %d, col: %u", xlrec->node.spcNode,
xlrec->node.dbNode, xlrec->node.relNode, xlrec->block, xlrec->status, xlrec->count,
xlrec->col);
} else {
appendStringInfo(buf, "bcm: rel %u/%u/%u/%d; blk %lu status: %d, count: %d, col: %u", xlrec->node.spcNode,
xlrec->node.dbNode, xlrec->node.relNode, bucket_id, xlrec->block, xlrec->status,
xlrec->count, xlrec->col);
}
} else if (info == XLOG_HEAP2_MULTI_INSERT) {
xl_heap_multi_insert *xlrec = NULL;
if (XLogRecGetInfo(record) & XLOG_HEAP_INIT_PAGE) {
xlrec = (xl_heap_multi_insert *)(rec + sizeof(TransactionId));
appendStringInfo(buf, "XLOG_HEAP2_MULTI_INSERT multi-insert (init): ");
} else {
xlrec = (xl_heap_multi_insert *)rec;
appendStringInfo(buf, "XLOG_HEAP2_MULTI_INSERT multi-insert: ");
}
appendStringInfo(buf, "%d tuples compressed(%d)", xlrec->ntuples, xlrec->isCompressed);
} else if (info == XLOG_HEAP2_LOGICAL_NEWPAGE) {
xl_heap_logical_newpage *xlrec = (xl_heap_logical_newpage *)rec;
int bucket_id = XLogRecGetBucketId(record);
if (bucket_id == -1) {
appendStringInfo(buf, "logical newpage rel %u/%u/%u; blk %u", xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->blkno);
} else {
appendStringInfo(buf, "logical newpage rel %u/%u/%u/%d; blk %u", xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, bucket_id, xlrec->blkno);
}
} else
appendStringInfo(buf, "UNKNOWN");
}
const char* heap3_type_name(uint8 subtype)
{
uint8 info = subtype & ~XLR_INFO_MASK;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP3_NEW_CID) {
return "heap3_new_cid";
} else if (info == XLOG_HEAP3_REWRITE) {
return "heap3_rewrite";
} else if (info == XLOG_HEAP3_INVALID) {
return "heap3_invalid";
} else if (info == XLOG_HEAP3_TRUNCATE) {
return "heap3_truncate";
} else {
return "unkown_type";
}
}
void heap3_desc(StringInfo buf, XLogReaderState *record)
{
uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
info &= XLOG_HEAP_OPMASK;
if (info == XLOG_HEAP3_NEW_CID) {
appendStringInfo(buf, "XLOG_HEAP_NEW_CID");
} else if (info == XLOG_HEAP3_REWRITE) {
appendStringInfo(buf, "XLOG_HEAP2_REWRITE");
} else if (info == XLOG_HEAP3_INVALID) {
xl_heap_invalid *xlrecInvalid = (xl_heap_invalid *)XLogRecGetData(record);
appendStringInfo(buf, "invalid: cutoff xid %lu", xlrecInvalid->cutoff_xid);
if (!XLogRecHasBlockImage(record, 0)) {
Size datalen;
OffsetNumber *offsets = (OffsetNumber *)XLogRecGetBlockData(record, 0, &datalen);
if (datalen > 0) {
OffsetNumber *offsets_end = (OffsetNumber *)((char *)offsets + datalen);
appendStringInfo(buf, " offsets: [");
while (offsets < offsets_end) {
appendStringInfo(buf, " %d ", *offsets);
offsets++;
}
appendStringInfo(buf, "]");
}
}
} else if (info == XLOG_HEAP3_TRUNCATE) {
appendStringInfo(buf, "XLOG_HEAP_TRUNCATE");
} else {
appendStringInfo(buf, "UNKNOWN");
}
}