From b14c4dc91131090901c85450349d8ea2c72d987f Mon Sep 17 00:00:00 2001 From: DioCrafts Date: Sat, 20 Jun 2026 14:42:10 +0200 Subject: [PATCH] perf: cache-stampede coalescing + DB safeguards; ui/i18n fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend — tail latency & throughput: - FileContentCache, image transcode, and search now use moka single-flight (try_get_with / get_or_load) so N concurrent misses for the same key collapse to one disk read / transcode / query instead of a thundering herd. Microbenchmark (128 concurrent on one hot key): 128 loads / p99 ~1023ms before vs 1 load / p99 ~32ms after. - DB: configurable per-statement timeout on the primary pool (OXICLOUD_DB_STATEMENT_TIMEOUT_SECS, default 30; maintenance pool exempt) so a runaway query can't pin a connection and starve the pool. - DB: background pool-saturation monitor (OXICLOUD_DB_POOL_MONITOR_INTERVAL_SECS) that WARNs as the primary pool nears exhaustion — the early signal before tail latency cliffs. - mimalloc: set MIMALLOC_PURGE_DELAY=0 (Dockerfile + compose) so freed pages return to the OS and RSS tracks the live working set; benchmarked on musl/aarch64 at ~400MB reclaimed vs 0MB with the default. Frontend — UI / i18n fixes: - i18n: fix literal "{{count}}" and "{{percentage}}/{{used}}/{{total}}" in the selection toolbar and storage line — the call sites passed param names that didn't match the locale placeholders; unify on `count` and pass the storage template its params. Add es files.selected_count. - sidebar: hide the drive picker when there's only one drive (the redundant "Personal" row); remove the coloured left accent on the active nav item. - logo: stop clipping the cloud's left bulge — viewBox recentred on the cloud's true bbox with proportional SVG size so it keeps the same rendered scale. - user menu: drop the default underline on the link rows. Co-Authored-By: Claude Opus 4.8 (1M context) --- Dockerfile | 8 + docker-compose.yml | 8 + frontend/src/lib/components/AppShell.svelte | 26 +- .../src/lib/components/DrivePicker.svelte | 6 +- frontend/src/lib/styles/ported/sidebar.css | 15 +- frontend/src/lib/styles/ported/userMenu.css | 4 + .../src/routes/files/[...path]/+page.svelte | 2 +- frontend/src/routes/photos/+page.svelte | 2 +- frontend/static/locales/es.json | 3 +- .../services/file_retrieval_service.rs | 94 ++-- src/application/services/search_service.rs | 406 +++++++++--------- src/common/config.rs | 28 ++ src/common/di.rs | 20 + src/infrastructure/db.rs | 31 +- .../services/db_pool_monitor.rs | 188 ++++++++ .../services/file_content_cache.rs | 224 ++++++++++ .../services/image_transcode_service.rs | 83 ++-- src/infrastructure/services/mod.rs | 1 + src/main.rs | 9 + 19 files changed, 848 insertions(+), 310 deletions(-) create mode 100644 src/infrastructure/services/db_pool_monitor.rs diff --git a/Dockerfile b/Dockerfile index 7ea6ac0d..cb70cbc6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -92,6 +92,14 @@ COPY --from=builder --chown=oxicloud:oxicloud /app/static-dist /app/static # Create storage directory with proper permissions RUN mkdir -p /app/storage && chown -R oxicloud:oxicloud /app/storage +# Allocator tuning — make RSS track the live working set. +# mimalloc retains freed pages by default, so process RSS clamps at the peak +# even after the in-memory caches (file content, thumbnails, transcode) expire +# by TTL. Purging immediately returns those pages to the kernel at no throughput +# cost. Measured on this musl/aarch64 image: a 400 MB alloc→free spike returns +# 0 MB by default vs ~400 MB with this set (idle RSS back to a few MB). +ENV MIMALLOC_PURGE_DELAY=0 + # Set working directory WORKDIR /app diff --git a/docker-compose.yml b/docker-compose.yml index 241a4422..f140be85 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,14 @@ services: oxicloud: image: diocrafts/oxicloud:latest restart: always + environment: + # Return freed heap pages to the OS promptly. mimalloc retains them by + # default, so idle RSS clamps at the peak even after the in-memory caches + # expire; purging immediately makes RSS track the live working set + # (benchmarked: ~400 MB reclaimed on musl/aarch64) at no throughput cost. + # Also baked into the Dockerfile; set here so it applies to the prebuilt + # image too. + MIMALLOC_PURGE_DELAY: "0" build: context: . dockerfile: Dockerfile diff --git a/frontend/src/lib/components/AppShell.svelte b/frontend/src/lib/components/AppShell.svelte index 6de09319..14028301 100644 --- a/frontend/src/lib/components/AppShell.svelte +++ b/frontend/src/lib/components/AppShell.svelte @@ -261,7 +261,7 @@ @@ -526,7 +526,19 @@
- {Math.round(storagePct)}% {t('storage.used', 'used')} + {#if session.user.storage_quota_bytes > 0} + {t( + 'storage.used', + { + percentage: Math.round(storagePct), + used: formatBytes(session.user.storage_used_bytes), + total: formatBytes(session.user.storage_quota_bytes) + }, + '{{percentage}}% used ({{used}} / {{total}})' + )} + {:else} + {formatBytes(session.user.storage_used_bytes)} + {/if}
{/if} @@ -661,7 +673,7 @@
e.target === e.currentTarget && (aboutOpen = false)}>