mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-28 20:17:18 -06:00
M1.5: thumbnail/preview cache (disk + memory LRU, prioritized job pool)
- new crate lightcraft-preview (L3): 128-bit content hashing (SipHash-1-3), cost-bounded Lru, DiskCache (JPEG q90 files keyed by content hash + settings hash + size + RENDER_CACHE_VERSION; temp+rename writes; LRU prune by mtime to 80% of budget; corrupt files dropped), PreviewCache (memory LRU over disk), JobPool (per-slot dedupe, priorities, reprioritize/drop, inline mode for wasm). - engine: Session::thumb_job buckets thumbnails to 128/256/384/512 and serves them from the cache without decoding the source; decoded thumbnail sources now in a 384 MB LRU (was unbounded); library attaches <library>/thumbs; library.info cache stats; library.clearPreviews. - ui-egui: Renderer runs on JobPool; thumbnails scrolled out of the prefetch area are dropped from the queue; on-screen thumbnails get re-prioritized; ui.inspect reports in-flight renders + thumb textures. - Demo library (24 photos): grid fully drawn 4.4 s cold -> 0.21 s warm (24/24 disk hits, no source decoded). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
e7b3724b5f
commit
bcecab7d84
@@ -386,8 +386,25 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
cmd!(query "library.info", "Library Info", [], None, "{}", always, |s, _| {
|
||||
let photos = s.catalog.len();
|
||||
let albums = s.catalog.albums().count();
|
||||
let (rendered_n, rendered_bytes) = s.media.rendered.mem_usage();
|
||||
let (sources_n, sources_bytes) = s.media.source_usage();
|
||||
let disk = s.media.rendered.disk().map(|d| {
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
json!({
|
||||
"path": d.dir().display().to_string(),
|
||||
"bytes": d.size(),
|
||||
"hits": d.hits.load(Relaxed),
|
||||
"misses": d.misses.load(Relaxed),
|
||||
"writes": d.writes.load(Relaxed),
|
||||
})
|
||||
});
|
||||
let cache = json!({
|
||||
"renderedInMemory": rendered_n, "renderedBytes": rendered_bytes,
|
||||
"sourcesInMemory": sources_n, "sourceBytes": sources_bytes,
|
||||
"disk": disk,
|
||||
});
|
||||
let Some(lib) = &s.library else {
|
||||
return Ok(json!({"persistent": false, "photos": photos, "albums": albums}));
|
||||
return Ok(json!({"persistent": false, "photos": photos, "albums": albums, "cache": cache}));
|
||||
};
|
||||
let j = lib.journal();
|
||||
Ok(json!({
|
||||
@@ -400,6 +417,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"logRecords": j.log_records(),
|
||||
"logBytes": j.log_bytes(),
|
||||
"lastError": lib.last_error,
|
||||
"cache": cache,
|
||||
"load": {
|
||||
"created": lib.report.created,
|
||||
"replayed": lib.report.replayed,
|
||||
@@ -412,6 +430,10 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
s.compact_library()?;
|
||||
ok()
|
||||
}),
|
||||
cmd!("library.clearPreviews", "Clear Preview Cache", ["File"], None, "{}", always, |s, _| {
|
||||
s.media.rendered.clear();
|
||||
ok()
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user