]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
detect_time_jump: don't clear cache on suspend-resume
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 2 Feb 2018 17:07:18 +0000 (18:07 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 13 Feb 2018 10:45:11 +0000 (11:45 +0100)
This changes more time than anticipated, as the old naming didn't apply
anymore (time of last cache clear).

NEWS
daemon/bindings.c
lib/cache/api.c
lib/cache/api.h
modules/detect_time_jump/README.rst
modules/detect_time_jump/detect_time_jump.lua

diff --git a/NEWS b/NEWS
index ac6b30a70d268d20c5e85c0497a0b688e6714a6b..8fb5cc639730eec2bfe865d7424cf2c740e7ce3e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+
+- detect_time_jump module: don't clear cache on suspend-resume (#284)
+
+
 Knot Resolver 2.0.0 (2018-01-31)
 ================================
 
index bac13c2f44819c78d4733a96a3949b04ab51360f..bdde5dfa54dbddf1398728b29f48c3e15f4c22f9 100644 (file)
@@ -731,20 +731,30 @@ static int cache_count(lua_State *L)
        return 0;
 }
 
-/** Return time of last cache clear */
-static int cache_last_clear(lua_State *L)
+/** Return time of last checkpoint, or re-set it if passed `true`. */
+static int cache_checkpoint(lua_State *L)
 {
        struct engine *engine = engine_luaget(L);
        struct kr_cache *cache = &engine->resolver.cache;
-       lua_newtable(L);
-       lua_pushnumber(L, cache->last_clear_monotime);
-       lua_setfield(L, -2, "monotime");
-       lua_newtable(L);
-       lua_pushnumber(L, cache->last_clear_walltime.tv_sec);
-       lua_setfield(L, -2, "sec");
-       lua_pushnumber(L, cache->last_clear_walltime.tv_usec);
-       lua_setfield(L, -2, "usec");
-       lua_setfield(L, -2, "walltime");
+
+       if (lua_gettop(L) == 0) { /* Return the current value. */
+               lua_newtable(L);
+               lua_pushnumber(L, cache->checkpoint_monotime);
+               lua_setfield(L, -2, "monotime");
+               lua_newtable(L);
+               lua_pushnumber(L, cache->checkpoint_walltime.tv_sec);
+               lua_setfield(L, -2, "sec");
+               lua_pushnumber(L, cache->checkpoint_walltime.tv_usec);
+               lua_setfield(L, -2, "usec");
+               lua_setfield(L, -2, "walltime");
+               return 1;
+       }
+
+       if (lua_gettop(L) != 1 || !lua_isboolean(L, 1) || !lua_toboolean(L, 1)) {
+               format_error(L, "cache.checkpoint() takes no parameters or a true value");
+               lua_error(L);
+       }
+       kr_cache_make_checkpoint(cache);
        return 1;
 }
 
@@ -1113,7 +1123,7 @@ int lib_cache(lua_State *L)
                { "backends", cache_backends },
                { "count",  cache_count },
                { "stats",  cache_stats },
-               { "last_clear",  cache_last_clear },
+               { "checkpoint", cache_checkpoint },
                { "open",   cache_open },
                { "close",  cache_close },
                { "prune",  cache_prune },
index e0eb6c06f586a0df936f3bd43045df2bbe745bef..4cebca665691828c5f4f2084085183e9b079e123 100644 (file)
@@ -64,13 +64,6 @@ static inline int cache_clear(struct kr_cache *cache)
        return cache_op(cache, clear);
 }
 
-/** @internal Set time when clearing cache. */
-static void reset_timestamps(struct kr_cache *cache)
-{
-       cache->last_clear_monotime = kr_now();
-       gettimeofday(&cache->last_clear_walltime, NULL);
-}
-
 /** @internal Open cache db transaction and check internal data version. */
 static int assert_right_version(struct kr_cache *cache)
 {
@@ -129,7 +122,7 @@ int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct k
        cache->ttl_min = KR_CACHE_DEFAULT_TTL_MIN;
        cache->ttl_max = KR_CACHE_DEFAULT_TTL_MAX;
        /* Check cache ABI version */
-       reset_timestamps(cache);
+       kr_cache_make_checkpoint(cache);
        (void) assert_right_version(cache);
        return 0;
 }
@@ -163,7 +156,7 @@ int kr_cache_clear(struct kr_cache *cache)
        }
        int ret = cache_clear(cache);
        if (ret == 0) {
-               reset_timestamps(cache);
+               kr_cache_make_checkpoint(cache);
                ret = assert_right_version(cache);
        }
        return ret;
index 40f24730c3063708533e407bf2f64a6ddd5fe2e1..11f9d3b45656870a9b7dd225cf4d5dddd28b73b2 100644 (file)
@@ -48,8 +48,10 @@ struct kr_cache
        } stats;
 
        uint32_t ttl_min, ttl_max; /**< TTL limits */
-       struct timeval last_clear_walltime; /**< Time of last cache clear */
-       uint64_t last_clear_monotime;  /**< Last cache clear in monotonic milliseconds */
+
+       /* A pair of stamps for detection of real-time shifts during runtime. */
+       struct timeval checkpoint_walltime; /**< Wall time on the last check-point. */
+       uint64_t checkpoint_monotime; /**< Monotonic milliseconds on the last check-point. */
 };
 
 /**
@@ -83,6 +85,14 @@ static inline bool kr_cache_is_open(struct kr_cache *cache)
        return cache->db != NULL;
 }
 
+/** (Re)set the time pair to the current values. */
+static inline void kr_cache_make_checkpoint(struct kr_cache *cache)
+{
+       cache->checkpoint_monotime = kr_now();
+       gettimeofday(&cache->checkpoint_walltime, NULL);
+}
+
+
 /**
  * Clear all items from the cache.
  * @param cache cache structure
index da92630b750b2832a2bf1a7ae5a01639cb5c564e..78932ac733823560925cb6a7608929374c16db6e 100644 (file)
@@ -4,11 +4,17 @@ Detect discontinuous jumps in the system time
 ---------------------------------------------
 
 This module detect discontinuous jumps in the system time when resolver
-is running. It clears cache when some time jumps occurs. 
+is running.  It clears cache when a significant backward time jumps occurs.
 
-Time jumps is ussualy created by NTP time change or by admin intervention.
-These change can affect cache records as they store timestamp and TTL in real 
+Time jumps are usualy created by NTP time change or by admin intervention.
+These change can affect cache records as they store timestamp and TTL in real
 time.
 
 If you want to preserve cache during time travel you should disable
 this module by ``modules.unload('detect_time_jump')``.
+
+Due to the way monotonic system time works on typical systems,
+suspend-resume cycles will be perceived as a foward time jumps,
+but this direction of shift does not have the risk of using records
+beyond their intended TTL, so forward jumps do not cause erasing the cache.
+
index e236f06866cd4419914d910a3d95a7d80c924e0c..d8b3dabe4891d97be06a8866a8b50febd22ddde1 100644 (file)
@@ -10,15 +10,18 @@ local event_id = nil
 -- time. In ideal case these differences should be almost same.
 -- If they differ more than mod.threshold value then clear cache.
 local function check_time()
-       local clear_time = cache.last_clear()
-       local cache_timeshift = clear_time.walltime.sec * 1000 - clear_time.monotime
+       local checkpoint = cache.checkpoint()
+       local cache_timeshift = checkpoint.walltime.sec * 1000 - checkpoint.monotime
        local actual_timeshift = os.time() * 1000 - tonumber(ffi.C.kr_now())
-       local time_diff = math.abs(cache_timeshift - actual_timeshift)
-       if time_diff > mod.threshold then
-               log("Detected time change, clearing cache\n" ..
+       local jump_backward = cache_timeshift - actual_timeshift
+       if jump_backward > mod.threshold then
+               log("Detected backwards time jump, clearing cache.\n" ..
                "But what does that mean? It means your future hasn't been written yet."
                )
                cache.clear()
+       elseif -jump_backward > mod.threshold then
+               log("Detected forward time jump.  (Suspend-resume, possibly.)")
+               cache.checkpoint(true)
        end
 end