1
Fork 0
mirror of https://github.com/thegeneralist01/archivr synced 2026-07-22 11:15:41 +02:00

feat: precompute cached_bytes per entry in DB (#13)

Store how many bytes of each entry's artifacts are already on disk from
an earlier entry (content-addressed blob deduplication means shared
blobs are only stored once).

Design
------
- Add `cached_bytes INTEGER NOT NULL DEFAULT 0` to `archived_entries`
- Precompute at capture time via `database::refresh_entry_cached_bytes`
  called after all artifacts are saved for every capture path
  (web page, generic URL, tweet, yt-dlp/local)
- One-time migration in `initialize_schema`: detects missing column via
  PRAGMA table_info, ALTERs the table, then back-fills all existing rows
  with the correlated subquery
- `database::cascade_cached_bytes_after_delete` ready for when entry
  deletion is implemented; designed to run asynchronously after the
  delete is acknowledged to the user
- `cached_bytes` included in `EntrySummary` and all four SELECT paths
  (list_root_entries, search_entries, list_entries_for_collection,
  entries_for_tag) via the shared ENTRY_SELECT_COLS constant

Frontend
--------
- `EntryRow` shows a `% cached` sub-line under the size when non-zero,
  with a tooltip showing the raw cached byte count
- No separate API endpoint or extra fetch — value rides in the existing
  entries list response at zero extra query cost per read
This commit is contained in:
TheGeneralist 2026-07-03 11:56:55 +02:00 committed by GitHub
parent c85cce579b
commit 90d17c9d25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 161 additions and 21 deletions

View file

@ -39,7 +39,14 @@ export default function EntryRow({ entry, archiveId, isSelected, onSelect }) {
<div className="col-type">
<span className="type-pill">{valueText(entry.entity_kind)}</span>
</div>
<div className="col-size">{formatBytes(entry.total_artifact_bytes)}</div>
<div className="col-size">
<span className="size-total">{formatBytes(entry.total_artifact_bytes)}</span>
{entry.cached_bytes > 0 && entry.total_artifact_bytes > 0 && (
<span className="size-cached-pct" title={`${formatBytes(entry.cached_bytes)} already on disk from an earlier entry`}>
{Math.round(entry.cached_bytes / entry.total_artifact_bytes * 100)}% cached
</span>
)}
</div>
<div className="url-cell col-url">{valueText(entry.original_url)}</div>
</div>
);