fix(downloads): a file asked for again during an over-cap pass stays whatever the clock says
The eviction pass called a file freshly used only when its last-access stamp was later than the pass's own clock. A hit stamped just before the pass began but committed after its SELECT, or stamped by a clock that had stepped back (the test VM's does), read as old, and the file the user had just asked for was evicted. The pass now keeps the stamp its SELECT saw and skips a file whose stamp changed since.
This commit is contained in:
+14
-15
@@ -282,33 +282,32 @@ def run_download_gc(db: Session) -> dict:
|
||||
kept_assets = select(DownloadJob.asset_id).where(
|
||||
DownloadJob.kept.is_(True), DownloadJob.asset_id.is_not(None)
|
||||
)
|
||||
candidate_ids = (
|
||||
db.execute(
|
||||
select(MediaAsset.id)
|
||||
.where(
|
||||
MediaAsset.status == "ready",
|
||||
MediaAsset.source_kind != "upload",
|
||||
MediaAsset.id.not_in(kept_assets),
|
||||
)
|
||||
.order_by(MediaAsset.last_access_at.asc().nulls_first())
|
||||
candidates = db.execute(
|
||||
select(MediaAsset.id, MediaAsset.last_access_at)
|
||||
.where(
|
||||
MediaAsset.status == "ready",
|
||||
MediaAsset.source_kind != "upload",
|
||||
MediaAsset.id.not_in(kept_assets),
|
||||
)
|
||||
.scalars()
|
||||
.all()
|
||||
)
|
||||
.order_by(MediaAsset.last_access_at.asc().nulls_first())
|
||||
).all()
|
||||
db.rollback()
|
||||
for asset_id in candidate_ids:
|
||||
for asset_id, seen_access in candidates:
|
||||
# Counted afresh before each: a file deleted since (this one, an upload, a candidate
|
||||
# further down) has freed its space, and no other user's file goes for that space.
|
||||
if _on_disk(db) <= cap:
|
||||
break
|
||||
# Locked and re-read like an expiry: since the SELECT a holder may have kept it,
|
||||
# every holder deleted it, or someone asked for it again (a fresh cache hit).
|
||||
# every holder deleted it, or someone asked for it again (a fresh cache hit). A hit
|
||||
# is a CHANGED stamp, not one later than this pass's clock: a hit stamped just
|
||||
# before the pass began but committed after the SELECT is still a hit, and a clock
|
||||
# that steps back would make a fresh one look old.
|
||||
asset, holders = _relock_evictable(db, asset_id)
|
||||
if (
|
||||
asset is None
|
||||
or asset.status != "ready"
|
||||
or any(j.kept for j in holders)
|
||||
or (asset.last_access_at is not None and asset.last_access_at > now)
|
||||
or asset.last_access_at != seen_access
|
||||
):
|
||||
db.commit()
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user