aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/autovacuum.c
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2006-07-10 16:20:52 +0000
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2006-07-10 16:20:52 +0000
commitd4cef0aa2a55fafbd9ce2783c1eb9e0157c6781e (patch)
tree321bcb690f559b2b87fe51b3fe094d9776ce690a /src/backend/postmaster/autovacuum.c
parente627c9b9a6aff106adba0c486c385a53eedf6c90 (diff)
downloadpostgresql-d4cef0aa2a55fafbd9ce2783c1eb9e0157c6781e.tar.gz
postgresql-d4cef0aa2a55fafbd9ce2783c1eb9e0157c6781e.zip
Improve vacuum code to track minimum Xids per table instead of per database.
To this end, add a couple of columns to pg_class, relminxid and relvacuumxid, based on which we calculate the pg_database columns after each vacuum. We now force all databases to be vacuumed, even template ones. A backend noticing too old a database (meaning pg_database.datminxid is in danger of falling behind Xid wraparound) will signal the postmaster, which in turn will start an autovacuum iteration to process the offending database. In principle this is only there to cope with frozen (non-connectable) databases without forcing users to set them to connectable, but it could force regular user database to go through a database-wide vacuum at any time. Maybe we should warn users about this somehow. Of course the real solution will be to use autovacuum all the time ;-) There are some additional improvements we could have in this area: for example the vacuum code could be smarter about not updating pg_database for each table when called by autovacuum, and do it only once the whole autovacuum iteration is done. I updated the system catalogs documentation, but I didn't modify the maintenance section. Also having some regression tests for this would be nice but it's not really a very straightforward thing to do. Catalog version bumped due to system catalog changes.
Diffstat (limited to 'src/backend/postmaster/autovacuum.c')
-rw-r--r--src/backend/postmaster/autovacuum.c112
1 files changed, 72 insertions, 40 deletions
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 6f9bfe2e9af..d9d691479d9 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.21 2006/06/27 22:16:43 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.22 2006/07/10 16:20:50 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -79,7 +79,7 @@ typedef struct autovac_dbase
{
Oid oid;
char *name;
- TransactionId frozenxid;
+ TransactionId minxid;
TransactionId vacuumxid;
PgStat_StatDBEntry *entry;
int32 age;
@@ -126,10 +126,6 @@ autovac_start(void)
time_t curtime;
pid_t AutoVacPID;
- /* Do nothing if no autovacuum process needed */
- if (!AutoVacuumingActive())
- return 0;
-
/*
* Do nothing if too soon since last autovacuum exit. This limits how
* often the daemon runs. Since the time per iteration can be quite
@@ -144,6 +140,7 @@ autovac_start(void)
*
* XXX todo: implement sleep scale factor that existed in contrib code.
*/
+
curtime = time(NULL);
if ((unsigned int) (curtime - last_autovac_stop_time) <
(unsigned int) autovacuum_naptime)
@@ -334,6 +331,14 @@ AutoVacMain(int argc, char *argv[])
* connected to it since the stats were last initialized, it doesn't need
* vacuuming.
*
+ * Note that if we are called when autovacuum is nominally disabled in
+ * postgresql.conf, we assume the postmaster has invoked us because a
+ * database is in danger of Xid wraparound. In that case, we only
+ * consider vacuuming whole databases, not individual tables; and we pick
+ * the oldest one, regardless of it's true age. So the criteria for
+ * deciding that a database needs a database-wide vacuum is elsewhere
+ * (currently in vac_truncate_clog).
+ *
* XXX This could be improved if we had more info about whether it needs
* vacuuming before connecting to it. Perhaps look through the pgstats
* data for the database's tables? One idea is to keep track of the
@@ -344,13 +349,8 @@ AutoVacMain(int argc, char *argv[])
db = NULL;
whole_db = false;
- foreach(cell, dblist)
+ if (AutoVacuumingActive())
{
- autovac_dbase *tmp = lfirst(cell);
- bool this_whole_db;
- int32 freeze_age,
- vacuum_age;
-
/*
* We look for the database that most urgently needs a database-wide
* vacuum. We decide that a database-wide vacuum is needed 100000
@@ -361,38 +361,70 @@ AutoVacMain(int argc, char *argv[])
* Unlike vacuum.c, we also look at vacuumxid. This is so that
* pg_clog can be kept trimmed to a reasonable size.
*/
- freeze_age = (int32) (nextXid - tmp->frozenxid);
- vacuum_age = (int32) (nextXid - tmp->vacuumxid);
- tmp->age = Max(freeze_age, vacuum_age);
-
- this_whole_db = (tmp->age >
- (int32) ((MaxTransactionId >> 3) * 3 - 100000));
- if (whole_db || this_whole_db)
+ foreach(cell, dblist)
{
- if (!this_whole_db)
- continue;
- if (db == NULL || tmp->age > db->age)
+ autovac_dbase *tmp = lfirst(cell);
+ bool this_whole_db;
+ int32 true_age,
+ vacuum_age;
+
+ true_age = (int32) (nextXid - tmp->minxid);
+ vacuum_age = (int32) (nextXid - tmp->vacuumxid);
+ tmp->age = Max(true_age, vacuum_age);
+
+ this_whole_db = (tmp->age >
+ (int32) ((MaxTransactionId >> 3) * 3 - 100000));
+
+ if (whole_db || this_whole_db)
{
- db = tmp;
- whole_db = true;
+ if (!this_whole_db)
+ continue;
+ if (db == NULL || tmp->age > db->age)
+ {
+ db = tmp;
+ whole_db = true;
+ }
+ continue;
}
- continue;
- }
- /*
- * Otherwise, skip a database with no pgstat entry; it means it hasn't
- * seen any activity.
- */
- tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);
- if (!tmp->entry)
- continue;
+ /*
+ * Otherwise, skip a database with no pgstat entry; it means it hasn't
+ * seen any activity.
+ */
+ tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid);
+ if (!tmp->entry)
+ continue;
+ /*
+ * Remember the db with oldest autovac time.
+ */
+ if (db == NULL ||
+ tmp->entry->last_autovac_time < db->entry->last_autovac_time)
+ db = tmp;
+ }
+ }
+ else
+ {
/*
- * Remember the db with oldest autovac time.
+ * If autovacuuming is not active, we must have gotten here because a
+ * backend signalled the postmaster. Pick up the database with the
+ * greatest age, and apply a database-wide vacuum on it.
*/
- if (db == NULL ||
- tmp->entry->last_autovac_time < db->entry->last_autovac_time)
- db = tmp;
+ int32 oldest = 0;
+
+ whole_db = true;
+ foreach(cell, dblist)
+ {
+ autovac_dbase *tmp = lfirst(cell);
+ int32 age = (int32) (nextXid - tmp->minxid);
+
+ if (age > oldest)
+ {
+ oldest = age;
+ db = tmp;
+ }
+ }
+ Assert(db);
}
if (db)
@@ -454,7 +486,7 @@ autovac_get_database_list(void)
FILE *db_file;
Oid db_id;
Oid db_tablespace;
- TransactionId db_frozenxid;
+ TransactionId db_minxid;
TransactionId db_vacuumxid;
filename = database_getflatfilename();
@@ -465,7 +497,7 @@ autovac_get_database_list(void)
errmsg("could not open file \"%s\": %m", filename)));
while (read_pg_database_line(db_file, thisname, &db_id,
- &db_tablespace, &db_frozenxid,
+ &db_tablespace, &db_minxid,
&db_vacuumxid))
{
autovac_dbase *db;
@@ -474,7 +506,7 @@ autovac_get_database_list(void)
db->oid = db_id;
db->name = pstrdup(thisname);
- db->frozenxid = db_frozenxid;
+ db->minxid = db_minxid;
db->vacuumxid = db_vacuumxid;
/* these get set later: */
db->entry = NULL;