feat(ncm): 缓存分目录(songs//covers/)+ 陈旧 mp3 缓存修复
任务1 缓存分目录(用户定案):\n- ncm_cache_init mkdir songs/ 与 covers/ 子目录 + 一次性迁移\n (根混放 song_*/cov*/cover_current.jpg 挪进两子目录,幂等,legacy_migrated 计数)\n- ncm_cache_path 按 id 前缀路由(cov*→covers/,其余→songs/)\n- LRU(evict/total_bytes/7天 .part 回收)只扫 songs/;clear 清 songs/+covers/ 的 song_*\n- cover.c save_cover_raw 落 covers/cover_current.jpg\n\n任务2 陈旧 mp3 缓存修复(真机实锤:hires 档键下存 mp3,播放命中旧档):\n- song_local_file 缓存命中且用户档>EXHIGH(无损+)且实体是 .mp3 = 静默降级产物\n → 迁移重命名到 exhigh 键 song_<id>_exhigh.mp3(选极高仍可用;目标已存在删旧)\n → 本档视为未命中走下载(311 flac 门禁拿真无损/正确降级)\n\n验证:cache_evict_sim case10(目录迁移一次成型)+P1-9;player_flow_sim P13(迁移+miss)\n+P1-12 零回归;stream/window/search/degrade/cover_chain/test_ncm_core(host+qemu) 全 PASS;\nbuild_ncm.sh -Wall -Wextra 0 warning。0 真实请求。新 ncm md5 a90ba8c3 (text1028458/bss1364484)。
This commit is contained in:
1 parent
986e3814bc
commit
de18cef02c
11 files changed
+299
-64
No files matched your search
@@ -8,6 +8,8 @@
|
||||
* ③ ncm_cache_lookup 刷新 mtime(LRU:被访问的最近优先存活);
|
||||
* ④ ncm_cache_set_limit_gb 越界钳制(1~100GB);
|
||||
* ⑤ ncm_cache_clear 删除 song_* 全部(mp3/封面/残留 .tmp)。
|
||||
* §NEW 缓存分目录:song_* 落 songs/、封面(song_cov*、cover_current.jpg)落 covers/;
|
||||
* LRU/7 天回收只扫 songs/;⑩ 覆盖 ncm_cache_init 一次性把根混放文件迁入两子目录。
|
||||
* 文件用 ftruncate 生成稀疏文件(逻辑大小可控,磁盘零消耗)。
|
||||
*
|
||||
* 编译(宿主,链接 core/ncm_cache.c + 本文件):
|
||||
@@ -103,20 +105,27 @@ static int cached_exists(const char *id, const char *ext)
|
||||
|
||||
static unsigned long long mb(unsigned long long n) { return n * 1024ULL * 1024ULL; }
|
||||
|
||||
static void sweep_dir(const char *dir)
|
||||
{
|
||||
DIR *d = opendir(dir);
|
||||
if (!d) return;
|
||||
struct dirent *e;
|
||||
while ((e = readdir(d))) {
|
||||
if (strncmp(e->d_name, "song_", 5) != 0) continue;
|
||||
char p[900];
|
||||
snprintf(p, sizeof p, "%s/%s", dir, e->d_name);
|
||||
unlink(p);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
/* 分目录后:song_* 落在 songs/(封面条目 song_cov* 在 covers/),清根 + 两个子目录。 */
|
||||
static void cleanup(void)
|
||||
{
|
||||
/* 递归删 g_dir 下 song_*(恢复干净池) */
|
||||
DIR *d = opendir(g_dir);
|
||||
if (d) {
|
||||
struct dirent *e;
|
||||
while ((e = readdir(d))) {
|
||||
if (strncmp(e->d_name, "song_", 5) != 0) continue;
|
||||
char p[800];
|
||||
snprintf(p, sizeof p, "%s/%s", g_dir, e->d_name);
|
||||
unlink(p);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
char sub[640];
|
||||
sweep_dir(g_dir);
|
||||
snprintf(sub, sizeof sub, "%s/songs", g_dir); sweep_dir(sub);
|
||||
snprintf(sub, sizeof sub, "%s/covers", g_dir); sweep_dir(sub);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
@@ -330,6 +339,54 @@ int main(void)
|
||||
CHECK(stat(lp, &st) == 0, "fresh .part kept (inflight/resumable)");
|
||||
}
|
||||
|
||||
/* ⑩ §NEW 缓存分目录:ncm_cache_init 一次性把根混放的 song_*、cov*、cover_current.jpg 迁入
|
||||
* songs//covers/(幂等),迁移后 lookup/total 照常在 songs/ 工作(覆盖场景 1)。 */
|
||||
printf("== case 10: init legacy migration songs//covers/ one-shot ==\n");
|
||||
cleanup();
|
||||
{
|
||||
char p[900], sp[900], path[900];
|
||||
struct stat st;
|
||||
/* 根放旧布局混血文件:歌曲(含双点畸形/在途 .tmp)+ 封面条目 + cover_current */
|
||||
snprintf(p, sizeof p, "%s/song_legacy..mp3", g_dir);
|
||||
FILE *f = fopen(p, "wb"); if (f) { fputs("OLD1", f); fclose(f); }
|
||||
snprintf(p, sizeof p, "%s/song_legacy2.mp3", g_dir);
|
||||
f = fopen(p, "wb"); if (f) { fputs("OLD2", f); fclose(f); }
|
||||
snprintf(p, sizeof p, "%s/song_legacy3.mp3.tmp", g_dir); /* 在途 .tmp 随迁 */
|
||||
f = fopen(p, "wb"); if (f) { fputs("TMP!", f); fclose(f); }
|
||||
snprintf(p, sizeof p, "%s/song_covDEAD.jpg", g_dir);
|
||||
f = fopen(p, "wb"); if (f) { fputs("COV", f); fclose(f); }
|
||||
snprintf(p, sizeof p, "%s/cover_current.jpg", g_dir);
|
||||
f = fopen(p, "wb"); if (f) { fputs("CUR", f); fclose(f); }
|
||||
|
||||
/* 重 init 触发迁移(memset 复位 + mkdir + 迁移);注意 limit 被复位到默认 10GB。 */
|
||||
ncm_cache_init(&g_c, g_dir);
|
||||
ncm_cache_set_limit_gb(&g_c, 1);
|
||||
CHECK(g_c.legacy_migrated == 5, "legacy_migrated=%d (expect 5)", g_c.legacy_migrated);
|
||||
|
||||
snprintf(sp, sizeof sp, "%s/songs/song_legacy..mp3", g_dir);
|
||||
CHECK(stat(sp, &st) == 0, "double-dot song moved into songs/");
|
||||
snprintf(sp, sizeof sp, "%s/songs/song_legacy2.mp3", g_dir);
|
||||
CHECK(stat(sp, &st) == 0, "song moved into songs/");
|
||||
snprintf(sp, sizeof sp, "%s/songs/song_legacy3.mp3.tmp", g_dir);
|
||||
CHECK(stat(sp, &st) == 0, "in-flight .tmp moved into songs/");
|
||||
snprintf(sp, sizeof sp, "%s/covers/song_covDEAD.jpg", g_dir);
|
||||
CHECK(stat(sp, &st) == 0, "cover cache entry moved into covers/");
|
||||
snprintf(sp, sizeof sp, "%s/covers/cover_current.jpg", g_dir);
|
||||
CHECK(stat(sp, &st) == 0, "cover_current.jpg moved into covers/");
|
||||
snprintf(sp, sizeof sp, "%s/song_legacy2.mp3", g_dir);
|
||||
CHECK(stat(sp, &st) != 0, "root song_* gone after migration");
|
||||
|
||||
/* 双点存量在 songs/ 内被 lookup 修成单点(不重下) */
|
||||
CHECK(ncm_cache_lookup(&g_c, "legacy", "mp3", path, sizeof path) == NCM_OK,
|
||||
"migrated double-dot lookup hit");
|
||||
CHECK(strstr(path, "song_legacy.mp3") != NULL && strstr(path, "..") == NULL,
|
||||
"double-dot fixed to single-dot (%s)", path);
|
||||
/* total 只计 songs/(OLD1 4B + OLD2 4B;.tmp 半成品/封面不在 LRU 池) */
|
||||
CHECK(ncm_cache_total_bytes(&g_c) == 8,
|
||||
"total counts songs only (=%llu, expect 8)",
|
||||
(unsigned long long)ncm_cache_total_bytes(&g_c));
|
||||
}
|
||||
|
||||
cleanup();
|
||||
printf("%s\n", g_fail ? "RESULT: FAIL" : "RESULT: PASS");
|
||||
return g_fail ? 1 : 0;
|
||||
|
||||
Reference in new issue
Block a user