From 434663f2aac4d5d0632c9d4309121f5856de5ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=90=E5=B0=8F=E9=B8=AD?= Date: Thu, 6 Aug 2026 22:13:17 +0800 Subject: [PATCH] fix(replication): report remote target latency as Go duration nanoseconds (#5771) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit madmin-go decodes LatencyStat.curr/avg/max as Go time.Duration (nanosecond integers), but the list-remote-targets admin response serialized them via the persisted milliseconds encoding, so mc showed latency values shrunk by 10^6 (e.g. 50ms rendered as 50ns). Extend remote_target_admin_json — the same response-only re-encode path already used for healthCheckDuration/totalDowntime — to emit the latency stats as nanoseconds, leaving the persisted bucket-targets wire format (milliseconds) untouched. list_targets overwrites latency from live health stats before serialization, so the response path is the single conversion point. Found by the MinIO compatibility review (P2). --- rustfs/src/admin/handlers/replication.rs | 54 +++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/rustfs/src/admin/handlers/replication.rs b/rustfs/src/admin/handlers/replication.rs index 6eaa5da6f..cb06ec828 100644 --- a/rustfs/src/admin/handlers/replication.rs +++ b/rustfs/src/admin/handlers/replication.rs @@ -348,9 +348,10 @@ impl RemoteTargetRequest { } /// Admin-response encoding of a remote target: the persisted bucket-targets -/// format keeps `healthCheckDuration`/`totalDowntime` in seconds, but madmin -/// decodes them as Go `time.Duration` (nanoseconds) — re-encode just those -/// fields without touching the persistence wire format. +/// format keeps `healthCheckDuration`/`totalDowntime` in seconds and the +/// `latency` stats in milliseconds, but madmin decodes all of them as Go +/// `time.Duration` (nanoseconds) — re-encode just those fields without +/// touching the persistence wire format. fn remote_target_admin_json(target: &BucketTarget) -> Result { fn go_duration_nanos(duration: Duration) -> serde_json::Value { // Saturate instead of truncating: >u64::MAX nanoseconds (~584 years) @@ -361,6 +362,11 @@ fn remote_target_admin_json(target: &BucketTarget) -> Result