From a0abe87f1c18122c8f1f01e808b006ac48f50b19 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Fri, 23 Mar 2007 21:45:17 +0000 Subject: [PATCH] Separate the code to start a new worker into its own function. The code is exactly the same, modulo whitespace. --- src/backend/postmaster/autovacuum.c | 185 +++++++++++++++------------- 1 file changed, 100 insertions(+), 85 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index e0b6330576..fb2de6f57a 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.36 2007/03/23 21:23:13 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.37 2007/03/23 21:45:17 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -118,6 +118,7 @@ static pid_t avworker_forkexec(void); NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]); NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]); +static void do_start_worker(void); static void do_autovacuum(PgStat_StatDBEntry *dbentry); static List *autovac_get_database_list(void); static void test_rel_for_autovac(Oid relid, PgStat_StatTabEntry *tabentry, @@ -218,9 +219,6 @@ NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; - List *dblist; - bool for_xid_wrap; - autovac_dbase *db; MemoryContext avlauncher_cxt; /* we are a postmaster subprocess now */ @@ -358,8 +356,6 @@ AutoVacLauncherMain(int argc, char *argv[]) for (;;) { - TransactionId xidForceLimit; - ListCell *cell; int worker_pid; /* @@ -407,86 +403,8 @@ AutoVacLauncherMain(int argc, char *argv[]) } } - /* Get a list of databases */ - dblist = autovac_get_database_list(); + do_start_worker(); - /* - * Determine the oldest datfrozenxid/relfrozenxid that we will allow - * to pass without forcing a vacuum. (This limit can be tightened for - * particular tables, but not loosened.) - */ - recentXid = ReadNewTransactionId(); - xidForceLimit = recentXid - autovacuum_freeze_max_age; - /* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */ - if (xidForceLimit < FirstNormalTransactionId) - xidForceLimit -= FirstNormalTransactionId; - - /* - * Choose a database to connect to. We pick the database that was least - * recently auto-vacuumed, or one that needs vacuuming to prevent Xid - * wraparound-related data loss. If any db at risk of wraparound is - * found, we pick the one with oldest datfrozenxid, independently of - * autovacuum times. - * - * Note that a database with no stats entry is not considered, except for - * Xid wraparound purposes. The theory is that if no one has ever - * connected to it since the stats were last initialized, it doesn't need - * vacuuming. - * - * 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 - * number of new and dead tuples per database in pgstats. However it - * isn't clear how to construct a metric that measures that and not cause - * starvation for less busy databases. - */ - db = NULL; - for_xid_wrap = false; - foreach(cell, dblist) - { - autovac_dbase *tmp = lfirst(cell); - - /* Find pgstat entry if any */ - tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid); - - /* Check to see if this one is at risk of wraparound */ - if (TransactionIdPrecedes(tmp->frozenxid, xidForceLimit)) - { - if (db == NULL || - TransactionIdPrecedes(tmp->frozenxid, db->frozenxid)) - db = tmp; - for_xid_wrap = true; - continue; - } - else if (for_xid_wrap) - continue; /* ignore not-at-risk DBs */ - - /* - * Otherwise, skip a database with no pgstat entry; it means it - * hasn't seen any activity. - */ - if (!tmp->entry) - continue; - - /* - * Remember the db with oldest autovac time. (If we are here, - * both tmp->entry and db->entry must be non-null.) - */ - if (db == NULL || - tmp->entry->last_autovac_time < db->entry->last_autovac_time) - db = tmp; - } - - /* Found a database -- process it */ - if (db != NULL) - { - LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE); - AutoVacuumShmem->process_db = db->oid; - LWLockRelease(AutovacuumLock); - - SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER); - } - sleep: /* * in emergency mode, exit immediately so that the postmaster can @@ -512,6 +430,103 @@ sleep: proc_exit(0); /* done */ } +/* + * do_start_worker + * + * Bare-bones procedure for starting an autovacuum worker from the launcher. + * It determines what database to work on, sets up shared memory stuff and + * signals postmaster to start the worker. + */ +static void +do_start_worker(void) +{ + List *dblist; + bool for_xid_wrap; + autovac_dbase *db; + ListCell *cell; + TransactionId xidForceLimit; + + /* Get a list of databases */ + dblist = autovac_get_database_list(); + + /* + * Determine the oldest datfrozenxid/relfrozenxid that we will allow + * to pass without forcing a vacuum. (This limit can be tightened for + * particular tables, but not loosened.) + */ + recentXid = ReadNewTransactionId(); + xidForceLimit = recentXid - autovacuum_freeze_max_age; + /* ensure it's a "normal" XID, else TransactionIdPrecedes misbehaves */ + if (xidForceLimit < FirstNormalTransactionId) + xidForceLimit -= FirstNormalTransactionId; + + /* + * Choose a database to connect to. We pick the database that was least + * recently auto-vacuumed, or one that needs vacuuming to prevent Xid + * wraparound-related data loss. If any db at risk of wraparound is + * found, we pick the one with oldest datfrozenxid, independently of + * autovacuum times. + * + * Note that a database with no stats entry is not considered, except for + * Xid wraparound purposes. The theory is that if no one has ever + * connected to it since the stats were last initialized, it doesn't need + * vacuuming. + * + * 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 + * number of new and dead tuples per database in pgstats. However it + * isn't clear how to construct a metric that measures that and not cause + * starvation for less busy databases. + */ + db = NULL; + for_xid_wrap = false; + foreach(cell, dblist) + { + autovac_dbase *tmp = lfirst(cell); + + /* Find pgstat entry if any */ + tmp->entry = pgstat_fetch_stat_dbentry(tmp->oid); + + /* Check to see if this one is at risk of wraparound */ + if (TransactionIdPrecedes(tmp->frozenxid, xidForceLimit)) + { + if (db == NULL || + TransactionIdPrecedes(tmp->frozenxid, db->frozenxid)) + db = tmp; + for_xid_wrap = true; + continue; + } + else if (for_xid_wrap) + continue; /* ignore not-at-risk DBs */ + + /* + * Otherwise, skip a database with no pgstat entry; it means it + * hasn't seen any activity. + */ + if (!tmp->entry) + continue; + + /* + * Remember the db with oldest autovac time. (If we are here, + * both tmp->entry and db->entry must be non-null.) + */ + if (db == NULL || + tmp->entry->last_autovac_time < db->entry->last_autovac_time) + db = tmp; + } + + /* Found a database -- process it */ + if (db != NULL) + { + LWLockAcquire(AutovacuumLock, LW_EXCLUSIVE); + AutoVacuumShmem->process_db = db->oid; + LWLockRelease(AutovacuumLock); + + SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_WORKER); + } +} + /* SIGHUP: set flag to re-read config file at next convenient time */ static void avl_sighup_handler(SIGNAL_ARGS) -- 2.40.0