tqual.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,080 行 · 第 1/3 页

C
1,080
字号
/*------------------------------------------------------------------------- * * tqual.c *	  POSTGRES "time" qualification code, ie, tuple visibility rules. * * 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.  The caller is responsible for noticing any * change in t_infomask and scheduling a disk write if so.	Note that 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.) * * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.70 2003/10/01 21:30:52 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "storage/sinval.h"#include "utils/tqual.h"/* * The SnapshotData structs are static to simplify memory allocation * (see the hack in GetSnapshotData to avoid repeated malloc/free). */static SnapshotData QuerySnapshotData;static SnapshotData SerializableSnapshotData;static SnapshotData CurrentSnapshotData;static SnapshotData SnapshotDirtyData;/* Externally visible pointers to valid snapshots: */Snapshot	QuerySnapshot = NULL;Snapshot	SerializableSnapshot = NULL;Snapshot	SnapshotDirty = &SnapshotDirtyData;/* These are updated by GetSnapshotData: */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){	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;					return false;				}				tuple->t_infomask |= HEAP_XMIN_COMMITTED;			}		}		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;				else				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					return false;				}			}		}		else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple)))		{			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */				return true;			Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)				return true;			return false;		}		else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))		{			if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */			return false;		}		else			tuple->t_infomask |= HEAP_XMIN_COMMITTED;	}	/* 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_MARKED_FOR_UPDATE)			return true;		return false;			/* updated by other */	}	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))	{		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)			return true;		return false;	}	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))	{		if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))			tuple->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */		return true;	}	/* xmax transaction committed */	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)	{		tuple->t_infomask |= HEAP_XMAX_INVALID;		return true;	}	tuple->t_infomask |= HEAP_XMAX_COMMITTED;	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){	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;					return false;				}				tuple->t_infomask |= HEAP_XMIN_COMMITTED;			}		}		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;				else				{					tuple->t_infomask |= HEAP_XMIN_INVALID;					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;			Assert(TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)));			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)				return true;			if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())				return true;	/* deleted after scan started */			else				return false;	/* deleted before scan started */		}		else if (!TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))		{			if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(tuple)))				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */			return false;		}		else			tuple->t_infomask |= HEAP_XMIN_COMMITTED;	}	/* 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_MARKED_FOR_UPDATE)			return true;		return false;	}	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))	{		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)			return true;		if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId())			return true;		/* deleted after scan started */		else			return false;		/* deleted before scan started */	}	if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))	{		if (TransactionIdDidAbort(HeapTupleHeaderGetXmax(tuple)))			tuple->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */		return true;	}	/* xmax transaction committed */	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)	{		tuple->t_infomask |= HEAP_XMAX_INVALID;		return true;	}	tuple->t_infomask |= HEAP_XMAX_COMMITTED;	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){	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;					return false;				}				tuple->t_infomask |= HEAP_XMIN_COMMITTED;

⌨️ 快捷键说明

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