fix(tuku): 评审 P2-1/P2-2——解压页与缩略图缓存互删自愈 + 大页溢出文档化
P2-1(必修):解压页缓存与缩略图 LRU 在 *.bmp 上相互踩踏 - ui/library 的 cache_prune 先按 page_cache 的共用判据 mr_cache_is_page_name 跳过 mrpage_*,不再把 BMP 解压页算进缩略图额度或 unlink(含 Vol10.cbz 这类 BMP 档不再出现「被缩略图 LRU 删掉 → 首页解码失败」); - mr_cache_touch 命中时 stat 校验文件存在与大小,缺失/尺寸不符即移出索引并按 未命中返回,调用方重新解压——外部清理/掉电残留/误删都能自愈,不再返回死路径。 P2-2(文档化一次性溢出): - page_cache.h 与 make_room_locked 写明:单条目本身超过 32MiB 时只保留该条、 其它全部淘汰,占用上限受页源单页 64MiB(MR_ZIP_PAGE_MAX_BYTES)约束; 大页仍可读,不因预算拒绝落缓存。 - 新增 33MiB 页夹具(PNG 头 + 可压零填充,deflate 后仅数十 KB)与断言: 大页可读、cache_bytes 允许超 32MiB、小页被淘汰、再来小页时大页按预算淘汰。 顺手:page_cache.h 注释包名 os.meow.picobrowser → os.meow.picbrowser(测试路径同步)。 测试:test_cbz 267 → 296 项全 PASS;run_tests.sh(zip 106)与 run_webtoon_tests.sh 全绿;交叉构建 sdk/tuku 零警告,产物静态 MIPS32r2 ELF。
This commit is contained in:
1 parent
562cc44931
commit
c775f8558c
5 files changed
+125
-13
No files matched your search
@@ -57,6 +57,11 @@ int mr_cache_dir_from_data(const char *data_dir, char *out, int outsz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mr_cache_is_page_name(const char *name)
|
||||
{
|
||||
return name && strncmp(name, MR_CACHE_PREFIX, strlen(MR_CACHE_PREFIX)) == 0;
|
||||
}
|
||||
|
||||
const char *mr_cache_dir(void)
|
||||
{
|
||||
return g_ready ? g_dir : "";
|
||||
@@ -95,6 +100,9 @@ static void idx_evict_locked(void)
|
||||
idx_remove_locked(oldest);
|
||||
}
|
||||
|
||||
/* 腾出 len 字节:页数或字节先到上限就淘汰最旧。单条 len 本身超过
|
||||
* MR_CACHE_MAX_BYTES 时会清空其它条目、让这一条独占(文档化的一次性溢出,
|
||||
* 上限由页源单页 64MiB 约束)——大页仍可读,不因预算拒绝落缓存。 */
|
||||
static void make_room_locked(long long len)
|
||||
{
|
||||
while (g_n > 0 && (g_n >= MR_CACHE_MAX_PAGES ||
|
||||
@@ -275,19 +283,27 @@ int mr_cache_touch(const char *path)
|
||||
return 0;
|
||||
}
|
||||
int i = idx_find_locked(path);
|
||||
/* 命中也要 stat 校验(P2-1 纵深防御):外部清理、掉电残留、或别的 LRU 误删
|
||||
* 都会让索引指向不存在的文件;假命中会让页源返回死路径且永不自愈。缺失或
|
||||
* 尺寸不符就从索引移除、按未命中处理,让调用方重新解压。 */
|
||||
struct stat st;
|
||||
int exists = stat(path, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0;
|
||||
if (i >= 0) {
|
||||
if (!exists || (long long)st.st_size != g_idx[i].size) {
|
||||
idx_remove_locked(i);
|
||||
pthread_mutex_unlock(&g_lock);
|
||||
return 0;
|
||||
}
|
||||
g_tick++;
|
||||
g_idx[i].used = g_tick;
|
||||
pthread_mutex_unlock(&g_lock);
|
||||
return 1;
|
||||
}
|
||||
/* 索引里没有(外部写入/索引满):磁盘上有就算命中,能装进索引就装。 */
|
||||
struct stat st;
|
||||
int ok = stat(path, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0;
|
||||
if (ok && g_n < MR_CACHE_MAX_PAGES && strlen(path) < MR_CACHE_FILE_MAX)
|
||||
if (exists && g_n < MR_CACHE_MAX_PAGES && strlen(path) < MR_CACHE_FILE_MAX)
|
||||
idx_add_locked(path, (long long)st.st_size);
|
||||
pthread_mutex_unlock(&g_lock);
|
||||
return ok ? 1 : 0;
|
||||
return exists ? 1 : 0;
|
||||
}
|
||||
|
||||
int mr_cache_store(const char *path, const void *data, size_t len)
|
||||
|
||||
Reference in new issue
Block a user