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

📄 subtrans.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * subtrans.c *		PostgreSQL subtransaction-log manager * * The pg_subtrans manager is a pg_clog-like manager that stores the parent * transaction Id for each transaction.  It is a fundamental part of the * nested transactions implementation.	A main transaction has a parent * of InvalidTransactionId, and each subtransaction has its immediate parent. * The tree can easily be walked from child to parent, but not in the * opposite direction. * * This code is based on clog.c, but the robustness requirements * are completely different from pg_clog, because we only need to remember * pg_subtrans information for currently-open transactions.  Thus, there is * no need to preserve data over a crash and restart. * * There are no XLOG interactions since we do not care about preserving * data across crashes.  During database startup, we simply force the * currently-active page of SUBTRANS to zeroes. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.11.2.1 2005/11/22 18:23:05 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/slru.h"#include "access/subtrans.h"#include "utils/tqual.h"/* * Defines for SubTrans page 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, * SubTrans page numbering also wraps around at * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE, and segment numbering at * 0xFFFFFFFF/SUBTRANS_XACTS_PER_PAGE/SLRU_SEGMENTS_PER_PAGE.  We need take no * explicit notice of that fact in this module, except when comparing segment * and page numbers in TruncateSUBTRANS (see SubTransPagePrecedes). *//* We need four bytes per xact */#define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId))#define TransactionIdToPage(xid) ((xid) / (TransactionId) SUBTRANS_XACTS_PER_PAGE)#define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE)/* * Link to shared-memory data structures for SUBTRANS control */static SlruCtlData SubTransCtlData;#define SubTransCtl  (&SubTransCtlData)static int	ZeroSUBTRANSPage(int pageno);static bool SubTransPagePrecedes(int page1, int page2);/* * Record the parent of a subtransaction in the subtrans log. */voidSubTransSetParent(TransactionId xid, TransactionId parent){	int			pageno = TransactionIdToPage(xid);	int			entryno = TransactionIdToEntry(xid);	int			slotno;	TransactionId *ptr;	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);	slotno = SimpleLruReadPage(SubTransCtl, pageno, xid);	ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];	ptr += entryno;	/* Current state should be 0 */	Assert(*ptr == InvalidTransactionId);	*ptr = parent;	SubTransCtl->shared->page_status[slotno] = SLRU_PAGE_DIRTY;	LWLockRelease(SubtransControlLock);}/* * Interrogate the parent of a transaction in the subtrans log. */TransactionIdSubTransGetParent(TransactionId xid){	int			pageno = TransactionIdToPage(xid);	int			entryno = TransactionIdToEntry(xid);	int			slotno;	TransactionId *ptr;	TransactionId parent;	/* Can't ask about stuff that might not be around anymore */	Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));	/* Bootstrap and frozen XIDs have no parent */	if (!TransactionIdIsNormal(xid))		return InvalidTransactionId;	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);	slotno = SimpleLruReadPage(SubTransCtl, pageno, xid);	ptr = (TransactionId *) SubTransCtl->shared->page_buffer[slotno];	ptr += entryno;	parent = *ptr;	LWLockRelease(SubtransControlLock);	return parent;}/* * SubTransGetTopmostTransaction * * Returns the topmost transaction of the given transaction id. * * Because we cannot look back further than TransactionXmin, it is possible * that this function will lie and return an intermediate subtransaction ID * instead of the true topmost parent ID.  This is OK, because in practice * we only care about detecting whether the topmost parent is still running * or is part of a current snapshot's list of still-running transactions. * Therefore, any XID before TransactionXmin is as good as any other. */TransactionIdSubTransGetTopmostTransaction(TransactionId xid){	TransactionId parentXid = xid,				previousXid = xid;	/* Can't ask about stuff that might not be around anymore */	Assert(TransactionIdFollowsOrEquals(xid, TransactionXmin));	while (TransactionIdIsValid(parentXid))	{		previousXid = parentXid;		if (TransactionIdPrecedes(parentXid, TransactionXmin))			break;		parentXid = SubTransGetParent(parentXid);	}	Assert(TransactionIdIsValid(previousXid));	return previousXid;}/* * Initialization of shared memory for SUBTRANS */SizeSUBTRANSShmemSize(void){	return SimpleLruShmemSize();}voidSUBTRANSShmemInit(void){	SubTransCtl->PagePrecedes = SubTransPagePrecedes;	SimpleLruInit(SubTransCtl, "SUBTRANS Ctl",				  SubtransControlLock, "pg_subtrans");	/* Override default assumption that writes should be fsync'd */	SubTransCtl->do_fsync = false;}/* * This func must be called ONCE on system install.  It creates * the initial SUBTRANS segment.  (The SUBTRANS directory is assumed to * have been created by the initdb shell script, and SUBTRANSShmemInit * must have been called already.) * * Note: it's not really necessary to create the initial segment now, * since slru.c would create it on first write anyway.	But we may as well * do it to be sure the directory is set up correctly. */voidBootStrapSUBTRANS(void){	int			slotno;	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);	/* Create and zero the first page of the subtrans log */	slotno = ZeroSUBTRANSPage(0);	/* Make sure it's written out */	SimpleLruWritePage(SubTransCtl, slotno, NULL);	Assert(SubTransCtl->shared->page_status[slotno] == SLRU_PAGE_CLEAN);	LWLockRelease(SubtransControlLock);}/* * Initialize (or reinitialize) a page of SUBTRANS to zeroes. * * 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 intZeroSUBTRANSPage(int pageno){	return SimpleLruZeroPage(SubTransCtl, pageno);}/* * This must be called ONCE during postmaster or standalone-backend startup, * after StartupXLOG has initialized ShmemVariableCache->nextXid. * * oldestActiveXID is the oldest XID of any prepared transaction, or nextXid * if there are none. */voidStartupSUBTRANS(TransactionId oldestActiveXID){	int			startPage;	int			endPage;	/*	 * Since we don't expect pg_subtrans to be valid across crashes, we	 * initialize the currently-active page(s) to zeroes during startup.	 * Whenever we advance into a new page, ExtendSUBTRANS will likewise zero	 * the new page without regard to whatever was previously on disk.	 */	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);	startPage = TransactionIdToPage(oldestActiveXID);	endPage = TransactionIdToPage(ShmemVariableCache->nextXid);	while (startPage != endPage)	{		(void) ZeroSUBTRANSPage(startPage);		startPage++;	}	(void) ZeroSUBTRANSPage(startPage);	LWLockRelease(SubtransControlLock);}/* * This must be called ONCE during postmaster or standalone-backend shutdown */voidShutdownSUBTRANS(void){	/*	 * Flush dirty SUBTRANS pages to disk	 *	 * This is not actually necessary from a correctness point of view. We do	 * it merely as a debugging aid.	 */	SimpleLruFlush(SubTransCtl, false);}/* * Perform a checkpoint --- either during shutdown, or on-the-fly */voidCheckPointSUBTRANS(void){	/*	 * Flush dirty SUBTRANS pages to disk	 *	 * This is not actually necessary from a correctness point of view. We do	 * it merely to improve the odds that writing of dirty pages is done by	 * the checkpoint process and not by backends.	 */	SimpleLruFlush(SubTransCtl, true);}/* * Make sure that SUBTRANS 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 subtrans page to make room * in shared memory. */voidExtendSUBTRANS(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 (TransactionIdToEntry(newestXact) != 0 &&		!TransactionIdEquals(newestXact, FirstNormalTransactionId))		return;	pageno = TransactionIdToPage(newestXact);	LWLockAcquire(SubtransControlLock, LW_EXCLUSIVE);	/* Zero the page */	ZeroSUBTRANSPage(pageno);	LWLockRelease(SubtransControlLock);}/* * Remove all SUBTRANS segments before the one holding the passed transaction ID * * This is normally called during checkpoint, with oldestXact being the * oldest TransactionXmin of any running transaction. */voidTruncateSUBTRANS(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(SubTransCtl, cutoffPage);}/* * Decide which of two SUBTRANS 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 boolSubTransPagePrecedes(int page1, int page2){	TransactionId xid1;	TransactionId xid2;	xid1 = ((TransactionId) page1) * SUBTRANS_XACTS_PER_PAGE;	xid1 += FirstNormalTransactionId;	xid2 = ((TransactionId) page2) * SUBTRANS_XACTS_PER_PAGE;	xid2 += FirstNormalTransactionId;	return TransactionIdPrecedes(xid1, xid2);}

⌨️ 快捷键说明

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