*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.117 2001/05/17 15:55:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.118 2001/06/09 18:16:55 tgl Exp $
*
*
* INTERFACE ROUTINES
- * heapgettup - fetch next heap tuple from a scan
* heap_open - open a heap relation by relationId
* heap_openr - open a heap relation by name
* heap_open[r]_nofail - same, but return NULL on failure instead of elog
* the POSTGRES heap access method used for all POSTGRES
* relations.
*
- * OLD COMMENTS
- * struct relscan hints: (struct should be made AM independent?)
- *
- * rs_ctid is the tid of the last tuple returned by getnext.
- * rs_ptid and rs_ntid are the tids of the previous and next tuples
- * returned by getnext, respectively. NULL indicates an end of
- * scan (either direction); NON indicates an unknow value.
- *
- * possible combinations:
- * rs_p rs_c rs_n interpretation
- * NULL NULL NULL empty scan
- * NULL NULL NON at begining of scan
- * NULL NULL t1 at begining of scan (with cached tid)
- * NON NULL NULL at end of scan
- * t1 NULL NULL at end of scan (with cached tid)
- * NULL t1 NULL just returned only tuple
- * NULL t1 NON just returned first tuple
- * NULL t1 t2 returned first tuple (with cached tid)
- * NON t1 NULL just returned last tuple
- * t2 t1 NULL returned last tuple (with cached tid)
- * t1 t2 NON in the middle of a forward scan
- * NON t2 t1 in the middle of a reverse scan
- * ti tj tk in the middle of a scan (w cached tid)
- *
- * Here NULL is ...tup == NULL && ...buf == InvalidBuffer,
- * and NON is ...tup == NULL && ...buf == UnknownBuffer.
- *
- * Currently, the NONTID values are not cached with their actual
- * values by getnext. Values may be cached by markpos since it stores
- * all three tids.
- *
- * NOTE: the calls to elog() must stop. Should decide on an interface
- * between the general and specific AM calls.
- *
- * XXX probably do not need a free tuple routine for heaps.
- * Huh? Free tuple is not necessary for tuples returned by scans, but
- * is necessary for tuples which are returned by
- * RelationGetTupleByItemPointer. -hirohama
- *
*-------------------------------------------------------------------------
*/
-
#include "postgres.h"
#include "access/heapam.h"
#include "access/hio.h"
#include "access/tuptoaster.h"
#include "access/valid.h"
+#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "utils/inval.h"
#include "utils/relcache.h"
-#include "access/xlogutils.h"
XLogRecPtr log_heap_move(Relation reln, Buffer oldbuf, ItemPointerData from,
Buffer newbuf, HeapTuple newtup);
unsigned nkeys,
ScanKey key)
{
-
/*
* Make sure we have up-to-date idea of number of blocks in relation.
* It is sufficient to do this once at scan start, since any tuples
*/
relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
- if (relation->rd_nblocks == 0)
- {
-
- /*
- * relation is empty
- */
- scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt =
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = scan->rs_ctup.t_data =
- scan->rs_ptup.t_data = NULL;
- scan->rs_nbuf = scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
- }
- else if (atend)
- {
-
- /*
- * reverse scan
- */
- scan->rs_ntup.t_datamcxt = scan->rs_ctup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = scan->rs_ctup.t_data = NULL;
- scan->rs_nbuf = scan->rs_cbuf = InvalidBuffer;
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ptup.t_data = NULL;
- scan->rs_pbuf = UnknownBuffer;
- }
- else
- {
-
- /*
- * forward scan
- */
- scan->rs_ctup.t_datamcxt = scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ctup.t_data = scan->rs_ptup.t_data = NULL;
- scan->rs_cbuf = scan->rs_pbuf = InvalidBuffer;
- scan->rs_ntup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = NULL;
- scan->rs_nbuf = UnknownBuffer;
- } /* invalid too */
+ scan->rs_ctup.t_datamcxt = NULL;
+ scan->rs_ctup.t_data = NULL;
+ scan->rs_cbuf = InvalidBuffer;
/* we don't have a marked position... */
- ItemPointerSetInvalid(&(scan->rs_mptid));
ItemPointerSetInvalid(&(scan->rs_mctid));
- ItemPointerSetInvalid(&(scan->rs_mntid));
- ItemPointerSetInvalid(&(scan->rs_mcd));
/*
* copy the scan key, if appropriate
memmove(scan->rs_key, key, nkeys * sizeof(ScanKeyData));
}
-/* ----------------
- * unpinscan - code common to heap_rescan and heap_endscan
- * ----------------
- */
-static void
-unpinscan(HeapScanDesc scan)
-{
- if (BufferIsValid(scan->rs_pbuf))
- ReleaseBuffer(scan->rs_pbuf);
-
- /*
- * Scan will pin buffer once for each non-NULL tuple pointer (ptup,
- * ctup, ntup), so they have to be unpinned multiple times.
- */
- if (BufferIsValid(scan->rs_cbuf))
- ReleaseBuffer(scan->rs_cbuf);
-
- if (BufferIsValid(scan->rs_nbuf))
- ReleaseBuffer(scan->rs_nbuf);
-
- /*
- * we don't bother to clear rs_pbuf etc --- caller must reinitialize
- * them if scan descriptor is not being deleted.
- */
-}
-
-/* ------------------------------------------
- * nextpage
- *
- * figure out the next page to scan after the current page
- * taking into account of possible adjustment of degrees of
- * parallelism
- * ------------------------------------------
- */
-static int
-nextpage(int page, int dir)
-{
- return (dir < 0) ? page - 1 : page + 1;
-}
-
/* ----------------
* heapgettup - fetch next heap tuple
*
* routine used by heap_getnext() which does most of the
* real work in scanning tuples.
*
- * The scan routines handle their own buffer lock/unlocking, so
- * there is no reason to request the buffer number unless
- * to want to perform some other operation with the result,
- * like pass it to another function.
+ * The passed-in *buffer must be either InvalidBuffer or the pinned
+ * current page of the scan. If we have to move to another page,
+ * we will unpin this buffer (if valid). On return, *buffer is either
+ * InvalidBuffer or the ID of a pinned buffer.
* ----------------
*/
static void
heapgettup(Relation relation,
- HeapTuple tuple,
int dir,
+ HeapTuple tuple,
Buffer *buffer,
Snapshot snapshot,
int nkeys,
int lines;
OffsetNumber lineoff;
int linesleft;
- ItemPointer tid = (tuple->t_data == NULL) ?
- (ItemPointer) NULL : &(tuple->t_self);
+ ItemPointer tid;
/*
* increment access statistics
IncrHeapAccessStat(local_heapgettup);
IncrHeapAccessStat(global_heapgettup);
+ tid = (tuple->t_data == NULL) ? (ItemPointer) NULL : &(tuple->t_self);
+
/*
* debugging stuff
*
#endif /* !defined(HEAPDEBUGALL) */
if (!ItemPointerIsValid(tid))
+ {
Assert(!PointerIsValid(tid));
+ tid = NULL;
+ }
tuple->t_tableOid = relation->rd_id;
*/
if (!(pages = relation->rd_nblocks))
{
+ if (BufferIsValid(*buffer))
+ ReleaseBuffer(*buffer);
+ *buffer = InvalidBuffer;
tuple->t_datamcxt = NULL;
tuple->t_data = NULL;
return;
*/
if (!dir)
{
-
/*
- * ``no movement'' scan direction
+ * ``no movement'' scan direction: refetch same tuple
*/
- /* assume it is a valid TID XXX */
- if (ItemPointerIsValid(tid) == false)
+ if (tid == NULL)
{
+ if (BufferIsValid(*buffer))
+ ReleaseBuffer(*buffer);
*buffer = InvalidBuffer;
tuple->t_datamcxt = NULL;
tuple->t_data = NULL;
return;
}
- *buffer = RelationGetBufferWithBuffer(relation,
- ItemPointerGetBlockNumber(tid),
- *buffer);
+ *buffer = ReleaseAndReadBuffer(*buffer,
+ relation,
+ ItemPointerGetBlockNumber(tid),
+ false);
if (!BufferIsValid(*buffer))
elog(ERROR, "heapgettup: failed ReadBuffer");
}
else if (dir < 0)
{
-
/*
* reverse scan direction
*/
- if (ItemPointerIsValid(tid) == false)
- tid = NULL;
if (tid == NULL)
{
page = pages - 1; /* final page */
}
if (page < 0)
{
+ if (BufferIsValid(*buffer))
+ ReleaseBuffer(*buffer);
*buffer = InvalidBuffer;
+ tuple->t_datamcxt = NULL;
tuple->t_data = NULL;
return;
}
- *buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
+ *buffer = ReleaseAndReadBuffer(*buffer,
+ relation,
+ page,
+ false);
if (!BufferIsValid(*buffer))
elog(ERROR, "heapgettup: failed ReadBuffer");
}
else
{
-
/*
* forward scan direction
*/
- if (ItemPointerIsValid(tid) == false)
+ if (tid == NULL)
{
page = 0; /* first page */
lineoff = FirstOffsetNumber; /* first offnum */
if (page >= pages)
{
+ if (BufferIsValid(*buffer))
+ ReleaseBuffer(*buffer);
*buffer = InvalidBuffer;
tuple->t_datamcxt = NULL;
tuple->t_data = NULL;
return;
}
- /* page and lineoff now reference the physically next tid */
- *buffer = RelationGetBufferWithBuffer(relation, page, *buffer);
+ *buffer = ReleaseAndReadBuffer(*buffer,
+ relation,
+ page,
+ false);
if (!BufferIsValid(*buffer))
elog(ERROR, "heapgettup: failed ReadBuffer");
dp = (Page) BufferGetPage(*buffer);
lines = PageGetMaxOffsetNumber(dp);
+ /* page and lineoff now reference the physically next tid */
+
}
/* 'dir' is now non-zero */
/*
* if we get here, it means we've exhausted the items on this page
- * and it's time to move to the next..
+ * and it's time to move to the next.
*/
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
- page = nextpage(page, dir);
+ page = (dir < 0) ? (page - 1) : (page + 1);
/*
- * return NULL if we've exhausted all the pages..
+ * return NULL if we've exhausted all the pages
*/
if (page < 0 || page >= pages)
{
return;
}
- *buffer = ReleaseAndReadBuffer(*buffer, relation, page, false);
-
+ *buffer = ReleaseAndReadBuffer(*buffer,
+ relation,
+ page,
+ false);
if (!BufferIsValid(*buffer))
elog(ERROR, "heapgettup: failed ReadBuffer");
+
LockBuffer(*buffer, BUFFER_LOCK_SHARE);
dp = (Page) BufferGetPage(*buffer);
lines = PageGetMaxOffsetNumber((Page) dp);
scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
scan->rs_rd = relation;
- scan->rs_atend = atend;
scan->rs_snapshot = snapshot;
scan->rs_nkeys = (short) nkeys;
bool scanFromEnd,
ScanKey key)
{
-
/*
* increment access statistics
*/
/*
* unpin scan buffers
*/
- unpinscan(scan);
+ if (BufferIsValid(scan->rs_cbuf))
+ ReleaseBuffer(scan->rs_cbuf);
/*
* reinitialize scan descriptor
*/
- scan->rs_atend = scanFromEnd;
initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key);
}
void
heap_endscan(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
/*
* unpin scan buffers
*/
- unpinscan(scan);
+ if (BufferIsValid(scan->rs_cbuf))
+ ReleaseBuffer(scan->rs_cbuf);
/*
* decrement relation reference count and free scan descriptor storage
RelationGetRelationName(scan->rs_rd), scan->rs_nkeys, backw)
#define HEAPDEBUG_2 \
- elog(DEBUG, "heap_getnext called with backw (no tracing yet)")
-
-#define HEAPDEBUG_3 \
- elog(DEBUG, "heap_getnext returns NULL at end")
-
-#define HEAPDEBUG_4 \
- elog(DEBUG, "heap_getnext valid buffer UNPIN'd")
-
-#define HEAPDEBUG_5 \
- elog(DEBUG, "heap_getnext next tuple was cached")
-
-#define HEAPDEBUG_6 \
elog(DEBUG, "heap_getnext returning EOS")
-#define HEAPDEBUG_7 \
+#define HEAPDEBUG_3 \
elog(DEBUG, "heap_getnext returning tuple");
#else
#define HEAPDEBUG_1
#define HEAPDEBUG_2
#define HEAPDEBUG_3
-#define HEAPDEBUG_4
-#define HEAPDEBUG_5
-#define HEAPDEBUG_6
-#define HEAPDEBUG_7
#endif /* !defined(HEAPDEBUGALL) */
HeapTuple
-heap_getnext(HeapScanDesc scandesc, int backw)
+heap_getnext(HeapScanDesc scan, int backw)
{
- HeapScanDesc scan = scandesc;
-
/*
* increment access statistics
*/
if (scan == NULL)
elog(ERROR, "heap_getnext: NULL relscan");
- /*
- * initialize return buffer to InvalidBuffer
- */
-
HEAPDEBUG_1; /* heap_getnext( info ) */
if (backw)
{
-
/*
* handle reverse scan
*/
- HEAPDEBUG_2; /* heap_getnext called with backw */
-
- if (scan->rs_ptup.t_data == scan->rs_ctup.t_data &&
- BufferIsInvalid(scan->rs_pbuf))
- return NULL;
-
- /*
- * Copy the "current" tuple/buffer to "next". Pin/unpin the
- * buffers accordingly
- */
- if (scan->rs_nbuf != scan->rs_cbuf)
- {
- if (BufferIsValid(scan->rs_nbuf))
- ReleaseBuffer(scan->rs_nbuf);
- if (BufferIsValid(scan->rs_cbuf))
- IncrBufferRefCount(scan->rs_cbuf);
- }
- scan->rs_ntup = scan->rs_ctup;
- scan->rs_nbuf = scan->rs_cbuf;
-
- if (scan->rs_ptup.t_data != NULL)
- {
- if (scan->rs_cbuf != scan->rs_pbuf)
- {
- if (BufferIsValid(scan->rs_cbuf))
- ReleaseBuffer(scan->rs_cbuf);
- if (BufferIsValid(scan->rs_pbuf))
- IncrBufferRefCount(scan->rs_pbuf);
- }
- scan->rs_ctup = scan->rs_ptup;
- scan->rs_cbuf = scan->rs_pbuf;
- }
- else
- { /* NONTUP */
-
- /*
- * Don't release scan->rs_cbuf at this point, because
- * heapgettup doesn't increase PrivateRefCount if it is
- * already set. On a backward scan, both rs_ctup and rs_ntup
- * usually point to the same buffer page, so
- * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
- * instance ctup is stored in a TupleTableSlot). - 01/09/94
- */
-
- heapgettup(scan->rs_rd,
- &(scan->rs_ctup),
- -1,
- &(scan->rs_cbuf),
- scan->rs_snapshot,
- scan->rs_nkeys,
- scan->rs_key);
- }
+ heapgettup(scan->rs_rd,
+ -1,
+ &(scan->rs_ctup),
+ &(scan->rs_cbuf),
+ scan->rs_snapshot,
+ scan->rs_nkeys,
+ scan->rs_key);
if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf))
{
- if (BufferIsValid(scan->rs_pbuf))
- ReleaseBuffer(scan->rs_pbuf);
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ptup.t_data = NULL;
- scan->rs_pbuf = InvalidBuffer;
+ HEAPDEBUG_2; /* heap_getnext returning EOS */
return NULL;
}
-
- if (BufferIsValid(scan->rs_pbuf))
- ReleaseBuffer(scan->rs_pbuf);
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ptup.t_data = NULL;
- scan->rs_pbuf = UnknownBuffer;
-
}
else
{
-
/*
* handle forward scan
*/
- if (scan->rs_ctup.t_data == scan->rs_ntup.t_data &&
- BufferIsInvalid(scan->rs_nbuf))
- {
- HEAPDEBUG_3; /* heap_getnext returns NULL at end */
- return NULL;
- }
-
- /*
- * Copy the "current" tuple/buffer to "previous". Pin/unpin the
- * buffers accordingly
- */
- if (scan->rs_pbuf != scan->rs_cbuf)
- {
- if (BufferIsValid(scan->rs_pbuf))
- ReleaseBuffer(scan->rs_pbuf);
- if (BufferIsValid(scan->rs_cbuf))
- IncrBufferRefCount(scan->rs_cbuf);
- }
- scan->rs_ptup = scan->rs_ctup;
- scan->rs_pbuf = scan->rs_cbuf;
-
- if (scan->rs_ntup.t_data != NULL)
- {
- if (scan->rs_cbuf != scan->rs_nbuf)
- {
- if (BufferIsValid(scan->rs_cbuf))
- ReleaseBuffer(scan->rs_cbuf);
- if (BufferIsValid(scan->rs_nbuf))
- IncrBufferRefCount(scan->rs_nbuf);
- }
- scan->rs_ctup = scan->rs_ntup;
- scan->rs_cbuf = scan->rs_nbuf;
- HEAPDEBUG_5; /* heap_getnext next tuple was cached */
- }
- else
- { /* NONTUP */
-
- /*
- * Don't release scan->rs_cbuf at this point, because
- * heapgettup doesn't increase PrivateRefCount if it is
- * already set. On a forward scan, both rs_ctup and rs_ptup
- * usually point to the same buffer page, so
- * PrivateRefCount[rs_cbuf] should be 2 (or more, if for
- * instance ctup is stored in a TupleTableSlot). - 01/09/93
- */
-
- heapgettup(scan->rs_rd,
- &(scan->rs_ctup),
- 1,
- &scan->rs_cbuf,
- scan->rs_snapshot,
- scan->rs_nkeys,
- scan->rs_key);
- }
+ heapgettup(scan->rs_rd,
+ 1,
+ &(scan->rs_ctup),
+ &(scan->rs_cbuf),
+ scan->rs_snapshot,
+ scan->rs_nkeys,
+ scan->rs_key);
if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf))
{
- if (BufferIsValid(scan->rs_nbuf))
- ReleaseBuffer(scan->rs_nbuf);
- scan->rs_ntup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = NULL;
- scan->rs_nbuf = InvalidBuffer;
- HEAPDEBUG_6; /* heap_getnext returning EOS */
+ HEAPDEBUG_2; /* heap_getnext returning EOS */
return NULL;
}
-
- if (BufferIsValid(scan->rs_nbuf))
- ReleaseBuffer(scan->rs_nbuf);
- scan->rs_ntup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = NULL;
- scan->rs_nbuf = UnknownBuffer;
}
/*
* to the proper return buffer and return the tuple.
*/
- HEAPDEBUG_7; /* heap_getnext returning tuple */
+ HEAPDEBUG_3; /* heap_getnext returning tuple */
return ((scan->rs_ctup.t_data == NULL) ? NULL : &(scan->rs_ctup));
}
void
heap_markpos(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
/* Note: no locking manipulations needed */
- if (scan->rs_ptup.t_data == NULL &&
- BufferIsUnknown(scan->rs_pbuf))
- { /* == NONTUP */
- scan->rs_ptup = scan->rs_ctup;
- heapgettup(scan->rs_rd,
- &(scan->rs_ptup),
- -1,
- &scan->rs_pbuf,
- scan->rs_snapshot,
- scan->rs_nkeys,
- scan->rs_key);
-
- }
- else if (scan->rs_ntup.t_data == NULL &&
- BufferIsUnknown(scan->rs_nbuf))
- { /* == NONTUP */
- scan->rs_ntup = scan->rs_ctup;
- heapgettup(scan->rs_rd,
- &(scan->rs_ntup),
- 1,
- &scan->rs_nbuf,
- scan->rs_snapshot,
- scan->rs_nkeys,
- scan->rs_key);
- }
-
- /*
- * Should not unpin the buffer pages. They may still be in use.
- */
- if (scan->rs_ptup.t_data != NULL)
- scan->rs_mptid = scan->rs_ptup.t_self;
- else
- ItemPointerSetInvalid(&scan->rs_mptid);
if (scan->rs_ctup.t_data != NULL)
scan->rs_mctid = scan->rs_ctup.t_self;
else
ItemPointerSetInvalid(&scan->rs_mctid);
- if (scan->rs_ntup.t_data != NULL)
- scan->rs_mntid = scan->rs_ntup.t_self;
- else
- ItemPointerSetInvalid(&scan->rs_mntid);
}
/* ----------------
* cause the added tuples to be visible when the scan continues.
* Problems also arise if the TID's are rearranged!!!
*
- * Now pins buffer once for each valid tuple pointer (rs_ptup,
- * rs_ctup, rs_ntup) referencing it.
- * - 01/13/94
- *
* XXX might be better to do direct access instead of
* using the generality of heapgettup().
*
void
heap_restrpos(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
/* Note: no locking manipulations needed */
- unpinscan(scan);
-
- /* force heapgettup to pin buffer for each loaded tuple */
- scan->rs_pbuf = InvalidBuffer;
+ /*
+ * unpin scan buffers
+ */
+ if (BufferIsValid(scan->rs_cbuf))
+ ReleaseBuffer(scan->rs_cbuf);
scan->rs_cbuf = InvalidBuffer;
- scan->rs_nbuf = InvalidBuffer;
-
- if (!ItemPointerIsValid(&scan->rs_mptid))
- {
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ptup.t_data = NULL;
- }
- else
- {
- scan->rs_ptup.t_self = scan->rs_mptid;
- scan->rs_ptup.t_datamcxt = NULL;
- scan->rs_ptup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
- heapgettup(scan->rs_rd,
- &(scan->rs_ptup),
- 0,
- &(scan->rs_pbuf),
- false,
- 0,
- (ScanKey) NULL);
- }
if (!ItemPointerIsValid(&scan->rs_mctid))
{
scan->rs_ctup.t_datamcxt = NULL;
scan->rs_ctup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
heapgettup(scan->rs_rd,
- &(scan->rs_ctup),
0,
+ &(scan->rs_ctup),
&(scan->rs_cbuf),
- false,
- 0,
- (ScanKey) NULL);
- }
-
- if (!ItemPointerIsValid(&scan->rs_mntid))
- {
- scan->rs_ntup.t_datamcxt = NULL;
- scan->rs_ntup.t_data = NULL;
- }
- else
- {
- scan->rs_ntup.t_datamcxt = NULL;
- scan->rs_ntup.t_self = scan->rs_mntid;
- scan->rs_ntup.t_data = (HeapTupleHeader) 0x1; /* for heapgettup */
- heapgettup(scan->rs_rd,
- &(scan->rs_ntup),
- 0,
- &scan->rs_nbuf,
- false,
+ scan->rs_snapshot,
0,
(ScanKey) NULL);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.111 2001/05/12 19:58:27 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.112 2001/06/09 18:16:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static int BufferReplace(BufferDesc *bufHdr);
void PrintBufferDescs(void);
-/* ---------------------------------------------------
- * RelationGetBufferWithBuffer
- * see if the given buffer is what we want
- * if yes, we don't need to bother the buffer manager
- * ---------------------------------------------------
- */
-Buffer
-RelationGetBufferWithBuffer(Relation relation,
- BlockNumber blockNumber,
- Buffer buffer)
-{
- BufferDesc *bufHdr;
-
- if (BufferIsValid(buffer))
- {
- if (!BufferIsLocal(buffer))
- {
- bufHdr = &BufferDescriptors[buffer - 1];
- SpinAcquire(BufMgrLock);
- if (bufHdr->tag.blockNum == blockNumber &&
- RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
- {
- SpinRelease(BufMgrLock);
- return buffer;
- }
- return ReadBufferInternal(relation, blockNumber, false, true);
- }
- else
- {
- bufHdr = &LocalBufferDescriptors[-buffer - 1];
- if (bufHdr->tag.blockNum == blockNumber &&
- RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
- return buffer;
- }
- }
- return ReadBufferInternal(relation, blockNumber, false, false);
-}
/*
* ReadBuffer -- returns a buffer containing the requested
* allocate a new block.
*
* Returns: the buffer number for the buffer containing
- * the block read or NULL on an error.
+ * the block read, or NULL on an error. If successful,
+ * the returned buffer has been pinned.
*
* Assume when this function is called, that reln has been
* opened already.
}
/*
- * BufferAlloc -- Get a buffer from the buffer pool but dont
- * read it.
+ * BufferAlloc -- Get a buffer from the buffer pool but don't
+ * read it. If successful, the returned buffer is pinned.
*
* Returns: descriptor for buffer
*
* Note: it is OK to pass buffer = InvalidBuffer, indicating that no old
* buffer actually needs to be released. This case is the same as ReadBuffer
* except for the isExtend option.
+ *
+ * Also, if the passed buffer is valid and already contains the desired block
+ * number, we simply return it without ever acquiring the spinlock at all.
+ * Since the passed buffer must be pinned, it's OK to examine its block
+ * number without getting the lock first.
*/
Buffer
ReleaseAndReadBuffer(Buffer buffer,
if (BufferIsLocal(buffer))
{
Assert(LocalRefCount[-buffer - 1] > 0);
+ bufHdr = &LocalBufferDescriptors[-buffer - 1];
+ if (bufHdr->tag.blockNum == blockNum &&
+ RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
+ return buffer;
LocalRefCount[-buffer - 1]--;
}
else
{
- bufHdr = &BufferDescriptors[buffer - 1];
Assert(PrivateRefCount[buffer - 1] > 0);
+ bufHdr = &BufferDescriptors[buffer - 1];
+ if (bufHdr->tag.blockNum == blockNum &&
+ RelFileNodeEquals(bufHdr->tag.rnode, relation->rd_node))
+ return buffer;
if (PrivateRefCount[buffer - 1] > 1)
PrivateRefCount[buffer - 1]--;
else
BufferDesc *buf = &(BufferDescriptors[i - 1]);
elog(NOTICE,
- "Buffer Leak: [%03d] (freeNext=%ld, freePrev=%ld, \
+ "Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, \
relname=%s, blockNum=%d, flags=0x%x, refcount=%d %ld)",
i - 1, buf->freeNext, buf->freePrev,
buf->blind.relname, buf->tag.blockNum, buf->flags,
SpinAcquire(BufMgrLock);
for (i = 0; i < NBuffers; ++i, ++buf)
{
- elog(DEBUG, "[%02d] (freeNext=%ld, freePrev=%ld, relname=%s, \
+ elog(DEBUG, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
blockNum=%d, flags=0x%x, refcount=%d %ld)",
i, buf->freeNext, buf->freePrev,
buf->blind.relname, buf->tag.blockNum, buf->flags,
for (i = 0; i < NBuffers; ++i, ++buf)
{
if (PrivateRefCount[i] > 0)
- elog(NOTICE, "[%02d] (freeNext=%ld, freePrev=%ld, relname=%s, \
+ elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
blockNum=%d, flags=0x%x, refcount=%d %ld)\n",
i, buf->freeNext, buf->freePrev, buf->blind.relname,
buf->tag.blockNum, buf->flags,
{
BufferDesc *buf = &BufferDescriptors[buffer - 1];
- fprintf(stderr, "PIN(Incr) %ld relname = %s, blockNum = %d, \
+ fprintf(stderr, "PIN(Incr) %d relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
buffer, buf->blind.relname, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line);
{
BufferDesc *buf = &BufferDescriptors[buffer - 1];
- fprintf(stderr, "UNPIN(Rel) %ld relname = %s, blockNum = %d, \
+ fprintf(stderr, "UNPIN(Rel) %d relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
buffer, buf->blind.relname, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line);
{
BufferDesc *buf = &BufferDescriptors[buffer - 1];
- fprintf(stderr, "UNPIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
+ fprintf(stderr, "UNPIN(Rel&Rd) %d relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
buffer, buf->blind.relname, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line);
{
BufferDesc *buf = &BufferDescriptors[b - 1];
- fprintf(stderr, "PIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
+ fprintf(stderr, "PIN(Rel&Rd) %d relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
b, buf->blind.relname, buf->tag.blockNum,
PrivateRefCount[b - 1], file, line);
{
S_UNLOCK(&(buf->cntx_lock));
RESUME_INTERRUPTS();
- elog(ERROR, "UNLockBuffer: buffer %lu is not locked", buffer);
+ elog(ERROR, "UNLockBuffer: buffer %d is not locked", buffer);
}
}
else if (mode == BUFFER_LOCK_SHARE)