aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/gist/gistscan.c7
-rw-r--r--src/backend/access/heap/heapam.c484
-rw-r--r--src/backend/access/index/genam.c40
-rw-r--r--src/backend/access/rtree/rtscan.c7
-rw-r--r--src/backend/storage/buffer/bufmgr.c76
-rw-r--r--src/include/access/relscan.h39
-rw-r--r--src/include/access/skey.h9
-rw-r--r--src/include/storage/buf.h19
-rw-r--r--src/include/storage/bufmgr.h8
9 files changed, 138 insertions, 551 deletions
diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c
index 9ffbd038982..362b489dac0 100644
--- a/src/backend/access/gist/gistscan.c
+++ b/src/backend/access/gist/gistscan.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.35 2001/05/31 18:16:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.36 2001/06/09 18:16:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -83,13 +83,8 @@ gistrescan(PG_FUNCTION_ARGS)
/*
* Clear all the pointers.
*/
-
- ItemPointerSetInvalid(&s->previousItemData);
ItemPointerSetInvalid(&s->currentItemData);
- ItemPointerSetInvalid(&s->nextItemData);
- ItemPointerSetInvalid(&s->previousMarkData);
ItemPointerSetInvalid(&s->currentMarkData);
- ItemPointerSetInvalid(&s->nextMarkData);
/*
* Set flags.
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index fb36736838a..91b1763d759 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,11 +8,10 @@
*
*
* 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
@@ -33,60 +32,20 @@
* 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);
@@ -116,7 +75,6 @@ initscan(HeapScanDesc scan,
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
@@ -125,50 +83,12 @@ initscan(HeapScanDesc scan,
*/
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
@@ -178,61 +98,21 @@ initscan(HeapScanDesc scan,
}
/* ----------------
- * 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,
@@ -245,8 +125,7 @@ heapgettup(Relation relation,
int lines;
OffsetNumber lineoff;
int linesleft;
- ItemPointer tid = (tuple->t_data == NULL) ?
- (ItemPointer) NULL : &(tuple->t_self);
+ ItemPointer tid;
/*
* increment access statistics
@@ -254,6 +133,8 @@ heapgettup(Relation relation,
IncrHeapAccessStat(local_heapgettup);
IncrHeapAccessStat(global_heapgettup);
+ tid = (tuple->t_data == NULL) ? (ItemPointer) NULL : &(tuple->t_self);
+
/*
* debugging stuff
*
@@ -280,7 +161,10 @@ heapgettup(Relation relation,
#endif /* !defined(HEAPDEBUGALL) */
if (!ItemPointerIsValid(tid))
+ {
Assert(!PointerIsValid(tid));
+ tid = NULL;
+ }
tuple->t_tableOid = relation->rd_id;
@@ -289,6 +173,9 @@ heapgettup(Relation relation,
*/
if (!(pages = relation->rd_nblocks))
{
+ if (BufferIsValid(*buffer))
+ ReleaseBuffer(*buffer);
+ *buffer = InvalidBuffer;
tuple->t_datamcxt = NULL;
tuple->t_data = NULL;
return;
@@ -299,22 +186,23 @@ heapgettup(Relation relation,
*/
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");
@@ -333,12 +221,9 @@ heapgettup(Relation relation,
}
else if (dir < 0)
{
-
/*
* reverse scan direction
*/
- if (ItemPointerIsValid(tid) == false)
- tid = NULL;
if (tid == NULL)
{
page = pages - 1; /* final page */
@@ -349,12 +234,18 @@ heapgettup(Relation relation,
}
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");
@@ -376,11 +267,10 @@ heapgettup(Relation relation,
}
else
{
-
/*
* forward scan direction
*/
- if (ItemPointerIsValid(tid) == false)
+ if (tid == NULL)
{
page = 0; /* first page */
lineoff = FirstOffsetNumber; /* first offnum */
@@ -394,14 +284,18 @@ heapgettup(Relation relation,
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");
@@ -409,6 +303,8 @@ heapgettup(Relation relation,
dp = (Page) BufferGetPage(*buffer);
lines = PageGetMaxOffsetNumber(dp);
+ /* page and lineoff now reference the physically next tid */
+
}
/* 'dir' is now non-zero */
@@ -469,13 +365,13 @@ heapgettup(Relation relation,
/*
* 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)
{
@@ -487,10 +383,13 @@ heapgettup(Relation relation,
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);
@@ -766,7 +665,6 @@ heap_beginscan(Relation relation,
scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
scan->rs_rd = relation;
- scan->rs_atend = atend;
scan->rs_snapshot = snapshot;
scan->rs_nkeys = (short) nkeys;
@@ -793,7 +691,6 @@ heap_rescan(HeapScanDesc scan,
bool scanFromEnd,
ScanKey key)
{
-
/*
* increment access statistics
*/
@@ -803,12 +700,12 @@ heap_rescan(HeapScanDesc scan,
/*
* 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);
}
@@ -822,7 +719,6 @@ heap_rescan(HeapScanDesc scan,
void
heap_endscan(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
@@ -834,7 +730,8 @@ heap_endscan(HeapScanDesc scan)
/*
* unpin scan buffers
*/
- unpinscan(scan);
+ if (BufferIsValid(scan->rs_cbuf))
+ ReleaseBuffer(scan->rs_cbuf);
/*
* decrement relation reference count and free scan descriptor storage
@@ -862,38 +759,20 @@ elog(DEBUG, "heap_getnext([%s,nkeys=%d],backw=%d) called", \
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
*/
@@ -908,165 +787,45 @@ heap_getnext(HeapScanDesc scandesc, int backw)
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;
}
/*
@@ -1074,7 +833,7 @@ heap_getnext(HeapScanDesc scandesc, int backw)
* 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));
}
@@ -1987,7 +1746,6 @@ l3:
void
heap_markpos(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
@@ -1996,47 +1754,10 @@ heap_markpos(HeapScanDesc scan)
/* 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);
}
/* ----------------
@@ -2048,10 +1769,6 @@ heap_markpos(HeapScanDesc scan)
* 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().
*
@@ -2063,7 +1780,6 @@ heap_markpos(HeapScanDesc scan)
void
heap_restrpos(HeapScanDesc scan)
{
-
/*
* increment access statistics
*/
@@ -2074,31 +1790,12 @@ heap_restrpos(HeapScanDesc scan)
/* 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))
{
@@ -2111,29 +1808,10 @@ heap_restrpos(HeapScanDesc scan)
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);
}
diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c
index 13499eef0a8..ee9cea6646c 100644
--- a/src/backend/access/index/genam.c
+++ b/src/backend/access/index/genam.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.26 2001/01/24 19:42:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.27 2001/06/09 18:16:56 tgl Exp $
*
* NOTES
* many of the old access method routines have been turned into
@@ -107,12 +107,8 @@ RelationGetIndexScan(Relation relation,
scan->opaque = NULL;
scan->numberOfKeys = numberOfKeys;
- ItemPointerSetInvalid(&scan->previousItemData);
ItemPointerSetInvalid(&scan->currentItemData);
- ItemPointerSetInvalid(&scan->nextItemData);
- ItemPointerSetInvalid(&scan->previousMarkData);
ItemPointerSetInvalid(&scan->currentMarkData);
- ItemPointerSetInvalid(&scan->nextMarkData);
/*
* mark cached function lookup data invalid; it will be set on first
@@ -176,9 +172,7 @@ IndexScanRestart(IndexScanDesc scan,
if (!IndexScanIsValid(scan))
elog(ERROR, "IndexScanRestart: invalid scan");
- ItemPointerSetInvalid(&scan->previousItemData);
ItemPointerSetInvalid(&scan->currentItemData);
- ItemPointerSetInvalid(&scan->nextItemData);
if (RelationGetNumberOfBlocks(scan->relation) == 0)
scan->flags = ScanUnmarked;
@@ -213,37 +207,7 @@ IndexScanRestart(IndexScanDesc scan,
void
IndexScanMarkPosition(IndexScanDesc scan)
{
- RetrieveIndexResult result;
-
- if (scan->flags & ScanUncheckedPrevious)
- {
- result = index_getnext(scan, BackwardScanDirection);
-
- if (result != NULL)
- {
- scan->previousItemData = result->index_iptr;
- pfree(result);
- }
- else
- ItemPointerSetInvalid(&scan->previousItemData);
- }
- else if (scan->flags & ScanUncheckedNext)
- {
- result = (RetrieveIndexResult)
- index_getnext(scan, ForwardScanDirection);
-
- if (result != NULL)
- {
- scan->nextItemData = result->index_iptr;
- pfree(result);
- }
- else
- ItemPointerSetInvalid(&scan->nextItemData);
- }
-
- scan->previousMarkData = scan->previousItemData;
scan->currentMarkData = scan->currentItemData;
- scan->nextMarkData = scan->nextItemData;
scan->flags = 0x0; /* XXX should have a symbolic name */
}
@@ -269,9 +233,7 @@ IndexScanRestorePosition(IndexScanDesc scan)
if (scan->flags & ScanUnmarked)
elog(ERROR, "IndexScanRestorePosition: no mark to restore");
- scan->previousItemData = scan->previousMarkData;
scan->currentItemData = scan->currentMarkData;
- scan->nextItemData = scan->nextMarkData;
scan->flags = 0x0; /* XXX should have a symbolic name */
}
diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c
index f3e6d52fe67..c9f1ab7b893 100644
--- a/src/backend/access/rtree/rtscan.c
+++ b/src/backend/access/rtree/rtscan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.36 2001/03/22 03:59:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.37 2001/06/09 18:16:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -85,13 +85,8 @@ rtrescan(PG_FUNCTION_ARGS)
/*
* Clear all the pointers.
*/
-
- ItemPointerSetInvalid(&s->previousItemData);
ItemPointerSetInvalid(&s->currentItemData);
- ItemPointerSetInvalid(&s->nextItemData);
- ItemPointerSetInvalid(&s->previousMarkData);
ItemPointerSetInvalid(&s->currentMarkData);
- ItemPointerSetInvalid(&s->nextMarkData);
/*
* Set flags.
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index d5ff24df022..06abd2e8675 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@@ -96,43 +96,6 @@ static int ReleaseBufferWithBufferLock(Buffer buffer);
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
@@ -141,7 +104,8 @@ RelationGetBufferWithBuffer(Relation relation,
* 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.
@@ -300,8 +264,8 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
}
/*
- * 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
*
@@ -684,6 +648,11 @@ WriteNoReleaseBuffer(Buffer 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,
@@ -698,12 +667,19 @@ 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
@@ -1002,7 +978,7 @@ BufferPoolCheckLeak()
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,
@@ -1396,7 +1372,7 @@ PrintBufferDescs()
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,
@@ -1426,7 +1402,7 @@ PrintPinnedBufs()
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,
@@ -1719,7 +1695,7 @@ IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
{
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);
@@ -1737,7 +1713,7 @@ ReleaseBuffer_Debug(char *file, int line, Buffer buffer)
{
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);
@@ -1765,7 +1741,7 @@ ReleaseAndReadBuffer_Debug(char *file,
{
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);
@@ -1774,7 +1750,7 @@ refcount = %ld, file: %s, line: %d\n",
{
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);
@@ -2057,7 +2033,7 @@ LockBuffer(Buffer buffer, int mode)
{
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)
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index b97b52979e4..8bfb514b1e4 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: relscan.h,v 1.20 2001/01/24 19:43:19 momjian Exp $
+ * $Id: relscan.h,v 1.21 2001/06/09 18:16:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,25 +16,16 @@
#include "utils/tqual.h"
-typedef ItemPointerData MarkData;
typedef struct HeapScanDescData
{
Relation rs_rd; /* pointer to relation descriptor */
- HeapTupleData rs_ptup; /* previous tuple in scan */
- HeapTupleData rs_ctup; /* current tuple in scan */
- HeapTupleData rs_ntup; /* next tuple in scan */
- Buffer rs_pbuf; /* previous buffer in scan */
- Buffer rs_cbuf; /* current buffer in scan */
- Buffer rs_nbuf; /* next buffer in scan */
- ItemPointerData rs_mptid; /* marked previous tid */
- ItemPointerData rs_mctid; /* marked current tid */
- ItemPointerData rs_mntid; /* marked next tid */
- ItemPointerData rs_mcd; /* marked current delta XXX ??? */
+ HeapTupleData rs_ctup; /* current tuple in scan, if any */
+ Buffer rs_cbuf; /* current buffer in scan, if any */
+ /* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
+ ItemPointerData rs_mctid; /* marked tid, if any */
Snapshot rs_snapshot; /* snapshot to see */
- bool rs_atend; /* restart scan at end? */
- uint16 rs_cdelta; /* current delta in chain */
- uint16 rs_nkeys; /* number of attributes in keys */
+ uint16 rs_nkeys; /* number of scan keys to select tuples */
ScanKey rs_key; /* key descriptors */
} HeapScanDescData;
@@ -43,22 +34,24 @@ typedef HeapScanDescData *HeapScanDesc;
typedef struct IndexScanDescData
{
Relation relation; /* relation descriptor */
- void *opaque; /* am-specific slot */
- ItemPointerData previousItemData; /* previous index pointer */
+ void *opaque; /* access-method-specific info */
ItemPointerData currentItemData; /* current index pointer */
- ItemPointerData nextItemData; /* next index pointer */
- MarkData previousMarkData; /* marked previous pointer */
- MarkData currentMarkData;/* marked current pointer */
- MarkData nextMarkData; /* marked next pointer */
+ ItemPointerData currentMarkData; /* marked current pointer */
uint8 flags; /* scan position flags */
bool scanFromEnd; /* restart scan at end? */
- uint16 numberOfKeys; /* number of key attributes */
- ScanKey keyData; /* key descriptor */
+ uint16 numberOfKeys; /* number of scan keys to select tuples */
+ ScanKey keyData; /* key descriptors */
FmgrInfo fn_getnext; /* cached lookup info for am's getnext fn */
} IndexScanDescData;
typedef IndexScanDescData *IndexScanDesc;
+/* IndexScanDesc flag bits (none of these are actually used currently) */
+#define ScanUnmarked 0x01
+#define ScanUncheckedPrevious 0x02
+#define ScanUncheckedNext 0x04
+
+
/* ----------------
* IndexScanDescPtr is used in the executor where we have to
* keep track of several index scans when using several indices
diff --git a/src/include/access/skey.h b/src/include/access/skey.h
index 2a00e26744e..4e49f51afb1 100644
--- a/src/include/access/skey.h
+++ b/src/include/access/skey.h
@@ -7,8 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: skey.h,v 1.15 2001/06/01 02:41:36 tgl Exp $
- *
+ * $Id: skey.h,v 1.16 2001/06/09 18:16:59 tgl Exp $
*
* Note:
* Needs more accessor/assignment routines.
@@ -20,6 +19,7 @@
#include "access/attnum.h"
#include "fmgr.h"
+
typedef struct ScanKeyData
{
bits16 sk_flags; /* flags */
@@ -38,11 +38,6 @@ typedef ScanKeyData *ScanKey;
#define SK_COMMUTE 0x8 /* commute function (not fully supported) */
-#define ScanUnmarked 0x01
-#define ScanUncheckedPrevious 0x02
-#define ScanUncheckedNext 0x04
-
-
/*
* prototypes for functions in access/common/scankey.c
*/
diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h
index c65e4cc9975..f31d5d5cc8d 100644
--- a/src/include/storage/buf.h
+++ b/src/include/storage/buf.h
@@ -7,17 +7,22 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: buf.h,v 1.8 2001/01/24 19:43:27 momjian Exp $
+ * $Id: buf.h,v 1.9 2001/06/09 18:16:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef BUF_H
#define BUF_H
-#define InvalidBuffer (0)
-#define UnknownBuffer (-99999)
+/*
+ * Buffer identifiers.
+ *
+ * Zero is invalid, positive is the index of a shared buffer (1..NBuffers),
+ * negative is the index of a local buffer (-1 .. -NLocBuffer).
+ */
+typedef int Buffer;
-typedef long Buffer;
+#define InvalidBuffer 0
/*
* BufferIsInvalid
@@ -26,12 +31,6 @@ typedef long Buffer;
#define BufferIsInvalid(buffer) ((buffer) == InvalidBuffer)
/*
- * BufferIsUnknown
- * True iff the buffer is unknown.
- */
-#define BufferIsUnknown(buffer) ((buffer) == UnknownBuffer)
-
-/*
* BufferIsLocal
* True iff the buffer is local (not visible to other servers).
*/
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index d45c8888c1d..9d7f568e193 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: bufmgr.h,v 1.51 2001/05/12 19:58:28 tgl Exp $
+ * $Id: bufmgr.h,v 1.52 2001/06/09 18:16:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -75,10 +75,6 @@ extern long *LocalRefCount;
* True iff the given buffer number is valid (either as a shared
* or local buffer).
*
- * Note:
- * BufferIsValid(InvalidBuffer) is False.
- * BufferIsValid(UnknownBuffer) is False.
- *
* Note: For a long time this was defined the same as BufferIsPinned,
* that is it would say False if you didn't hold a pin on the buffer.
* I believe this was bogus and served only to mask logic errors.
@@ -158,8 +154,6 @@ extern long *LocalRefCount;
/*
* prototypes for functions in bufmgr.c
*/
-extern Buffer RelationGetBufferWithBuffer(Relation relation,
- BlockNumber blockNumber, Buffer buffer);
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern int WriteBuffer(Buffer buffer);
extern int WriteNoReleaseBuffer(Buffer buffer);