*** a/src/backend/postmaster/autovacuum.c --- b/src/backend/postmaster/autovacuum.c *************** *** 1890,1895 **** get_database_list(void) --- 1890,1919 ---- return dblist; } + typedef struct vacuum_table + { + Oid reloid; + bool wraparound; + } vacuum_table; + + /* + * qsort comparator. Tables marked for wraparound sort first. + */ + static int + vacpriority_comparator(const void *a, const void *b) + { + const vacuum_table *taba = *(vacuum_table *const *) a; + const vacuum_table *tabb = *(vacuum_table *const *) b; + + if (taba->wraparound == tabb->wraparound) + return 0; + + if (taba->wraparound) + return -1; + else + return 1; + } + /* * Process a database table-by-table * *************** *** 1903,1917 **** do_autovacuum(void) HeapTuple tuple; 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; TupleDesc pg_class_desc; /* * StartTransactionCommand and CommitTransactionCommand will automatically --- 1927,1943 ---- HeapTuple tuple; HeapScanDesc relScan; Form_pg_database dbForm; HASHCTL ctl; HTAB *table_toast_map; PgStat_StatDBEntry *shared; PgStat_StatDBEntry *dbentry; BufferAccessStrategy bstrategy; ScanKeyData key; TupleDesc pg_class_desc; + vacuum_table **tables; + int ntables; + int maxtables; + int i; /* * StartTransactionCommand and CommitTransactionCommand will automatically *************** *** 1986,1991 **** do_autovacuum(void) --- 2012,2022 ---- &ctl, HASH_ELEM | HASH_FUNCTION); + /* initialize our tasklist */ + ntables = 0; + maxtables = 32; + tables = palloc(maxtables * sizeof(vacuum_table *)); + /* * Scan pg_class to determine which tables to vacuum. * *************** *** 2077,2085 **** do_autovacuum(void) } else { ! /* 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 --- 2108,2133 ---- } else { ! /* relations that need work are added to our tasklist */ if (dovacuum || doanalyze) ! { ! vacuum_table *tab; ! ! /* enlarge the array if necessary */ ! if (ntables >= maxtables) ! { ! maxtables *= 2; ! tables = repalloc(tables, ! maxtables * sizeof(vacuum_table *)); ! } ! ! tab = palloc(sizeof(vacuum_table)); ! ! tab->reloid = relid; ! tab->wraparound = wraparound; ! ! tables[ntables++] = tab; ! } /* * Remember the association for the second pass. Note: we must do *************** *** 2162,2168 **** do_autovacuum(void) /* ignore analyze for toast tables */ if (dovacuum) ! table_oids = lappend_oid(table_oids, relid); } heap_endscan(relScan); --- 2210,2233 ---- /* ignore analyze for toast tables */ if (dovacuum) ! { ! vacuum_table *tab; ! ! /* enlarge the array if necessary */ ! if (ntables >= maxtables) ! { ! maxtables *= 2; ! tables = repalloc(tables, ! maxtables * sizeof(vacuum_table *)); ! } ! ! tab = palloc(sizeof(vacuum_table)); ! ! tab->reloid = relid; ! tab->wraparound = wraparound; ! ! tables[ntables++] = tab; ! } } heap_endscan(relScan); *************** *** 2185,2196 **** do_autovacuum(void) ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * Perform operations on collected tables. */ ! foreach(cell, table_oids) { - Oid relid = lfirst_oid(cell); autovac_table *tab; bool skipit; int stdVacuumCostDelay; --- 2250,2264 ---- ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_MAXSIZE); + /* sort our task list */ + qsort(tables, ntables, sizeof(vacuum_table *), + vacpriority_comparator); + /* * Perform operations on collected tables. */ ! for (i = 0; i < ntables; i++) { autovac_table *tab; bool skipit; int stdVacuumCostDelay; *************** *** 2224,2230 **** do_autovacuum(void) if (worker->wi_dboid != MyDatabaseId) continue; ! if (worker->wi_tableoid == relid) { skipit = true; break; --- 2292,2298 ---- if (worker->wi_dboid != MyDatabaseId) continue; ! if (worker->wi_tableoid == tables[i]->reloid) { skipit = true; break; *************** *** 2248,2254 **** do_autovacuum(void) * the race condition is not closed but it is very small. */ MemoryContextSwitchTo(AutovacMemCxt); ! tab = table_recheck_autovac(relid, table_toast_map, pg_class_desc); if (tab == NULL) { /* someone else vacuumed the table, or it went away */ --- 2316,2323 ---- * the race condition is not closed but it is very small. */ MemoryContextSwitchTo(AutovacMemCxt); ! tab = table_recheck_autovac(tables[i]->reloid, table_toast_map, ! pg_class_desc); if (tab == NULL) { /* someone else vacuumed the table, or it went away */ *************** *** 2260,2266 **** do_autovacuum(void) * Ok, good to go. Store the table in shared memory before releasing * the lock so that other workers don't vacuum it concurrently. */ ! MyWorkerInfo->wi_tableoid = relid; LWLockRelease(AutovacuumScheduleLock); /* --- 2329,2335 ---- * Ok, good to go. Store the table in shared memory before releasing * the lock so that other workers don't vacuum it concurrently. */ ! MyWorkerInfo->wi_tableoid = tables[i]->reloid; LWLockRelease(AutovacuumScheduleLock); /* *************** *** 2361,2366 **** deleted: --- 2430,2436 ---- if (tab->at_relname != NULL) pfree(tab->at_relname); pfree(tab); + pfree(tables[i]); /* * Remove my info from shared memory. We could, but intentionally