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:
@@ -424,6 +424,18 @@ pub struct DatabaseConfig {
|
||||
/// Minimum connections for the maintenance pool.
|
||||
/// Defaults to 1.
|
||||
pub maintenance_min_connections: u32,
|
||||
/// Per-statement timeout (seconds) applied to the **primary** pool via
|
||||
/// `SET statement_timeout` on every connection. Bounds the worst-case query
|
||||
/// so a single runaway statement can't pin a pool slot and starve
|
||||
/// interactive requests (correlated tail-latency cliff). `0` disables it.
|
||||
/// The maintenance pool is always exempt — its batch jobs (integrity scans,
|
||||
/// GC) may legitimately run long. Env: `OXICLOUD_DB_STATEMENT_TIMEOUT_SECS`.
|
||||
pub statement_timeout_secs: u64,
|
||||
/// Interval (seconds) of the background watchdog that samples primary-pool
|
||||
/// saturation and logs a WARN when connections are near exhaustion (the
|
||||
/// signal to raise `max_connections` or hunt slow queries). `0` disables
|
||||
/// it. Default: 30. Env: `OXICLOUD_DB_POOL_MONITOR_INTERVAL_SECS`.
|
||||
pub pool_monitor_interval_secs: u64,
|
||||
}
|
||||
|
||||
impl Default for DatabaseConfig {
|
||||
@@ -438,6 +450,8 @@ impl Default for DatabaseConfig {
|
||||
max_lifetime_secs: 1800,
|
||||
maintenance_max_connections: 5,
|
||||
maintenance_min_connections: 1,
|
||||
statement_timeout_secs: 30,
|
||||
pool_monitor_interval_secs: 30,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1233,6 +1247,20 @@ impl AppConfig {
|
||||
config.database.maintenance_min_connections = val;
|
||||
}
|
||||
|
||||
if let Ok(stmt_timeout) =
|
||||
env::var("OXICLOUD_DB_STATEMENT_TIMEOUT_SECS").map(|v| v.parse::<u64>())
|
||||
&& let Ok(val) = stmt_timeout
|
||||
{
|
||||
config.database.statement_timeout_secs = val;
|
||||
}
|
||||
|
||||
if let Ok(interval) =
|
||||
env::var("OXICLOUD_DB_POOL_MONITOR_INTERVAL_SECS").map(|v| v.parse::<u64>())
|
||||
&& let Ok(val) = interval
|
||||
{
|
||||
config.database.pool_monitor_interval_secs = val;
|
||||
}
|
||||
|
||||
// Auth configuration
|
||||
if let Some(jwt_secret) = env::var("OXICLOUD_JWT_SECRET")
|
||||
.ok()
|
||||
|
||||
Reference in New Issue
Block a user