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

📄 heapam.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	/*	 * fill in *tuple fields	 */	tuple->t_datamcxt = NULL;	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	 */	HeapTupleSatisfies(tuple, relation, buffer, dp,					   snapshot, 0, NULL, valid);	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 in *pgstat_info, if given. */		if (pgstat_info != NULL)			pgstat_count_heap_fetch(pgstat_info);		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_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))		{			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);			ReleaseBuffer(buffer);			break;		}		lp = PageGetItemId(dp, offnum);		if (!ItemIdIsUsed(lp))		{			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);			ReleaseBuffer(buffer);			break;		}		/* OK to access the tuple */		tp.t_self = ctid;		tp.t_datamcxt = NULL;		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)))		{			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);			ReleaseBuffer(buffer);			break;		}		/*		 * Check time qualification of tuple; if visible, set it as the new		 * result candidate.		 */		HeapTupleSatisfies(&tp, relation, buffer, dp,						   snapshot, 0, NULL, valid);		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))		{			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);			ReleaseBuffer(buffer);			break;		}		ctid = tp.t_data->t_ctid;		priorXmax = HeapTupleHeaderGetXmax(tp.t_data);		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);		ReleaseBuffer(buffer);	}							/* end of loop */}/* *	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, that the relation gets fsync'd before commit, and that the * transaction emits at least one WAL record to ensure RecordTransactionCommit * will decide to WAL-log the commit. * * use_fsm is passed directly to RelationGetBufferForTuple, which see for * more info. * * 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_infomask |= HEAP_XMAX_INVALID;	HeapTupleHeaderSetXmin(tup->t_data, xid);	HeapTupleHeaderSetCmin(tup->t_data, cid);	HeapTupleHeaderSetXmax(tup->t_data, 0);		/* zero out Datum fields */	HeapTupleHeaderSetCmax(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 (HeapTupleHasExternal(tup) ||		(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))		heaptup = toast_insert_or_update(relation, tup, NULL);	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);	/* XLOG stuff */	if (relation->rd_istemp)	{		/* No XLOG record, but still need to flag that XID exists on disk */		MyXactMadeTempRelUpdate = true;	}	else if (use_wal)	{		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;		rdata[0].len = SizeOfHeapInsert;		rdata[0].buffer = InvalidBuffer;		rdata[0].next = &(rdata[1]);		xlhdr.t_natts = heaptup->t_data->t_natts;		xlhdr.t_infomask = heaptup->t_data->t_infomask;		xlhdr.t_hoff = heaptup->t_data->t_hoff;		/*		 * note we mark rdata[1] as belonging to buffer; if XLogInsert decides		 * to write the whole page to the xlog, we don't need to store		 * xl_heap_header in the xlog.		 */		rdata[1].data = (char *) &xlhdr;		rdata[1].len = SizeOfHeapHeader;		rdata[1].buffer = buffer;		rdata[1].buffer_std = true;		rdata[1].next = &(rdata[2]);		/* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */		rdata[2].data = (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits);		rdata[2].len = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);		rdata[2].buffer = buffer;		rdata[2].buffer_std = true;		rdata[2].next = NULL;		/*		 * If this is the single and first tuple on page, we can reinit the		 * page instead of restoring the whole thing.  Set flag, and hide		 * buffer references from XLogInsert.		 */		if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&			PageGetMaxOffsetNumber(page) == FirstOffsetNumber)		{			info |= XLOG_HEAP_INIT_PAGE;			rdata[1].buffer = rdata[2].buffer = InvalidBuffer;		}		recptr = XLogInsert(RM_HEAP_ID, info, rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);	}	END_CRIT_SECTION();	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	WriteBuffer(buffer);	/*	 * If tuple is cachable, mark it for invalidation from the caches in case	 * we abort.  Note it is OK to do this after WriteBuffer releases the	 * buffer, because the heaptup data structure is all in local memory, not	 * in the shared buffer.	 */	CacheInvalidateHeapTuple(relation, heaptup);	pgstat_count_heap_insert(&relation->pgstat_info);	/*	 * If heaptup is a private copy, release it.  Don't forget to copy t_self	 * back to the caller's image, too.	 */	if (heaptup != tup)	{		tup->t_self = heaptup->t_self;		heap_freetuple(heaptup);	}	return HeapTupleGetOid(tup);}/* *	simple_heap_insert - insert a tuple * * Currently, this routine differs from heap_insert only in supplying * a default command ID.  But it should be used rather than using * heap_insert directly in most places where we are modifying system catalogs. */Oidsimple_heap_insert(Relation relation, HeapTuple tup){	return heap_insert(relation, tup, GetCurrentCommandId(), true, true);}/* *	heap_delete - delete a tuple * * NB: do not call this directly unless you are prepared to deal with * concurrent-update conditions.  Use simple_heap_delete instead. * *	relation - table to be modified (caller must hold suitable lock) *	tid - TID of tuple to be deleted *	ctid - output parameter, used only for failure case (see below) *	update_xmax - output parameter, used only for failure case (see below) *	cid - delete command ID (used for visibility test, and stored into *		cmax if successful) *	crosscheck - if not InvalidSnapshot, also check tuple against this *	wait - true if should wait for any conflicting update to commit/abort * * Normal, successful return value is HeapTupleMayBeUpdated, which * actually means we did delete it.  Failure return codes are * HeapTupleSelfUpdated, HeapTupleUpdated, or HeapTupleBeingUpdated * (the last only possible if wait == false). * * In the failure cases, the routine returns the tuple's t_ctid and t_xmax. * If t_ctid is the same as tid, the tuple was deleted; if different, the * tuple was updated, and t_ctid is the location of the replacement tuple. * (t_xmax is needed to verify that the replacement tuple matches.) */HTSU_Resultheap_delete(Relation relation, ItemPointer tid,			ItemPointer ctid, TransactionId *update_xmax,			CommandId cid, Snapshot crosscheck, bool wait){	HTSU_Result result;	TransactionId xid = GetCurrentTransactionId();	ItemId		lp;	HeapTupleData tp;	PageHeader	dp;	Buffer		buffer;	bool		have_tuple_lock = false;	Assert(ItemPointerIsValid(tid));	buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));	LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);	dp = (PageHeader) BufferGetPage(buffer);	lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid));	tp.t_datamcxt = NULL;	tp.t_data = (HeapTupleHeader) PageGetItem(dp, lp);	tp.t_len = ItemIdGetLength(lp);	tp.t_self = *tid;l1:	result = HeapTupleSatisfiesUpdate(tp.t_data, cid, buffer);	if (result == HeapTupleInvisible)	{		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);		ReleaseBuffer(buffer);		elog(ERROR, "attempted to delete invisible tuple");	}	else if (result == HeapTupleBeingUpdated && wait)	{		TransactionId xwait;		uint16		infomask;		/* must copy state data before unlocking buffer */		xwait = HeapTupleHeaderGetXmax(tp.t_data);		infomask = tp.t_data->t_infomask;		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);		/*		 * Acquire tuple lock to establish our priority for the tuple (see		 * heap_lock_tuple).  LockTuple will release us when we are		 * next-in-line for the tuple.		 *		 * If we are forced to "start over" below, we keep the tuple lock;		 * this arranges that we stay at the head of the line while rechecking		 * tuple state.		 */		if (!have_tuple_lock)		{			LockTuple(relation, &(tp.t_self), ExclusiveLock);			have_tuple_lock = true;		}		/*		 * Sleep until concurrent transaction ends.  Note that we don't care		 * if the locker has an exclusive or shared lock, because we need		 * exclusive.		 */

⌨️ 快捷键说明

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