P1-1(会静默开错图):取消「书库从列表推导图片下标」。 - 新增 mr_reader_open_dir_at_name(dir, name):阅读器打开目录册后,在**自己刚枚举出的 全量目录册**(mr_dir_book,与翻页同一份枚举)里按 basename 定位起始页(先精确, 再大小写不敏感兜底;找不到退回续读/首页)。书库点击只传文件名。 - 删除 mr_library_image_index(不再有跨枚举的隐式契约)。 - 截断提示文案改为「仅显示前 2000 项(图片可在阅读器中翻到)」。 - 修复前(cb02722 探针,2100 张 4 位名夹具):rows=2000/truncated=1/ library_images=2000/reader_pages=2100/**mismatched=590**(首行 p1412 → 打开 p1411); 评审夹具为 1995/2000。修复后:2000 个可见图片行按名定位 **0 mismatch**, 2100 页全量可翻;26 次真实 UI 点开(首尾各 3 + 20 个确定性伪随机)逐张命中。 连带处理(评审 r1): 1. 删掉 reader_page_enter 的 c->view 死写(reopen 判定用 activity active/depth); 顺手删掉 library_page_create 里同款死写。 2. 阅读器册间衔接根锁定:新增 mr_path_within_root + mr_book_adjacent_rooted, book_switch 用浏览根(默认 MR_ROOT_DIR,测试可注入)钳制相邻册; 根外的兄弟册按「没有相邻册」处理。test_cont_adjacent A7 验证「明文 _ex 会越根、 rooted 拒绝、根内翻册不受影响」;test_mode_switch_host H6 验证条漫末页不越根。 3. test_reader_perf 不再依赖顶栏 tap 命中时序:模式切换改走测试钩子 mr_reader_test_toggle_mode()(与顶栏动作同一个 mode_set),负载下稳定。 4. page_cache 注释去掉「缩略图缓存/缩略图线程」过时描述(只改文字)。 回归:run_tests.sh(library 81 / nav 74 / lazy 57 / perf 25 / … / open_book 含 2100 用例) 与 run_webtoon_tests.sh(含 A7/H6)全 PASS;交叉构建零警告。
76 lines
3.6 KiB
C
76 lines
3.6 KiB
C
/* logic/reader/page_cache.h — 档案册解压页的磁盘缓存(纯 C,不依赖 SDK)。
|
||
*
|
||
* 为什么需要磁盘缓存:SDK 的图像解码入口只吃文件路径(meow_img_load_file_dim),
|
||
* 而 zip 里的页是压缩流。档案页源在 open(i) 时把条目解压成缓存文件,再用同一个
|
||
* 解码回调按路径解码——两种阅读模式(翻页/条漫)与目录册走完全相同的代码路径。
|
||
*
|
||
* 目录与上限(纪律):
|
||
* - 目录 = <数据目录>/cache(数据目录形如 .../MeowData/os.meow.picbrowser/data);
|
||
* 文件名统一前缀 mrpage_,与其它可能落在这目录的临时文件互不影响;
|
||
* - 上限 = 64 页 或 32MiB,先到者触发 LRU 淘汰(按最近使用计数);
|
||
* - **单条目溢出**:某页解压后本身就超过 32MiB 时允许一次性溢出——只保留该条、
|
||
* 其它条目全部淘汰,占用上限受页源单页上限 64MiB(MR_ZIP_PAGE_MAX_BYTES)约束。
|
||
* 这样超大页仍可阅读,不会因为预算拒绝落缓存而变成永久空白页;
|
||
* - mr_cache_init() 首次成功时清掉上一进程遗留的 mrpage_*(孤儿页);
|
||
* - 写入走 "<name>.part" + rename,进程崩溃不会留下半个缓存文件。
|
||
*
|
||
* 键 = 档案路径 + 档案 mtime/size + 条目名 + 页下标:档案被替换(mtime/size 变)或
|
||
* 同名条目重复出现时不会命中旧内容。文件名保留图片扩展名(解码入口按扩展名区分
|
||
* JPEG 的「解码期缩解」路径)。
|
||
*
|
||
* 线程:内部互斥量;可在解码线程/主线程并发调用。
|
||
* 纯 C:宿主测试可直接编译(见 tuku/test/test_cbz.c)。
|
||
*/
|
||
#ifndef MR_PAGE_CACHE_H
|
||
#define MR_PAGE_CACHE_H
|
||
|
||
#include <stddef.h>
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#define MR_CACHE_MAX_PAGES 64
|
||
#define MR_CACHE_MAX_BYTES (32LL * 1024 * 1024)
|
||
#define MR_CACHE_PREFIX "mrpage_"
|
||
#define MR_CACHE_DIR_MAX 200
|
||
#define MR_CACHE_FILE_MAX 256
|
||
|
||
/* 数据目录 → 缓存目录(纯字符串):末尾的 "data" 段替换为 "cache"。
|
||
* 例:/…/MeowData/os.meow.picbrowser/data → /…/MeowData/os.meow.picbrowser/cache。
|
||
* 成功 0;参数非法/缓冲不足 -1。 */
|
||
int mr_cache_dir_from_data(const char *data_dir, char *out, int outsz);
|
||
|
||
/* 文件名是否属于解压页缓存(mrpage_ 前缀)。启动清孤儿用这一判据,
|
||
* 保证同目录的其它文件不被误删。1=解压页缓存。 */
|
||
int mr_cache_is_page_name(const char *name);
|
||
|
||
/* 建立/切换缓存目录并清孤儿。0=可用;-1=不可用(之后 store/touch 均失败)。
|
||
* 同一目录重复调用为无操作(不会删掉正在用的页)。 */
|
||
int mr_cache_init(const char *data_dir);
|
||
|
||
/* 释放索引(不删文件);测试用。可重复调用。 */
|
||
void mr_cache_shutdown(void);
|
||
|
||
int mr_cache_ready(void);
|
||
const char *mr_cache_dir(void); /* 未初始化返回空串 */
|
||
|
||
/* 计算某页缓存文件路径(不碰磁盘)。扩展名取自 entry 名(未知时 .img)。 */
|
||
int mr_cache_path(const char *archive, long long mtime, long long size,
|
||
const char *entry, int page_index, char *out, int outsz);
|
||
|
||
/* 缓存命中:文件在索引里(或磁盘上存在)则刷新 LRU 并返回 1,否则 0。 */
|
||
int mr_cache_touch(const char *path);
|
||
|
||
/* 写入缓存并纳入 LRU;1=成功。len==0 视为失败(空页没有解码价值)。 */
|
||
int mr_cache_store(const char *path, const void *data, size_t len);
|
||
|
||
/* 观测(宿主测试断言 LRU 纪律用):当前索引页数 / 字节数。 */
|
||
int mr_cache_count(void);
|
||
long long mr_cache_bytes(void);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif /* MR_PAGE_CACHE_H */
|