cache: single-pass directory walk in eviction functions
evict_oldest and evict_oldest_thumbnails now collect paths, stats, and sizes in one iterdir() pass instead of separate passes for sorting, sizing, and deleting. evict_oldest also accepts a current_bytes arg to skip a redundant cache_size_bytes() call.
This commit is contained in:
parent
10f1b3fd10
commit
b964a77688
@ -599,23 +599,36 @@ def cache_file_count(include_thumbnails: bool = True) -> tuple[int, int]:
|
|||||||
return images, thumbs
|
return images, thumbs
|
||||||
|
|
||||||
|
|
||||||
def evict_oldest(max_bytes: int, protected_paths: set[str] | None = None) -> int:
|
def evict_oldest(max_bytes: int, protected_paths: set[str] | None = None,
|
||||||
"""Delete oldest non-protected cached images until under max_bytes. Returns count deleted."""
|
current_bytes: int | None = None) -> int:
|
||||||
protected = protected_paths or set()
|
"""Delete oldest non-protected cached images until under max_bytes. Returns count deleted.
|
||||||
files = sorted(cache_dir().iterdir(), key=lambda f: f.stat().st_mtime)
|
|
||||||
deleted = 0
|
|
||||||
current = cache_size_bytes(include_thumbnails=False)
|
|
||||||
|
|
||||||
for f in files:
|
*current_bytes* avoids a redundant directory scan when the caller
|
||||||
|
already measured the cache size.
|
||||||
|
"""
|
||||||
|
protected = protected_paths or set()
|
||||||
|
# Single directory walk: collect (path, stat) pairs, sort by mtime,
|
||||||
|
# and sum sizes — avoids the previous pattern of iterdir() for the
|
||||||
|
# sort + a second full iterdir()+stat() inside cache_size_bytes().
|
||||||
|
entries = []
|
||||||
|
total = 0
|
||||||
|
for f in cache_dir().iterdir():
|
||||||
|
if not f.is_file():
|
||||||
|
continue
|
||||||
|
st = f.stat()
|
||||||
|
entries.append((f, st))
|
||||||
|
total += st.st_size
|
||||||
|
current = current_bytes if current_bytes is not None else total
|
||||||
|
entries.sort(key=lambda e: e[1].st_mtime)
|
||||||
|
deleted = 0
|
||||||
|
for f, st in entries:
|
||||||
if current <= max_bytes:
|
if current <= max_bytes:
|
||||||
break
|
break
|
||||||
if not f.is_file() or str(f) in protected or f.suffix == ".part":
|
if str(f) in protected or f.suffix == ".part":
|
||||||
continue
|
continue
|
||||||
size = f.stat().st_size
|
|
||||||
f.unlink()
|
f.unlink()
|
||||||
current -= size
|
current -= st.st_size
|
||||||
deleted += 1
|
deleted += 1
|
||||||
|
|
||||||
return deleted
|
return deleted
|
||||||
|
|
||||||
|
|
||||||
@ -624,17 +637,23 @@ def evict_oldest_thumbnails(max_bytes: int) -> int:
|
|||||||
td = thumbnails_dir()
|
td = thumbnails_dir()
|
||||||
if not td.exists():
|
if not td.exists():
|
||||||
return 0
|
return 0
|
||||||
files = sorted(td.iterdir(), key=lambda f: f.stat().st_mtime)
|
entries = []
|
||||||
deleted = 0
|
current = 0
|
||||||
current = sum(f.stat().st_size for f in td.iterdir() if f.is_file())
|
for f in td.iterdir():
|
||||||
for f in files:
|
|
||||||
if current <= max_bytes:
|
|
||||||
break
|
|
||||||
if not f.is_file():
|
if not f.is_file():
|
||||||
continue
|
continue
|
||||||
size = f.stat().st_size
|
st = f.stat()
|
||||||
|
entries.append((f, st))
|
||||||
|
current += st.st_size
|
||||||
|
if current <= max_bytes:
|
||||||
|
return 0
|
||||||
|
entries.sort(key=lambda e: e[1].st_mtime)
|
||||||
|
deleted = 0
|
||||||
|
for f, st in entries:
|
||||||
|
if current <= max_bytes:
|
||||||
|
break
|
||||||
f.unlink()
|
f.unlink()
|
||||||
current -= size
|
current -= st.st_size
|
||||||
deleted += 1
|
deleted += 1
|
||||||
return deleted
|
return deleted
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user