perf: serve ranges from RAM cache, stream ZIPs, overlap ingest settle, O(1) chunk gate
Round 2 of benchmark-gated optimizations (benches/ROUND2.md; every change gated by a before/after in examples/bench_round2.rs — an AFTER that did not beat its BEFORE was to be rolled back; none needed it): - Range requests (REST/DAV/shares) answered from the moka content cache for sub-10MB files: PG resolve + open/seek/read -> Bytes::slice. 256KiB seeks: 1,730/s -> 3.7M/s (p50 552us -> 0.15us). - Streaming folder/share ZIPs via tokio duplex: TTFB no longer scales with archive size (326ms -> 0.4ms on 192MiB corpus; total also faster). Content-Length dropped (size unknown up front). - NC chunked-upload per-PUT gate: O(k) directory scan+stat -> in-RAM per-session counter (lazy rebuild on cold start). 1,000-chunk upload gate cost: 33.1s -> 0.09s cumulative. - Delta download + commit-verify now use the CDC path's buffered(read_prefetch) read-ahead: 64-chunk drain at 5ms open latency 440ms -> 51ms; order preserved. - CDC ingest settles batches on a spawned task (depth-1 pipeline) so the source stream keeps flowing during PG pin + backend writes; rollback ledger shared + lock-serialized so compensation stays exact on cancellation. 512MiB paced ingest: 60-69 -> 74-75 MB/s. OXICLOUD_INGEST_OVERLAP=0 restores inline settling (ops/bench hatch). - Frontend: instant-upload BLAKE3 hashing moved off the main thread to a bounded Web Worker pool (File handles by reference); vitest gate asserts the pool beats sequential (first gate draft posting buffers was 2.6x slower and was rewritten — copies dominated). Validation: cargo fmt + clippy -D warnings clean; 514 unit + 544 integration tests green; 270 frontend tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CBK1RdtzyP6759Muqe1K1w
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* OxiCloud — whole-file BLAKE3 hashing worker.
|
||||
*
|
||||
* Computes the instant-upload ("does the server already own this?") hashes
|
||||
* OFF the main thread. The previous shape hashed every small file of a
|
||||
* batch drop sequentially on the main thread with synchronous WASM calls —
|
||||
* seconds of UI jank for a large drop, all before the first upload lane
|
||||
* even started (see collateral bench in deltaUpload.hash.test.ts).
|
||||
*
|
||||
* Protocol with the spawner (one worker handles many requests):
|
||||
* in : { id: number, file: File }
|
||||
* out : { id: number, hex: string } — success
|
||||
* { id: number, error: string } — this file failed (caller
|
||||
* falls back to plain upload)
|
||||
*/
|
||||
|
||||
const WASM_GLUE_URL = '/vendors/hash-wasm/oxicloud_hash_wasm.js';
|
||||
|
||||
let modPromise = null;
|
||||
function load() {
|
||||
if (!modPromise) {
|
||||
modPromise = import(WASM_GLUE_URL).then(async (mod) => {
|
||||
await mod.default();
|
||||
return mod;
|
||||
});
|
||||
}
|
||||
return modPromise;
|
||||
}
|
||||
|
||||
self.onmessage = async (ev) => {
|
||||
const { id, file } = ev.data;
|
||||
try {
|
||||
const mod = await load();
|
||||
const bytes = new Uint8Array(await file.arrayBuffer());
|
||||
const hex = mod.blake3Hex(bytes);
|
||||
self.postMessage({ id, hex });
|
||||
} catch (err) {
|
||||
self.postMessage({ id, error: String(err) });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user