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

📄 heapam.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * heapam.c *	  heap access method code * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.249.2.3 2008/09/11 14:01:35 alvherre Exp $ * * * INTERFACE ROUTINES *		relation_open	- open any relation by relation OID *		relation_openrv - open any relation specified by a RangeVar *		relation_close	- close any relation *		heap_open		- open a heap relation by relation OID *		heap_openrv		- open a heap relation specified by a RangeVar *		heap_close		- (now just a macro for relation_close) *		heap_beginscan	- begin relation scan *		heap_rescan		- restart a relation scan *		heap_endscan	- end relation scan *		heap_getnext	- retrieve next tuple in scan *		heap_fetch		- retrieve tuple with given tid *		heap_insert		- insert tuple into a relation *		heap_delete		- delete a tuple from a relation *		heap_update		- replace a tuple in a relation with another tuple *		heap_markpos	- mark scan position *		heap_restrpos	- restore position to marked location *		heap_sync		- sync heap, for when no WAL has been written * * NOTES *	  This file contains the heap_ routines which implement *	  the POSTGRES heap access method used for all POSTGRES *	  relations. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/hio.h"#include "access/multixact.h"#include "access/transam.h"#include "access/tuptoaster.h"#include "access/valid.h"#include "access/xact.h"#include "catalog/catalog.h"#include "catalog/namespace.h"#include "miscadmin.h"#include "pgstat.h"#include "storage/procarray.h"#include "storage/smgr.h"#include "utils/datum.h"#include "utils/inval.h"#include "utils/lsyscache.h"#include "utils/relcache.h"#include "utils/syscache.h"/* GUC variable */bool	synchronize_seqscans = true;static HeapScanDesc heap_beginscan_internal(Relation relation,						Snapshot snapshot,						int nkeys, ScanKey key,						bool allow_strat, bool allow_sync,						bool is_bitmapscan);static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,		   ItemPointerData from, Buffer newbuf, HeapTuple newtup, bool move);static bool HeapSatisfiesHOTUpdate(Relation relation, Bitmapset *hot_attrs,					   HeapTuple oldtup, HeapTuple newtup);/* ---------------------------------------------------------------- *						 heap support routines * ---------------------------------------------------------------- *//* ---------------- *		initscan - scan code common to heap_beginscan and heap_rescan * ---------------- */static voidinitscan(HeapScanDesc scan, ScanKey key){	bool		allow_strat;	bool		allow_sync;	/*	 * Determine the number of blocks we have to scan.	 *	 * It is sufficient to do this once at scan start, since any tuples added	 * while the scan is in progress will be invisible to my snapshot anyway.	 * (That is not true when using a non-MVCC snapshot.  However, we couldn't	 * guarantee to return tuples added after scan start anyway, since they	 * might go into pages we already scanned.	To guarantee consistent	 * results for a non-MVCC snapshot, the caller must hold some higher-level	 * lock that ensures the interesting tuple(s) won't change.)	 */	scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);	/*	 * If the table is large relative to NBuffers, use a bulk-read access	 * strategy and enable synchronized scanning (see syncscan.c).	Although	 * the thresholds for these features could be different, we make them the	 * same so that there are only two behaviors to tune rather than four.	 * (However, some callers need to be able to disable one or both of	 * these behaviors, independently of the size of the table; also there	 * is a GUC variable that can disable synchronized scanning.)	 *	 * During a rescan, don't make a new strategy object if we don't have to.	 */	if (!scan->rs_rd->rd_istemp &&		scan->rs_nblocks > NBuffers / 4)	{		allow_strat = scan->rs_allow_strat;		allow_sync = scan->rs_allow_sync;	}	else		allow_strat = allow_sync = false;	if (allow_strat)	{		if (scan->rs_strategy == NULL)			scan->rs_strategy = GetAccessStrategy(BAS_BULKREAD);	}	else	{		if (scan->rs_strategy != NULL)			FreeAccessStrategy(scan->rs_strategy);		scan->rs_strategy = NULL;	}	if (allow_sync && synchronize_seqscans)	{		scan->rs_syncscan = true;		scan->rs_startblock = ss_get_location(scan->rs_rd, scan->rs_nblocks);	}	else	{		scan->rs_syncscan = false;		scan->rs_startblock = 0;	}	scan->rs_inited = false;	scan->rs_ctup.t_data = NULL;	ItemPointerSetInvalid(&scan->rs_ctup.t_self);	scan->rs_cbuf = InvalidBuffer;	scan->rs_cblock = InvalidBlockNumber;	/* we don't have a marked position... */	ItemPointerSetInvalid(&(scan->rs_mctid));	/* page-at-a-time fields are always invalid when not rs_inited */	/*	 * copy the scan key, if appropriate	 */	if (key != NULL)		memcpy(scan->rs_key, key, scan->rs_nkeys * sizeof(ScanKeyData));	/*	 * Currently, we don't have a stats counter for bitmap heap scans (but the	 * underlying bitmap index scans will be counted).	 */	if (!scan->rs_bitmapscan)		pgstat_count_heap_scan(scan->rs_rd);}/* * heapgetpage - subroutine for heapgettup() * * This routine reads and pins the specified page of the relation. * In page-at-a-time mode it performs additional work, namely determining * which tuples on the page are visible. */static voidheapgetpage(HeapScanDesc scan, BlockNumber page){	Buffer		buffer;	Snapshot	snapshot;	Page		dp;	int			lines;	int			ntup;	OffsetNumber lineoff;	ItemId		lpp;	Assert(page < scan->rs_nblocks);	/* release previous scan buffer, if any */	if (BufferIsValid(scan->rs_cbuf))	{		ReleaseBuffer(scan->rs_cbuf);		scan->rs_cbuf = InvalidBuffer;	}	/* read page using selected strategy */	scan->rs_cbuf = ReadBufferWithStrategy(scan->rs_rd,										   page,										   scan->rs_strategy);	scan->rs_cblock = page;	if (!scan->rs_pageatatime)		return;	buffer = scan->rs_cbuf;	snapshot = scan->rs_snapshot;	/*	 * Prune and repair fragmentation for the whole page, if possible.	 */	Assert(TransactionIdIsValid(RecentGlobalXmin));	heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);	/*	 * We must hold share lock on the buffer content while examining tuple	 * visibility.	Afterwards, however, the tuples we have found to be	 * visible are guaranteed good as long as we hold the buffer pin.	 */	LockBuffer(buffer, BUFFER_LOCK_SHARE);	dp = (Page) BufferGetPage(buffer);	lines = PageGetMaxOffsetNumber(dp);	ntup = 0;	for (lineoff = FirstOffsetNumber, lpp = PageGetItemId(dp, lineoff);		 lineoff <= lines;		 lineoff++, lpp++)	{		if (ItemIdIsNormal(lpp))		{			HeapTupleData loctup;			bool		valid;			loctup.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);			loctup.t_len = ItemIdGetLength(lpp);			ItemPointerSet(&(loctup.t_self), page, lineoff);			valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);			if (valid)				scan->rs_vistuples[ntup++] = lineoff;		}	}	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	Assert(ntup <= MaxHeapTuplesPerPage);	scan->rs_ntuples = ntup;}/* ---------------- *		heapgettup - fetch next heap tuple * *		Initialize the scan if not already done; then advance to the next *		tuple as indicated by "dir"; return the next tuple in scan->rs_ctup, *		or set scan->rs_ctup.t_data = NULL if no more tuples. * * dir == NoMovementScanDirection means "re-fetch the tuple indicated * by scan->rs_ctup". * * Note: the reason nkeys/key are passed separately, even though they are * kept in the scan descriptor, is that the caller may not want us to check * the scankeys. * * Note: when we fall off the end of the scan in either direction, we * reset rs_inited.  This means that a further request with the same * scan direction will restart the scan, which is a bit odd, but a * request with the opposite scan direction will start a fresh scan * in the proper direction.  The latter is required behavior for cursors, * while the former case is generally undefined behavior in Postgres * so we don't care too much. * ---------------- */static voidheapgettup(HeapScanDesc scan,		   ScanDirection dir,		   int nkeys,		   ScanKey key){	HeapTuple	tuple = &(scan->rs_ctup);	Snapshot	snapshot = scan->rs_snapshot;	bool		backward = ScanDirectionIsBackward(dir);	BlockNumber page;	bool		finished;	Page		dp;	int			lines;	OffsetNumber lineoff;	int			linesleft;	ItemId		lpp;	/*	 * calculate next starting lineoff, given scan direction	 */	if (ScanDirectionIsForward(dir))	{		if (!scan->rs_inited)		{			/*			 * return null immediately if relation is empty			 */			if (scan->rs_nblocks == 0)			{				Assert(!BufferIsValid(scan->rs_cbuf));				tuple->t_data = NULL;				return;			}			page = scan->rs_startblock; /* first page */			heapgetpage(scan, page);			lineoff = FirstOffsetNumber;		/* first offnum */			scan->rs_inited = true;		}		else		{			/* continue from previously returned page/tuple */			page = scan->rs_cblock;		/* current page */			lineoff =			/* next offnum */				OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));		}		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(scan->rs_cbuf);		lines = PageGetMaxOffsetNumber(dp);		/* page and lineoff now reference the physically next tid */		linesleft = lines - lineoff + 1;	}	else if (backward)	{		if (!scan->rs_inited)		{			/*			 * return null immediately if relation is empty			 */			if (scan->rs_nblocks == 0)			{				Assert(!BufferIsValid(scan->rs_cbuf));				tuple->t_data = NULL;				return;			}			/*			 * Disable reporting to syncscan logic in a backwards scan; it's			 * not very likely anyone else is doing the same thing at the same			 * time, and much more likely that we'll just bollix things for			 * forward scanners.			 */			scan->rs_syncscan = false;			/* start from last page of the scan */			if (scan->rs_startblock > 0)				page = scan->rs_startblock - 1;			else				page = scan->rs_nblocks - 1;			heapgetpage(scan, page);		}		else		{			/* continue from previously returned page/tuple */			page = scan->rs_cblock;		/* current page */		}		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);		dp = (Page) BufferGetPage(scan->rs_cbuf);		lines = PageGetMaxOffsetNumber(dp);		if (!scan->rs_inited)		{			lineoff = lines;	/* final offnum */			scan->rs_inited = true;		}		else		{			lineoff =			/* previous offnum */				OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));		}		/* page and lineoff now reference the physically previous tid */		linesleft = lineoff;	}	else	{		/*		 * ``no movement'' scan direction: refetch prior tuple		 */		if (!scan->rs_inited)		{			Assert(!BufferIsValid(scan->rs_cbuf));			tuple->t_data = NULL;			return;		}		page = ItemPointerGetBlockNumber(&(tuple->t_self));		if (page != scan->rs_cblock)			heapgetpage(scan, page);		/* Since the tuple was previously fetched, needn't lock page here */		dp = (Page) BufferGetPage(scan->rs_cbuf);		lineoff = ItemPointerGetOffsetNumber(&(tuple->t_self));		lpp = PageGetItemId(dp, lineoff);		Assert(ItemIdIsNormal(lpp));		tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);		tuple->t_len = ItemIdGetLength(lpp);		return;	}	/*	 * advance the scan until we find a qualifying tuple or run out of stuff	 * to scan	 */	lpp = PageGetItemId(dp, lineoff);	for (;;)	{		while (linesleft > 0)		{			if (ItemIdIsNormal(lpp))			{				bool		valid;				tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);				tuple->t_len = ItemIdGetLength(lpp);				ItemPointerSet(&(tuple->t_self), page, lineoff);				/*				 * if current tuple qualifies, return it.				 */				valid = HeapTupleSatisfiesVisibility(tuple,													 snapshot,													 scan->rs_cbuf);				if (valid && key != NULL)					HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),								nkeys, key, valid);				if (valid)				{					LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);					return;				}			}			/*			 * otherwise move to the next item on the page			 */			--linesleft;			if (backward)			{				--lpp;			/* move back in this page's ItemId array */				--lineoff;			}			else			{				++lpp;			/* move forward in this page's ItemId array */				++lineoff;			}		}		/*		 * if we get here, it means we've exhausted the items on this page and		 * it's time to move to the next.		 */		LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);

⌨️ 快捷键说明

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