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.
This commit is contained in:
Willy Tarreau 2024-09-04 16:55:43 +02:00
parent 531bf44a65
commit e8b1ad4c2b
1 changed files with 6 additions and 0 deletions

View File

@ -222,6 +222,12 @@ void clock_update_local_date(int max_wait, int interrupted)
__tv_islt(&max_deadline, &date))) { // big jump forwards __tv_islt(&max_deadline, &date))) { // big jump forwards
if (!interrupted) if (!interrupted)
now_ns += ms_to_ns(max_wait); 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 { } else {
/* The date is still within expectations. Let's apply the /* The date is still within expectations. Let's apply the
* now_offset to the system date. Note: ofs if made of two * now_offset to the system date. Note: ofs if made of two