mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-22 03:05:32 +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
|
|
@ -28,6 +28,8 @@ pub struct EntrySummary {
|
|||
pub parent_entry_uid: Option<String>,
|
||||
/// True if a `favicon` artifact exists for this entry.
|
||||
pub has_favicon: bool,
|
||||
/// Bytes of blobs already on disk from an earlier entry (precomputed at capture time).
|
||||
pub cached_bytes: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
|
||||
|
|
@ -206,7 +208,8 @@ pub fn list_root_entries(conn: &rusqlite::Connection, caller_bits: u32) -> Resul
|
|||
COUNT(ea.id) AS artifact_count,
|
||||
COALESCE(SUM(b.byte_size), 0) AS total_artifact_bytes,
|
||||
NULL AS parent_entry_uid,
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon,
|
||||
e.cached_bytes
|
||||
FROM archived_entries e
|
||||
JOIN source_identities si ON si.id = e.source_identity_id
|
||||
LEFT JOIN entry_artifacts ea ON ea.entry_id = e.id
|
||||
|
|
@ -238,6 +241,7 @@ pub fn list_root_entries(conn: &rusqlite::Connection, caller_bits: u32) -> Resul
|
|||
total_artifact_bytes: row.get(8)?,
|
||||
parent_entry_uid: row.get(9)?,
|
||||
has_favicon: row.get::<_, i64>(10)? != 0,
|
||||
cached_bytes: row.get(11)?,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<Vec<_>>>()?;
|
||||
|
|
@ -425,6 +429,7 @@ pub fn list_entries_for_collection(
|
|||
total_artifact_bytes: row.get(8)?,
|
||||
parent_entry_uid: row.get(9)?,
|
||||
has_favicon: row.get::<_, i64>(10)? != 0,
|
||||
cached_bytes: row.get(11)?,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<Vec<_>>>()?;
|
||||
|
|
@ -539,7 +544,8 @@ const ENTRY_SELECT_COLS: &str =
|
|||
e.visibility, si.canonical_url, COUNT(ea.id) AS artifact_count, \
|
||||
COALESCE(SUM(b.byte_size), 0) AS total_artifact_bytes, \
|
||||
parent.entry_uid AS parent_entry_uid, \
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon";
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon, \
|
||||
e.cached_bytes";
|
||||
|
||||
const ENTRY_FROM_JOINS: &str =
|
||||
"FROM archived_entries e \
|
||||
|
|
@ -649,6 +655,7 @@ pub fn search_entries(
|
|||
total_artifact_bytes: row.get(8)?,
|
||||
parent_entry_uid: row.get(9)?,
|
||||
has_favicon: row.get::<_, i64>(10)? != 0,
|
||||
cached_bytes: row.get(11)?,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<Vec<_>>>()?;
|
||||
|
|
@ -810,7 +817,8 @@ pub fn entries_for_tag(
|
|||
e.visibility, si.canonical_url, COUNT(ea.id) AS artifact_count,
|
||||
COALESCE(SUM(b.byte_size), 0) AS total_artifact_bytes,
|
||||
parent.entry_uid AS parent_entry_uid,
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon
|
||||
EXISTS(SELECT 1 FROM entry_artifacts fav WHERE fav.entry_id = e.id AND fav.artifact_role = 'favicon') AS has_favicon,
|
||||
e.cached_bytes
|
||||
FROM archived_entries e
|
||||
JOIN source_identities si ON si.id = e.source_identity_id
|
||||
LEFT JOIN entry_artifacts ea ON ea.entry_id = e.id
|
||||
|
|
@ -835,6 +843,7 @@ pub fn entries_for_tag(
|
|||
total_artifact_bytes: row.get(8)?,
|
||||
parent_entry_uid: row.get(9)?,
|
||||
has_favicon: row.get::<_, i64>(10)? != 0,
|
||||
cached_bytes: row.get(11)?,
|
||||
})
|
||||
})?
|
||||
.collect::<rusqlite::Result<Vec<_>>>()?;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue