]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: stats-file: processes share the same clock source from shm-stats-file
authorAurelien DARRAGON <adarragon@haproxy.com>
Wed, 27 Aug 2025 14:14:53 +0000 (16:14 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Wed, 3 Sep 2025 13:59:27 +0000 (15:59 +0200)
The use of the "shm-stats-file" directive now implies that all processes
using the same file now share a common clock source, this is required
for consistency regarding time-related operations.

The clock source is stored in the shm stats file header.
When the directive is set, all processes share the same clock
(global_now_ms and global_now_ns both point to variables in the map),
this is required for time-based counters such as freq counters to work
consistently. Since all processes manipulate global clock with atomic
operations exclusively during runtime, and don't systematically relies
on it (thanks to local now_ms and now_ns), it is pretty much transparent.

include/haproxy/stats-file-t.h
src/stats-file.c

index ba0f77cb6f123727968a6700a1e172476e313ab3..4e2e229a65461457d74a4bdb5b4c6a7b5219a79d 100644 (file)
@@ -24,6 +24,9 @@ struct shm_stats_file_hdr {
                uint8_t major;
                uint8_t minor;
        } version;
+       uint global_now_ms;   /* global monotonic date (ms) common to all processes using the shm */
+       ullong global_now_ns; /* global monotonic date (ns) common to all processes using the shm */
+       llong now_offset;     /* offset applied to global monotonic date on startup */
 };
 
 struct shm_stats_file_object {
index edd43f4e76f83c623259dd4ffe0b69e77aa41495..9ecdcc6940edb7f851fffd9cbd6bf0c0b2dd3f9c 100644 (file)
@@ -538,10 +538,50 @@ int shm_stats_file_prepare(void)
                memset(shm_stats_file_hdr, 0, sizeof(*shm_stats_file_hdr));
                shm_stats_file_hdr->version.major = SHM_STATS_FILE_VER_MAJOR;
                shm_stats_file_hdr->version.minor = SHM_STATS_FILE_VER_MINOR;
+
+               /* set global clock for the first time */
+               shm_stats_file_hdr->global_now_ms = *global_now_ms;
+               shm_stats_file_hdr->global_now_ns = *global_now_ns;
+               shm_stats_file_hdr->now_offset = clock_get_now_offset();
        }
        else if (!shm_stats_file_check_ver(shm_stats_file_hdr))
                goto err_version;
 
+       /* from now on use the shared global time */
+       global_now_ms = &shm_stats_file_hdr->global_now_ms;
+       global_now_ns = &shm_stats_file_hdr->global_now_ns;
+
+       if (!first) {
+               llong adjt_offset;
+
+               /* set adjusted offset which corresponds to the corrected offset
+                * relative to the initial offset stored in the shared memory instead
+                * of our process-local one
+                */
+               adjt_offset = -clock_get_now_offset() + shm_stats_file_hdr->now_offset;
+
+               /* we now rely on global_now_* from the shm, so the boot
+                * offset that was initially applied in clock_init_process_date()
+                * is no longer relevant. So we fix it by applying the one from the
+                * initial process instead
+                */
+               now_ns = now_ns + adjt_offset;
+               start_time_ns = start_time_ns + adjt_offset;
+               clock_set_now_offset(shm_stats_file_hdr->now_offset);
+
+               /* ensure global_now_* is consistent before continuing */
+               clock_update_global_date();
+       }
+
+       /* now that global_now_ns is accurate, recompute precise now_offset
+        * if needed (in case it is dynamic when monotonic clock not available)
+        */
+       if (!th_ctx->curr_mono_time)
+               clock_set_now_offset(HA_ATOMIC_LOAD(global_now_ns) - tv_to_ns(&date));
+
+       /* sync local and global clocks, so all clocks are consistent */
+       clock_update_date(0, 1);
+
  end:
        return ERR_NONE;