perf: cache-stampede coalescing + DB safeguards; ui/i18n fixes

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 <a> underline on the link rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DioCrafts
2026-06-20 14:42:10 +02:00
parent ca18858630
commit b14c4dc911
19 changed files with 848 additions and 310 deletions
+20 -6
View File
@@ -261,7 +261,7 @@
<div class="sidebar" class:open={sidebarOpen}>
<a href="/files" class="logo-container">
<div class="logo">
<svg viewBox="120 120 280 280" aria-hidden="true">
<svg viewBox="95 67 320 320" aria-hidden="true">
<path
d="M345 310c32 0 58-26 58-58s-26-58-58-58c-6.2 0-12 0.9-17.5 2.7C318 166 289 143 255 143c-34.3 0-63.1 22.6-73 53.7C176.9 195.7 171 195 165 195c-32 0-58 26-58 58s26 58 58 58h180z"
/>
@@ -302,7 +302,7 @@
session.user.storage_quota_bytes
)}
{:else}
{formatBytes(session.user.storage_used_bytes)} {t('storage.used', 'used')}
{formatBytes(session.user.storage_used_bytes)}
{/if}
</div>
</div>
@@ -526,7 +526,19 @@
<div class="user-menu-storage-fill" style:width="{storagePct}%"></div>
</div>
<div class="user-menu-storage-text">
{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}
</div>
</div>
{/if}
@@ -661,7 +673,7 @@
<div class="about-overlay" onclick={(e) => e.target === e.currentTarget && (aboutOpen = false)}>
<div class="about-modal" role="dialog" aria-modal="true" aria-labelledby="about-modal-title">
<div class="about-modal__logo">
<svg viewBox="120 120 280 280" aria-hidden="true">
<svg viewBox="95 67 320 320" aria-hidden="true">
<path
d="M345 310c32 0 58-26 58-58s-26-58-58-58c-6.2 0-12 0.9-17.5 2.7C318 166 289 143 255 143c-34.3 0-63.1 22.6-73 53.7C176.9 195.7 171 195 165 195c-32 0-58 26-58 58s26 58 58 58h180z"
/>
@@ -1071,8 +1083,10 @@
}
.about-modal__logo {
width: 64px;
height: 64px;
/* 73px (not 64) so the cloud keeps its rendered scale after the viewBox
grew 280→320 to stop clipping its left bulge: 73/320 ≈ 64/280. */
width: 73px;
height: 73px;
color: var(--color-accent);
}