On 24. Aug 2024, at 5.06, Jochen Bern via dovecot dovecot@dovecot.org wrote:
On 21.08.24 11:35, Timo Sirainen wrote:
[Lots and lots of "but my NTP sync is much more precise than that" in the FreeBSD thread] The way Dovecot works is:
- It finds the next timeout, sees that it happens in e.g. 5 milliseconds.
- Then it calls kqueue() to wait for I/O for max 5 milliseconds
- Then it notices that it actually returned more than 105 milliseconds later, and then logs a warning about it.
I think that more information is needed to pinpoint possible causes, and one of the open questions is: What clock does dovecot look at to determine how long it *actually* stayed dormant? On Linux, software that has need of a monotonously increasing "time" to derive guaranteed unique IDs from often looks at the kernel uptime - which is essentially a count of ticks since bootup, and *not* being corrected by NTP.
Dovecot is doing simply gettimeofday() calls before and after epoll/kqueue/etc. It would be possible to use e.g. clock_gettime(CLOCK_MONOTONIC) to see whether there really was a time change, but this seems a bit excessive since Dovecot needs the real time in any case, so the current checks are "free", while doing calls to get monotonic time would only be useful to handle issues with time changes.
Another possibility would be to start using timerfd API when it's supported. Looks like it exists also in FreeBSD. This might be a good idea, although some parts of Dovecot can create/update a lot of timeouts, so I wonder how efficient it is to have syscalls updating the timers all the time. But I guess it would be fine.
Similarly, it should be determined whether the timeouts of I/O function called (i.e., kqueue()) are or aren't influenced by NTP's corrections to system time.
I doubt clock changes affect those calls, since they ask to wait for N microseconds, not until a specific time.
Also, this is kind of a problem when it does happen. Since Dovecot thinks the time moved e.g. 100ms forward, it adjusts all timeouts to happen 100ms backwards. If this wasn't a true time jump, then these timeouts now happen 100ms earlier.
That is, of course, a dangerous approach if you do *not* have a guarantee that the timeouts of the I/O function called are *otherwise* true to the requested duration. But shouldn't those other concurrently-running timeouts notice an actual discontinuity of the timescale just the same as the first one did? Maybe some sort of "N 'nay's needed for a vote of nonconfidence" mechanism would be safer ...
There's only one timeout concurrently running per process. In theory the processes could talk to each other to find out whether there is such a time jump in more processes, but that would be very complicated.