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

📄 tqual.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * tqual.c *	  POSTGRES "time" qualification code, ie, tuple visibility rules. * * The caller must hold at least a shared buffer context lock on the buffer * containing the tuple.  (VACUUM FULL assumes it's sufficient to have * exclusive lock on the containing relation, instead.) * * NOTE: all the HeapTupleSatisfies routines will update the tuple's * "hint" status bits if we see that the inserting or deleting transaction * has now committed or aborted. * * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array) * before TransactionIdDidCommit/TransactionIdDidAbort (which look in * pg_clog).  Otherwise we have a race condition: we might decide that a * just-committed transaction crashed, because none of the tests succeed. * xact.c is careful to record commit/abort in pg_clog before it unsets * MyProc->xid in PGPROC array.  That fixes that problem, but it also * means there is a window where TransactionIdIsInProgress and * TransactionIdDidCommit will both return true.  If we check only * TransactionIdDidCommit, we could consider a tuple committed when a * later GetSnapshotData call will still think the originating transaction * is in progress, which leads to application-level inconsistency.	The * upshot is that we gotta check TransactionIdIsInProgress first in all * code paths, except for a few cases where we are looking at * subtransactions of our own main transaction and so there can't be any * race condition. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.91.2.1 2005/11/22 18:23:25 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/multixact.h"#include "access/subtrans.h"#include "storage/procarray.h"#include "utils/tqual.h"/* * These SnapshotData structs are static to simplify memory allocation * (see the hack in GetSnapshotData to avoid repeated malloc/free). */static SnapshotData SnapshotDirtyData;static SnapshotData SerializableSnapshotData;static SnapshotData LatestSnapshotData;/* Externally visible pointers to valid snapshots: */Snapshot	SnapshotDirty = &SnapshotDirtyData;Snapshot	SerializableSnapshot = NULL;Snapshot	LatestSnapshot = NULL;/* * This pointer is not maintained by this module, but it's convenient * to declare it here anyway.  Callers typically assign a copy of * GetTransactionSnapshot's result to ActiveSnapshot. */Snapshot	ActiveSnapshot = NULL;/* These are updated by GetSnapshotData: */TransactionId TransactionXmin = InvalidTransactionId;TransactionId RecentXmin = InvalidTransactionId;TransactionId RecentGlobalXmin = InvalidTransactionId;/* * HeapTupleSatisfiesItself *		True iff heap tuple is valid "for itself". * *	Here, we consider the effects of: *		all committed transactions (as of the current instant) *		previous commands of this transaction *		changes made by the current command * * Note: *		Assumes heap tuple is valid. * * The satisfaction of "itself" requires the following: * * ((Xmin == my-transaction &&				the row was updated by the current transaction, and *		(Xmax is null						it was not deleted *		 [|| Xmax != my-transaction)])			[or it was deleted by another transaction] * || * * (Xmin is committed &&					the row was modified by a committed transaction, and *		(Xmax is null ||					the row has not been deleted, or *			(Xmax != my-transaction &&			the row was deleted by another transaction *			 Xmax is not committed)))			that has not been committed */boolHeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer){	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))	{		if (tuple->t_infomask & HEAP_XMIN_INVALID)			return false;		if (tuple->t_infomask & HEAP_MOVED_OFF)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (TransactionIdIsCurrentTransactionId(xvac))				return false;			if (!TransactionIdIsInProgress(xvac))			{				if (TransactionIdDidCommit(xvac))				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					SetBufferCommitInfoNeedsSave(buffer);					return false;				}				tuple->t_infomask |= HEAP_XMIN_COMMITTED;				SetBufferCommitInfoNeedsSave(buffer);			}		}		else if (tuple->t_infomask & HEAP_MOVED_IN)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (!TransactionIdIsCurrentTransactionId(xvac))			{				if (TransactionIdIsInProgress(xvac))					return false;				if (TransactionIdDidCommit(xvac))				{					tuple->t_infomask |= HEAP_XMIN_COMMITTED;					SetBufferCommitInfoNeedsSave(buffer);				}				else				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					SetBufferCommitInfoNeedsSave(buffer);					return false;				}			}		}		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))		{			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */				return true;			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */				return true;			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));			/* deleting subtransaction aborted? */			if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))			{				tuple->t_infomask |= HEAP_XMAX_INVALID;				SetBufferCommitInfoNeedsSave(buffer);				return true;			}			Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));			return false;		}		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))			return false;		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))		{			tuple->t_infomask |= HEAP_XMIN_COMMITTED;			SetBufferCommitInfoNeedsSave(buffer);		}		else		{			/* it must have aborted or crashed */			tuple->t_infomask |= HEAP_XMIN_INVALID;			SetBufferCommitInfoNeedsSave(buffer);			return false;		}	}	/* by here, the inserting transaction has committed */	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */		return true;	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)	{		if (tuple->t_infomask & HEAP_IS_LOCKED)			return true;		return false;			/* updated by other */	}	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)	{		/* MultiXacts are currently only allowed to lock tuples */		Assert(tuple->t_infomask & HEAP_IS_LOCKED);		return true;	}	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))	{		if (tuple->t_infomask & HEAP_IS_LOCKED)			return true;		return false;	}	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))		return true;	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))	{		/* it must have aborted or crashed */		tuple->t_infomask |= HEAP_XMAX_INVALID;		SetBufferCommitInfoNeedsSave(buffer);		return true;	}	/* xmax transaction committed */	if (tuple->t_infomask & HEAP_IS_LOCKED)	{		tuple->t_infomask |= HEAP_XMAX_INVALID;		SetBufferCommitInfoNeedsSave(buffer);		return true;	}	tuple->t_infomask |= HEAP_XMAX_COMMITTED;	SetBufferCommitInfoNeedsSave(buffer);	return false;}/* * HeapTupleSatisfiesNow *		True iff heap tuple is valid "now". * *	Here, we consider the effects of: *		all committed transactions (as of the current instant) *		previous commands of this transaction * * Note we do _not_ include changes made by the current command.  This * solves the "Halloween problem" wherein an UPDATE might try to re-update * its own output tuples. * * Note: *		Assumes heap tuple is valid. * * The satisfaction of "now" requires the following: * * ((Xmin == my-transaction &&				changed by the current transaction *	 Cmin != my-command &&					but not by this command, and *		(Xmax is null ||						the row has not been deleted, or *			(Xmax == my-transaction &&			it was deleted by the current transaction *			 Cmax != my-command)))				but not by this command, * ||										or * *	(Xmin is committed &&					the row was modified by a committed transaction, and *		(Xmax is null ||					the row has not been deleted, or *			(Xmax == my-transaction &&			the row is being deleted by this command, or *			 Cmax == my-command) || *			(Xmax is not committed &&			the row was deleted by another transaction *			 Xmax != my-transaction))))			that has not been committed * *		mao says 17 march 1993:  the tests in this routine are correct; *		if you think they're not, you're wrong, and you should think *		about it again.  i know, it happened to me.  we don't need to *		check commit time against the start time of this transaction *		because 2ph locking protects us from doing the wrong thing. *		if you mess around here, you'll break serializability.  the only *		problem with this code is that it does the wrong thing for system *		catalog updates, because the catalogs aren't subject to 2ph, so *		the serializability guarantees we provide don't extend to xacts *		that do catalog accesses.  this is unfortunate, but not critical. */boolHeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer){	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))	{		if (tuple->t_infomask & HEAP_XMIN_INVALID)			return false;		if (tuple->t_infomask & HEAP_MOVED_OFF)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (TransactionIdIsCurrentTransactionId(xvac))				return false;			if (!TransactionIdIsInProgress(xvac))			{				if (TransactionIdDidCommit(xvac))				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					SetBufferCommitInfoNeedsSave(buffer);					return false;				}				tuple->t_infomask |= HEAP_XMIN_COMMITTED;				SetBufferCommitInfoNeedsSave(buffer);			}		}		else if (tuple->t_infomask & HEAP_MOVED_IN)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (!TransactionIdIsCurrentTransactionId(xvac))			{				if (TransactionIdIsInProgress(xvac))					return false;				if (TransactionIdDidCommit(xvac))				{					tuple->t_infomask |= HEAP_XMIN_COMMITTED;					SetBufferCommitInfoNeedsSave(buffer);				}				else				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					SetBufferCommitInfoNeedsSave(buffer);					return false;				}			}		}		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))		{			if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId())				return false;	/* inserted after scan started */			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */				return true;			if (tuple->t_infomask & HEAP_IS_LOCKED)		/* not deleter */				return true;			Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI));			/* deleting subtransaction aborted? */			if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))			{				tuple->t_infomask |= HEAP_XMAX_INVALID;				SetBufferCommitInfoNeedsSave(buffer);				return true;			}			Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));			if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())				return true;	/* deleted after scan started */			else				return false;	/* deleted before scan started */		}		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))			return false;		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))		{			tuple->t_infomask |= HEAP_XMIN_COMMITTED;			SetBufferCommitInfoNeedsSave(buffer);		}		else		{			/* it must have aborted or crashed */			tuple->t_infomask |= HEAP_XMIN_INVALID;			SetBufferCommitInfoNeedsSave(buffer);			return false;		}	}	/* by here, the inserting transaction has committed */	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */		return true;	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)	{		if (tuple->t_infomask & HEAP_IS_LOCKED)			return true;		return false;	}	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)	{		/* MultiXacts are currently only allowed to lock tuples */		Assert(tuple->t_infomask & HEAP_IS_LOCKED);		return true;	}	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))	{		if (tuple->t_infomask & HEAP_IS_LOCKED)			return true;		if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())			return true;		/* deleted after scan started */		else			return false;		/* deleted before scan started */	}	if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))		return true;	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))	{		/* it must have aborted or crashed */		tuple->t_infomask |= HEAP_XMAX_INVALID;		SetBufferCommitInfoNeedsSave(buffer);		return true;	}	/* xmax transaction committed */	if (tuple->t_infomask & HEAP_IS_LOCKED)	{		tuple->t_infomask |= HEAP_XMAX_INVALID;		SetBufferCommitInfoNeedsSave(buffer);		return true;	}	tuple->t_infomask |= HEAP_XMAX_COMMITTED;	SetBufferCommitInfoNeedsSave(buffer);	return false;}/* * HeapTupleSatisfiesToast *		True iff heap tuple is valid as a TOAST row. * * This is a simplified version that only checks for VACUUM moving conditions. * It's appropriate for TOAST usage because TOAST really doesn't want to do * its own time qual checks; if you can see the main table row that contains * a TOAST reference, you should be able to see the TOASTed value.	However, * vacuuming a TOAST table is independent of the main table, and in case such * a vacuum fails partway through, we'd better do this much checking. * * Among other things, this means you can't do UPDATEs of rows in a TOAST * table. */boolHeapTupleSatisfiesToast(HeapTupleHeader tuple, Buffer buffer){	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))	{		if (tuple->t_infomask & HEAP_XMIN_INVALID)			return false;		if (tuple->t_infomask & HEAP_MOVED_OFF)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (TransactionIdIsCurrentTransactionId(xvac))				return false;			if (!TransactionIdIsInProgress(xvac))			{

⌨️ 快捷键说明

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