From 51b68daa195ba37af1c87ba324eea504bd4cacdd Mon Sep 17 00:00:00 2001 From: dormando Date: Tue, 9 Aug 2011 14:57:51 -0700 Subject: Use a monotonically increasing timer gettimeofday() can flip around all willy-nilly, and is actually common for users to cause this by having memcached start on boot before ntp launches and corrects system time. libevent fires events on a monotonically increasing clock, so we can more or less safely tick our internal timer up by one second every time the handler runs. Unfortunately we support expiration by date. If memcached's start time isn't in sync with the rest of the world this feature won't work well, but it never did. Was originally going to make this optional, but I can't come up with a great reason to do so. If it turns out this isn't "accurate enough", we can add the clock_gettime() code inline. --- memcached.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/memcached.c b/memcached.c index e47920f..21ee227 100644 --- a/memcached.c +++ b/memcached.c @@ -95,11 +95,6 @@ static int add_iov(conn *c, const void *buf, int len); static int add_msghdr(conn *c); -/* time handling */ -static void set_current_time(void); /* update the global variable holding - global 32-bit seconds-since-start time - (to avoid 64 bit time_t) */ - static void conn_free(conn *c); /** exported globals **/ @@ -2002,8 +1997,6 @@ static void process_bin_flush(conn *c) { exptime = ntohl(req->message.body.expiration); } - set_current_time(); - if (exptime > 0) { settings.oldest_live = realtime(exptime) - 1; } else { @@ -3060,7 +3053,6 @@ static void process_command(conn *c, char *command) { } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) { time_t exptime = 0; - set_current_time(); set_noreply_maybe(c, tokens, ntokens); @@ -4107,14 +4099,10 @@ static int server_socket_unix(const char *path, int access_mask) { volatile rel_time_t current_time; static struct event clockevent; -/* time-sensitive callers can call it by hand with this, outside the normal ever-1-second timer */ -static void set_current_time(void) { - struct timeval timer; - - gettimeofday(&timer, NULL); - current_time = (rel_time_t) (timer.tv_sec - process_started); -} - +/* libevent uses a monotonic clock when available for event scheduling. Aside + * from jitter, simply ticking our internal timer here is accurate enough. + * Note that users who are setting explicit dates for expiration times *must* + * ensure their clocks are correct before starting memcached. */ static void clock_handler(const int fd, const short which, void *arg) { struct timeval t = {.tv_sec = 1, .tv_usec = 0}; static bool initialized = false; @@ -4124,13 +4112,16 @@ static void clock_handler(const int fd, const short which, void *arg) { evtimer_del(&clockevent); } else { initialized = true; + /* process_started is initialized to time() - 2. We initialize to 1 so + * flush_all won't underflow during tests. */ + current_time = 1; } evtimer_set(&clockevent, clock_handler, 0); event_base_set(main_base, &clockevent); evtimer_add(&clockevent, &t); - set_current_time(); + current_time++; } static void usage(void) { -- cgit v1.2.1