feat: thumbnail dedup — store thumbnails by blob_hash instead of file_id (#233)
Thumbnails are now keyed by blob_hash on disk so identical files share
a single set of thumbnails (icon/preview/large). For 4000 duplicate
files with the same content, this reduces thumbnail storage from 12,000
files to just 3.
Changes:
- get_thumbnail_path() keys by blob_hash instead of file_id
- get_thumbnail(), get_cached_thumbnail(), generate_all_sizes_background()
accept blob_hash parameter for disk dedup
- generate_all_sizes_background() fast path: if blob-hash thumbnails
already exist on disk, skip image processing entirely and just
populate moka cache for the new file_id
- delete_thumbnails() only invalidates moka cache (shared disk
thumbnails must not be deleted when one file is removed)
- delete_blob_thumbnails() added for GC; garbage_collect() now cleans
up orphaned thumbnail files alongside blob files
- External thumbnails (video frames) stored as ext-{file_id}.jpg
since they are client-generated and not dedup-able
- ThumbnailPort trait updated with blob_hash parameters
- All handler call sites updated (file_handler, preview_handler)
- Tests updated for new signatures
This commit is contained in:
@@ -359,7 +359,7 @@ impl FileHandler {
|
||||
// Try moka (RAM) → disk before touching the database.
|
||||
// If the thumbnail exists it was authorized at creation time.
|
||||
if let Some(data) = thumbnail_service
|
||||
.get_cached_thumbnail(&id, thumb_size.into())
|
||||
.get_cached_thumbnail(&id, None, thumb_size.into())
|
||||
.await
|
||||
{
|
||||
return Response::builder()
|
||||
@@ -411,7 +411,7 @@ impl FileHandler {
|
||||
let file_path = state.core.dedup_service.blob_path(&blob_hash);
|
||||
|
||||
match thumbnail_service
|
||||
.get_thumbnail(&id, thumb_size.into(), &file_path)
|
||||
.get_thumbnail(&id, &blob_hash, thumb_size.into(), &file_path)
|
||||
.await
|
||||
{
|
||||
Ok(data) => Response::builder()
|
||||
@@ -742,10 +742,11 @@ impl FileHandler {
|
||||
let file_id = file.id.clone();
|
||||
let thumbnail_service = state.core.thumbnail_service.clone();
|
||||
let file_path = state.core.dedup_service.blob_path(&blob_hash);
|
||||
let blob_hash_owned = blob_hash.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
tracing::info!("🖼️ Generating thumbnails for: {}", file_id);
|
||||
thumbnail_service.generate_all_sizes_background(file_id, file_path);
|
||||
thumbnail_service.generate_all_sizes_background(file_id, blob_hash_owned, file_path);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user