Files
MeowOS-SDK/tuku/logic/reader/page_cache.h
T
AskaEth 4befbfe14c 图库: 书库点图改按文件名定位(修 P1 截断错位)+ 册间衔接根锁定(M18 评审 r1)
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;交叉构建零警告。
2026-11-05 20:26:40 +08:00

76 lines
3.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 */