Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > There's two things I'm not happy about in this patch:
>
> > 1. it uses a List to keep the mapping of heap<->toast Oids. This is
> > needed to be able to fetch the main rel's pg_autovacuum entry to process
> > the toast table. This incurs in O(n^2) behavior.
>
> Use a dynahash table instead?
Right, the attached patch does that.
Note that this patch allows a toast table to be vacuumed by the user:
alvherre=# vacuum pg_toast.pg_toast_39970;
VACUUM
I don't have a problem with that, but if anyone thinks this is not a
good idea, please speak up.
--
Alvaro Herrera http://www.CommandPrompt.com/
PostgreSQL Replication, Consulting, Custom Development, 24x7 support
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.375
diff -c -p -r1.375 vacuum.c
*** src/backend/commands/vacuum.c 5 Jun 2008 15:47:32 -0000 1.375
--- src/backend/commands/vacuum.c 8 Aug 2008 16:42:02 -0000
*************** static BufferAccessStrategy vac_strategy
*** 213,220 ****
static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
const char *stmttype);
static void vac_truncate_clog(TransactionId frozenXID);
! static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
! bool for_wraparound);
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages);
--- 213,220 ----
static List *get_rel_oids(Oid relid, const RangeVar *vacrel,
const char *stmttype);
static void vac_truncate_clog(TransactionId frozenXID);
! static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast,
! bool for_wraparound);
static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages);
*************** static Size PageGetFreeSpaceWithFillFact
*** 268,273 ****
--- 268,276 ----
* OID to be processed, and vacstmt->relation is ignored. (The non-invalid
* case is currently only used by autovacuum.)
*
+ * do_toast is passed as FALSE by autovacuum, because it processes TOAST
+ * tables separately.
+ *
* for_wraparound is used by autovacuum to let us know when it's forcing
* a vacuum for wraparound, which should not be auto-cancelled.
*
*************** static Size PageGetFreeSpaceWithFillFact
*** 281,287 ****
* at transaction commit.
*/
void
! vacuum(VacuumStmt *vacstmt, Oid relid,
BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
{
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
--- 284,290 ----
* at transaction commit.
*/
void
! vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel)
{
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
*************** vacuum(VacuumStmt *vacstmt, Oid relid,
*** 433,439 ****
Oid relid = lfirst_oid(cur);
if (vacstmt->vacuum)
! vacuum_rel(relid, vacstmt, RELKIND_RELATION, for_wraparound);
if (vacstmt->analyze)
{
--- 436,442 ----
Oid relid = lfirst_oid(cur);
if (vacstmt->vacuum)
! vacuum_rel(relid, vacstmt, do_toast, for_wraparound);
if (vacstmt->analyze)
{
*************** vac_truncate_clog(TransactionId frozenXI
*** 975,982 ****
* At entry and exit, we are not inside a transaction.
*/
static void
! vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
! bool for_wraparound)
{
LOCKMODE lmode;
Relation onerel;
--- 978,984 ----
* At entry and exit, we are not inside a transaction.
*/
static void
! vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
{
LOCKMODE lmode;
Relation onerel;
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1013,1020 ****
* by autovacuum; it's used to avoid cancelling a vacuum that was
* invoked in an emergency.
*
! * Note: this flag remains set until CommitTransaction or
! * AbortTransaction. We don't want to clear it until we reset
* MyProc->xid/xmin, else OldestXmin might appear to go backwards,
* which is probably Not Good.
*/
--- 1015,1022 ----
* by autovacuum; it's used to avoid cancelling a vacuum that was
* invoked in an emergency.
*
! * Note: these flags remain set until CommitTransaction or
! * AbortTransaction. We don't want to clear them until we reset
* MyProc->xid/xmin, else OldestXmin might appear to go backwards,
* which is probably Not Good.
*/
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1087,1096 ****
}
/*
! * Check that it's a plain table; we used to do this in get_rel_oids() but
! * seems safer to check after we've locked the relation.
*/
! if (onerel->rd_rel->relkind != expected_relkind)
{
ereport(WARNING,
(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
--- 1089,1099 ----
}
/*
! * Check that it's a vacuumable table; we used to do this in get_rel_oids()
! * but seems safer to check after we've locked the relation.
*/
! if (onerel->rd_rel->relkind != RELKIND_RELATION &&
! onerel->rd_rel->relkind != RELKIND_TOASTVALUE)
{
ereport(WARNING,
(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1132,1140 ****
LockRelationIdForSession(&onerelid, lmode);
/*
! * Remember the relation's TOAST relation for later
*/
! toast_relid = onerel->rd_rel->reltoastrelid;
/*
* Switch to the table owner's userid, so that any index functions are
--- 1135,1147 ----
LockRelationIdForSession(&onerelid, lmode);
/*
! * Remember the relation's TOAST relation for later, if the caller asked
! * us to process it.
*/
! if (do_toast)
! toast_relid = onerel->rd_rel->reltoastrelid;
! else
! toast_relid = InvalidOid;
/*
* Switch to the table owner's userid, so that any index functions are
*************** vacuum_rel(Oid relid, VacuumStmt *vacstm
*** 1173,1179 ****
* totally unimportant for toast relations.
*/
if (toast_relid != InvalidOid)
! vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE, for_wraparound);
/*
* Now release the session-level lock on the master table.
--- 1180,1186 ----
* totally unimportant for toast relations.
*/
if (toast_relid != InvalidOid)
! vacuum_rel(toast_relid, vacstmt, false, for_wraparound);
/*
* Now release the session-level lock on the master table.
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.83
diff -c -p -r1.83 autovacuum.c
*** src/backend/postmaster/autovacuum.c 23 Jul 2008 20:20:10 -0000 1.83
--- src/backend/postmaster/autovacuum.c 8 Aug 2008 20:33:24 -0000
***************
*** 93,98 ****
--- 93,99 ----
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "tcop/tcopprot.h"
+ #include "utils/dynahash.h"
#include "utils/flatfiles.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
*************** typedef struct avw_dbase
*** 161,168 ****
/* struct to keep track of tables to vacuum and/or analyze, in 1st pass */
typedef struct av_relation
{
Oid ar_relid;
- Oid ar_toastrelid;
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
--- 162,169 ----
/* struct to keep track of tables to vacuum and/or analyze, in 1st pass */
typedef struct av_relation
{
+ Oid ar_toastrelid; /* must be first -- used as hash key */
Oid ar_relid;
} av_relation;
/* struct to keep track of tables to vacuum and/or analyze, after rechecking */
*************** static void autovac_balance_cost(void);
*** 279,285 ****
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
! static autovac_table *table_recheck_autovac(Oid relid);
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry, bool *dovacuum,
--- 280,286 ----
static void do_autovacuum(void);
static void FreeWorkerInfo(int code, Datum arg);
! static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map);
static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
Form_pg_class classForm,
PgStat_StatTabEntry *tabentry, bool *dovacuum,
*************** static void relation_needs_vacanalyze(Oi
*** 287,293 ****
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
! static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid);
static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
PgStat_StatDBEntry *shared,
PgStat_StatDBEntry *dbentry);
--- 288,295 ----
static void autovacuum_do_vac_analyze(autovac_table *tab,
BufferAccessStrategy bstrategy);
! static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
! HTAB *table_toast_map);
static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
PgStat_StatDBEntry *shared,
PgStat_StatDBEntry *dbentry);
*************** do_autovacuum(void)
*** 1821,1832 ****
HeapScanDesc relScan;
Form_pg_database dbForm;
List *table_oids = NIL;
! List *toast_oids = NIL;
! List *table_toast_list = NIL;
ListCell *volatile cell;
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
BufferAccessStrategy bstrategy;
/*
* StartTransactionCommand and CommitTransactionCommand will automatically
--- 1823,1835 ----
HeapScanDesc relScan;
Form_pg_database dbForm;
List *table_oids = NIL;
! HASHCTL ctl;
! HTAB *table_toast_map;
ListCell *volatile cell;
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
BufferAccessStrategy bstrategy;
+ ScanKeyData key;
/*
* StartTransactionCommand and CommitTransactionCommand will automatically
*************** do_autovacuum(void)
*** 1884,1908 ****
classRel = heap_open(RelationRelationId, AccessShareLock);
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
/*
! * Scan pg_class and determine which tables to vacuum.
*
! * The stats subsystem collects stats for toast tables independently of
! * the stats for their parent tables. We need to check those stats since
! * in cases with short, wide tables there might be proportionally much
! * more activity in the toast table than in its parent.
*
! * Since we can only issue VACUUM against the parent table, we need to
! * transpose a decision to vacuum a toast table into a decision to vacuum
! * its parent. There's no point in considering ANALYZE on a toast table,
! * either. To support this, we keep a list of OIDs of toast tables that
! * need vacuuming alongside the list of regular tables. Regular tables
! * will be entered into the table list even if they appear not to need
! * vacuuming; we go back and re-mark them after finding all the vacuumable
! * toast tables.
*/
! relScan = heap_beginscan(classRel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
--- 1887,1928 ----
classRel = heap_open(RelationRelationId, AccessShareLock);
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
+ /* create hash table for toast <-> main relid mapping */
+ MemSet(&ctl, 0, sizeof(ctl));
+ ctl.keysize = sizeof(Oid);
+ ctl.entrysize = sizeof(Oid) * 2;
+ ctl.hash = oid_hash;
+
+ table_toast_map = hash_create("TOAST to main relid map",
+ 100,
+ &ctl,
+ HASH_ELEM | HASH_FUNCTION);
+
/*
! * Scan pg_class to determine which tables to vacuum.
*
! * We do this in two passes: on the first one we collect the list of
! * plain relations, and on the second one we collect TOAST tables.
! * The reason for doing the second pass is that during it we want to use
! * the main relation's pg_autovacuum entry if the TOAST table does not have
! * any, and we cannot obtain it unless we know beforehand what's the main
! * table OID.
*
! * We need to check TOAST tables separately because in cases with short,
! * wide tables there might be proportionally much more activity in the
! * TOAST table than in its parent.
*/
! ScanKeyInit(&key,
! Anum_pg_class_relkind,
! BTEqualStrategyNumber, F_CHAREQ,
! CharGetDatum(RELKIND_RELATION));
!
! relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
+ /*
+ * On the first pass, we collect main tables to vacuum, and also the
+ * main table relid to TOAST relid mapping.
+ */
while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
*************** do_autovacuum(void)
*** 1915,1929 ****
bool wraparound;
int backendID;
- /* Consider only regular and toast tables. */
- if (classForm->relkind != RELKIND_RELATION &&
- classForm->relkind != RELKIND_TOASTVALUE)
- continue;
-
relid = HeapTupleGetOid(tuple);
/* Fetch the pg_autovacuum tuple for the relation, if any */
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
--- 1935,1944 ----
bool wraparound;
int backendID;
relid = HeapTupleGetOid(tuple);
/* Fetch the pg_autovacuum tuple for the relation, if any */
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid, NULL);
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
*************** do_autovacuum(void)
*** 1952,1958 ****
* vacuum for wraparound, forcibly drop it. Otherwise just
* log a complaint.
*/
! if (wraparound && classForm->relkind == RELKIND_RELATION)
{
ObjectAddress object;
--- 1967,1973 ----
* vacuum for wraparound, forcibly drop it. Otherwise just
* log a complaint.
*/
! if (wraparound)
{
ObjectAddress object;
*************** do_autovacuum(void)
*** 1976,2040 ****
}
}
}
! else if (classForm->relkind == RELKIND_RELATION)
{
/* Plain relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
! else if (OidIsValid(classForm->reltoastrelid))
{
! /*
! * If it doesn't appear to need vacuuming, but it has a toast
! * table, remember the association to revisit below.
! */
! av_relation *rel = palloc(sizeof(av_relation));
! rel->ar_relid = relid;
! rel->ar_toastrelid = classForm->reltoastrelid;
! table_toast_list = lappend(table_toast_list, rel);
}
}
- else
- {
- /* TOAST relations that need vacuum are added to toast_oids */
- if (dovacuum)
- toast_oids = lappend_oid(toast_oids, relid);
- }
if (HeapTupleIsValid(avTup))
heap_freetuple(avTup);
}
heap_endscan(relScan);
- heap_close(avRel, AccessShareLock);
- heap_close(classRel, AccessShareLock);
! /*
! * Add to the list of tables to vacuum, the OIDs of the tables that
! * correspond to the saved OIDs of toast tables needing vacuum.
! */
! foreach(cell, toast_oids)
{
! Oid toastoid = lfirst_oid(cell);
! ListCell *cell2;
! foreach(cell2, table_toast_list)
! {
! av_relation *ar = lfirst(cell2);
! if (ar->ar_toastrelid == toastoid)
! {
! table_oids = lappend_oid(table_oids, ar->ar_relid);
! break;
! }
! }
}
! list_free_deep(table_toast_list);
! table_toast_list = NIL;
! list_free(toast_oids);
! toast_oids = NIL;
/*
* Create a buffer access strategy object for VACUUM to use. We want to
--- 1991,2078 ----
}
}
}
! else
{
/* Plain relations that need work are added to table_oids */
if (dovacuum || doanalyze)
table_oids = lappend_oid(table_oids, relid);
!
! /*
! * Remember the association for the second pass. Note: we must do
! * this even if the table is going to be vacuumed, because we
! * don't automatically vacuum toast tables along the parent table.
! */
! if (OidIsValid(classForm->reltoastrelid))
{
! av_relation *hentry;
! bool found;
! hentry = hash_search(table_toast_map,
! (void *) &classForm->reltoastrelid,
! HASH_ENTER, &found);
! if (!found)
! {
! /* hash_search already filled in the key */
! hentry->ar_relid = relid;
! }
}
}
if (HeapTupleIsValid(avTup))
heap_freetuple(avTup);
}
heap_endscan(relScan);
! /* second pass: check TOAST tables */
! ScanKeyInit(&key,
! Anum_pg_class_relkind,
! BTEqualStrategyNumber, F_CHAREQ,
! CharGetDatum(RELKIND_TOASTVALUE));
!
! relScan = heap_beginscan(classRel, SnapshotNow, 1, &key);
! while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
{
! Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
! Form_pg_autovacuum avForm = NULL;
! PgStat_StatTabEntry *tabentry;
! HeapTuple avTup;
! Oid relid;
! bool dovacuum;
! bool doanalyze;
! bool wraparound;
! /*
! * Skip temp tables (i.e. those in temp namespaces). We cannot safely
! * process other backends' temp tables.
! */
! if (isAnyTempNamespace(classForm->relnamespace))
! continue;
! relid = HeapTupleGetOid(tuple);
!
! /* Fetch the pg_autovacuum tuple for this rel */
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map);
!
! if (HeapTupleIsValid(avTup))
! avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
!
! /* Fetch the pgstat entry for this table */
! tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
! shared, dbentry);
!
! relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
! &dovacuum, &doanalyze, &wraparound);
!
! /* ignore analyze for toast tables */
! if (dovacuum)
! table_oids = lappend_oid(table_oids, relid);
}
! heap_endscan(relScan);
! heap_close(avRel, AccessShareLock);
! heap_close(classRel, AccessShareLock);
/*
* Create a buffer access strategy object for VACUUM to use. We want to
*************** do_autovacuum(void)
*** 2118,2124 ****
* vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL). This is a bug.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid);
if (tab == NULL)
{
/* someone else vacuumed the table */
--- 2156,2162 ----
* vacuumed in the last 500ms (PGSTAT_STAT_INTERVAL). This is a bug.
*/
MemoryContextSwitchTo(AutovacMemCxt);
! tab = table_recheck_autovac(relid, table_toast_map);
if (tab == NULL)
{
/* someone else vacuumed the table */
*************** deleted:
*** 2244,2252 ****
/*
* Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if
* there isn't any. avRel is pg_autovacuum, already open and suitably locked.
*/
static HeapTuple
! get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid)
{
ScanKeyData entry[1];
SysScanDesc avScan;
--- 2282,2295 ----
/*
* Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if
* there isn't any. avRel is pg_autovacuum, already open and suitably locked.
+ *
+ * If table_toast_map is not null, use it to find an alternative OID with which
+ * to search a pg_autovacuum entry, if the passed relid does not yield one
+ * directly.
*/
static HeapTuple
! get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
! HTAB *table_toast_map)
{
ScanKeyData entry[1];
SysScanDesc avScan;
*************** get_pg_autovacuum_tuple_relid(Relation a
*** 2267,2272 ****
--- 2310,2328 ----
systable_endscan(avScan);
+ if (!HeapTupleIsValid(avTup) && table_toast_map != NULL)
+ {
+ av_relation *hentry;
+ bool found;
+
+ hentry = hash_search(table_toast_map, (void *) &relid,
+ HASH_FIND, &found);
+ if (found)
+ /* avoid second recursion */
+ avTup = get_pg_autovacuum_tuple_relid(avRel, hentry->ar_relid,
+ NULL);
+ }
+
return avTup;
}
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2297,2310 ****
/*
* table_recheck_autovac
*
! * Recheck whether a plain table still needs vacuum or analyze; be it because
! * it does directly, or because its TOAST table does. Return value is a valid
! * autovac_table pointer if it does, NULL otherwise.
*
* Note that the returned autovac_table does not have the name fields set.
*/
static autovac_table *
! table_recheck_autovac(Oid relid)
{
Form_pg_autovacuum avForm = NULL;
Form_pg_class classForm;
--- 2353,2365 ----
/*
* table_recheck_autovac
*
! * Recheck whether a table still needs vacuum or analyze. Return value is a
! * valid autovac_table pointer if it does, NULL otherwise.
*
* Note that the returned autovac_table does not have the name fields set.
*/
static autovac_table *
! table_recheck_autovac(Oid relid, HTAB *table_toast_map)
{
Form_pg_autovacuum avForm = NULL;
Form_pg_class classForm;
*************** table_recheck_autovac(Oid relid)
*** 2315,2325 ****
bool doanalyze;
autovac_table *tab = NULL;
PgStat_StatTabEntry *tabentry;
- bool doit = false;
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
! bool wraparound,
! toast_wraparound = false;
/* use fresh stats */
autovac_refresh_stats();
--- 2370,2378 ----
bool doanalyze;
autovac_table *tab = NULL;
PgStat_StatTabEntry *tabentry;
PgStat_StatDBEntry *shared;
PgStat_StatDBEntry *dbentry;
! bool wraparound;
/* use fresh stats */
autovac_refresh_stats();
*************** table_recheck_autovac(Oid relid)
*** 2335,2343 ****
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /* fetch the pg_autovacuum entry, if any */
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid);
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
--- 2388,2402 ----
return NULL;
classForm = (Form_pg_class) GETSTRUCT(classTup);
! /*
! * Fetch the pg_autovacuum entry, if any. For a toast table, also try the
! * main rel's pg_autovacuum entry if there isn't one for the TOAST table
! * itself.
! */
avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
! classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
!
if (HeapTupleIsValid(avTup))
avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
*************** table_recheck_autovac(Oid relid)
*** 2348,2398 ****
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
! /* OK, it needs vacuum by itself */
! if (dovacuum)
! doit = true;
! /* it doesn't need vacuum, but what about it's TOAST table? */
! else if (OidIsValid(classForm->reltoastrelid))
! {
! Oid toastrelid = classForm->reltoastrelid;
! HeapTuple toastClassTup;
!
! toastClassTup = SearchSysCacheCopy(RELOID,
! ObjectIdGetDatum(toastrelid),
! 0, 0, 0);
! if (HeapTupleIsValid(toastClassTup))
! {
! bool toast_dovacuum;
! bool toast_doanalyze;
! bool toast_wraparound;
! Form_pg_class toastClassForm;
! PgStat_StatTabEntry *toasttabentry;
!
! toastClassForm = (Form_pg_class) GETSTRUCT(toastClassTup);
! toasttabentry = get_pgstat_tabentry_relid(toastrelid,
! toastClassForm->relisshared,
! shared, dbentry);
!
! /* note we use the pg_autovacuum entry for the main table */
! relation_needs_vacanalyze(toastrelid, avForm,
! toastClassForm, toasttabentry,
! &toast_dovacuum, &toast_doanalyze,
! &toast_wraparound);
! /* we only consider VACUUM for toast tables */
! if (toast_dovacuum)
! {
! dovacuum = true;
! doit = true;
! }
!
! heap_freetuple(toastClassTup);
! }
! }
!
! if (doanalyze)
! doit = true;
! if (doit)
{
int freeze_min_age;
int vac_cost_limit;
--- 2407,2418 ----
relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
&dovacuum, &doanalyze, &wraparound);
! /* ignore ANALYZE for toast tables */
! if (classForm->relkind == RELKIND_TOASTVALUE)
! doanalyze = false;
! /* OK, it needs something done */
! if (doanalyze || dovacuum)
{
int freeze_min_age;
int vac_cost_limit;
*************** table_recheck_autovac(Oid relid)
*** 2439,2445 ****
tab->at_freeze_min_age = freeze_min_age;
tab->at_vacuum_cost_limit = vac_cost_limit;
tab->at_vacuum_cost_delay = vac_cost_delay;
! tab->at_wraparound = wraparound || toast_wraparound;
tab->at_relname = NULL;
tab->at_nspname = NULL;
tab->at_datname = NULL;
--- 2459,2465 ----
tab->at_freeze_min_age = freeze_min_age;
tab->at_vacuum_cost_limit = vac_cost_limit;
tab->at_vacuum_cost_delay = vac_cost_delay;
! tab->at_wraparound = wraparound;
tab->at_relname = NULL;
tab->at_nspname = NULL;
tab->at_datname = NULL;
*************** autovacuum_do_vac_analyze(autovac_table
*** 2633,2639 ****
/* Let pgstat know what we're doing */
autovac_report_activity(tab);
! vacuum(&vacstmt, tab->at_relid, bstrategy, tab->at_wraparound, true);
}
/*
--- 2653,2659 ----
/* Let pgstat know what we're doing */
autovac_report_activity(tab);
! vacuum(&vacstmt, tab->at_relid, false, bstrategy, tab->at_wraparound, true);
}
/*
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.295
diff -c -p -r1.295 utility.c
*** src/backend/tcop/utility.c 18 Jul 2008 20:26:06 -0000 1.295
--- src/backend/tcop/utility.c 8 Aug 2008 15:51:22 -0000
*************** ProcessUtility(Node *parsetree,
*** 836,842 ****
break;
case T_VacuumStmt:
! vacuum((VacuumStmt *) parsetree, InvalidOid, NULL, false,
isTopLevel);
break;
--- 836,842 ----
break;
case T_VacuumStmt:
! vacuum((VacuumStmt *) parsetree, InvalidOid, true, NULL, false,
isTopLevel);
break;
Index: src/include/commands/vacuum.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/commands/vacuum.h,v
retrieving revision 1.79
diff -c -p -r1.79 vacuum.h
*** src/include/commands/vacuum.h 1 Jul 2008 10:33:09 -0000 1.79
--- src/include/commands/vacuum.h 8 Aug 2008 15:51:22 -0000
*************** extern int vacuum_freeze_min_age;
*** 125,131 ****
/* in commands/vacuum.c */
! extern void vacuum(VacuumStmt *vacstmt, Oid relid,
BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
int *nindexes, Relation **Irel);
--- 125,131 ----
/* in commands/vacuum.c */
! extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast,
BufferAccessStrategy bstrategy, bool for_wraparound, bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
int *nindexes, Relation **Irel);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers