v0.4.20: close reindex publish race + harden preload guard
Some checks failed
build / build (push) Has been cancelled
Some checks failed
build / build (push) Has been cancelled
Reviewer-flagged: the existing-cache reindex branch in VideoCache.download only ran one epoch check before READY.put, so a /videoCache clear landing between the check and the put could leave a stale entry pointing at a now-deleted file. Same pattern as the post-move fix in v0.4.19, applied to the reindex path: pre-check, put, post-check + rollback on mismatch. Also: preload() previously gated on READY.containsKey(url), which silently blocks a re-preload if READY holds a stale key whose backing file is gone (e.g. user deleted the file manually, or the cleanup half of a clear race). Switched to lookup(url) — same intent, but lookup verifies the file actually exists on disk, so stale keys self-heal on the next preload.
This commit is contained in:
@@ -5,7 +5,7 @@ org.gradle.configuration-cache=false
|
|||||||
|
|
||||||
# Mod
|
# Mod
|
||||||
mod_id=video_player
|
mod_id=video_player
|
||||||
mod_version=0.4.19
|
mod_version=0.4.20
|
||||||
maven_group=com.ejclaw.videoplayer
|
maven_group=com.ejclaw.videoplayer
|
||||||
archives_base_name=video_player
|
archives_base_name=video_player
|
||||||
|
|
||||||
|
|||||||
@@ -190,7 +190,11 @@ public final class VideoCache {
|
|||||||
public static void preload(String url) {
|
public static void preload(String url) {
|
||||||
if (url == null || url.isEmpty()) return;
|
if (url == null || url.isEmpty()) return;
|
||||||
if (!(url.startsWith("http://") || url.startsWith("https://"))) return;
|
if (!(url.startsWith("http://") || url.startsWith("https://"))) return;
|
||||||
if (READY.containsKey(url)) {
|
// Use lookup() (which also verifies the file exists on disk) instead of
|
||||||
|
// READY.containsKey — defends against READY containing a stale entry whose
|
||||||
|
// backing file was removed by clearAll() / a user-side file delete. Without this,
|
||||||
|
// a stale key would silently block a re-preload.
|
||||||
|
if (lookup(url) != null) {
|
||||||
VideoPlayerMod.LOG.info("[{}] preload: already cached {}", VideoPlayerMod.MOD_ID, url);
|
VideoPlayerMod.LOG.info("[{}] preload: already cached {}", VideoPlayerMod.MOD_ID, url);
|
||||||
notifyChat("[videopreload] 이미 캐시됨: " + url, ChatFormatting.GRAY);
|
notifyChat("[videopreload] 이미 캐시됨: " + url, ChatFormatting.GRAY);
|
||||||
return;
|
return;
|
||||||
@@ -255,8 +259,22 @@ public final class VideoCache {
|
|||||||
// Resume-friendly: if the file's already on disk from an earlier session, just
|
// Resume-friendly: if the file's already on disk from an earlier session, just
|
||||||
// index it without re-downloading.
|
// index it without re-downloading.
|
||||||
if (Files.exists(finalPath) && Files.size(finalPath) > 0) {
|
if (Files.exists(finalPath) && Files.size(finalPath) > 0) {
|
||||||
|
// Pre-publish check — bail if clearAll has run since submit.
|
||||||
if (CACHE_EPOCH.get() != startEpoch) return;
|
if (CACHE_EPOCH.get() != startEpoch) return;
|
||||||
READY.put(url, finalPath);
|
READY.put(url, finalPath);
|
||||||
|
// Post-publish re-check: same window as the post-move check on the download
|
||||||
|
// path. If clearAll landed between the epoch read above and the READY.put,
|
||||||
|
// it would have wiped READY + the file, and our put() resurrected a stale
|
||||||
|
// entry pointing at a now-deleted path. Roll it back: remove our entry
|
||||||
|
// (compareAndRemove via remove(key, value) to avoid clobbering a concurrent
|
||||||
|
// legitimate re-put) and best-effort delete the file.
|
||||||
|
if (CACHE_EPOCH.get() != startEpoch) {
|
||||||
|
READY.remove(url, finalPath);
|
||||||
|
try { Files.deleteIfExists(finalPath); } catch (Throwable ignored) {}
|
||||||
|
VideoPlayerMod.LOG.info("[{}] preload: reindex cancelled (clearAll ran) — {}",
|
||||||
|
VideoPlayerMod.MOD_ID, url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
VideoPlayerMod.LOG.info("[{}] preload: indexed existing cache {} -> {}",
|
VideoPlayerMod.LOG.info("[{}] preload: indexed existing cache {} -> {}",
|
||||||
VideoPlayerMod.MOD_ID, url, finalPath.getFileName());
|
VideoPlayerMod.MOD_ID, url, finalPath.getFileName());
|
||||||
notifyChat("[videopreload] 기존 캐시 사용: " + url, ChatFormatting.GREEN);
|
notifyChat("[videopreload] 기존 캐시 사용: " + url, ChatFormatting.GREEN);
|
||||||
|
|||||||
Reference in New Issue
Block a user