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

📄 heapam.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	lp = PageGetItemId(dp, offnum);	/*	 * Must check for deleted tuple.	 */	if (!ItemIdIsNormal(lp))	{		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);		if (keep_buf)			*userbuf = buffer;		else		{			ReleaseBuffer(buffer);			*userbuf = InvalidBuffer;		}		tuple->t_data = NULL;		return false;	}	/*	 * fill in *tuple fields	 */	tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);	tuple->t_len = ItemIdGetLength(lp);	tuple->t_tableOid = RelationGetRelid(relation);	/*	 * check time qualification of tuple, then release lock	 */	valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	if (valid)	{		/*		 * All checks passed, so return the tuple as valid. Caller is now		 * responsible for releasing the buffer.		 */		*userbuf = buffer;		/* Count the successful fetch against appropriate rel, if any */		if (stats_relation != NULL)			pgstat_count_heap_fetch(stats_relation);		return true;	}	/* Tuple failed time qual, but maybe caller wants to see it anyway. */	if (keep_buf)		*userbuf = buffer;	else	{		ReleaseBuffer(buffer);		*userbuf = InvalidBuffer;	}	return false;}/* *	heap_hot_search_buffer	- search HOT chain for tuple satisfying snapshot * * On entry, *tid is the TID of a tuple (either a simple tuple, or the root * of a HOT chain), and buffer is the buffer holding this tuple.  We search * for the first chain member satisfying the given snapshot.  If one is * found, we update *tid to reference that tuple's offset number, and * return TRUE.  If no match, return FALSE without modifying *tid. * * If all_dead is not NULL, we check non-visible tuples to see if they are * globally dead; *all_dead is set TRUE if all members of the HOT chain * are vacuumable, FALSE if not. * * Unlike heap_fetch, the caller must already have pin and (at least) share * lock on the buffer; it is still pinned/locked at exit.  Also unlike * heap_fetch, we do not report any pgstats count; caller may do so if wanted. */boolheap_hot_search_buffer(ItemPointer tid, Buffer buffer, Snapshot snapshot,					   bool *all_dead){	Page		dp = (Page) BufferGetPage(buffer);	TransactionId prev_xmax = InvalidTransactionId;	OffsetNumber offnum;	bool		at_chain_start;	if (all_dead)		*all_dead = true;	Assert(TransactionIdIsValid(RecentGlobalXmin));	Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));	offnum = ItemPointerGetOffsetNumber(tid);	at_chain_start = true;	/* Scan through possible multiple members of HOT-chain */	for (;;)	{		ItemId		lp;		HeapTupleData heapTuple;		/* check for bogus TID */		if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))			break;		lp = PageGetItemId(dp, offnum);		/* check for unused, dead, or redirected items */		if (!ItemIdIsNormal(lp))		{			/* We should only see a redirect at start of chain */			if (ItemIdIsRedirected(lp) && at_chain_start)			{				/* Follow the redirect */				offnum = ItemIdGetRedirect(lp);				at_chain_start = false;				continue;			}			/* else must be end of chain */			break;		}		heapTuple.t_data = (HeapTupleHeader) PageGetItem(dp, lp);		heapTuple.t_len = ItemIdGetLength(lp);		/*		 * Shouldn't see a HEAP_ONLY tuple at chain start.		 */		if (at_chain_start && HeapTupleIsHeapOnly(&heapTuple))			break;		/*		 * The xmin should match the previous xmax value, else chain is		 * broken.		 */		if (TransactionIdIsValid(prev_xmax) &&			!TransactionIdEquals(prev_xmax,								 HeapTupleHeaderGetXmin(heapTuple.t_data)))			break;		/* If it's visible per the snapshot, we must return it */		if (HeapTupleSatisfiesVisibility(&heapTuple, snapshot, buffer))		{			ItemPointerSetOffsetNumber(tid, offnum);			if (all_dead)				*all_dead = false;			return true;		}		/*		 * If we can't see it, maybe no one else can either.  At caller		 * request, check whether all chain members are dead to all		 * transactions.		 */		if (all_dead && *all_dead &&			HeapTupleSatisfiesVacuum(heapTuple.t_data, RecentGlobalXmin,									 buffer) != HEAPTUPLE_DEAD)			*all_dead = false;		/*		 * Check to see if HOT chain continues past this tuple; if so fetch		 * the next offnum and loop around.		 */		if (HeapTupleIsHotUpdated(&heapTuple))		{			Assert(ItemPointerGetBlockNumber(&heapTuple.t_data->t_ctid) ==				   ItemPointerGetBlockNumber(tid));			offnum = ItemPointerGetOffsetNumber(&heapTuple.t_data->t_ctid);			at_chain_start = false;			prev_xmax = HeapTupleHeaderGetXmax(heapTuple.t_data);		}		else			break;				/* end of chain */	}	return false;}/* *	heap_hot_search		- search HOT chain for tuple satisfying snapshot * * This has the same API as heap_hot_search_buffer, except that the caller * does not provide the buffer containing the page, rather we access it * locally. */boolheap_hot_search(ItemPointer tid, Relation relation, Snapshot snapshot,				bool *all_dead){	bool		result;	Buffer		buffer;	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));	LockBuffer(buffer, BUFFER_LOCK_SHARE);	result = heap_hot_search_buffer(tid, buffer, snapshot, all_dead);	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	ReleaseBuffer(buffer);	return result;}/* *	heap_get_latest_tid -  get the latest tid of a specified tuple * * Actually, this gets the latest version that is visible according to * the passed snapshot.  You can pass SnapshotDirty to get the very latest, * possibly uncommitted version. * * *tid is both an input and an output parameter: it is updated to * show the latest version of the row.	Note that it will not be changed * if no version of the row passes the snapshot test. */voidheap_get_latest_tid(Relation relation,					Snapshot snapshot,					ItemPointer tid){	BlockNumber blk;	ItemPointerData ctid;	TransactionId priorXmax;	/* this is to avoid Assert failures on bad input */	if (!ItemPointerIsValid(tid))		return;	/*	 * Since this can be called with user-supplied TID, don't trust the input	 * too much.  (RelationGetNumberOfBlocks is an expensive check, so we	 * don't check t_ctid links again this way.  Note that it would not do to	 * call it just once and save the result, either.)	 */	blk = ItemPointerGetBlockNumber(tid);	if (blk >= RelationGetNumberOfBlocks(relation))		elog(ERROR, "block number %u is out of range for relation \"%s\"",			 blk, RelationGetRelationName(relation));	/*	 * Loop to chase down t_ctid links.  At top of loop, ctid is the tuple we	 * need to examine, and *tid is the TID we will return if ctid turns out	 * to be bogus.	 *	 * Note that we will loop until we reach the end of the t_ctid chain.	 * Depending on the snapshot passed, there might be at most one visible	 * version of the row, but we don't try to optimize for that.	 */	ctid = *tid;	priorXmax = InvalidTransactionId;	/* cannot check first XMIN */	for (;;)	{		Buffer		buffer;		PageHeader	dp;		OffsetNumber offnum;		ItemId		lp;		HeapTupleData tp;		bool		valid;		/*		 * Read, pin, and lock the page.		 */		buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));		LockBuffer(buffer, BUFFER_LOCK_SHARE);		dp = (PageHeader) BufferGetPage(buffer);		/*		 * Check for bogus item number.  This is not treated as an error		 * condition because it can happen while following a t_ctid link. We		 * just assume that the prior tid is OK and return it unchanged.		 */		offnum = ItemPointerGetOffsetNumber(&ctid);		if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))		{			UnlockReleaseBuffer(buffer);			break;		}		lp = PageGetItemId(dp, offnum);		if (!ItemIdIsNormal(lp))		{			UnlockReleaseBuffer(buffer);			break;		}		/* OK to access the tuple */		tp.t_self = ctid;		tp.t_data = (HeapTupleHeader) PageGetItem(dp, lp);		tp.t_len = ItemIdGetLength(lp);		/*		 * After following a t_ctid link, we might arrive at an unrelated		 * tuple.  Check for XMIN match.		 */		if (TransactionIdIsValid(priorXmax) &&		  !TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(tp.t_data)))		{			UnlockReleaseBuffer(buffer);			break;		}		/*		 * Check time qualification of tuple; if visible, set it as the new		 * result candidate.		 */		valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);		if (valid)			*tid = ctid;		/*		 * If there's a valid t_ctid link, follow it, else we're done.		 */		if ((tp.t_data->t_infomask & (HEAP_XMAX_INVALID | HEAP_IS_LOCKED)) ||			ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid))		{			UnlockReleaseBuffer(buffer);			break;		}		ctid = tp.t_data->t_ctid;		priorXmax = HeapTupleHeaderGetXmax(tp.t_data);		UnlockReleaseBuffer(buffer);	}							/* end of loop */}/* * UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends * * This is called after we have waited for the XMAX transaction to terminate. * If the transaction aborted, we guarantee the XMAX_INVALID hint bit will * be set on exit.	If the transaction committed, we set the XMAX_COMMITTED * hint bit if possible --- but beware that that may not yet be possible, * if the transaction committed asynchronously.  Hence callers should look * only at XMAX_INVALID. */static voidUpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid){	Assert(TransactionIdEquals(HeapTupleHeaderGetXmax(tuple), xid));	if (!(tuple->t_infomask & (HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID)))	{		if (TransactionIdDidCommit(xid))			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,								 xid);		else			HeapTupleSetHintBits(tuple, buffer, HEAP_XMAX_INVALID,								 InvalidTransactionId);	}}/* *	heap_insert		- insert tuple into a heap * * The new tuple is stamped with current transaction ID and the specified * command ID. * * If use_wal is false, the new tuple is not logged in WAL, even for a * non-temp relation.  Safe usage of this behavior requires that we arrange * that all new tuples go into new pages not containing any tuples from other * transactions, and that the relation gets fsync'd before commit. * (See also heap_sync() comments) * * use_fsm is passed directly to RelationGetBufferForTuple, which see for * more info. * * Note that use_wal and use_fsm will be applied when inserting into the * heap's TOAST table, too, if the tuple requires any out-of-line data. * * The return value is the OID assigned to the tuple (either here or by the * caller), or InvalidOid if no OID.  The header fields of *tup are updated * to match the stored tuple; in particular tup->t_self receives the actual * TID where the tuple was stored.	But note that any toasting of fields * within the tuple data is NOT reflected into *tup. */Oidheap_insert(Relation relation, HeapTuple tup, CommandId cid,			bool use_wal, bool use_fsm){	TransactionId xid = GetCurrentTransactionId();	HeapTuple	heaptup;	Buffer		buffer;	if (relation->rd_rel->relhasoids)	{#ifdef NOT_USED		/* this is redundant with an Assert in HeapTupleSetOid */		Assert(tup->t_data->t_infomask & HEAP_HASOID);#endif		/*		 * If the object id of this tuple has already been assigned, trust the		 * caller.	There are a couple of ways this can happen.  At initial db		 * creation, the backend program sets oids for tuples. When we define		 * an index, we set the oid.  Finally, in the future, we may allow		 * users to set their own object ids in order to support a persistent		 * object store (objects need to contain pointers to one another).		 */		if (!OidIsValid(HeapTupleGetOid(tup)))			HeapTupleSetOid(tup, GetNewOid(relation));	}	else	{		/* check there is not space for an OID */		Assert(!(tup->t_data->t_infomask & HEAP_HASOID));	}	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;	HeapTupleHeaderSetXmin(tup->t_data, xid);	HeapTupleHeaderSetCmin(tup->t_data, cid);	HeapTupleHeaderSetXmax(tup->t_data, 0);		/* for cleanliness */	tup->t_tableOid = RelationGetRelid(relation);	/*	 * If the new tuple is too big for storage or contains already toasted	 * out-of-line attributes from some other relation, invoke the toaster.	 *	 * Note: below this point, heaptup is the data we actually intend to store	 * into the relation; tup is the caller's original untoasted data.	 */	if (relation->rd_rel->relkind != RELKIND_RELATION)	{		/* toast table entries should never be recursively toasted */		Assert(!HeapTupleHasExternal(tup));		heaptup = tup;	}	else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)		heaptup = toast_insert_or_update(relation, tup, NULL,										 use_wal, use_fsm);	else		heaptup = tup;	/* Find buffer to insert this tuple into */	buffer = RelationGetBufferForTuple(relation, heaptup->t_len,									   InvalidBuffer, use_fsm);	/* NO EREPORT(ERROR) from here till changes are logged */	START_CRIT_SECTION();	RelationPutHeapTuple(relation, buffer, heaptup);	/*	 * XXX Should we set PageSetPrunable on this page ?	 *	 * The inserting transaction may eventually abort thus making this tuple	 * DEAD and hence available for pruning. Though we don't want to optimize	 * for aborts, if no other tuple in this page is UPDATEd/DELETEd, the	 * aborted tuple will never be pruned until next vacuum is triggered.	 *	 * If you do add PageSetPrunable here, add it in heap_xlog_insert too.	 */	MarkBufferDirty(buffer);	/* XLOG stuff */	if (use_wal && !relation->rd_istemp)	{		xl_heap_insert xlrec;		xl_heap_header xlhdr;		XLogRecPtr	recptr;		XLogRecData rdata[3];		Page		page = BufferGetPage(buffer);		uint8		info = XLOG_HEAP_INSERT;		xlrec.target.node = relation->rd_node;		xlrec.target.tid = heaptup->t_self;		rdata[0].data = (char *) &xlrec;

⌨️ 快捷键说明

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