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:
@@ -955,6 +955,24 @@ impl AppServiceFactory {
|
||||
tracing::info!("Tree-ETag flush service initialized");
|
||||
}
|
||||
|
||||
/// Start the primary-pool saturation watchdog (Finding #3). Logs a WARN as
|
||||
/// the user-facing pool approaches exhaustion — the early signal for raising
|
||||
/// `max_connections` or chasing a slow query before tail latency cliffs.
|
||||
/// Skipped when `pool_monitor_interval_secs == 0`.
|
||||
fn start_db_pool_monitor(&self, primary_pool: &Arc<PgPool>) {
|
||||
let interval = self.config.database.pool_monitor_interval_secs;
|
||||
if interval == 0 {
|
||||
return;
|
||||
}
|
||||
crate::infrastructure::services::db_pool_monitor::DbPoolMonitor::new(
|
||||
primary_pool.as_ref().clone(),
|
||||
"primary",
|
||||
self.config.database.max_connections,
|
||||
interval,
|
||||
)
|
||||
.start();
|
||||
}
|
||||
|
||||
/// Opens (or rebuilds) the embedded Tantivy content index. Returns the
|
||||
/// index plus a reseed flag (true when the on-disk index was missing or
|
||||
/// version-stale and must be repopulated from `storage.files`). Any
|
||||
@@ -1149,6 +1167,8 @@ impl AppServiceFactory {
|
||||
|
||||
self.start_tree_etag_flush_job(&maintenance_pool);
|
||||
|
||||
self.start_db_pool_monitor(&pool);
|
||||
|
||||
self.start_content_index_job(&maintenance_pool, &core, content_index);
|
||||
|
||||
// User-lifecycle dispatcher. Hook order is registration order;
|
||||
|
||||
Reference in New Issue
Block a user