*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.129 2008/12/13 19:13:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.130 2008/12/17 09:15:02 heikki Exp $
*
*-------------------------------------------------------------------------
*/
/*
* analyze_rel() -- analyze one relation
+ *
+ * If update_reltuples is true, we update reltuples and relpages columns
+ * in pg_class. Caller should pass false if we're part of VACUUM ANALYZE,
+ * and the VACUUM didn't skip any pages. We only have an approximate count,
+ * so we don't want to overwrite the accurate values already inserted by the
+ * VACUUM in that case. VACUUM always scans all indexes, however, so the
+ * pg_class entries for indexes are never updated if we're part of VACUUM
+ * ANALYZE.
*/
void
analyze_rel(Oid relid, VacuumStmt *vacstmt,
- BufferAccessStrategy bstrategy)
+ BufferAccessStrategy bstrategy, bool update_reltuples)
{
Relation onerel;
int attr_cnt,
* autovacuum code doesn't go nuts trying to get stats about a
* zero-column table.
*/
- if (!vacstmt->vacuum)
+ if (update_reltuples)
pgstat_report_analyze(onerel, 0, 0);
goto cleanup;
}
}
/*
- * If we are running a standalone ANALYZE, update pages/tuples stats 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.
+ * Update pages/tuples stats in pg_class.
*/
- if (!vacstmt->vacuum)
+ if (update_reltuples)
{
vac_update_relstats(onerel,
RelationGetNumberOfBlocks(onerel),
totalrows, hasindex, InvalidTransactionId);
+ /* report results to the stats collector, too */
+ pgstat_report_analyze(onerel, totalrows, totaldeadrows);
+ }
+ /*
+ * Same for indexes. Vacuum always scans all indexes, so if we're part of
+ * VACUUM ANALYZE, don't overwrite the accurate count already inserted by
+ * VACUUM.
+ */
+ if (!vacstmt->vacuum)
+ {
for (ind = 0; ind < nindexes; ind++)
{
AnlIndexData *thisdata = &indexdata[ind];
RelationGetNumberOfBlocks(Irel[ind]),
totalindexrows, false, InvalidTransactionId);
}
-
- /* report results to the stats collector, too */
- pgstat_report_analyze(onerel, totalrows, totaldeadrows);
}
/* We skip to here if there were no analyzable columns */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.382 2008/12/03 13:05:22 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.383 2008/12/17 09:15:02 heikki Exp $
*
*-------------------------------------------------------------------------
*/
const char *stmttype);
static void vac_truncate_clog(TransactionId frozenXID);
static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
- bool for_wraparound);
+ bool for_wraparound, bool *scanned_all);
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages);
foreach(cur, relations)
{
Oid relid = lfirst_oid(cur);
+ bool scanned_all = false;
if (vacstmt->vacuum)
- vacuum_rel(relid, vacstmt, do_toast, for_wraparound);
+ vacuum_rel(relid, vacstmt, do_toast, for_wraparound,
+ &scanned_all);
if (vacstmt->analyze)
{
else
old_context = MemoryContextSwitchTo(anl_context);
- analyze_rel(relid, vacstmt, vac_strategy);
+ analyze_rel(relid, vacstmt, vac_strategy, !scanned_all);
if (use_own_xacts)
{
dirty = true;
}
- /*
- * If anything changed, write out the tuple. Even if nothing changed,
- * force relcache invalidation so all backends reset their rd_targblock
- * --- otherwise it might point to a page we truncated away.
- */
+ /* If anything changed, write out the tuple. */
if (dirty)
- {
heap_inplace_update(rd, ctup);
- /* the above sends a cache inval message */
- }
- else
- {
- /* no need to change tuple, but force relcache inval anyway */
- CacheInvalidateRelcacheByTuple(ctup);
- }
heap_close(rd, RowExclusiveLock);
}
* many small transactions. Otherwise, two-phase locking would require
* us to lock the entire database during one pass of the vacuum cleaner.
*
+ * We'll return true in *scanned_all if the vacuum scanned all heap
+ * pages, and updated pg_class.
+ *
* At entry and exit, we are not inside a transaction.
*/
static void
-vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
+vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound,
+ bool *scanned_all)
{
LOCKMODE lmode;
Relation onerel;
Oid save_userid;
bool save_secdefcxt;
+ if (scanned_all)
+ *scanned_all = false;
+
/* Begin a transaction for vacuuming this relation */
StartTransactionCommand();
if (vacstmt->full)
full_vacuum_rel(onerel, vacstmt);
else
- lazy_vacuum_rel(onerel, vacstmt, vac_strategy);
+ lazy_vacuum_rel(onerel, vacstmt, vac_strategy, scanned_all);
/* Restore userid */
SetUserIdAndContext(save_userid, save_secdefcxt);
* totally unimportant for toast relations.
*/
if (toast_relid != InvalidOid)
- vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
+ vacuum_rel(toast_relid, vacstmt, false, for_wraparound, NULL);
/*
* Now release the session-level lock on the master table.
/* report results to the stats collector, too */
pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared,
- vacstmt->analyze, vacrelstats->rel_tuples);
+ true, vacstmt->analyze, vacrelstats->rel_tuples);
}
if (blkno < nblocks)
{
RelationTruncate(onerel, blkno);
+
+ /* force relcache inval so all backends reset their rd_targblock */
+ CacheInvalidateRelcache(onerel);
+
vacrelstats->rel_pages = blkno; /* set new number of blocks */
}
RelationGetRelationName(onerel),
vacrelstats->rel_pages, relblocks)));
RelationTruncate(onerel, relblocks);
+
+ /* force relcache inval so all backends reset their rd_targblock */
+ CacheInvalidateRelcache(onerel);
+
vacrelstats->rel_pages = relblocks; /* set new number of blocks */
}
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.113 2008/12/04 11:42:23 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.114 2008/12/17 09:15:02 heikki 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"
*/
void
lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
- BufferAccessStrategy bstrategy)
+ BufferAccessStrategy bstrategy, bool *scanned_all)
{
LVRelStats *vacrelstats;
Relation *Irel;
vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
vacrelstats->num_index_scans = 0;
- vacrelstats->scanned_all = true;
+ vacrelstats->scanned_all = true; /* will be cleared if we skip a page */
/* Open all indexes of the relation */
vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
FreeSpaceMapVacuum(onerel);
/*
- * Update statistics in pg_class. We can only advance relfrozenxid if we
- * didn't skip any pages.
+ * Update statistics in pg_class. But only if we didn't skip any pages;
+ * the tuple count only includes tuples from the pages we've visited, and
+ * we haven't frozen tuples in unvisited pages either. The page count is
+ * accurate in any case, but because we use the reltuples / relpages
+ * ratio in the planner, it's better to not update relpages either if we
+ * can't update reltuples.
*/
- vac_update_relstats(onerel,
- vacrelstats->rel_pages, vacrelstats->rel_tuples,
- vacrelstats->hasindex,
- vacrelstats->scanned_all ? FreezeLimit : InvalidOid);
+ if (vacrelstats->scanned_all)
+ vac_update_relstats(onerel,
+ vacrelstats->rel_pages, vacrelstats->rel_tuples,
+ vacrelstats->hasindex,
+ FreezeLimit);
/* report results to the stats collector, too */
- pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared,
+ pgstat_report_vacuum(RelationGetRelid(onerel),
+ onerel->rd_rel->relisshared,
+ vacrelstats->scanned_all,
vacstmt->analyze, vacrelstats->rel_tuples);
/* and log the action if appropriate */
vacrelstats->tuples_deleted, vacrelstats->rel_tuples,
pg_rusage_show(&ru0))));
}
+
+ if (scanned_all)
+ *scanned_all = vacrelstats->scanned_all;
}
*/
RelationTruncate(onerel, new_rel_pages);
+ /* force relcache inval so all backends reset their rd_targblock */
+ CacheInvalidateRelcache(onerel);
+
/*
* Note: once we have truncated, we *must* keep the exclusive lock until
- * commit. The sinval message that will be sent at commit (as a result of
- * vac_update_relstats()) must be received by other backends, to cause
- * them to reset their rd_targblock values, before they can safely access
- * the table again.
+ * commit. The sinval message won't be sent until commit, and other
+ * backends must see it and reset their rd_targblock values before they
+ * can safely access the table again.
*/
/* update statistics */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.643 2008/12/04 17:51:26 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.644 2008/12/17 09:15:02 heikki Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
n->analyze = false;
n->full = $2;
n->freeze_min_age = $3 ? 0 : -1;
- n->scan_all = $3;
+ n->scan_all = $2 || $3;
n->verbose = $4;
n->relation = NULL;
n->va_cols = NIL;
n->analyze = false;
n->full = $2;
n->freeze_min_age = $3 ? 0 : -1;
- n->scan_all = $3;
+ n->scan_all = $2 || $3;
n->verbose = $4;
n->relation = $5;
n->va_cols = NIL;
n->vacuum = true;
n->full = $2;
n->freeze_min_age = $3 ? 0 : -1;
- n->scan_all = $3;
+ n->scan_all = $2 || $3;
n->verbose |= $4;
$$ = (Node *)n;
}
*
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.185 2008/12/08 15:44:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.186 2008/12/17 09:15:03 heikki Exp $
* ----------
*/
#include "postgres.h"
* ---------
*/
void
-pgstat_report_vacuum(Oid tableoid, bool shared,
+pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all,
bool analyze, PgStat_Counter tuples)
{
PgStat_MsgVacuum msg;
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
msg.m_tableoid = tableoid;
+ msg.m_scanned_all = scanned_all;
msg.m_analyze = analyze;
msg.m_autovacuum = IsAutoVacuumWorkerProcess(); /* is this autovacuum? */
msg.m_vacuumtime = GetCurrentTimestamp();
tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
else
tabentry->vacuum_timestamp = msg->m_vacuumtime;
- tabentry->n_live_tuples = msg->m_tuples;
+ if (msg->m_scanned_all)
+ tabentry->n_live_tuples = msg->m_tuples;
/* Resetting dead_tuples to 0 is an approximation ... */
tabentry->n_dead_tuples = 0;
if (msg->m_analyze)
{
- tabentry->last_anl_tuples = msg->m_tuples;
+ if (msg->m_scanned_all)
+ tabentry->last_anl_tuples = msg->m_tuples;
if (msg->m_autovacuum)
tabentry->autovac_analyze_timestamp = msg->m_vacuumtime;
else
{
/* last_anl_tuples must never exceed n_live_tuples+n_dead_tuples */
tabentry->last_anl_tuples = Min(tabentry->last_anl_tuples,
- msg->m_tuples);
+ tabentry->n_live_tuples);
}
}
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.81 2008/11/10 00:49:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.82 2008/12/17 09:15:03 heikki Exp $
*
*-------------------------------------------------------------------------
*/
/* in commands/vacuumlazy.c */
extern void lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
- BufferAccessStrategy bstrategy);
+ BufferAccessStrategy bstrategy, bool *scanned_all);
/* in commands/analyze.c */
extern void analyze_rel(Oid relid, VacuumStmt *vacstmt,
- BufferAccessStrategy bstrategy);
+ BufferAccessStrategy bstrategy, bool update_reltuples);
#endif /* VACUUM_H */
*
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.79 2008/11/03 01:17:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.80 2008/12/17 09:15:03 heikki Exp $
* ----------
*/
#ifndef PGSTAT_H
Oid m_tableoid;
bool m_analyze;
bool m_autovacuum;
+ bool m_scanned_all;
TimestampTz m_vacuumtime;
PgStat_Counter m_tuples;
} PgStat_MsgVacuum;
extern void pgstat_reset_counters(void);
extern void pgstat_report_autovac(Oid dboid);
-extern void pgstat_report_vacuum(Oid tableoid, bool shared,
+extern void pgstat_report_vacuum(Oid tableoid, bool shared, bool scanned_all,
bool analyze, PgStat_Counter tuples);
extern void pgstat_report_analyze(Relation rel,
PgStat_Counter livetuples,