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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers