Avoid integer overflow issues in autovacuum.

This commit is contained in:
Alvaro Herrera 2007-06-13 21:24:56 +00:00
parent e976fd43c6
commit a0a26c47d4
2 changed files with 63 additions and 26 deletions

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.49 2007/06/08 21:21:28 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/autovacuum.c,v 1.50 2007/06/13 21:24:55 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -18,6 +18,7 @@
#include <signal.h> #include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@ -73,6 +74,10 @@ int autovacuum_vac_cost_limit;
int Log_autovacuum = -1; int Log_autovacuum = -1;
/* maximum sleep duration in the launcher, in seconds */
#define AV_SLEEP_QUANTUM 10
/* Flags to tell if we are in an autovacuum process */ /* Flags to tell if we are in an autovacuum process */
static bool am_autovacuum_launcher = false; static bool am_autovacuum_launcher = false;
static bool am_autovacuum_worker = false; static bool am_autovacuum_worker = false;
@ -197,7 +202,8 @@ NON_EXEC_STATIC void AutoVacWorkerMain(int argc, char *argv[]);
NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]); NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]);
static Oid do_start_worker(void); static Oid do_start_worker(void);
static uint64 launcher_determine_sleep(bool canlaunch, bool recursing); static void launcher_determine_sleep(bool canlaunch, bool recursing,
struct timeval *nap);
static void launch_worker(TimestampTz now); static void launch_worker(TimestampTz now);
static List *get_database_list(void); static List *get_database_list(void);
static void rebuild_database_list(Oid newdb); static void rebuild_database_list(Oid newdb);
@ -487,7 +493,7 @@ AutoVacLauncherMain(int argc, char *argv[])
for (;;) for (;;)
{ {
uint64 micros; struct timeval nap;
bool can_launch; bool can_launch;
TimestampTz current_time = 0; TimestampTz current_time = 0;
@ -498,11 +504,39 @@ AutoVacLauncherMain(int argc, char *argv[])
if (!PostmasterIsAlive(true)) if (!PostmasterIsAlive(true))
exit(1); exit(1);
micros = launcher_determine_sleep(AutoVacuumShmem->av_freeWorkers != launcher_determine_sleep(AutoVacuumShmem->av_freeWorkers !=
INVALID_OFFSET, false); INVALID_OFFSET, false, &nap);
/* Sleep for a while according to schedule */ /*
pg_usleep(micros); * Sleep for a while according to schedule. We only sleep in
* AV_SLEEP_QUANTUM second intervals, in order to promptly notice
* postmaster death.
*/
while (nap.tv_sec > 0 || nap.tv_usec > 0)
{
uint32 sleeptime;
sleeptime = nap.tv_usec;
nap.tv_usec = 0;
if (nap.tv_sec > 0)
{
sleeptime += Min(nap.tv_sec, AV_SLEEP_QUANTUM) * 1000000;
nap.tv_sec -= Min(nap.tv_sec, AV_SLEEP_QUANTUM);
}
pg_usleep(sleeptime);
/*
* Emergency bailout if postmaster has died. This is to avoid the
* necessity for manual cleanup of all postmaster children.
*/
if (!PostmasterIsAlive(true))
exit(1);
if (avlauncher_shutdown_request || got_SIGHUP || got_SIGUSR1)
break;
}
/* the normal shutdown case */ /* the normal shutdown case */
if (avlauncher_shutdown_request) if (avlauncher_shutdown_request)
@ -647,16 +681,15 @@ AutoVacLauncherMain(int argc, char *argv[])
} }
/* /*
* Determine the time to sleep, in microseconds, based on the database list. * Determine the time to sleep, based on the database list.
* *
* The "canlaunch" parameter indicates whether we can start a worker right now, * The "canlaunch" parameter indicates whether we can start a worker right now,
* for example due to the workers being all busy. * for example due to the workers being all busy. If this is false, we will
* cause a long sleep, which will be interrupted when a worker exits.
*/ */
static uint64 static void
launcher_determine_sleep(bool canlaunch, bool recursing) launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval *nap)
{ {
long secs;
int usecs;
Dlelem *elem; Dlelem *elem;
/* /*
@ -667,23 +700,28 @@ launcher_determine_sleep(bool canlaunch, bool recursing)
*/ */
if (!canlaunch) if (!canlaunch)
{ {
secs = autovacuum_naptime; nap->tv_sec = autovacuum_naptime;
usecs = 0; nap->tv_usec = 0;
} }
else if ((elem = DLGetTail(DatabaseList)) != NULL) else if ((elem = DLGetTail(DatabaseList)) != NULL)
{ {
avl_dbase *avdb = DLE_VAL(elem); avl_dbase *avdb = DLE_VAL(elem);
TimestampTz current_time = GetCurrentTimestamp(); TimestampTz current_time = GetCurrentTimestamp();
TimestampTz next_wakeup; TimestampTz next_wakeup;
long secs;
int usecs;
next_wakeup = avdb->adl_next_worker; next_wakeup = avdb->adl_next_worker;
TimestampDifference(current_time, next_wakeup, &secs, &usecs); TimestampDifference(current_time, next_wakeup, &secs, &usecs);
nap->tv_sec = secs;
nap->tv_usec = usecs;
} }
else else
{ {
/* list is empty, sleep for whole autovacuum_naptime seconds */ /* list is empty, sleep for whole autovacuum_naptime seconds */
secs = autovacuum_naptime; nap->tv_sec = autovacuum_naptime;
usecs = 0; nap->tv_usec = 0;
} }
/* /*
@ -696,20 +734,19 @@ launcher_determine_sleep(bool canlaunch, bool recursing)
* We only recurse once. rebuild_database_list should always return times * We only recurse once. rebuild_database_list should always return times
* in the future, but it seems best not to trust too much on that. * in the future, but it seems best not to trust too much on that.
*/ */
if (secs == 0L && usecs == 0 && !recursing) if (nap->tv_sec == 0L && nap->tv_usec == 0 && !recursing)
{ {
rebuild_database_list(InvalidOid); rebuild_database_list(InvalidOid);
return launcher_determine_sleep(canlaunch, true); launcher_determine_sleep(canlaunch, true, nap);
return;
} }
/* 100ms is the smallest time we'll allow the launcher to sleep */ /* 100ms is the smallest time we'll allow the launcher to sleep */
if (secs <= 0L && usecs <= 100000) if (nap->tv_sec <= 0L && nap->tv_usec <= 100000)
{ {
secs = 0L; nap->tv_sec = 0L;
usecs = 100000; /* 100 ms */ nap->tv_usec = 100000; /* 100 ms */
} }
return secs * 1000000 + usecs;
} }
/* /*

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.396 2007/06/08 18:23:52 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.397 2007/06/13 21:24:56 alvherre Exp $
* *
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
@ -1645,7 +1645,7 @@ static struct config_int ConfigureNamesInt[] =
GUC_UNIT_S GUC_UNIT_S
}, },
&autovacuum_naptime, &autovacuum_naptime,
60, 1, INT_MAX, NULL, NULL 60, 1, INT_MAX / 1000, NULL, NULL
}, },
{ {
{"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM, {"autovacuum_vacuum_threshold", PGC_SIGHUP, AUTOVACUUM,