void smgr_desc(StringInfo buf, uint8 xl_info, char *rec) { uint8 info = xl_info & ~XLR_INFO_MASK; if (info == XLOG_SMGR_CREATE) { xl_smgr_create *xlrec = (xl_smgr_create *) rec; char *path = relpathperm(xlrec->rnode, xlrec->forkNum); appendStringInfo(buf, "file create: %s", path); pfree(path); } else if (info == XLOG_SMGR_TRUNCATE) { xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec; char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM); appendStringInfo(buf, "file truncate: %s to %u blocks", path, xlrec->blkno); pfree(path); } else appendStringInfoString(buf, "UNKNOWN"); }
/* Forget any invalid pages in a whole database */ static void forget_invalid_pages_db(Oid dbid) { HASH_SEQ_STATUS status; xl_invalid_page *hentry; if (invalid_page_tab == NULL) return; /* nothing to do */ hash_seq_init(&status, invalid_page_tab); while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL) { if (hentry->key.node.dbNode == dbid) { if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2) { char *path = relpathperm(hentry->key.node, hentry->key.forkno); elog(DEBUG2, "page %u of relation %s has been dropped", hentry->key.blkno, path); pfree(path); } if (hash_search(invalid_page_tab, (void *) &hentry->key, HASH_REMOVE, NULL) == NULL) elog(ERROR, "hash table corrupted"); } } }
/* Forget any invalid pages >= minblkno, because they've been dropped */ static void forget_invalid_pages(struct fnode node, enum fork forkno, block_t minblkno) { struct hseq_status status; xl_invalid_page *hentry; if (invalid_page_tab == NULL) return; /* nothing to do */ hseq_init(&status, invalid_page_tab); while ((hentry = (xl_invalid_page *) hseq_search(&status)) != NULL) { if (FNODE_EQ(hentry->key.node, node) && hentry->key.forkno == forkno && hentry->key.blkno >= minblkno) { if (log_min_messages <= DEBUG2 || client_min_messages <= DEBUG2) { char *path = relpathperm(hentry->key.node, forkno); elog(DEBUG2, "page %u of relation %s has been" " dropped", hentry->key.blkno, path); pfree(path); } if (hsearch(invalid_page_tab, (void*) &hentry->key, H_REMOVE, NULL) == NULL) elog(ERROR, "hash table corrupted"); } } }
static void xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec) { int i; appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time)); if (xlrec->nrels > 0) { appendStringInfoString(buf, "; rels:"); for (i = 0; i < xlrec->nrels; i++) { char *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM); appendStringInfo(buf, " %s", path); pfree(path); } } if (xlrec->nsubxacts > 0) { TransactionId *xacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels]; appendStringInfoString(buf, "; subxacts:"); for (i = 0; i < xlrec->nsubxacts; i++) appendStringInfo(buf, " %u", xacts[i]); } }
/* Log a reference to an invalid page */ static void log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present) { xl_invalid_page_key key; xl_invalid_page *hentry; bool found; /* * Log references to invalid pages at DEBUG1 level. This allows some * tracing of the cause (note the elog context mechanism will tell us * something about the XLOG record that generated the reference). */ if (log_min_messages <= DEBUG1 || client_min_messages <= DEBUG1) { char *path = relpathperm(node, forkno); if (present) elog(DEBUG1, "page %u of relation %s is uninitialized", blkno, path); else elog(DEBUG1, "page %u of relation %s does not exist", blkno, path); pfree(path); } if (invalid_page_tab == NULL) { /* create hash table when first needed */ HASHCTL ctl; memset(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(xl_invalid_page_key); ctl.entrysize = sizeof(xl_invalid_page); ctl.hash = tag_hash; invalid_page_tab = hash_create("XLOG invalid-page table", 100, &ctl, HASH_ELEM | HASH_FUNCTION); } /* we currently assume xl_invalid_page_key contains no padding */ key.node = node; key.forkno = forkno; key.blkno = blkno; hentry = (xl_invalid_page *) hash_search(invalid_page_tab, (void *) &key, HASH_ENTER, &found); if (!found) { /* hash_search already filled in the key */ hentry->present = present; } else { /* repeat reference ... leave "present" as it was */ } }
static void xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec) { int i; TransactionId *subxacts; subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels]; appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time)); if (xlrec->nrels > 0) { appendStringInfo(buf, "; rels:"); for (i = 0; i < xlrec->nrels; i++) { char *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM); appendStringInfo(buf, " %s", path); pfree(path); } } if (xlrec->nsubxacts > 0) { appendStringInfo(buf, "; subxacts:"); for (i = 0; i < xlrec->nsubxacts; i++) appendStringInfo(buf, " %u", subxacts[i]); } if (xlrec->nmsgs > 0) { SharedInvalidationMessage *msgs; 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); /* remaining cases not expected, but print something anyway */ 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); } } }
void smgr_desc(StringInfo buf, XLogRecord *record) { char *rec = XLogRecGetData(record); uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == XLOG_SMGR_CREATE) { xl_smgr_create *xlrec = (xl_smgr_create *) rec; char *path = relpathperm(xlrec->rnode, xlrec->forkNum); appendStringInfo(buf, "%s", path); pfree(path); } else if (info == XLOG_SMGR_TRUNCATE) { xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec; char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM); appendStringInfo(buf, "%s to %u blocks", path, xlrec->blkno); pfree(path); } }
/* Report a reference to an invalid page */ static void report_invalid_page(int elevel, RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present) { char *path = relpathperm(node, forkno); if (present) elog(elevel, "page %u of relation %s is uninitialized", blkno, path); else elog(elevel, "page %u of relation %s does not exist", blkno, path); pfree(path); }
char * datasegpath(RelFileNode rnode, ForkNumber forknum, BlockNumber segno) { char *path = relpathperm(rnode, forknum); if (segno > 0) { char *segpath = pg_malloc(strlen(path) + 13); sprintf(segpath, "%s.%u", path, segno); pg_free(path); return segpath; } else return path; }
/* * A helper function to create the path of a relation file and segment. * * The returned path is palloc'd */ static char * datasegpath(RelFileNode rnode, ForkNumber forknum, BlockNumber segno) { char *path; char *segpath; path = relpathperm(rnode, forknum); if (segno > 0) { segpath = psprintf("%s.%u", path, segno); pfree(path); return segpath; } else return path; }
/* Complain about any remaining invalid-page entries */ void xlog_check_invalid_pages(void) { struct hseq_status status; xl_invalid_page *hentry; bool foundone; foundone = false; if (invalid_page_tab == NULL) return; /* nothing to do */ hseq_init(&status, invalid_page_tab); /* * Our strategy is to emit WARNING messages for all remaining entries * and only PANIC after we've dumped all the available info. */ while ((hentry = (xl_invalid_page *)hseq_search(&status)) != NULL) { char *path; path = relpathperm(hentry->key.node, hentry->key.forkno); if (hentry->present) elog(WARNING, "page %u of relation %s was" " uninitialized", hentry->key.blkno, path); else elog(WARNING, "page %u of relation %s did not exist", hentry->key.blkno, path); pfree(path); foundone = true; } if (foundone) elog(PANIC, "WAL contains references to invalid pages"); hash_destroy(invalid_page_tab); invalid_page_tab = NULL; }
static void xact_desc_commit(StringInfo buf, uint8 info, xl_xact_commit *xlrec, RepOriginId origin_id) { xl_xact_parsed_commit parsed; int i; ParseCommitRecord(info, xlrec, &parsed); /* If this is a prepared xact, show the xid of the original xact */ if (TransactionIdIsValid(parsed.twophase_xid)) appendStringInfo(buf, "%u: ", parsed.twophase_xid); appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time)); if (parsed.nrels > 0) { appendStringInfoString(buf, "; rels:"); for (i = 0; i < parsed.nrels; i++) { char *path = relpathperm(parsed.xnodes[i], MAIN_FORKNUM); appendStringInfo(buf, " %s", path); pfree(path); } } if (parsed.nsubxacts > 0) { appendStringInfoString(buf, "; subxacts:"); for (i = 0; i < parsed.nsubxacts; i++) appendStringInfo(buf, " %u", parsed.subxacts[i]); } if (parsed.nmsgs > 0) { if (XactCompletionRelcacheInitFileInval(parsed.xinfo)) appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u", parsed.dbId, parsed.tsId); appendStringInfoString(buf, "; inval msgs:"); for (i = 0; i < parsed.nmsgs; i++) { SharedInvalidationMessage *msg = &parsed.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); /* not expected, but print something anyway */ else if (msg->id == SHAREDINVALSMGR_ID) appendStringInfoString(buf, " smgr"); /* not expected, but print something anyway */ else if (msg->id == SHAREDINVALRELMAP_ID) appendStringInfoString(buf, " relmap"); else if (msg->id == SHAREDINVALSNAPSHOT_ID) appendStringInfo(buf, " snapshot %u", msg->sn.relId); else appendStringInfo(buf, " unknown id %d", msg->id); } } if (XactCompletionForceSyncCommit(parsed.xinfo)) appendStringInfo(buf, "; sync"); if (parsed.xinfo & XACT_XINFO_HAS_ORIGIN) { appendStringInfo(buf, "; origin: node %u, lsn %X/%X, at %s", origin_id, (uint32)(parsed.origin_lsn >> 32), (uint32)parsed.origin_lsn, timestamptz_to_str(parsed.origin_timestamp)); }