mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-21 18:55:36 +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:
parent
c85cce579b
commit
90d17c9d25
10 changed files with 161 additions and 21 deletions
|
|
@ -241,7 +241,7 @@ export default function App() {
|
|||
</div>
|
||||
)}
|
||||
{view === 'archive' && (
|
||||
<EntriesView
|
||||
<EntriesView
|
||||
entries={entries}
|
||||
selectedEntryUid={selectedEntryUid}
|
||||
onSelectEntry={selectEntry}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -310,7 +310,16 @@ select {
|
|||
.col-added { width: 162px; color: var(--muted); }
|
||||
.col-title { flex: 1 1 0; min-width: 0; overflow: hidden; display: flex; align-items: center; gap: 0.42em; }
|
||||
.col-type { width: 116px; }
|
||||
.col-size { width: 96px; }
|
||||
.col-size { width: 100px; display: flex; flex-direction: column; justify-content: center; gap: 1px; }
|
||||
.size-total { font-variant-numeric: tabular-nums; }
|
||||
.size-cached-pct {
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
opacity: 0.8;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.col-url { flex: 0 0 30%; min-width: 0; overflow: hidden; }
|
||||
|
||||
.entry-header-row > div:first-child,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue