/*
- * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.14 2004/04/01 21:28:43 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.15 2004/05/08 19:09:24 tgl Exp $
*
* Copyright (c) 2001,2002 Tatsuo Ishii
*
*/
attinmeta = TupleDescGetAttInMetadata(tupdesc);
- nblocks = RelationGetNumberOfBlocks(rel);
scan = heap_beginscan(rel, SnapshotAny, 0, NULL);
+ nblocks = scan->rs_nblocks; /* # blocks to be scanned */
+
/* scan the relation */
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.165 2004/04/21 18:24:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.166 2004/05/08 19:09:24 tgl Exp $
*
*
* INTERFACE ROUTINES
initscan(HeapScanDesc scan, ScanKey key)
{
/*
- * Make sure we have up-to-date idea of number of blocks in relation.
+ * 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
* transaction anyway...
*/
- scan->rs_rd->rd_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
+ scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
scan->rs_ctup.t_datamcxt = NULL;
scan->rs_ctup.t_data = NULL;
Buffer *buffer,
Snapshot snapshot,
int nkeys,
- ScanKey key)
+ ScanKey key,
+ BlockNumber pages)
{
ItemId lpp;
Page dp;
BlockNumber page;
- BlockNumber pages;
int lines;
OffsetNumber lineoff;
int linesleft;
/*
* return null immediately if relation is empty
*/
- if ((pages = relation->rd_nblocks) == 0)
+ if (pages == 0)
{
if (BufferIsValid(*buffer))
ReleaseBuffer(*buffer);
&(scan->rs_cbuf),
scan->rs_snapshot,
scan->rs_nkeys,
- scan->rs_key);
+ scan->rs_key,
+ scan->rs_nblocks);
if (scan->rs_ctup.t_data == NULL && !BufferIsValid(scan->rs_cbuf))
{
&(scan->rs_cbuf),
scan->rs_snapshot,
0,
- NULL);
+ NULL,
+ scan->rs_nblocks);
}
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.114 2004/04/21 18:24:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.115 2004/05/08 19:09:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Do the physical truncation.
*/
- if (rel->rd_smgr == NULL)
- rel->rd_smgr = smgropen(rel->rd_node);
- new_pages = smgrtruncate(rel->rd_smgr, new_pages);
- rel->rd_nblocks = new_pages; /* update relcache
- * immediately */
- rel->rd_targblock = InvalidBlockNumber;
+ RelationTruncate(rel, new_pages);
num_pages = new_pages;
}
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.263 2004/05/05 04:48:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.264 2004/05/08 19:09:24 tgl Exp $
*
*
* INTERFACE ROUTINES
*/
DropRelationBuffers(currentIndex);
- /* Now truncate the actual data and set blocks to zero */
- if (currentIndex->rd_smgr == NULL)
- currentIndex->rd_smgr = smgropen(currentIndex->rd_node);
- smgrtruncate(currentIndex->rd_smgr, 0);
- currentIndex->rd_nblocks = 0;
- currentIndex->rd_targblock = InvalidBlockNumber;
+ /* Now truncate the actual data */
+ RelationTruncate(currentIndex, 0);
/* Initialize the index and rebuild */
index_build(heapRelation, currentIndex, indexInfo);
*/
DropRelationBuffers(rel);
- /* Now truncate the actual data and set blocks to zero */
- if (rel->rd_smgr == NULL)
- rel->rd_smgr = smgropen(rel->rd_node);
- smgrtruncate(rel->rd_smgr, 0);
- rel->rd_nblocks = 0;
- rel->rd_targblock = InvalidBlockNumber;
+ /* Now truncate the actual data */
+ RelationTruncate(rel, 0);
/* If this relation has indexes, truncate the indexes too */
RelationTruncateIndexes(rid);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.230 2004/05/08 00:34:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.231 2004/05/08 19:09:24 tgl Exp $
*
*
* INTERFACE ROUTINES
*/
DropRelationBuffers(iRel);
- /* Now truncate the actual data and set blocks to zero */
- if (iRel->rd_smgr == NULL)
- iRel->rd_smgr = smgropen(iRel->rd_node);
- smgrtruncate(iRel->rd_smgr, 0);
- iRel->rd_nblocks = 0;
- iRel->rd_targblock = InvalidBlockNumber;
+ /* Now truncate the actual data */
+ RelationTruncate(iRel, 0);
}
else
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.70 2004/02/15 21:01:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.71 2004/05/08 19:09:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* If we are running a standalone ANALYZE, update pages/tuples stats
- * in pg_class. We have the accurate page count from heap_beginscan,
+ * in pg_class. We know the accurate page count from the smgr,
* but only an approximate number of tuples; therefore, if we are part
* of VACUUM ANALYZE do *not* overwrite the accurate count already
* inserted by VACUUM. The same consideration applies to indexes.
if (!vacstmt->vacuum)
{
vac_update_relstats(RelationGetRelid(onerel),
- onerel->rd_nblocks,
+ RelationGetNumberOfBlocks(onerel),
totalrows,
hasindex);
for (ind = 0; ind < nindexes; ind++)
{
int numrows = 0;
HeapScanDesc scan;
+ BlockNumber totalblocks;
HeapTuple tuple;
ItemPointer lasttuple;
BlockNumber lastblock,
* Do a simple linear scan until we reach the target number of rows.
*/
scan = heap_beginscan(onerel, SnapshotNow, 0, NULL);
+ totalblocks = scan->rs_nblocks; /* grab current relation size */
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
rows[numrows++] = heap_copytuple(tuple);
ereport(elevel,
(errmsg("\"%s\": %u pages, %d rows sampled, %.0f estimated total rows",
RelationGetRelationName(onerel),
- onerel->rd_nblocks, numrows, *totalrows)));
+ totalblocks, numrows, *totalrows)));
return numrows;
}
pageloop:;
/*
- * Have we fallen off the end of the relation? (We rely on
- * heap_beginscan to have updated rd_nblocks.)
+ * Have we fallen off the end of the relation?
*/
- if (targblock >= onerel->rd_nblocks)
+ if (targblock >= totalblocks)
break;
/*
/*
* Estimate total number of valid rows in relation.
*/
- *totalrows = floor((double) onerel->rd_nblocks * tuplesperpage + 0.5);
+ *totalrows = floor((double) totalblocks * tuplesperpage + 0.5);
/*
* Emit some interesting relation info
ereport(elevel,
(errmsg("\"%s\": %u pages, %d rows sampled, %.0f estimated total rows",
RelationGetRelationName(onerel),
- onerel->rd_nblocks, numrows, *totalrows)));
+ totalblocks, numrows, *totalrows)));
return numrows;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.109 2004/04/06 16:39:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.110 2004/05/08 19:09:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
sequence_magic *sm;
Form_pg_sequence seq;
- if (rel->rd_nblocks > 1)
- elog(ERROR, "invalid number of blocks in sequence \"%s\"",
- RelationGetRelationName(rel));
-
*buf = ReadBuffer(rel, 0);
if (!BufferIsValid(*buf))
elog(ERROR, "ReadBuffer failed");
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.274 2004/02/12 05:39:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.275 2004/05/08 19:09:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* truncate relation, if needed */
if (blkno < nblocks)
{
- if (onerel->rd_smgr == NULL)
- onerel->rd_smgr = smgropen(onerel->rd_node);
- blkno = smgrtruncate(onerel->rd_smgr, blkno);
- onerel->rd_nblocks = blkno; /* update relcache immediately */
- onerel->rd_targblock = InvalidBlockNumber;
+ RelationTruncate(onerel, blkno);
vacrelstats->rel_pages = blkno; /* set new number of blocks */
}
(errmsg("\"%s\": truncated %u to %u pages",
RelationGetRelationName(onerel),
vacrelstats->rel_pages, relblocks)));
- if (onerel->rd_smgr == NULL)
- onerel->rd_smgr = smgropen(onerel->rd_node);
- relblocks = smgrtruncate(onerel->rd_smgr, relblocks);
- onerel->rd_nblocks = relblocks; /* update relcache immediately */
- onerel->rd_targblock = InvalidBlockNumber;
+ RelationTruncate(onerel, relblocks);
vacrelstats->rel_pages = relblocks; /* set new number of
* blocks */
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.39 2004/04/25 23:50:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.40 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* Do the physical truncation.
*/
- if (onerel->rd_smgr == NULL)
- onerel->rd_smgr = smgropen(onerel->rd_node);
- new_rel_pages = smgrtruncate(onerel->rd_smgr, new_rel_pages);
- onerel->rd_nblocks = new_rel_pages; /* update relcache immediately */
- onerel->rd_targblock = InvalidBlockNumber;
+ RelationTruncate(onerel, new_rel_pages);
vacrelstats->rel_pages = new_rel_pages; /* save new number of
* blocks */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.164 2004/04/25 23:50:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.165 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* Assume when this function is called, that reln has been
* opened already.
- *
- * Note: a side effect of a P_NEW call is to update reln->rd_nblocks.
*/
Buffer
ReadBuffer(Relation reln, BlockNumber blockNum)
if (reln->rd_smgr == NULL)
reln->rd_smgr = smgropen(reln->rd_node);
+ /* Substitute proper block number if caller asked for P_NEW */
+ if (isExtend)
+ blockNum = smgrnblocks(reln->rd_smgr);
+
if (isLocalBuf)
{
ReadLocalBufferCount++;
pgstat_count_buffer_read(&reln->pgstat_info, reln);
- /* Substitute proper block number if caller asked for P_NEW */
- if (isExtend)
- blockNum = reln->rd_nblocks;
-
bufHdr = LocalBufferAlloc(reln, blockNum, &found);
if (found)
LocalBufferHitCount++;
{
ReadBufferCount++;
pgstat_count_buffer_read(&reln->pgstat_info, reln);
- /* Substitute proper block number if caller asked for P_NEW */
- if (isExtend)
- {
- /* must be sure we have accurate file length! */
- blockNum = reln->rd_nblocks = smgrnblocks(reln->rd_smgr);
- }
-
/*
* lookup the buffer. IO_IN_PROGRESS is set if the requested
* block is not currently in memory.
/* new buffers are zero-filled */
MemSet((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
smgrextend(reln->rd_smgr, blockNum, (char *) MAKE_PTR(bufHdr->data));
- /* After successful extend, increment relation length */
- reln->rd_nblocks++;
}
else
{
/*
* RelationGetNumberOfBlocks
* Determines the current number of pages in the relation.
- * Side effect: relation->rd_nblocks is updated.
*/
BlockNumber
RelationGetNumberOfBlocks(Relation relation)
{
- /*
- * relation->rd_nblocks should be accurate already if the relation is
- * new or temp, because no one else should be modifying it. Otherwise
- * we need to ask the smgr for the current physical file length.
- *
- * Don't call smgr on a view or a composite type, either.
- */
- if (relation->rd_rel->relkind == RELKIND_VIEW ||
- relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
- relation->rd_nblocks = 0;
- else if (!relation->rd_isnew && !relation->rd_istemp)
- {
- /* Open it at the smgr level if not already done */
- if (relation->rd_smgr == NULL)
- relation->rd_smgr = smgropen(relation->rd_node);
-
- relation->rd_nblocks = smgrnblocks(relation->rd_smgr);
- }
+ /* Open it at the smgr level if not already done */
+ if (relation->rd_smgr == NULL)
+ relation->rd_smgr = smgropen(relation->rd_node);
- return relation->rd_nblocks;
+ return smgrnblocks(relation->rd_smgr);
}
/*
- * RelationUpdateNumberOfBlocks
- * Forcibly update relation->rd_nblocks.
+ * RelationTruncate
+ * Physically truncate a relation to the specified number of blocks.
*
- * If the relcache drops an entry for a temp relation, it must call this
- * routine after recreating the relcache entry, so that rd_nblocks is
- * re-sync'd with reality. See RelationGetNumberOfBlocks.
+ * Caller should already have done something to flush any buffered pages
+ * that are to be dropped.
*/
void
-RelationUpdateNumberOfBlocks(Relation relation)
+RelationTruncate(Relation rel, BlockNumber nblocks)
{
- if (relation->rd_rel->relkind == RELKIND_VIEW ||
- relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
- relation->rd_nblocks = 0;
- else
- {
- /* Open it at the smgr level if not already done */
- if (relation->rd_smgr == NULL)
- relation->rd_smgr = smgropen(relation->rd_node);
+ /* Open it at the smgr level if not already done */
+ if (rel->rd_smgr == NULL)
+ rel->rd_smgr = smgropen(rel->rd_node);
- relation->rd_nblocks = smgrnblocks(relation->rd_smgr);
- }
+ /* Make sure rd_targblock isn't pointing somewhere past end */
+ rel->rd_targblock = InvalidBlockNumber;
+
+ /* Do the real work */
+ smgrtruncate(rel->rd_smgr, nblocks);
}
/* ---------------------------------------------------------------------
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.201 2004/04/01 21:28:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.202 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
RelationCacheInsert(relation);
MemoryContextSwitchTo(oldcxt);
- /*
- * If it's a temp rel, RelationGetNumberOfBlocks will assume that
- * rd_nblocks is correct. Must forcibly update the block count when
- * creating the relcache entry. But if we are doing a rebuild, don't
- * do this yet; leave it to RelationClearRelation to do at the end.
- * (Otherwise, an elog in RelationUpdateNumberOfBlocks would leave us
- * with inconsistent relcache state.)
- */
- if (relation->rd_istemp && oldrelation == NULL)
- RelationUpdateNumberOfBlocks(relation);
-
return relation;
}
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
relation->rd_node.relNode = relp->relfilenode;
heap_freetuple(pg_class_tuple);
- /* Must adjust number of blocks after we know the new relfilenode */
relation->rd_targblock = InvalidBlockNumber;
- RelationUpdateNumberOfBlocks(relation);
/* Okay, now it's valid again */
relation->rd_isnailed = 1;
}
/*
* Never, never ever blow away a nailed-in system relation, because
- * we'd be unable to recover. However, we must update rd_nblocks and
- * reset rd_targblock, in case we got called because of a relation
- * cache flush that was triggered by VACUUM. If it's a nailed index,
- * then we need to re-read the pg_class row to see if its relfilenode
- * changed. We can't necessarily do that here, because we might be in
- * a failed transaction. We assume it's okay to do it if there are open
- * references to the relcache entry (cf notes for AtEOXact_RelationCache).
- * Otherwise just mark the entry as possibly invalid, and it'll be fixed
- * when next opened.
+ * we'd be unable to recover. However, we must reset rd_targblock, in
+ * case we got called because of a relation cache flush that was triggered
+ * by VACUUM.
+ *
+ * If it's a nailed index, then we need to re-read the pg_class row to see
+ * if its relfilenode changed. We can't necessarily do that here, because
+ * we might be in a failed transaction. We assume it's okay to do it if
+ * there are open references to the relcache entry (cf notes for
+ * AtEOXact_RelationCache). Otherwise just mark the entry as possibly
+ * invalid, and it'll be fixed when next opened.
*/
if (relation->rd_isnailed)
{
+ relation->rd_targblock = InvalidBlockNumber;
if (relation->rd_rel->relkind == RELKIND_INDEX)
{
relation->rd_isnailed = 2; /* needs to be revalidated */
if (relation->rd_refcnt > 1)
RelationReloadClassinfo(relation);
}
- else
- {
- relation->rd_targblock = InvalidBlockNumber;
- RelationUpdateNumberOfBlocks(relation);
- }
return;
}
if (old_rulescxt)
MemoryContextDelete(old_rulescxt);
}
-
- /*
- * Update rd_nblocks. This is kind of expensive, but I think we
- * must do it in case relation has been truncated... we definitely
- * must do it if the rel is new or temp, since
- * RelationGetNumberOfBlocks will subsequently assume that the
- * block count is correct.
- */
- RelationUpdateNumberOfBlocks(relation);
}
}
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.34 2003/11/29 22:40:55 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/access/relscan.h,v 1.35 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Snapshot rs_snapshot; /* snapshot to see */
int rs_nkeys; /* number of scan keys */
ScanKey rs_key; /* array of scan key descriptors */
+ BlockNumber rs_nblocks; /* number of blocks to scan */
/* scan current state */
HeapTupleData rs_ctup; /* current tuple in scan, if any */
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.78 2004/04/25 23:50:58 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.79 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void FlushBufferPool(void);
extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
-extern void RelationUpdateNumberOfBlocks(Relation relation);
+extern void RelationTruncate(Relation rel, BlockNumber nblocks);
extern int FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock);
extern void DropRelationBuffers(Relation rel);
extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp);
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.73 2004/02/10 01:55:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.74 2004/05/08 19:09:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
RelFileNode rd_node; /* relation physical identifier */
/* use "struct" here to avoid needing to include smgr.h: */
struct SMgrRelationData *rd_smgr; /* cached file handle, or NULL */
- BlockNumber rd_nblocks; /* number of blocks in rel */
BlockNumber rd_targblock; /* current insertion target block, or
* InvalidBlockNumber */
int rd_refcnt; /* reference count */