*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.77 2010/01/02 16:57:34 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.78 2010/02/09 21:43:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
+#include "storage/smgr.h"
/*
*
* HEAP_INSERT_SKIP_FSM is also useful for non-WAL-logged additions to a
* relation, if the caller holds exclusive lock and is careful to invalidate
- * relation->rd_targblock before the first insertion --- that ensures that
+ * relation's smgr_targblock before the first insertion --- that ensures that
* all insertions will occur into newly added pages and not be intermixed
* with tuples from other transactions. That way, a crash can't risk losing
* any committed data of other transactions. (See heap_insert's comments
else if (bistate && bistate->current_buf != InvalidBuffer)
targetBlock = BufferGetBlockNumber(bistate->current_buf);
else
- targetBlock = relation->rd_targblock;
+ targetBlock = RelationGetTargetBlock(relation);
if (targetBlock == InvalidBlockNumber && use_fsm)
{
if (len + saveFreeSpace <= pageFreeSpace)
{
/* use this page as future insert target, too */
- relation->rd_targblock = targetBlock;
+ RelationSetTargetBlock(relation, targetBlock);
return buffer;
}
* current backend to make more insertions or not, which is probably a
* good bet most of the time. So for now, don't add it to FSM yet.
*/
- relation->rd_targblock = BufferGetBlockNumber(buffer);
+ RelationSetTargetBlock(relation, BufferGetBlockNumber(buffer));
return buffer;
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/visibilitymap.c,v 1.7 2010/01/02 16:57:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/visibilitymap.c,v 1.8 2010/02/09 21:43:29 tgl Exp $
*
* INTERFACE ROUTINES
* visibilitymap_clear - clear a bit in the visibility map
#include "storage/bufpage.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
-#include "utils/inval.h"
+
/*#define TRACE_VISIBILITYMAP */
}
/*
- * visibilitymap_test - truncate the visibility map
+ * visibilitymap_truncate - truncate the visibility map
+ *
+ * The caller must hold AccessExclusiveLock on the relation, to ensure that
+ * other backends receive the smgr invalidation event that this function sends
+ * before they access the VM again.
+ *
+ * nheapblocks is the new size of the heap.
*/
void
visibilitymap_truncate(Relation rel, BlockNumber nheapblocks)
elog(DEBUG1, "vm_truncate %s %d", RelationGetRelationName(rel), nheapblocks);
#endif
+ RelationOpenSmgr(rel);
+
/*
* If no visibility map has been created yet for this relation, there's
* nothing to truncate.
else
newnblocks = truncBlock;
- if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) < newnblocks)
+ if (smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM) <= newnblocks)
{
/* nothing to do, the file was already smaller than requested size */
return;
}
+ /* Truncate the unused VM pages, and send smgr inval message */
smgrtruncate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, newnblocks,
rel->rd_istemp);
/*
- * Need to invalidate the relcache entry, because rd_vm_nblocks seen by
- * other backends is no longer valid.
+ * We might as well update the local smgr_vm_nblocks setting.
+ * smgrtruncate sent an smgr cache inval message, which will cause
+ * other backends to invalidate their copy of smgr_vm_nblocks, and
+ * this one too at the next command boundary. But this ensures it
+ * isn't outright wrong until then.
*/
- if (!InRecovery)
- CacheInvalidateRelcache(rel);
-
- rel->rd_vm_nblocks = newnblocks;
+ if (rel->rd_smgr)
+ rel->rd_smgr->smgr_vm_nblocks = newnblocks;
}
/*
RelationOpenSmgr(rel);
/*
- * The current size of the visibility map fork is kept in relcache, to
- * avoid reading beyond EOF. If we haven't cached the size of the map yet,
- * do that first.
+ * If we haven't cached the size of the visibility map fork yet, check it
+ * first. Also recheck if the requested block seems to be past end, since
+ * our cached value might be stale. (We send smgr inval messages on
+ * truncation, but not on extension.)
*/
- if (rel->rd_vm_nblocks == InvalidBlockNumber)
+ if (rel->rd_smgr->smgr_vm_nblocks == InvalidBlockNumber ||
+ blkno >= rel->rd_smgr->smgr_vm_nblocks)
{
if (smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
- rel->rd_vm_nblocks = smgrnblocks(rel->rd_smgr,
- VISIBILITYMAP_FORKNUM);
+ rel->rd_smgr->smgr_vm_nblocks = smgrnblocks(rel->rd_smgr,
+ VISIBILITYMAP_FORKNUM);
else
- rel->rd_vm_nblocks = 0;
+ rel->rd_smgr->smgr_vm_nblocks = 0;
}
/* Handle requests beyond EOF */
- if (blkno >= rel->rd_vm_nblocks)
+ if (blkno >= rel->rd_smgr->smgr_vm_nblocks)
{
if (extend)
vm_extend(rel, blkno + 1);
* separate lock tag type for it.
*
* Note that another backend might have extended or created the relation
- * before we get the lock.
+ * by the time we get the lock.
*/
LockRelationForExtension(rel, ExclusiveLock);
- /* Create the file first if it doesn't exist */
- if ((rel->rd_vm_nblocks == 0 || rel->rd_vm_nblocks == InvalidBlockNumber)
- && !smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
- {
+ /* Might have to re-open if a cache flush happened */
+ RelationOpenSmgr(rel);
+
+ /*
+ * Create the file first if it doesn't exist. If smgr_vm_nblocks
+ * is positive then it must exist, no need for an smgrexists call.
+ */
+ if ((rel->rd_smgr->smgr_vm_nblocks == 0 ||
+ rel->rd_smgr->smgr_vm_nblocks == InvalidBlockNumber) &&
+ !smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM))
smgrcreate(rel->rd_smgr, VISIBILITYMAP_FORKNUM, false);
- vm_nblocks_now = 0;
- }
- else
- vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
+
+ vm_nblocks_now = smgrnblocks(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
while (vm_nblocks_now < vm_nblocks)
{
vm_nblocks_now++;
}
+ /* Update local cache with the up-to-date size */
+ rel->rd_smgr->smgr_vm_nblocks = vm_nblocks_now;
+
UnlockRelationForExtension(rel, ExclusiveLock);
pfree(pg);
-
- /* Update the relcache with the up-to-date size */
- if (!InRecovery)
- CacheInvalidateRelcache(rel);
- rel->rd_vm_nblocks = vm_nblocks_now;
}
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.69 2010/01/02 16:57:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.70 2010/02/09 21:43:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
rel->rd_lockInfo.lockRelId.dbId = rnode.dbNode;
rel->rd_lockInfo.lockRelId.relId = rnode.relNode;
- rel->rd_targblock = InvalidBlockNumber;
- rel->rd_fsm_nblocks = InvalidBlockNumber;
- rel->rd_vm_nblocks = InvalidBlockNumber;
rel->rd_smgr = NULL;
return rel;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/storage.c,v 1.9 2010/02/08 19:59:49 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/storage.c,v 1.10 2010/02/09 21:43:30 tgl Exp $
*
* NOTES
* Some of this code used to be in storage/smgr/smgr.c, and the
/* Open it at the smgr level if not already done */
RelationOpenSmgr(rel);
- /* Make sure rd_targblock isn't pointing somewhere past end */
- rel->rd_targblock = InvalidBlockNumber;
+ /*
+ * Make sure smgr_targblock etc aren't pointing somewhere past new end
+ */
+ rel->rd_smgr->smgr_targblock = InvalidBlockNumber;
+ rel->rd_smgr->smgr_fsm_nblocks = InvalidBlockNumber;
+ rel->rd_smgr->smgr_vm_nblocks = InvalidBlockNumber;
/* Truncate the FSM first if it exists */
fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
{
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) XLogRecGetData(record);
SMgrRelation reln;
+ Relation rel;
reln = smgropen(xlrec->rnode);
/* Also tell xlogutils.c about it */
XLogTruncateRelation(xlrec->rnode, MAIN_FORKNUM, xlrec->blkno);
- /* Truncate FSM too */
- if (smgrexists(reln, FSM_FORKNUM))
- {
- Relation rel = CreateFakeRelcacheEntry(xlrec->rnode);
+ /* Truncate FSM and VM too */
+ rel = CreateFakeRelcacheEntry(xlrec->rnode);
+ if (smgrexists(reln, FSM_FORKNUM))
FreeSpaceMapTruncateRel(rel, xlrec->blkno);
- FreeFakeRelcacheEntry(rel);
- }
+ if (smgrexists(reln, VISIBILITYMAP_FORKNUM))
+ visibilitymap_truncate(rel, xlrec->blkno);
+
+ FreeFakeRelcacheEntry(rel);
}
else
elog(PANIC, "smgr_redo: unknown op code %u", info);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.199 2010/02/07 22:40:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.200 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/procarray.h"
+#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
indexForm->indisclustered = false;
simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
CatalogUpdateIndexes(pg_index, indexTuple);
- /* Ensure we see the update in the index's relcache entry */
- CacheInvalidateRelcacheByRelid(thisIndexOid);
}
else if (thisIndexOid == indexOid)
{
indexForm->indisclustered = true;
simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
CatalogUpdateIndexes(pg_index, indexTuple);
- /* Ensure we see the update in the index's relcache entry */
- CacheInvalidateRelcacheByRelid(thisIndexOid);
}
heap_freetuple(indexTuple);
}
XLogReportUnloggedStatement(reason);
}
- /* use_wal off requires rd_targblock be initially invalid */
- Assert(NewHeap->rd_targblock == InvalidBlockNumber);
+ /* use_wal off requires smgr_targblock be initially invalid */
+ Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber);
/*
* If both tables have TOAST tables, perform toast swap by content. It is
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.164 2010/01/02 16:57:37 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.165 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
+#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
sm->magic = SEQ_MAGIC;
/* hack: ensure heap_insert will insert on the just-created page */
- rel->rd_targblock = 0;
+ RelationSetTargetBlock(rel, 0);
/* Now form & insert sequence tuple */
tuple = heap_form_tuple(tupDesc, value, null);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.406 2010/02/08 16:50:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.407 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Oid save_userid;
int save_sec_context;
int save_nestlevel;
- bool heldoff;
if (scanned_all)
*scanned_all = false;
cluster_rel(relid, InvalidOid, false,
(vacstmt->options & VACOPT_VERBOSE) != 0,
vacstmt->freeze_min_age, vacstmt->freeze_table_age);
- heldoff = false;
}
else
- heldoff = lazy_vacuum_rel(onerel, vacstmt, vac_strategy, scanned_all);
+ lazy_vacuum_rel(onerel, vacstmt, vac_strategy, scanned_all);
/* Roll back any GUC changes executed by index functions */
AtEOXact_GUC(false, save_nestlevel);
PopActiveSnapshot();
CommitTransactionCommand();
- /* now we can allow interrupts again, if disabled */
- if (heldoff)
- RESUME_INTERRUPTS();
-
/*
* If the relation has a secondary toast rel, vacuum that too while we
* still hold the session lock on the master table. Note however that
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.130 2010/02/09 00:28:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.131 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
-#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_rusage.h"
LVRelStats *vacrelstats);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
int tupindex, LVRelStats *vacrelstats);
-static bool lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats);
+static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats);
static BlockNumber count_nondeletable_pages(Relation onerel,
LVRelStats *vacrelstats);
static void lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks);
*
* At entry, we have already established a transaction and opened
* and locked the relation.
- *
- * The return value indicates whether this function has held off
- * interrupts -- if true, caller must RESUME_INTERRUPTS() after commit.
*/
-bool
+void
lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
BufferAccessStrategy bstrategy, bool *scanned_all)
{
TimestampTz starttime = 0;
bool scan_all;
TransactionId freezeTableLimit;
- bool heldoff = false;
pg_rusage_init(&ru0);
/* Done with indexes */
vac_close_indexes(nindexes, Irel, NoLock);
- /* Vacuum the Free Space Map */
- FreeSpaceMapVacuum(onerel);
-
/*
* Optionally truncate the relation.
*
- * NB: there should be as little code as possible after this point,
- * to minimize the chance of failure as well as the time spent ignoring
- * cancel/die interrupts.
- *
* Don't even think about it unless we have a shot at releasing a goodly
* number of pages. Otherwise, the time taken isn't worth it.
*/
if (possibly_freeable > 0 &&
(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION))
- heldoff = lazy_truncate_heap(onerel, vacrelstats);
+ lazy_truncate_heap(onerel, vacrelstats);
+
+ /* Vacuum the Free Space Map */
+ FreeSpaceMapVacuum(onerel);
/*
* Update statistics in pg_class. But only if we didn't skip any pages;
if (scanned_all)
*scanned_all = vacrelstats->scanned_all;
-
- return heldoff;
}
/*
/*
* lazy_truncate_heap - try to truncate off any empty pages at the end
- *
- * The return value indicates whether this function has held off
- * interrupts -- if true, caller must RESUME_INTERRUPTS() after commit.
*/
-static bool
+static void
lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
{
BlockNumber old_rel_pages = vacrelstats->rel_pages;
* possible considering we already hold a lower-grade lock).
*/
if (!ConditionalLockRelation(onerel, AccessExclusiveLock))
- return false;
+ return;
/*
* Now that we have exclusive lock, look to see if the rel has grown
/* might as well use the latest news when we update pg_class stats */
vacrelstats->rel_pages = new_rel_pages;
UnlockRelation(onerel, AccessExclusiveLock);
- return false;
+ return;
}
/*
{
/* can't do anything after all */
UnlockRelation(onerel, AccessExclusiveLock);
- return false;
+ return;
}
/*
- * Prevent cancel/die interrupts from now till commit. Once we have
- * truncated, it is essential that we send the sinval message before
- * releasing exclusive lock on the relation; both of which will
- * happen during commit. Other backends must receive the sinval
- * message to reset their rd_targblock values before they can safely
- * write to the table again. While we can't positively guarantee
- * no error before commit, we can at least prevent cancel interrupts.
- *
- * XXX it would be better if we had a way to send the inval message
- * nontransactionally; an error after the truncate will mean that the
- * message is lost. Note however that turning this all into a critical
- * section would not be an improvement. Making it critical would mean
- * that an error forces PANIC, whereas losing the sinval will at worst
- * cause unexpected nonfatal errors in other sessions.
+ * Okay to truncate.
*/
- HOLD_INTERRUPTS();
-
- /* force relcache inval so all backends reset their rd_targblock */
- CacheInvalidateRelcache(onerel);
+ RelationTruncate(onerel, new_rel_pages);
/*
- * Okay to truncate. Do as little as possible between here and commit.
+ * We can release the exclusive lock as soon as we have truncated. Other
+ * backends can't safely access the relation until they have processed the
+ * smgr invalidation that smgrtruncate sent out ... but that should happen
+ * as part of standard invalidation processing once they acquire lock on
+ * the relation.
*/
- RelationTruncate(onerel, new_rel_pages);
+ UnlockRelation(onerel, AccessExclusiveLock);
/* update statistics */
vacrelstats->rel_pages = new_rel_pages;
old_rel_pages, new_rel_pages),
errdetail("%s.",
pg_rusage_show(&ru0))));
-
- return true; /* interrupts are held off */
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.345 2010/02/07 20:48:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.346 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parsetree.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
+#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
(XLogIsNeeded() ? 0 : HEAP_INSERT_SKIP_WAL);
myState->bistate = GetBulkInsertState();
- /* Not using WAL requires rd_targblock be initially invalid */
- Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber);
+ /* Not using WAL requires smgr_targblock be initially invalid */
+ Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber);
}
/*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.75 2010/02/09 00:28:57 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.76 2010/02/09 21:43:30 tgl Exp $
*
*
* NOTES:
#include "access/htup.h"
#include "access/xlogutils.h"
-#include "storage/bufpage.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
+#include "storage/bufpage.h"
#include "storage/freespace.h"
#include "storage/fsm_internals.h"
#include "storage/lmgr.h"
#include "storage/lwlock.h"
#include "storage/smgr.h"
#include "utils/rel.h"
-#include "utils/inval.h"
-#include "miscadmin.h"
+
/*
* We use just one byte to store the amount of free space on a page, so we
/*
* FreeSpaceMapTruncateRel - adjust for truncation of a relation.
*
- * The caller must hold AccessExclusiveLock on the relation, to ensure
- * that other backends receive the relcache invalidation event that this
- * function sends, before accessing the FSM again.
+ * The caller must hold AccessExclusiveLock on the relation, to ensure that
+ * other backends receive the smgr invalidation event that this function sends
+ * before they access the FSM again.
*
* nblocks is the new size of the heap.
*/
return; /* nothing to do; the FSM was already smaller */
}
- /* Truncate the unused FSM pages */
+ /* Truncate the unused FSM pages, and send smgr inval message */
smgrtruncate(rel->rd_smgr, FSM_FORKNUM, new_nfsmblocks, rel->rd_istemp);
/*
- * Need to invalidate the relcache entry, because rd_fsm_nblocks seen by
- * other backends is no longer valid.
+ * We might as well update the local smgr_fsm_nblocks setting.
+ * smgrtruncate sent an smgr cache inval message, which will cause
+ * other backends to invalidate their copy of smgr_fsm_nblocks, and
+ * this one too at the next command boundary. But this ensures it
+ * isn't outright wrong until then.
*/
- if (!InRecovery)
- CacheInvalidateRelcache(rel);
-
- rel->rd_fsm_nblocks = new_nfsmblocks;
+ if (rel->rd_smgr)
+ rel->rd_smgr->smgr_fsm_nblocks = new_nfsmblocks;
}
/*
RelationOpenSmgr(rel);
- /* If we haven't cached the size of the FSM yet, check it first */
- if (rel->rd_fsm_nblocks == InvalidBlockNumber)
+ /*
+ * If we haven't cached the size of the FSM yet, check it first. Also
+ * recheck if the requested block seems to be past end, since our
+ * cached value might be stale. (We send smgr inval messages on
+ * truncation, but not on extension.)
+ */
+ if (rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber ||
+ blkno >= rel->rd_smgr->smgr_fsm_nblocks)
{
if (smgrexists(rel->rd_smgr, FSM_FORKNUM))
- rel->rd_fsm_nblocks = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+ rel->rd_smgr->smgr_fsm_nblocks = smgrnblocks(rel->rd_smgr,
+ FSM_FORKNUM);
else
- rel->rd_fsm_nblocks = 0;
+ rel->rd_smgr->smgr_fsm_nblocks = 0;
}
/* Handle requests beyond EOF */
- if (blkno >= rel->rd_fsm_nblocks)
+ if (blkno >= rel->rd_smgr->smgr_fsm_nblocks)
{
if (extend)
fsm_extend(rel, blkno + 1);
* it.
*
* Note that another backend might have extended or created the relation
- * before we get the lock.
+ * by the time we get the lock.
*/
LockRelationForExtension(rel, ExclusiveLock);
- /* Create the FSM file first if it doesn't exist */
- if ((rel->rd_fsm_nblocks == 0 || rel->rd_fsm_nblocks == InvalidBlockNumber)
- && !smgrexists(rel->rd_smgr, FSM_FORKNUM))
- {
+ /* Might have to re-open if a cache flush happened */
+ RelationOpenSmgr(rel);
+
+ /*
+ * Create the FSM file first if it doesn't exist. If smgr_fsm_nblocks
+ * is positive then it must exist, no need for an smgrexists call.
+ */
+ if ((rel->rd_smgr->smgr_fsm_nblocks == 0 ||
+ rel->rd_smgr->smgr_fsm_nblocks == InvalidBlockNumber) &&
+ !smgrexists(rel->rd_smgr, FSM_FORKNUM))
smgrcreate(rel->rd_smgr, FSM_FORKNUM, false);
- fsm_nblocks_now = 0;
- }
- else
- fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
+
+ fsm_nblocks_now = smgrnblocks(rel->rd_smgr, FSM_FORKNUM);
while (fsm_nblocks_now < fsm_nblocks)
{
fsm_nblocks_now++;
}
+ /* Update local cache with the up-to-date size */
+ rel->rd_smgr->smgr_fsm_nblocks = fsm_nblocks_now;
+
UnlockRelationForExtension(rel, ExclusiveLock);
pfree(pg);
-
- /* Update the relcache with the up-to-date size */
- if (!InRecovery)
- CacheInvalidateRelcache(rel);
- rel->rd_fsm_nblocks = fsm_nblocks_now;
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.119 2010/02/03 01:14:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.120 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* hash_search already filled in the lookup key */
reln->smgr_owner = NULL;
+ reln->smgr_targblock = InvalidBlockNumber;
+ reln->smgr_fsm_nblocks = InvalidBlockNumber;
+ reln->smgr_vm_nblocks = InvalidBlockNumber;
reln->smgr_which = 0; /* we only have md.c at present */
/* mark it not open */
* anyway).
*/
+ /*
+ * Send a shared-inval message to force other backends to close any
+ * dangling smgr references they may have for this rel. We should do
+ * this before starting the actual unlinking, in case we fail partway
+ * through that step. Note that the sinval message will eventually come
+ * back to this backend, too, and thereby provide a backstop that we
+ * closed our own smgr rel.
+ */
+ CacheInvalidateSmgr(rnode);
+
/*
* Delete the physical file(s).
*
* xact.
*/
(*(smgrsw[which].smgr_unlink)) (rnode, forknum, isRedo);
-
- /*
- * Lastly, send a shared-inval message to force other backends to close
- * any dangling smgr references they may have for this rel. We do this
- * last because the sinval will eventually come back to this backend, too,
- * and thereby provide a backstop that we closed our own smgr rel.
- */
- CacheInvalidateSmgr(rnode);
}
/*
*/
DropRelFileNodeBuffers(reln->smgr_rnode, forknum, isTemp, nblocks);
- /*
- * Do the truncation.
- */
- (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks,
- isTemp);
-
/*
* Send a shared-inval message to force other backends to close any smgr
* references they may have for this rel. This is useful because they
- * might have open file pointers to segments that got removed. (The inval
+ * might have open file pointers to segments that got removed, and/or
+ * smgr_targblock variables pointing past the new rel end. (The inval
* message will come back to our backend, too, causing a
- * probably-unnecessary smgr flush. But we don't expect that this is
- * a performance-critical path.)
+ * probably-unnecessary local smgr flush. But we don't expect that this
+ * is a performance-critical path.) As in the unlink code, we want to
+ * be sure the message is sent before we start changing things on-disk.
*/
CacheInvalidateSmgr(reln->smgr_rnode);
+
+ /*
+ * Do the truncation.
+ */
+ (*(smgrsw[reln->smgr_which].smgr_truncate)) (reln, forknum, nblocks,
+ isTemp);
}
/*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.304 2010/02/08 05:53:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.305 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
relation = (Relation) palloc0(sizeof(RelationData));
- /*
- * clear fields of reldesc that should initialize to something non-zero
- */
- relation->rd_targblock = InvalidBlockNumber;
- relation->rd_fsm_nblocks = InvalidBlockNumber;
- relation->rd_vm_nblocks = InvalidBlockNumber;
-
/* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL;
* allocate new relation desc, clear all fields of reldesc
*/
relation = (Relation) palloc0(sizeof(RelationData));
- relation->rd_targblock = InvalidBlockNumber;
- relation->rd_fsm_nblocks = InvalidBlockNumber;
- relation->rd_vm_nblocks = InvalidBlockNumber;
/* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL;
/* Should be closed at smgr level */
Assert(relation->rd_smgr == NULL);
- /*
- * Must reset targblock, fsm_nblocks and vm_nblocks in case rel was
- * truncated
- */
- relation->rd_targblock = InvalidBlockNumber;
- relation->rd_fsm_nblocks = InvalidBlockNumber;
- relation->rd_vm_nblocks = InvalidBlockNumber;
- /* Must free any AM cached data, too */
+ /* Must free any AM cached data upon relcache flush */
if (relation->rd_amcache)
pfree(relation->rd_amcache);
relation->rd_amcache = NULL;
/*
* Never, never ever blow away a nailed-in system relation, because 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. Likewise reset the fsm and vm size info. Also, redo
- * RelationInitPhysicalAddr in case it is a mapped relation whose mapping
- * changed.
+ * be unable to recover. However, we must redo RelationInitPhysicalAddr
+ * in case it is a mapped relation whose mapping changed.
*
* 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
*/
if (relation->rd_isnailed)
{
- relation->rd_targblock = InvalidBlockNumber;
- relation->rd_fsm_nblocks = InvalidBlockNumber;
- relation->rd_vm_nblocks = InvalidBlockNumber;
- /* We must recalculate physical address in case it changed */
RelationInitPhysicalAddr(relation);
if (relation->rd_rel->relkind == RELKIND_INDEX)
*/
rel = (Relation) palloc0(sizeof(RelationData));
- rel->rd_targblock = InvalidBlockNumber;
- rel->rd_fsm_nblocks = InvalidBlockNumber;
- rel->rd_vm_nblocks = InvalidBlockNumber;
-
/* make sure relation is marked as having no open file yet */
rel->rd_smgr = NULL;
* Reset transient-state fields in the relcache entry
*/
rel->rd_smgr = NULL;
- rel->rd_targblock = InvalidBlockNumber;
- rel->rd_fsm_nblocks = InvalidBlockNumber;
- rel->rd_vm_nblocks = InvalidBlockNumber;
if (rel->rd_isnailed)
rel->rd_refcnt = 1;
else
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.88 2010/02/08 04:33:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.89 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void vacuum_delay_point(void);
/* in commands/vacuumlazy.c */
-extern bool lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
+extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
BufferAccessStrategy bstrategy, bool *scanned_all);
/* in commands/analyze.c */
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.69 2010/01/02 16:58:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/smgr.h,v 1.70 2010/02/09 21:43:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* pointer to owning pointer, or NULL if none */
struct SMgrRelationData **smgr_owner;
+ /*
+ * These next three fields are not actually used or manipulated by smgr,
+ * except that they are reset to InvalidBlockNumber upon a cache flush
+ * event (in particular, upon truncation of the relation). Higher levels
+ * store cached state here so that it will be reset when truncation
+ * happens. In all three cases, InvalidBlockNumber means "unknown".
+ */
+ BlockNumber smgr_targblock; /* current insertion target block */
+ BlockNumber smgr_fsm_nblocks; /* last known size of fsm fork */
+ BlockNumber smgr_vm_nblocks; /* last known size of vm fork */
+
/* additional public fields may someday exist here */
/*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.122 2010/02/07 20:48:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.123 2010/02/09 21:43:30 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_targblock; /* current insertion target block, or
- * InvalidBlockNumber */
int rd_refcnt; /* reference count */
bool rd_istemp; /* rel is a temporary relation */
bool rd_islocaltemp; /* rel is a temp rel of this session */
*/
Oid rd_toastoid; /* Real TOAST table's OID, or InvalidOid */
- /*
- * sizes of the free space and visibility map forks, or InvalidBlockNumber
- * if not known yet
- */
- BlockNumber rd_fsm_nblocks;
- BlockNumber rd_vm_nblocks;
-
/* use "struct" here to avoid needing to include pgstat.h: */
struct PgStat_TableStatus *pgstat_info; /* statistics collection area */
} RelationData;
} \
} while (0)
+/*
+ * RelationGetTargetBlock
+ * Fetch relation's current insertion target block.
+ *
+ * Returns InvalidBlockNumber if there is no current target block. Note
+ * that the target block status is discarded on any smgr-level invalidation.
+ */
+#define RelationGetTargetBlock(relation) \
+ ( (relation)->rd_smgr != NULL ? (relation)->rd_smgr->smgr_targblock : InvalidBlockNumber )
+
+/*
+ * RelationSetTargetBlock
+ * Set relation's current insertion target block.
+ */
+#define RelationSetTargetBlock(relation, targblock) \
+ do { \
+ RelationOpenSmgr(relation); \
+ (relation)->rd_smgr->smgr_targblock = (targblock); \
+ } while (0)
+
/*
* RELATION_IS_LOCAL
* If a rel is either temp or newly created in the current transaction,