tqual.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 1,436 行 · 第 1/3 页

C
1,436
字号
				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));			if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))			{				/* deleting subtransaction must have aborted */				SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,							InvalidTransactionId);				return true;			}			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)				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)))			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,						HeapTupleHeaderGetXmin(tuple));		else		{			/* it must have aborted or crashed */			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,						InvalidTransactionId);			return false;		}	}	/*	 * By here, the inserting transaction has committed - have to check	 * when...	 */	if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot))		return false;			/* treat as still in progress */	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */		return true;	if (tuple->t_infomask & HEAP_IS_LOCKED)		return true;	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 (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))	{		if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))		{			if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)				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 */			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,						InvalidTransactionId);			return true;		}		/* xmax transaction committed */		SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,					HeapTupleHeaderGetXmax(tuple));	}	/*	 * OK, the deleting transaction committed too ... but when?	 */	if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot))		return true;			/* treat as still in progress */	return false;}/* * HeapTupleSatisfiesVacuum * *	Determine the status of tuples for VACUUM purposes.  Here, what *	we mainly want to know is if a tuple is potentially visible to *any* *	running transaction.  If so, it can't be removed yet by VACUUM. * * OldestXmin is a cutoff XID (obtained from GetOldestXmin()).	Tuples * deleted by XIDs >= OldestXmin are deemed "recently dead"; they might * still be visible to some open transaction, so we can't remove them, * even if we see that the deleting transaction has committed. */HTSV_ResultHeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,						 Buffer buffer){	/*	 * Has inserting transaction committed?	 *	 * If the inserting transaction aborted, then the tuple was never visible	 * to any other transaction, so we can delete it immediately.	 */	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))	{		if (tuple->t_infomask & HEAP_XMIN_INVALID)			return HEAPTUPLE_DEAD;		else if (tuple->t_infomask & HEAP_MOVED_OFF)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (TransactionIdIsCurrentTransactionId(xvac))				return HEAPTUPLE_DELETE_IN_PROGRESS;			if (TransactionIdIsInProgress(xvac))				return HEAPTUPLE_DELETE_IN_PROGRESS;			if (TransactionIdDidCommit(xvac))			{				SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,							InvalidTransactionId);				return HEAPTUPLE_DEAD;			}			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,						InvalidTransactionId);		}		else if (tuple->t_infomask & HEAP_MOVED_IN)		{			TransactionId xvac = HeapTupleHeaderGetXvac(tuple);			if (TransactionIdIsCurrentTransactionId(xvac))				return HEAPTUPLE_INSERT_IN_PROGRESS;			if (TransactionIdIsInProgress(xvac))				return HEAPTUPLE_INSERT_IN_PROGRESS;			if (TransactionIdDidCommit(xvac))				SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,							InvalidTransactionId);			else			{				SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,							InvalidTransactionId);				return HEAPTUPLE_DEAD;			}		}		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))		{			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */				return HEAPTUPLE_INSERT_IN_PROGRESS;			if (tuple->t_infomask & HEAP_IS_LOCKED)				return HEAPTUPLE_INSERT_IN_PROGRESS;			/* inserted and then deleted by same xact */			return HEAPTUPLE_DELETE_IN_PROGRESS;		}		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,						HeapTupleHeaderGetXmin(tuple));		else		{			/*			 * Not in Progress, Not Committed, so either Aborted or crashed			 */			SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,						InvalidTransactionId);			return HEAPTUPLE_DEAD;		}		/*		 * At this point the xmin is known committed, but we might not have		 * been able to set the hint bit yet; so we can no longer Assert that		 * it's set.		 */	}	/*	 * Okay, the inserter committed, so it was good at some point.	Now what	 * about the deleting transaction?	 */	if (tuple->t_infomask & HEAP_XMAX_INVALID)		return HEAPTUPLE_LIVE;	if (tuple->t_infomask & HEAP_IS_LOCKED)	{		/*		 * "Deleting" xact really only locked it, so the tuple is live in any		 * case.  However, we should make sure that either XMAX_COMMITTED or		 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of		 * examining the tuple for future xacts.  Also, marking dead		 * MultiXacts as invalid here provides defense against MultiXactId		 * wraparound (see also comments in heap_freeze_tuple()).		 */		if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))		{			if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)			{				if (MultiXactIdIsRunning(HeapTupleHeaderGetXmax(tuple)))					return HEAPTUPLE_LIVE;			}			else			{				if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))					return HEAPTUPLE_LIVE;			}			/*			 * We don't really care whether xmax did commit, abort or crash.			 * We know that xmax did lock the tuple, but it did not and will			 * never actually update it.			 */			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,						InvalidTransactionId);		}		return HEAPTUPLE_LIVE;	}	if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)	{		/* MultiXacts are currently only allowed to lock tuples */		Assert(tuple->t_infomask & HEAP_IS_LOCKED);		return HEAPTUPLE_LIVE;	}	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))	{		if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))			return HEAPTUPLE_DELETE_IN_PROGRESS;		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))			SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,						HeapTupleHeaderGetXmax(tuple));		else		{			/*			 * Not in Progress, Not Committed, so either Aborted or crashed			 */			SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,						InvalidTransactionId);			return HEAPTUPLE_LIVE;		}		/*		 * At this point the xmax is known committed, but we might not have		 * been able to set the hint bit yet; so we can no longer Assert that		 * it's set.		 */	}	/*	 * Deleter committed, but check special cases.	 */	if (TransactionIdEquals(HeapTupleHeaderGetXmin(tuple),							HeapTupleHeaderGetXmax(tuple)))	{		/*		 * Inserter also deleted it, so it was never visible to anyone else.		 * However, we can only remove it early if it's not an updated tuple;		 * else its parent tuple is linking to it via t_ctid, and this tuple		 * mustn't go away before the parent does.		 */		if (!(tuple->t_infomask & HEAP_UPDATED))			return HEAPTUPLE_DEAD;	}	if (!TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin))	{		/* deleting xact is too recent, tuple could still be visible */		return HEAPTUPLE_RECENTLY_DEAD;	}	/* Otherwise, it's dead and removable */	return HEAPTUPLE_DEAD;}/* * GetTransactionSnapshot *		Get the appropriate snapshot for a new query in a transaction. * * The SerializableSnapshot is the first one taken in a transaction. * In serializable mode we just use that one throughout the transaction. * In read-committed mode, we take a new snapshot each time we are called. * * Note that the return value points at static storage that will be modified * by future calls and by CommandCounterIncrement().  Callers should copy * the result with CopySnapshot() if it is to be used very long. */SnapshotGetTransactionSnapshot(void){	/* First call in transaction? */	if (SerializableSnapshot == NULL)	{		SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true);		return SerializableSnapshot;	}	if (IsXactIsoLevelSerializable)		return SerializableSnapshot;	LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);	return LatestSnapshot;}/* * GetLatestSnapshot *		Get a snapshot that is up-to-date as of the current instant, *		even if we are executing in SERIALIZABLE mode. */SnapshotGetLatestSnapshot(void){	/* Should not be first call in transaction */	if (SerializableSnapshot == NULL)		elog(ERROR, "no snapshot has been set");	LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false);	return LatestSnapshot;}/* * CopySnapshot *		Copy the given snapshot. * * The copy is palloc'd in the current memory context. */SnapshotCopySnapshot(Snapshot snapshot){	Snapshot	newsnap;	Size		subxipoff;	Size		size;	/* We allocate any XID arrays needed in the same palloc block. */	size = subxipoff = sizeof(SnapshotData) +		snapshot->xcnt * sizeof(TransactionId);	if (snapshot->subxcnt > 0)		size += snapshot->subxcnt * sizeof(TransactionId);	newsnap = (Snapshot) palloc(size);	memcpy(newsnap, snapshot, sizeof(SnapshotData));	/* setup XID array */	if (snapshot->xcnt > 0)	{		newsnap->xip = (TransactionId *) (newsnap + 1);		memcpy(newsnap->xip, snapshot->xip,			   snapshot->xcnt * sizeof(TransactionId));	}	else		newsnap->xip = NULL;	/* setup subXID array */	if (snapshot->subxcnt > 0)	{		newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);		memcpy(newsnap->subxip, snapshot->subxip,			   snapshot->subxcnt * sizeof(TransactionId));	}	else		newsnap->subxip = NULL;	return newsnap;}/* * FreeSnapshot *		Free a snapshot previously copied with CopySnapshot. * * This is currently identical to pfree, but is provided for cleanliness. * * Do *not* apply this to the results of GetTransactionSnapshot or * GetLatestSnapshot, since those are just static structs. */voidFreeSnapshot(Snapshot snapshot){	pfree(snapshot);}/* * FreeXactSnapshot *		Free snapshot(s) at end of transaction. */voidFreeXactSnapshot(void){	/*	 * We do not free the xip arrays for the static snapshot structs; they	 * will be reused soon. So this is now just a state change to prevent	 * outside callers from accessing the snapshots.	 */	SerializableSnapshot = NULL;	LatestSnapshot = NULL;	ActiveSnapshot = NULL;		/* just for cleanliness */}/* * XidInMVCCSnapshot *		Is the given XID still-in-progress according to the snapshot? * * Note: GetSnapshotData never stores either top xid or subxids of our own * backend into a snapshot, so these xids will not be reported as "running" * by this function.  This is OK for current uses, because we actually only * apply this for known-committed XIDs. */static boolXidInMVCCSnapshot(TransactionId xid, Snapshot snapshot){	uint32		i;	/*	 * Make a quick range check to eliminate most XIDs without looking at the	 * xip arrays.	Note that this is OK even if we convert a subxact XID to	 * its parent below, because a subxact with XID < xmin has surely also got	 * a parent with XID < xmin, while one with XID >= xmax must belong to a	 * parent that was not yet committed at the time of this snapshot.	 */	/* Any xid < xmin is not in-progress */	if (TransactionIdPrecedes(xid, snapshot->xmin))		return false;	/* Any xid >= xmax is in-progress */	if (TransactionIdFollowsOrEquals(xid, snapshot->xmax))		return true;	/*	 * If the snapshot contains full subxact data, the fastest way to check	 * things is just to compare the given XID against both subxact XIDs and	 * top-level XIDs.	If the snapshot overflowed, we have to use pg_subtrans	 * to convert a subxact XID to its parent XID, but then we need only look	 * at top-level XIDs not subxacts.	 */	if (snapshot->subxcnt >= 0)	{		/* full data, so search subxip */		int32		j;		for (j = 0; j < snapshot->subxcnt; j++)		{			if (TransactionIdEquals(xid, snapshot->subxip[j]))				return true;		}		/* not there, fall through to search xip[] */	}	else	{		/* overflowed, so convert xid to top-level */		xid = SubTransGetTopmostTransaction(xid);		/*		 * If xid was indeed a subxact, we might now have an xid < xmin, so		 * recheck to avoid an array scan.	No point in rechecking xmax.		 */		if (TransactionIdPrecedes(xid, snapshot->xmin))			return false;	}	for (i = 0; i < snapshot->xcnt; i++)	{		if (TransactionIdEquals(xid, snapshot->xip[i]))			return true;	}	return false;}

⌨️ 快捷键说明

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