📄 clog.c
字号:
*/voidStartupCLOG(void){ TransactionId xid = ShmemVariableCache->nextXid; int pageno = TransactionIdToPage(xid); LWLockAcquire(CLogControlLock, LW_EXCLUSIVE); /* * Initialize our idea of the latest page number. */ ClogCtl->shared->latest_page_number = pageno; /* * Zero out the remainder of the current clog page. Under normal * circumstances it should be zeroes already, but it seems at least * theoretically possible that XLOG replay will have settled on a nextXID * value that is less than the last XID actually used and marked by the * previous database lifecycle (since subtransaction commit writes clog * but makes no WAL entry). Let's just be safe. (We need not worry about * pages beyond the current one, since those will be zeroed when first * used. For the same reason, there is no need to do anything when * nextXid is exactly at a page boundary; and it's likely that the * "current" page doesn't exist yet in that case.) */ if (TransactionIdToPgIndex(xid) != 0) { int byteno = TransactionIdToByte(xid); int bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT; int slotno; char *byteptr; slotno = SimpleLruReadPage(ClogCtl, pageno, false, xid); byteptr = ClogCtl->shared->page_buffer[slotno] + byteno; /* Zero so-far-unused positions in the current byte */ *byteptr &= (1 << bshift) - 1; /* Zero the rest of the page */ MemSet(byteptr + 1, 0, BLCKSZ - byteno - 1); ClogCtl->shared->page_dirty[slotno] = true; } LWLockRelease(CLogControlLock);}/* * This must be called ONCE during postmaster or standalone-backend shutdown */voidShutdownCLOG(void){ /* Flush dirty CLOG pages to disk */ SimpleLruFlush(ClogCtl, false);}/* * Perform a checkpoint --- either during shutdown, or on-the-fly */voidCheckPointCLOG(void){ /* Flush dirty CLOG pages to disk */ SimpleLruFlush(ClogCtl, true);}/* * Make sure that CLOG has room for a newly-allocated XID. * * NB: this is called while holding XidGenLock. We want it to be very fast * most of the time; even when it's not so fast, no actual I/O need happen * unless we're forced to write out a dirty clog or xlog page to make room * in shared memory. */voidExtendCLOG(TransactionId newestXact){ int pageno; /* * No work except at first XID of a page. But beware: just after * wraparound, the first XID of page zero is FirstNormalTransactionId. */ if (TransactionIdToPgIndex(newestXact) != 0 && !TransactionIdEquals(newestXact, FirstNormalTransactionId)) return; pageno = TransactionIdToPage(newestXact); LWLockAcquire(CLogControlLock, LW_EXCLUSIVE); /* Zero the page and make an XLOG entry about it */ ZeroCLOGPage(pageno, true); LWLockRelease(CLogControlLock);}/* * Remove all CLOG segments before the one holding the passed transaction ID * * Before removing any CLOG data, we must flush XLOG to disk, to ensure * that any recently-emitted HEAP_FREEZE records have reached disk; otherwise * a crash and restart might leave us with some unfrozen tuples referencing * removed CLOG data. We choose to emit a special TRUNCATE XLOG record too. * Replaying the deletion from XLOG is not critical, since the files could * just as well be removed later, but doing so prevents a long-running hot * standby server from acquiring an unreasonably bloated CLOG directory. * * Since CLOG segments hold a large number of transactions, the opportunity to * actually remove a segment is fairly rare, and so it seems best not to do * the XLOG flush unless we have confirmed that there is a removable segment. */voidTruncateCLOG(TransactionId oldestXact){ int cutoffPage; /* * The cutoff point is the start of the segment containing oldestXact. We * pass the *page* containing oldestXact to SimpleLruTruncate. */ cutoffPage = TransactionIdToPage(oldestXact); /* Check to see if there's any files that could be removed */ if (!SlruScanDirectory(ClogCtl, cutoffPage, false)) return; /* nothing to remove */ /* Write XLOG record and flush XLOG to disk */ WriteTruncateXlogRec(cutoffPage); /* Now we can remove the old CLOG segment(s) */ SimpleLruTruncate(ClogCtl, cutoffPage);}/* * Decide which of two CLOG page numbers is "older" for truncation purposes. * * We need to use comparison of TransactionIds here in order to do the right * thing with wraparound XID arithmetic. However, if we are asked about * page number zero, we don't want to hand InvalidTransactionId to * TransactionIdPrecedes: it'll get weird about permanent xact IDs. So, * offset both xids by FirstNormalTransactionId to avoid that. */static boolCLOGPagePrecedes(int page1, int page2){ TransactionId xid1; TransactionId xid2; xid1 = ((TransactionId) page1) * CLOG_XACTS_PER_PAGE; xid1 += FirstNormalTransactionId; xid2 = ((TransactionId) page2) * CLOG_XACTS_PER_PAGE; xid2 += FirstNormalTransactionId; return TransactionIdPrecedes(xid1, xid2);}/* * Write a ZEROPAGE xlog record */static voidWriteZeroPageXlogRec(int pageno){ XLogRecData rdata; rdata.data = (char *) (&pageno); rdata.len = sizeof(int); rdata.buffer = InvalidBuffer; rdata.next = NULL; (void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE, &rdata);}/* * Write a TRUNCATE xlog record * * We must flush the xlog record to disk before returning --- see notes * in TruncateCLOG(). */static voidWriteTruncateXlogRec(int pageno){ XLogRecData rdata; XLogRecPtr recptr; rdata.data = (char *) (&pageno); rdata.len = sizeof(int); rdata.buffer = InvalidBuffer; rdata.next = NULL; recptr = XLogInsert(RM_CLOG_ID, CLOG_TRUNCATE, &rdata); XLogFlush(recptr);}/* * CLOG resource manager's routines */voidclog_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == CLOG_ZEROPAGE) { int pageno; int slotno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); LWLockAcquire(CLogControlLock, LW_EXCLUSIVE); slotno = ZeroCLOGPage(pageno, false); SimpleLruWritePage(ClogCtl, slotno, NULL); Assert(!ClogCtl->shared->page_dirty[slotno]); LWLockRelease(CLogControlLock); } else if (info == CLOG_TRUNCATE) { int pageno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); /* * During XLOG replay, latest_page_number isn't set up yet; insert a * suitable value to bypass the sanity test in SimpleLruTruncate. */ ClogCtl->shared->latest_page_number = pageno; SimpleLruTruncate(ClogCtl, pageno); } else elog(PANIC, "clog_redo: unknown op code %u", info);}voidclog_desc(StringInfo buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; if (info == CLOG_ZEROPAGE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "zeropage: %d", pageno); } else if (info == CLOG_TRUNCATE) { int pageno; memcpy(&pageno, rec, sizeof(int)); appendStringInfo(buf, "truncate before: %d", pageno); } else appendStringInfo(buf, "UNKNOWN");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -