mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
Remove unnecessary calls of FlushRelationBuffers: there is no need
to write out data that we are about to tell the filesystem to drop. smgr_internal_unlink already had a DropRelFileNodeBuffers call to get rid of dead buffers without a write after it's no longer possible to roll back the deleting transaction. Adding a similar call in smgrtruncate simplifies callers and makes the overall division of labor clearer. This patch removes the former behavior that VACUUM would write all dirty buffers of a relation unconditionally.
This commit is contained in:
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.124 2004/12/31 21:59:22 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.125 2005/03/20 22:00:50 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -772,17 +772,6 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Okay to truncate.
|
* Okay to truncate.
|
||||||
*
|
|
||||||
* First, flush any shared buffers for the blocks we intend to
|
|
||||||
* delete. FlushRelationBuffers is a bit more than we need
|
|
||||||
* for this, since it will also write out dirty buffers for
|
|
||||||
* blocks we aren't deleting, but it's the closest thing in
|
|
||||||
* bufmgr's API.
|
|
||||||
*/
|
|
||||||
FlushRelationBuffers(rel, new_pages);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the physical truncation.
|
|
||||||
*/
|
*/
|
||||||
RelationTruncate(rel, new_pages);
|
RelationTruncate(rel, new_pages);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.280 2005/01/27 03:17:17 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.281 2005/03/20 22:00:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -1174,12 +1174,6 @@ heap_drop_with_catalog(Oid relid)
|
|||||||
*/
|
*/
|
||||||
rel = relation_open(relid, AccessExclusiveLock);
|
rel = relation_open(relid, AccessExclusiveLock);
|
||||||
|
|
||||||
/*
|
|
||||||
* Release all buffers that belong to this relation, after writing any
|
|
||||||
* that are dirty
|
|
||||||
*/
|
|
||||||
FlushRelationBuffers(rel, (BlockNumber) 0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Schedule unlinking of the relation's physical file at commit.
|
* Schedule unlinking of the relation's physical file at commit.
|
||||||
*/
|
*/
|
||||||
@ -1958,13 +1952,7 @@ RelationTruncateIndexes(Oid heapId)
|
|||||||
/* Fetch info needed for index_build */
|
/* Fetch info needed for index_build */
|
||||||
indexInfo = BuildIndexInfo(currentIndex);
|
indexInfo = BuildIndexInfo(currentIndex);
|
||||||
|
|
||||||
/*
|
/* Now truncate the actual file (and discard buffers) */
|
||||||
* Drop any buffers associated with this index. If they're dirty,
|
|
||||||
* they're just dropped without bothering to flush to disk.
|
|
||||||
*/
|
|
||||||
DropRelationBuffers(currentIndex);
|
|
||||||
|
|
||||||
/* Now truncate the actual data */
|
|
||||||
RelationTruncate(currentIndex, 0);
|
RelationTruncate(currentIndex, 0);
|
||||||
|
|
||||||
/* Initialize the index and rebuild */
|
/* Initialize the index and rebuild */
|
||||||
@ -2024,13 +2012,7 @@ heap_truncate(List *relids)
|
|||||||
{
|
{
|
||||||
Relation rel = lfirst(cell);
|
Relation rel = lfirst(cell);
|
||||||
|
|
||||||
/*
|
/* Truncate the actual file (and discard buffers) */
|
||||||
* Release any buffers associated with this relation. If they're
|
|
||||||
* dirty, they're just dropped without bothering to flush to disk.
|
|
||||||
*/
|
|
||||||
DropRelationBuffers(rel);
|
|
||||||
|
|
||||||
/* Now truncate the actual data */
|
|
||||||
RelationTruncate(rel, 0);
|
RelationTruncate(rel, 0);
|
||||||
|
|
||||||
/* If this relation has indexes, truncate the indexes too */
|
/* If this relation has indexes, truncate the indexes too */
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.247 2005/03/16 21:38:04 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.248 2005/03/20 22:00:51 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -775,10 +775,8 @@ index_drop(Oid indexId)
|
|||||||
LockRelation(userIndexRelation, AccessExclusiveLock);
|
LockRelation(userIndexRelation, AccessExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* flush buffer cache and schedule physical removal of the file
|
* Schedule physical removal of the file
|
||||||
*/
|
*/
|
||||||
FlushRelationBuffers(userIndexRelation, (BlockNumber) 0);
|
|
||||||
|
|
||||||
RelationOpenSmgr(userIndexRelation);
|
RelationOpenSmgr(userIndexRelation);
|
||||||
smgrscheduleunlink(userIndexRelation->rd_smgr,
|
smgrscheduleunlink(userIndexRelation->rd_smgr,
|
||||||
userIndexRelation->rd_istemp);
|
userIndexRelation->rd_istemp);
|
||||||
@ -1617,14 +1615,7 @@ reindex_index(Oid indexId)
|
|||||||
|
|
||||||
if (inplace)
|
if (inplace)
|
||||||
{
|
{
|
||||||
/*
|
/* Truncate the actual file (and discard buffers) */
|
||||||
* Release any buffers associated with this index. If they're
|
|
||||||
* dirty, they're just dropped without bothering to flush to
|
|
||||||
* disk.
|
|
||||||
*/
|
|
||||||
DropRelationBuffers(iRel);
|
|
||||||
|
|
||||||
/* Now truncate the actual data */
|
|
||||||
RelationTruncate(iRel, 0);
|
RelationTruncate(iRel, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.132 2005/02/06 20:19:08 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.133 2005/03/20 22:00:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -709,8 +709,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
|
|||||||
void
|
void
|
||||||
swap_relation_files(Oid r1, Oid r2)
|
swap_relation_files(Oid r1, Oid r2)
|
||||||
{
|
{
|
||||||
Relation relRelation,
|
Relation relRelation;
|
||||||
rel;
|
|
||||||
HeapTuple reltup1,
|
HeapTuple reltup1,
|
||||||
reltup2;
|
reltup2;
|
||||||
Form_pg_class relform1,
|
Form_pg_class relform1,
|
||||||
@ -735,20 +734,6 @@ swap_relation_files(Oid r1, Oid r2)
|
|||||||
elog(ERROR, "cache lookup failed for relation %u", r2);
|
elog(ERROR, "cache lookup failed for relation %u", r2);
|
||||||
relform2 = (Form_pg_class) GETSTRUCT(reltup2);
|
relform2 = (Form_pg_class) GETSTRUCT(reltup2);
|
||||||
|
|
||||||
/*
|
|
||||||
* The buffer manager gets confused if we swap relfilenodes for
|
|
||||||
* relations that are not both local or non-local to this transaction.
|
|
||||||
* Flush the buffers on both relations so the buffer manager can
|
|
||||||
* forget about'em. (XXX this might not be necessary anymore?)
|
|
||||||
*/
|
|
||||||
rel = relation_open(r1, NoLock);
|
|
||||||
FlushRelationBuffers(rel, 0);
|
|
||||||
relation_close(rel, NoLock);
|
|
||||||
|
|
||||||
rel = relation_open(r2, NoLock);
|
|
||||||
FlushRelationBuffers(rel, 0);
|
|
||||||
relation_close(rel, NoLock);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actually swap the fields in the two tuples
|
* Actually swap the fields in the two tuples
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.147 2005/03/16 21:38:05 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.148 2005/03/20 22:00:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -5628,13 +5628,12 @@ copy_relation_data(Relation rel, SMgrRelation dst)
|
|||||||
Page page = (Page) buf;
|
Page page = (Page) buf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we copy the data directly without looking at the shared
|
* Since we copy the file directly without looking at the shared
|
||||||
* buffers, we'd better first flush out any pages of the source
|
* buffers, we'd better first flush out any pages of the source
|
||||||
* relation that are in shared buffers. We assume no new pages will
|
* relation that are in shared buffers. We assume no new changes
|
||||||
* get loaded into buffers while we are holding exclusive lock on the
|
* will be made while we are holding exclusive lock on the rel.
|
||||||
* rel.
|
|
||||||
*/
|
*/
|
||||||
FlushRelationBuffers(rel, 0);
|
FlushRelationBuffers(rel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to log the copied data in WAL iff WAL archiving is enabled
|
* We need to log the copied data in WAL iff WAL archiving is enabled
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.304 2005/03/16 21:38:05 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.305 2005/03/20 22:00:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1138,16 +1138,6 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt)
|
|||||||
/* Clean pages from vacuum_pages list */
|
/* Clean pages from vacuum_pages list */
|
||||||
vacuum_heap(vacrelstats, onerel, &vacuum_pages);
|
vacuum_heap(vacrelstats, onerel, &vacuum_pages);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Flush dirty pages out to disk. We must do this even if we
|
|
||||||
* didn't do anything else, because we want to ensure that all
|
|
||||||
* tuples have correct on-row commit status on disk (see
|
|
||||||
* bufmgr.c's comments for FlushRelationBuffers()).
|
|
||||||
*/
|
|
||||||
FlushRelationBuffers(onerel, vacrelstats->rel_pages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update shared free space map with final free space info */
|
/* update shared free space map with final free space info */
|
||||||
@ -2420,15 +2410,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
|
|||||||
pfree(Nvacpagelist.pagedesc);
|
pfree(Nvacpagelist.pagedesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Truncate relation, if needed */
|
||||||
* Flush dirty pages out to disk. We do this unconditionally, even if
|
|
||||||
* we don't need to truncate, because we want to ensure that all
|
|
||||||
* tuples have correct on-row commit status on disk (see bufmgr.c's
|
|
||||||
* comments for FlushRelationBuffers()).
|
|
||||||
*/
|
|
||||||
FlushRelationBuffers(onerel, blkno);
|
|
||||||
|
|
||||||
/* truncate relation, if needed */
|
|
||||||
if (blkno < nblocks)
|
if (blkno < nblocks)
|
||||||
{
|
{
|
||||||
RelationTruncate(onerel, blkno);
|
RelationTruncate(onerel, blkno);
|
||||||
@ -2818,27 +2800,17 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Truncate relation if there are some empty end-pages */
|
||||||
* Flush dirty pages out to disk. We do this unconditionally, even if
|
|
||||||
* we don't need to truncate, because we want to ensure that all
|
|
||||||
* tuples have correct on-row commit status on disk (see bufmgr.c's
|
|
||||||
* comments for FlushRelationBuffers()).
|
|
||||||
*/
|
|
||||||
Assert(vacrelstats->rel_pages >= vacuum_pages->empty_end_pages);
|
Assert(vacrelstats->rel_pages >= vacuum_pages->empty_end_pages);
|
||||||
relblocks = vacrelstats->rel_pages - vacuum_pages->empty_end_pages;
|
|
||||||
|
|
||||||
FlushRelationBuffers(onerel, relblocks);
|
|
||||||
|
|
||||||
/* truncate relation if there are some empty end-pages */
|
|
||||||
if (vacuum_pages->empty_end_pages > 0)
|
if (vacuum_pages->empty_end_pages > 0)
|
||||||
{
|
{
|
||||||
|
relblocks = vacrelstats->rel_pages - vacuum_pages->empty_end_pages;
|
||||||
ereport(elevel,
|
ereport(elevel,
|
||||||
(errmsg("\"%s\": truncated %u to %u pages",
|
(errmsg("\"%s\": truncated %u to %u pages",
|
||||||
RelationGetRelationName(onerel),
|
RelationGetRelationName(onerel),
|
||||||
vacrelstats->rel_pages, relblocks)));
|
vacrelstats->rel_pages, relblocks)));
|
||||||
RelationTruncate(onerel, relblocks);
|
RelationTruncate(onerel, relblocks);
|
||||||
vacrelstats->rel_pages = relblocks; /* set new number of
|
vacrelstats->rel_pages = relblocks; /* set new number of blocks */
|
||||||
* blocks */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.50 2004/12/31 21:59:42 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.51 2005/03/20 22:00:52 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -773,16 +773,6 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay to truncate.
|
* Okay to truncate.
|
||||||
*
|
|
||||||
* First, flush any shared buffers for the blocks we intend to delete.
|
|
||||||
* FlushRelationBuffers is a bit more than we need for this, since it
|
|
||||||
* will also write out dirty buffers for blocks we aren't deleting,
|
|
||||||
* but it's the closest thing in bufmgr's API.
|
|
||||||
*/
|
|
||||||
FlushRelationBuffers(onerel, new_rel_pages);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the physical truncation.
|
|
||||||
*/
|
*/
|
||||||
RelationTruncate(onerel, new_rel_pages);
|
RelationTruncate(onerel, new_rel_pages);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.187 2005/03/18 05:25:23 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.188 2005/03/20 22:00:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1298,8 +1298,8 @@ RelationGetNumberOfBlocks(Relation relation)
|
|||||||
* RelationTruncate
|
* RelationTruncate
|
||||||
* Physically truncate a relation to the specified number of blocks.
|
* Physically truncate a relation to the specified number of blocks.
|
||||||
*
|
*
|
||||||
* Caller should already have done something to flush any buffered pages
|
* As of Postgres 8.1, this includes getting rid of any buffers for the
|
||||||
* that are to be dropped.
|
* blocks that are to be dropped; previously, callers had to do that.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
RelationTruncate(Relation rel, BlockNumber nblocks)
|
RelationTruncate(Relation rel, BlockNumber nblocks)
|
||||||
@ -1314,38 +1314,30 @@ RelationTruncate(Relation rel, BlockNumber nblocks)
|
|||||||
smgrtruncate(rel->rd_smgr, nblocks, rel->rd_istemp);
|
smgrtruncate(rel->rd_smgr, nblocks, rel->rd_istemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
|
||||||
* DropRelationBuffers
|
|
||||||
*
|
|
||||||
* This function removes all the buffered pages for a relation
|
|
||||||
* from the buffer pool. Dirty pages are simply dropped, without
|
|
||||||
* bothering to write them out first. This is NOT rollback-able,
|
|
||||||
* and so should be used only with extreme caution!
|
|
||||||
*
|
|
||||||
* There is no particularly good reason why this doesn't have a
|
|
||||||
* firstDelBlock parameter, except that current callers don't need it.
|
|
||||||
*
|
|
||||||
* We assume that the caller holds an exclusive lock on the relation,
|
|
||||||
* which should assure that no new buffers will be acquired for the rel
|
|
||||||
* meanwhile.
|
|
||||||
* --------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
DropRelationBuffers(Relation rel)
|
|
||||||
{
|
|
||||||
DropRelFileNodeBuffers(rel->rd_node, rel->rd_istemp, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* DropRelFileNodeBuffers
|
* DropRelFileNodeBuffers
|
||||||
*
|
*
|
||||||
* This is the same as DropRelationBuffers, except that the target
|
* This function removes from the buffer pool all the pages of the
|
||||||
* relation is specified by RelFileNode and temp status, and one
|
* specified relation that have block numbers >= firstDelBlock.
|
||||||
* may specify the first block to drop.
|
* (In particular, with firstDelBlock = 0, all pages are removed.)
|
||||||
|
* Dirty pages are simply dropped, without bothering to write them
|
||||||
|
* out first. Therefore, this is NOT rollback-able, and so should be
|
||||||
|
* used only with extreme caution!
|
||||||
*
|
*
|
||||||
* This is NOT rollback-able. One legitimate use is to clear the
|
* Currently, this is called only from smgr.c when the underlying file
|
||||||
* buffer cache of buffers for a relation that is being deleted
|
* is about to be deleted or truncated (firstDelBlock is needed for
|
||||||
* during transaction abort.
|
* the truncation case). The data in the affected pages would therefore
|
||||||
|
* be deleted momentarily anyway, and there is no point in writing it.
|
||||||
|
* It is the responsibility of higher-level code to ensure that the
|
||||||
|
* deletion or truncation does not lose any data that could be needed
|
||||||
|
* later. It is also the responsibility of higher-level code to ensure
|
||||||
|
* that no other process could be trying to load more pages of the
|
||||||
|
* relation into buffers.
|
||||||
|
*
|
||||||
|
* XXX currently it sequentially searches the buffer pool, should be
|
||||||
|
* changed to more clever ways of searching. However, this routine
|
||||||
|
* is used only in code paths that aren't very performance-critical,
|
||||||
|
* and we shouldn't slow down the hot paths to make it faster ...
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -1398,7 +1390,7 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
|
|||||||
* bothering to write them out first. This is used when we destroy a
|
* bothering to write them out first. This is used when we destroy a
|
||||||
* database, to avoid trying to flush data to disk when the directory
|
* database, to avoid trying to flush data to disk when the directory
|
||||||
* tree no longer exists. Implementation is pretty similar to
|
* tree no longer exists. Implementation is pretty similar to
|
||||||
* DropRelationBuffers() which is for destroying just one relation.
|
* DropRelFileNodeBuffers() which is for destroying just one relation.
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -1480,44 +1472,24 @@ PrintPinnedBufs(void)
|
|||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* FlushRelationBuffers
|
* FlushRelationBuffers
|
||||||
*
|
*
|
||||||
* This function writes all dirty pages of a relation out to disk.
|
* This function writes all dirty pages of a relation out to disk
|
||||||
* Furthermore, pages that have blocknumber >= firstDelBlock are
|
* (or more accurately, out to kernel disk buffers), ensuring that the
|
||||||
* actually removed from the buffer pool.
|
* kernel has an up-to-date view of the relation.
|
||||||
*
|
*
|
||||||
* This is called by DROP TABLE to clear buffers for the relation
|
* Generally, the caller should be holding AccessExclusiveLock on the
|
||||||
* from the buffer pool. Note that we must write dirty buffers,
|
* target relation to ensure that no other backend is busy dirtying
|
||||||
* rather than just dropping the changes, because our transaction
|
* more blocks of the relation; the effects can't be expected to last
|
||||||
* might abort later on; we want to roll back safely in that case.
|
* after the lock is released.
|
||||||
*
|
|
||||||
* This is also called by VACUUM before truncating the relation to the
|
|
||||||
* given number of blocks. It might seem unnecessary for VACUUM to
|
|
||||||
* write dirty pages before firstDelBlock, since VACUUM should already
|
|
||||||
* have committed its changes. However, it is possible for there still
|
|
||||||
* to be dirty pages: if some page had unwritten on-row tuple status
|
|
||||||
* updates from a prior transaction, and VACUUM had no additional
|
|
||||||
* changes to make to that page, then VACUUM won't have written it.
|
|
||||||
* This is harmless in most cases but will break pg_upgrade, which
|
|
||||||
* relies on VACUUM to ensure that *all* tuples have correct on-row
|
|
||||||
* status. So, we check and flush all dirty pages of the rel
|
|
||||||
* regardless of block number.
|
|
||||||
*
|
|
||||||
* In all cases, the caller should be holding AccessExclusiveLock on
|
|
||||||
* the target relation to ensure that no other backend is busy reading
|
|
||||||
* more blocks of the relation (or might do so before we commit).
|
|
||||||
* This should also ensure that no one is busy dirtying these blocks.
|
|
||||||
*
|
|
||||||
* Formerly, we considered it an error condition if we found dirty
|
|
||||||
* buffers here. However, since BufferSync no longer forces out all
|
|
||||||
* dirty buffers at every xact commit, it's possible for dirty buffers
|
|
||||||
* to still be present in the cache due to failure of an earlier
|
|
||||||
* transaction. So, must flush dirty buffers without complaint.
|
|
||||||
*
|
*
|
||||||
* XXX currently it sequentially searches the buffer pool, should be
|
* XXX currently it sequentially searches the buffer pool, should be
|
||||||
* changed to more clever ways of searching.
|
* changed to more clever ways of searching. This routine is not
|
||||||
|
* used in any performance-critical code paths, so it's not worth
|
||||||
|
* adding additional overhead to normal paths to make it go faster;
|
||||||
|
* but see also DropRelFileNodeBuffers.
|
||||||
* --------------------------------------------------------------------
|
* --------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
FlushRelationBuffers(Relation rel)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
BufferDesc *bufHdr;
|
BufferDesc *bufHdr;
|
||||||
@ -1530,38 +1502,26 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
|||||||
for (i = 0; i < NLocBuffer; i++)
|
for (i = 0; i < NLocBuffer; i++)
|
||||||
{
|
{
|
||||||
bufHdr = &LocalBufferDescriptors[i];
|
bufHdr = &LocalBufferDescriptors[i];
|
||||||
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
|
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
|
||||||
|
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
|
||||||
{
|
{
|
||||||
if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
|
ErrorContextCallback errcontext;
|
||||||
{
|
|
||||||
ErrorContextCallback errcontext;
|
|
||||||
|
|
||||||
/* Setup error traceback support for ereport() */
|
/* Setup error traceback support for ereport() */
|
||||||
errcontext.callback = buffer_write_error_callback;
|
errcontext.callback = buffer_write_error_callback;
|
||||||
errcontext.arg = bufHdr;
|
errcontext.arg = bufHdr;
|
||||||
errcontext.previous = error_context_stack;
|
errcontext.previous = error_context_stack;
|
||||||
error_context_stack = &errcontext;
|
error_context_stack = &errcontext;
|
||||||
|
|
||||||
smgrwrite(rel->rd_smgr,
|
smgrwrite(rel->rd_smgr,
|
||||||
bufHdr->tag.blockNum,
|
bufHdr->tag.blockNum,
|
||||||
(char *) LocalBufHdrGetBlock(bufHdr),
|
(char *) LocalBufHdrGetBlock(bufHdr),
|
||||||
true);
|
true);
|
||||||
|
|
||||||
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
|
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
|
||||||
|
|
||||||
/* Pop the error context stack */
|
/* Pop the error context stack */
|
||||||
error_context_stack = errcontext.previous;
|
error_context_stack = errcontext.previous;
|
||||||
}
|
|
||||||
if (LocalRefCount[i] > 0)
|
|
||||||
elog(ERROR, "FlushRelationBuffers(\"%s\" (local), %u): block %u is referenced (%d)",
|
|
||||||
RelationGetRelationName(rel), firstDelBlock,
|
|
||||||
bufHdr->tag.blockNum, LocalRefCount[i]);
|
|
||||||
if (bufHdr->tag.blockNum >= firstDelBlock)
|
|
||||||
{
|
|
||||||
CLEAR_BUFFERTAG(bufHdr->tag);
|
|
||||||
bufHdr->flags = 0;
|
|
||||||
bufHdr->usage_count = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1574,33 +1534,15 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
|
|||||||
for (i = 0; i < NBuffers; i++)
|
for (i = 0; i < NBuffers; i++)
|
||||||
{
|
{
|
||||||
bufHdr = &BufferDescriptors[i];
|
bufHdr = &BufferDescriptors[i];
|
||||||
recheck:
|
|
||||||
LockBufHdr(bufHdr);
|
LockBufHdr(bufHdr);
|
||||||
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node))
|
if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&
|
||||||
|
(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
|
||||||
{
|
{
|
||||||
if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
|
PinBuffer_Locked(bufHdr);
|
||||||
{
|
LWLockAcquire(bufHdr->content_lock, LW_SHARED);
|
||||||
PinBuffer_Locked(bufHdr);
|
FlushBuffer(bufHdr, rel->rd_smgr);
|
||||||
LWLockAcquire(bufHdr->content_lock, LW_SHARED);
|
LWLockRelease(bufHdr->content_lock);
|
||||||
FlushBuffer(bufHdr, rel->rd_smgr);
|
UnpinBuffer(bufHdr, true, false /* no freelist change */ );
|
||||||
LWLockRelease(bufHdr->content_lock);
|
|
||||||
UnpinBuffer(bufHdr, true, false /* no freelist change */ );
|
|
||||||
/*
|
|
||||||
* As soon as we unpin, it's possible for someone to take
|
|
||||||
* the buffer away from us; so loop back to re-lock and
|
|
||||||
* re-check if it still belongs to the target relation.
|
|
||||||
*/
|
|
||||||
goto recheck;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Even though it's not dirty, it could still be pinned because
|
|
||||||
* TerminateIO and UnpinBuffer are separate actions. Hence,
|
|
||||||
* we can't error out on nonzero reference count here.
|
|
||||||
*/
|
|
||||||
if (bufHdr->tag.blockNum >= firstDelBlock)
|
|
||||||
InvalidateBuffer(bufHdr); /* releases spinlock */
|
|
||||||
else
|
|
||||||
UnlockBufHdr(bufHdr);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
UnlockBufHdr(bufHdr);
|
UnlockBufHdr(bufHdr);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.85 2005/01/10 20:02:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.86 2005/03/20 22:00:53 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -461,8 +461,8 @@ static void
|
|||||||
smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
|
smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Get rid of any leftover buffers for the rel (shouldn't be any in
|
* Get rid of any remaining buffers for the relation. bufmgr will just
|
||||||
* the commit case, but there can be in the abort case).
|
* drop them without bothering to write the contents.
|
||||||
*/
|
*/
|
||||||
DropRelFileNodeBuffers(rnode, isTemp, 0);
|
DropRelFileNodeBuffers(rnode, isTemp, 0);
|
||||||
|
|
||||||
@ -599,6 +599,12 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
|
|||||||
{
|
{
|
||||||
BlockNumber newblks;
|
BlockNumber newblks;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get rid of any buffers for the about-to-be-deleted blocks.
|
||||||
|
* bufmgr will just drop them without bothering to write the contents.
|
||||||
|
*/
|
||||||
|
DropRelFileNodeBuffers(reln->smgr_rnode, isTemp, nblocks);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the free space map to forget anything it may have stored for
|
* Tell the free space map to forget anything it may have stored for
|
||||||
* the about-to-be-deleted blocks. We want to be sure it won't return
|
* the about-to-be-deleted blocks. We want to be sure it won't return
|
||||||
@ -873,6 +879,8 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
|
|
||||||
reln = smgropen(xlrec->rnode);
|
reln = smgropen(xlrec->rnode);
|
||||||
|
|
||||||
|
/* Can't use smgrtruncate because it would try to xlog */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First, force bufmgr to drop any buffers it has for the to-be-
|
* First, force bufmgr to drop any buffers it has for the to-be-
|
||||||
* truncated blocks. We must do this, else subsequent
|
* truncated blocks. We must do this, else subsequent
|
||||||
@ -880,8 +888,6 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
*/
|
*/
|
||||||
DropRelFileNodeBuffers(xlrec->rnode, false, xlrec->blkno);
|
DropRelFileNodeBuffers(xlrec->rnode, false, xlrec->blkno);
|
||||||
|
|
||||||
/* Can't use smgrtruncate because it would try to xlog */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the free space map to forget anything it may have stored
|
* Tell the free space map to forget anything it may have stored
|
||||||
* for the about-to-be-deleted blocks. We want to be sure it
|
* for the about-to-be-deleted blocks. We want to be sure it
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.92 2005/03/19 23:27:10 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/storage/bufmgr.h,v 1.93 2005/03/20 22:00:54 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -132,8 +132,7 @@ extern void FlushBufferPool(void);
|
|||||||
extern BlockNumber BufferGetBlockNumber(Buffer buffer);
|
extern BlockNumber BufferGetBlockNumber(Buffer buffer);
|
||||||
extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
|
extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
|
||||||
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
|
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
|
||||||
extern void FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock);
|
extern void FlushRelationBuffers(Relation rel);
|
||||||
extern void DropRelationBuffers(Relation rel);
|
|
||||||
extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
|
extern void DropRelFileNodeBuffers(RelFileNode rnode, bool istemp,
|
||||||
BlockNumber firstDelBlock);
|
BlockNumber firstDelBlock);
|
||||||
extern void DropBuffers(Oid dbid);
|
extern void DropBuffers(Oid dbid);
|
||||||
|
Reference in New Issue
Block a user