From 753ab4e89b9a5952e50bc77d404198520b362a3a Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Mon, 27 Apr 2026 11:14:09 +0200 Subject: hydration with pack (#1016) - Feature: Hub hydration packs small files into raw CAS pack blobs to reduce request count for modules dominated by tiny metadata files - `--hub-hydration-enable-pack` (Lua: `hub.hydration.enablepack`, default true) - `--hub-hydration-pack-threshold-bytes` (Lua: `hub.hydration.packthresholdbytes`, default 256 KiB) - `--hub-hydration-max-pack-bytes` (Lua: `hub.hydration.maxpackbytes`, default 4 MiB) - Feature: Hub hydration and dehydration can be disabled per direction - `--hub-enable-hydration` (Lua: `hub.enablehydration`, default true) - `--hub-enable-dehydration` (Lua: `hub.enabledehydration`, default true) - Feature: Hub hydration accepts a configurable file exclude list via `HydrationOptions` `excludes` (array of wildcards). Built-in defaults skip transient runtime files (`.lock`, `.sentry-native/*`, `state_marker`, `*.bak`, `gc/reserve.gc`, `auth/*`) so they no longer participate in dehydrate scans. Override semantics: a present field replaces the default outright; explicit `[]` opts out of all defaults. - Improvement: Hub hydration completion logs now report per-request average and max latency, peak in-flight workers, queue wait, and hash-cache hit percentage; loose and pack-blob transfers are reported separately - Improvement: Hub hydration pre-creates unique parent directories before scheduling parallel writes - Improvement: S3 hydration retries transient HTTP failures (timeouts, 429 throttling, 5xx server errors, connection errors) up to 3 times via the HTTP client retry layer - Improvement: S3 hydration multipart chunk size is persisted in `state.cbo` per module so hydrate replays the partitioning used at dehydrate; default raised to 64 MiB (was 32 MiB) - Improvement: Hub hydration `Obliterate` retries backend delete once before falling back to local cleanup --- src/zencore/string.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'src/zencore/string.cpp') diff --git a/src/zencore/string.cpp b/src/zencore/string.cpp index 34519b83b..4072aec56 100644 --- a/src/zencore/string.cpp +++ b/src/zencore/string.cpp @@ -482,6 +482,24 @@ NiceTimeSpanMsToBuffer(uint64_t Millis, std::span Buffer) } } +size_t +NiceTimeSpanUsToBuffer(uint64_t Micros, std::span Buffer) +{ + if (Micros < 1000) + { + return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "us", Micros); + } + else if (Micros < 10000) + { + return snprintf(Buffer.data(), Buffer.size(), "%.2fms", Micros / 1000.0); + } + else if (Micros < 1000000) + { + return snprintf(Buffer.data(), Buffer.size(), "%.1fms", Micros / 1000.0); + } + return NiceTimeSpanMsToBuffer(Micros / 1000, Buffer); +} + ////////////////////////////////////////////////////////////////////////// template @@ -850,6 +868,13 @@ TEST_CASE("niceNum") NiceNumGeneral(100000000000000, Buffer, kNicenumTime); CHECK(StringEquals(Buffer, "100000s")); + + // floor() instead of round(): 999.5us must NOT render as "1000us". + NiceNumGeneral(999500, Buffer, kNicenumTime); + CHECK(StringEquals(Buffer, "999us")); + + NiceNumGeneral(999999, Buffer, kNicenumTime); + CHECK(StringEquals(Buffer, "999us")); } SUBCASE("bytes") @@ -917,6 +942,43 @@ TEST_CASE("niceNum") NiceTimeSpanMsToBuffer(360000000, Buffer); CHECK(StringEquals(Buffer, "100h00m")); } + + SUBCASE("timespan_us") + { + NiceTimeSpanUsToBuffer(0, Buffer); + CHECK(StringEquals(Buffer, "0us")); + + NiceTimeSpanUsToBuffer(1, Buffer); + CHECK(StringEquals(Buffer, "1us")); + + NiceTimeSpanUsToBuffer(999, Buffer); + CHECK(StringEquals(Buffer, "999us")); + + NiceTimeSpanUsToBuffer(1000, Buffer); + CHECK(StringEquals(Buffer, "1.00ms")); + + NiceTimeSpanUsToBuffer(1500, Buffer); + CHECK(StringEquals(Buffer, "1.50ms")); + + NiceTimeSpanUsToBuffer(9999, Buffer); + CHECK(StringEquals(Buffer, "10.00ms")); // %.2f rounds 9.999 -> 10.00 + + NiceTimeSpanUsToBuffer(10000, Buffer); + CHECK(StringEquals(Buffer, "10.0ms")); + + NiceTimeSpanUsToBuffer(999500, Buffer); + CHECK(StringEquals(Buffer, "999.5ms")); + + NiceTimeSpanUsToBuffer(999999, Buffer); + CHECK(StringEquals(Buffer, "1000.0ms")); // boundary just below 1s + + // >=1s delegates to NiceTimeSpanMs. + NiceTimeSpanUsToBuffer(1000000, Buffer); + CHECK(StringEquals(Buffer, "1.00s")); + + NiceTimeSpanUsToBuffer(60000000, Buffer); + CHECK(StringEquals(Buffer, "1m00s")); + } } TEST_CASE("StringBuilder") -- cgit v1.2.3