diff -urN autovacuum.c autovacuum.c.new --- autovacuum.c 2015-06-20 15:36:49.520565000 +0530 +++ autovacuum.c.new 2015-06-20 17:14:15.454835000 +0530 @@ -839,16 +839,22 @@ } /* - * If the result is exactly zero, it means a database had an entry with - * time in the past. Rebuild the list so that the databases are evenly - * distributed again, and recalculate the time to sleep. This can happen - * if there are more tables needing vacuum than workers, and they all take - * longer to vacuum than autovacuum_naptime. + * In an ideal situation sleep time is always greater than zero and less + * than autovacuum_naptime. Any other value indicates a possible time shift. + * If the result is greater than autovacuum_naptime, it means system time + * has shifted back, specifically more than autovacuum_naptime. If the + * result is exactly zero, it means a database had an entry with time in + * the past. This can happen either if there are more tables needing vacuum + * then workers, and they all take longer to vacuum than autovacuum_naptime + * or if system time is shifted to future. + * + * In such cases, rebuild the list so that the databases are evenly + * distributed again, and recalculate the time to sleep. * * 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. */ - if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing) + if (((nap->tv_sec == 0 && nap->tv_usec == 0) || nap->tv_sec > autovacuum_naptime) && !recursing) { rebuild_database_list(InvalidOid); launcher_determine_sleep(canlaunch, true, nap); @@ -861,6 +867,14 @@ nap->tv_sec = 0; nap->tv_usec = MIN_AUTOVAC_SLEEPTIME * 1000; } + + /* + * If the sleep time is too large, clamp it to autovacuum_naptime. + * This avoids an essentially infinite sleep in strange cases like + * clocks going backwards a few years. + */ + if (nap->tv_sec > autovacuum_naptime) + nap->tv_sec = autovacuum_naptime; } /* diff -urN unix_latch.c unix_latch.c.new --- unix_latch.c 2015-06-20 17:22:44.749235000 +0530 +++ unix_latch.c.new 2015-06-20 17:49:29.901562000 +0530 @@ -465,14 +465,28 @@ { INSTR_TIME_SET_CURRENT(cur_time); INSTR_TIME_SUBTRACT(cur_time, start_time); - cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time); - if (cur_timeout < 0) - cur_timeout = 0; + + /* + * In normal situations the difference is always positive. + * The difference can be negative only if current_time is + * greater than start_time i.e. system time shifted to past + * time. We treat this situation as timeout. + */ + if ((long) INSTR_TIME_GET_MILLISEC(cur_time) < 0) + { + result |= WL_TIMEOUT; + } + else + { + cur_timeout = timeout - (long) INSTR_TIME_GET_MILLISEC(cur_time); + if (cur_timeout < 0) + cur_timeout = 0; #ifndef HAVE_POLL - tv.tv_sec = cur_timeout / 1000L; - tv.tv_usec = (cur_timeout % 1000L) * 1000L; + tv.tv_sec = cur_timeout / 1000L; + tv.tv_usec = (cur_timeout % 1000L) * 1000L; #endif + } } } while (result == 0); waiting = false;