⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clog.c

📁 PostgreSQL7.4.6 for Linux
💻 C
字号:
/*------------------------------------------------------------------------- * * clog.c *		PostgreSQL transaction-commit-log manager * * This module replaces the old "pg_log" access code, which treated pg_log * essentially like a relation, in that it went through the regular buffer * manager.  The problem with that was that there wasn't any good way to * recycle storage space for transactions so old that they'll never be * looked up again.  Now we use specialized access code so that the commit * log can be broken into relatively small, independent segments. * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.18 2003/08/04 02:39:57 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <dirent.h>#include <errno.h>#include <sys/stat.h>#include <unistd.h>#include "access/clog.h"#include "access/slru.h"#include "storage/lwlock.h"#include "miscadmin.h"/* * Defines for CLOG page and segment sizes.  A page is the same BLCKSZ * as is used everywhere else in Postgres. * * Note: because TransactionIds are 32 bits and wrap around at 0xFFFFFFFF, * CLOG page numbering also wraps around at 0xFFFFFFFF/CLOG_XACTS_PER_PAGE, * and CLOG segment numbering at 0xFFFFFFFF/CLOG_XACTS_PER_SEGMENT.  We need * take no explicit notice of that fact in this module, except when comparing * segment and page numbers in TruncateCLOG (see CLOGPagePrecedes). *//* We need two bits per xact, so four xacts fit in a byte */#define CLOG_BITS_PER_XACT	2#define CLOG_XACTS_PER_BYTE 4#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)#define CLOG_XACT_BITMASK	((1 << CLOG_BITS_PER_XACT) - 1)#define TransactionIdToPage(xid)	((xid) / (TransactionId) CLOG_XACTS_PER_PAGE)#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE)#define TransactionIdToByte(xid)	(TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)#define TransactionIdToBIndex(xid)	((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)/*---------- * Shared-memory data structures for CLOG control * * XLOG interactions: this module generates an XLOG record whenever a new * CLOG page is initialized to zeroes.	Other writes of CLOG come from * recording of transaction commit or abort in xact.c, which generates its * own XLOG records for these events and will re-perform the status update * on redo; so we need make no additional XLOG entry here.	Also, the XLOG * is guaranteed flushed through the XLOG commit record before we are called * to log a commit, so the WAL rule "write xlog before data" is satisfied * automatically for commits, and we don't really care for aborts.  Therefore, * we don't need to mark XLOG pages with LSN information; we have enough * synchronization already. *---------- */static SlruCtlData ClogCtlData;static SlruCtl ClogCtl = &ClogCtlData;static int	ZeroCLOGPage(int pageno, bool writeXlog);static bool CLOGPagePrecedes(int page1, int page2);static void WriteZeroPageXlogRec(int pageno);/* * Record the final state of a transaction in the commit log. * * NB: this is a low-level routine and is NOT the preferred entry point * for most uses; TransactionLogUpdate() in transam.c is the intended caller. */voidTransactionIdSetStatus(TransactionId xid, XidStatus status){	int			pageno = TransactionIdToPage(xid);	int			byteno = TransactionIdToByte(xid);	int			bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;	char	   *byteptr;	Assert(status == TRANSACTION_STATUS_COMMITTED ||		   status == TRANSACTION_STATUS_ABORTED);	LWLockAcquire(ClogCtl->locks->ControlLock, LW_EXCLUSIVE);	byteptr = SimpleLruReadPage(ClogCtl, pageno, xid, true);	byteptr += byteno;	/* Current state should be 0 or target state */	Assert(((*byteptr >> bshift) & CLOG_XACT_BITMASK) == 0 ||		   ((*byteptr >> bshift) & CLOG_XACT_BITMASK) == status);	*byteptr |= (status << bshift);	/* ...->page_status[slotno] = CLOG_PAGE_DIRTY; already done */	LWLockRelease(ClogCtl->locks->ControlLock);}/* * Interrogate the state of a transaction in the commit log. * * NB: this is a low-level routine and is NOT the preferred entry point * for most uses; TransactionLogTest() in transam.c is the intended caller. */XidStatusTransactionIdGetStatus(TransactionId xid){	int			pageno = TransactionIdToPage(xid);	int			byteno = TransactionIdToByte(xid);	int			bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;	char	   *byteptr;	XidStatus	status;	LWLockAcquire(ClogCtl->locks->ControlLock, LW_EXCLUSIVE);	byteptr = SimpleLruReadPage(ClogCtl, pageno, xid, false);	byteptr += byteno;	status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;	LWLockRelease(ClogCtl->locks->ControlLock);	return status;}/* * Initialization of shared memory for CLOG */intCLOGShmemSize(void){	return SimpleLruShmemSize();}voidCLOGShmemInit(void){	SimpleLruInit(ClogCtl, "CLOG Ctl", "pg_clog");	ClogCtl->PagePrecedes = CLOGPagePrecedes;}/* * This func must be called ONCE on system install.  It creates * the initial CLOG segment.  (The CLOG directory is assumed to * have been created by the initdb shell script, and CLOGShmemInit * must have been called already.) */voidBootStrapCLOG(void){	int			slotno;	LWLockAcquire(ClogCtl->locks->ControlLock, LW_EXCLUSIVE);	/* Create and zero the first page of the commit log */	slotno = ZeroCLOGPage(0, false);	/* Make sure it's written out */	SimpleLruWritePage(ClogCtl, slotno);	/* Assert(ClogCtl->page_status[slotno] == CLOG_PAGE_CLEAN); */	LWLockRelease(ClogCtl->locks->ControlLock);}/* * Initialize (or reinitialize) a page of CLOG to zeroes. * If writeXlog is TRUE, also emit an XLOG record saying we did this. * * The page is not actually written, just set up in shared memory. * The slot number of the new page is returned. * * Control lock must be held at entry, and will be held at exit. */static intZeroCLOGPage(int pageno, bool writeXlog){	int			slotno = SimpleLruZeroPage(ClogCtl, pageno);	if (writeXlog)		WriteZeroPageXlogRec(pageno);	return slotno;}/* * This must be called ONCE during postmaster or standalone-backend startup, * after StartupXLOG has initialized ShmemVariableCache->nextXid. */voidStartupCLOG(void){	/*	 * Initialize our idea of the latest page number.	 */	SimpleLruSetLatestPage(ClogCtl, TransactionIdToPage(ShmemVariableCache->nextXid));}/* * This must be called ONCE during postmaster or standalone-backend shutdown */voidShutdownCLOG(void){	SimpleLruFlush(ClogCtl, false);}/* * Perform a checkpoint --- either during shutdown, or on-the-fly */voidCheckPointCLOG(void){	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(ClogCtl->locks->ControlLock, LW_EXCLUSIVE);	/* Zero the page and make an XLOG entry about it */	ZeroCLOGPage(pageno, true);	LWLockRelease(ClogCtl->locks->ControlLock);}/* * Remove all CLOG segments before the one holding the passed transaction ID * * When this is called, we know that the database logically contains no * reference to transaction IDs older than oldestXact.	However, we must * not truncate the CLOG until we have performed a checkpoint, to ensure * that no such references remain on disk either; else a crash just after * the truncation might leave us with a problem.  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 checkpoint * unless we have confirmed that there is a removable segment.	Therefore * we issue the checkpoint command here, not in higher-level code as might * seem cleaner. */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);	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 * * Note: xlog record is marked as outside transaction control, since we * want it to be redone whether the invoking transaction commits or not. * (Besides which, this is normally done just before entering a transaction.) */static voidWriteZeroPageXlogRec(int pageno){	XLogRecData rdata;	rdata.buffer = InvalidBuffer;	rdata.data = (char *) (&pageno);	rdata.len = sizeof(int);	rdata.next = NULL;	(void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE | XLOG_NO_TRAN, &rdata);}/* * 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(ClogCtl->locks->ControlLock, LW_EXCLUSIVE);		slotno = ZeroCLOGPage(pageno, false);		SimpleLruWritePage(ClogCtl, slotno);		/* Assert(ClogCtl->page_status[slotno] == SLRU_PAGE_CLEAN); */		LWLockRelease(ClogCtl->locks->ControlLock);	}}voidclog_undo(XLogRecPtr lsn, XLogRecord *record){}voidclog_desc(char *buf, uint8 xl_info, char *rec){	uint8		info = xl_info & ~XLR_INFO_MASK;	if (info == CLOG_ZEROPAGE)	{		int			pageno;		memcpy(&pageno, rec, sizeof(int));		sprintf(buf + strlen(buf), "zeropage: %d", pageno);	}	else		strcat(buf, "UNKNOWN");}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -