BUG/MEDIUM: clock: also update the date offset on time jumps
In GH issue #2704, @swimlessbird and @xanoxes reported problems handling
time jumps. Indeed, since 2.7 with commit 4eaf85f5d9 ("MINOR: clock: do
not update the global date too often") we refrain from updating the global
offset in case it didn't change. But there's a catch: in case of a large
time jump, if the poller was interrupted, the local time remains the same
and we return immediately from there without updating the offset. It then
becomes incorrect regarding the "date" value, and upon subsequent call to
the poller, there's no way to detect a jump anymore so we apply the old,
incorrect offset and the date becomes wrong. Worse, going back to the
original time (then in the past), global_now_ns remains higher than the
local time and neither get updated anymore.
What is missing in practice is to immediately update the offset when
detecting a time jump. In an ideal world, the offset would be updated
upon every call, that's what was being done prior to commit above but
it's extremely CPU intensive on large systems. However we can perfectly
afford to update the offset every time we detect a time jump, as it's
not as common.
This needs to be backported as far as 2.8. Thanks to both participants
above for providing very helpful details.
(cherry picked from commit e8b1ad4c2b3985eb9e826fd279e419719a2c03ce)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit 61d73137f19a4b8402818060a1f347b8ab4af64e)
Signed-off-by: Willy Tarreau <w@1wt.eu>
(cherry picked from commit cb59c4430b18b31ac4c0a97e1ab68b4283cffa61)
Signed-off-by: Willy Tarreau <w@1wt.eu>
diff --git a/src/clock.c b/src/clock.c
index 7734389..296bf63 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -222,6 +222,12 @@
__tv_islt(&max_deadline, &date))) { // big jump forwards
if (!interrupted)
now_ns += ms_to_ns(max_wait);
+
+ /* this event is rare, but it requires proper handling because if
+ * we just left now_ns where it was, the date will not be updated
+ * by clock_update_global_date().
+ */
+ HA_ATOMIC_STORE(&now_offset, now_ns - tv_to_ns(&date));
} else {
/* The date is still within expectations. Let's apply the
* now_offset to the system date. Note: ofs if made of two