feat(offline_cache): enforce cache size limit on new track downloads
Pre-flight check_cache_limit reads the current total_size_bytes and returns an informative error if the cache is already at or over the configured limit. Wired into v2_cache_track_for_offline (single) and v2_cache_tracks_batch_for_offline (batch). Re-download paths are not gated since they target tracks already counted toward the total. The check intentionally does not predict the new track's size; preventing cache from growing further once at the limit is enough for v1. cc
This commit is contained in:
2 files changed
+44
No files matched your search
@@ -923,8 +923,13 @@ pub async fn v2_cache_track_for_offline(
|
|||||||
let file_path = cache_state.track_file_path(track_id, "flac");
|
let file_path = cache_state.track_file_path(track_id, "flac");
|
||||||
let file_path_str = file_path.to_string_lossy().to_string();
|
let file_path_str = file_path.to_string_lossy().to_string();
|
||||||
{
|
{
|
||||||
|
let limit_bytes = *cache_state.limit_bytes.lock().await;
|
||||||
let guard = cache_state.db.lock().await;
|
let guard = cache_state.db.lock().await;
|
||||||
let db = guard.as_ref().ok_or("No active session - please log in")?;
|
let db = guard.as_ref().ok_or("No active session - please log in")?;
|
||||||
|
// Pre-flight: refuse new downloads when the cache is already at or
|
||||||
|
// above the configured limit (Fix #5d).
|
||||||
|
let cache_root = std::path::PathBuf::from(cache_state.get_cache_path());
|
||||||
|
crate::offline_cache::maintenance::check_cache_limit(db, &cache_root, limit_bytes)?;
|
||||||
db.insert_track(&track_info, &file_path_str)?;
|
db.insert_track(&track_info, &file_path_str)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,8 +1000,14 @@ pub async fn v2_cache_tracks_batch_for_offline(
|
|||||||
|
|
||||||
// Single transactional batch insert
|
// Single transactional batch insert
|
||||||
{
|
{
|
||||||
|
let limit_bytes = *cache_state.limit_bytes.lock().await;
|
||||||
let guard = cache_state.db.lock().await;
|
let guard = cache_state.db.lock().await;
|
||||||
let db = guard.as_ref().ok_or("No active session - please log in")?;
|
let db = guard.as_ref().ok_or("No active session - please log in")?;
|
||||||
|
// Pre-flight: refuse new batch downloads when the cache is already at
|
||||||
|
// or above the configured limit (Fix #5d). One check covers the whole
|
||||||
|
// batch; this is intentionally simple and does not predict batch size.
|
||||||
|
let cache_root = std::path::PathBuf::from(cache_state.get_cache_path());
|
||||||
|
crate::offline_cache::maintenance::check_cache_limit(db, &cache_root, limit_bytes)?;
|
||||||
let refs: Vec<(&crate::offline_cache::TrackCacheInfo, String)> = batch
|
let refs: Vec<(&crate::offline_cache::TrackCacheInfo, String)> = batch
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(info, path)| (info, path.clone()))
|
.map(|(info, path)| (info, path.clone()))
|
||||||
|
|||||||
@@ -41,6 +41,39 @@ pub fn remove_album_cached_tracks(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pre-flight cache-limit check executed before queuing new downloads.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(())` when:
|
||||||
|
/// - `limit_bytes` is `None` (no limit configured); OR
|
||||||
|
/// - the current `total_size_bytes` from the cache stats is strictly below the
|
||||||
|
/// configured limit.
|
||||||
|
///
|
||||||
|
/// Returns `Err(message)` when the cache has already met or exceeded the
|
||||||
|
/// configured limit. The message is suitable for surfacing to end users via a
|
||||||
|
/// toast.
|
||||||
|
///
|
||||||
|
/// Intentionally simple: it does not predict the new track's size. Sufficient
|
||||||
|
/// for v1 — the user gets feedback the moment they hit the limit and can free
|
||||||
|
/// space or raise the limit through the offline cache manager.
|
||||||
|
pub fn check_cache_limit(
|
||||||
|
db: &OfflineCacheDb,
|
||||||
|
offline_root: &Path,
|
||||||
|
limit_bytes: Option<u64>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let limit = match limit_bytes {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Ok(()),
|
||||||
|
};
|
||||||
|
let stats = db.get_stats(&offline_root.to_string_lossy(), Some(limit))?;
|
||||||
|
if stats.total_size_bytes >= limit {
|
||||||
|
return Err(
|
||||||
|
"Offline cache limit reached. Free space or raise the limit in the offline cache manager."
|
||||||
|
.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Filters tracks targeted by re-download: skip in-flight Downloading,
|
/// Filters tracks targeted by re-download: skip in-flight Downloading,
|
||||||
/// optionally restrict to Failed only.
|
/// optionally restrict to Failed only.
|
||||||
pub fn select_redownload_targets(
|
pub fn select_redownload_targets(
|
||||||
|
|||||||
Reference in new issue
Block a user