26,000편(26TB, SMB) 라이브러리에서 지문 생성이 하루에 10%밖에 진행되지 않았다.
원인은 구조다: 프레임 지문을 만들려고 **파일을 처음부터 끝까지 읽는다**(실측 96.8%).
동시 실행을 2→8로 올려도 차이가 없었다 — 대역 병목이라 읽는 양을 줄이는 것 말고는 방법이 없다.
오디오 지문은 `-vn`으로 영상 청크를 건너뛰어 파일의 일부만 읽는다(컨테이너별 실측):
mp4 0.4% · mov 0.4% · ts 0.3% · mkv 1.6% ← 전체 패스 96.8%
그래서 3단계로 나눴다.
- ① 오디오 지문을 전 파일에 먼저 (sig_state=3). 26TB가 아니라 100~400GB를 읽는다.
- ② 저장된 지문으로 후보 쌍을 뽑아 걸린 파일을 표시 (sig_state=4). 파일을 읽지 않는다.
- ③ 프레임은 우선순위대로 — 오디오 짝 있음(4) → 소리 없음(0) → 짝 없음(3).
중복일 가능성이 높은 것부터 처리하므로 결과가 며칠이 아니라 몇 분 뒤부터 나온다.
후보 판정은 탐지와 같은 함수(candidates_from_tokens)를 쓴다 — 규칙이 갈라지면
"지문 단계에서는 후보였는데 탐지에서는 아니다"는 설명 불가능한 상태가 생긴다.
측정으로 정한 것들:
- 오디오만으로는 그룹이 **0개**다(시각 확인이 프레임을 요구한다). ②③이 없으면 무의미하다.
- 오디오는 배속·피치 변화에 무너진다. 216개 토큰 중 공통:
워터마크 216 · 레터박스 216 · 재인코딩 211 · 중간자르기 22/59
1.25배속 3 · 피치+6% 8 · atempo1.05 40/205
배속 사본은 프레임 경로가 뒤에서 채운다(그쪽에 배속 후보 로직이 있다).
근거를 tests/audio_speed_evidence.rs에 고정했다.
- 절감 크기는 중복률에 비례한다. 픽스처는 10편 중 8편이 파생 사본이라 20%만 줄지만,
실제 라이브러리에서 짝이 5%면 26TB가 1.4TB가 된다. 그 비율은 ②가 로그로 알려준다.
함께 고친 것 — 편집 백업이 영구히 쌓이던 문제
- 자르기·반전은 원본을 .archive_trash/edits에 남기는데 지우는 코드가 없었다.
되돌리기는 최근 배치만 보므로 그 창을 벗어난 백업은 되돌릴 수도 없이 자리만 차지했다.
미디어 드라이브에 쌓이므로 영상 라이브러리에서는 수십 GB가 된다.
- 창(20배치)을 벗어난 것만 지운다. 앱 시작 시·편집할 때마다·사이드바 버튼으로 돈다.
- 백업이 사라진 배치는 되돌리기 후보에서 뺀다 — Ctrl+Z가 조용히 실패하면 이유를 알 수 없다.
- 사이드바 정리 영역에 「편집 백업 N개 · N MB」로 용량을 노출한다.
빌드: profile.dev에서 의존성 디버그 정보를 뺐다(PDB 200여 개가 시간·디스크를 크게 먹는다).
자체 크레이트는 line-tables-only — 패닉 위치는 그대로 안다.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
75 lines
2.3 KiB
TOML
75 lines
2.3 KiB
TOML
[workspace]
|
|
members = [
|
|
"crates/archive-db",
|
|
"crates/archive-vfs",
|
|
"crates/archive-indexer",
|
|
"crates/archive-media",
|
|
]
|
|
|
|
[workspace.dependencies]
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
thiserror = "2"
|
|
anyhow = "1"
|
|
tokio = { version = "1", features = ["full"] }
|
|
tracing = "0.1"
|
|
bytes = "1"
|
|
async-trait = "0.1"
|
|
crossbeam-channel = "0.5"
|
|
|
|
[package]
|
|
name = "archive"
|
|
version = "0.1.0"
|
|
description = "사진/영상 라이브러리 관리 프로그램"
|
|
edition = "2021"
|
|
rust-version = "1.80"
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dependencies]
|
|
tauri = { version = "2", features = [] }
|
|
tauri-plugin-shell = "2"
|
|
tauri-plugin-dialog = "2"
|
|
tauri-plugin-single-instance = "2"
|
|
tauri-plugin-window-state = "2"
|
|
|
|
archive-db = { path = "crates/archive-db" }
|
|
archive-vfs = { path = "crates/archive-vfs" }
|
|
archive-indexer = { path = "crates/archive-indexer" }
|
|
archive-media = { path = "crates/archive-media" }
|
|
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
# 릴리스 GUI 빌드에는 콘솔이 없다 — 파일로 남기지 않으면 진단이 통째로 사라진다.
|
|
tracing-appender = "0.2"
|
|
dirs = "6"
|
|
rusqlite = { version = "0.40", features = ["bundled"] }
|
|
notify-debouncer-full = "0.7"
|
|
crossbeam-channel = { workspace = true }
|
|
async-trait = { workspace = true }
|
|
mime_guess = "2"
|
|
|
|
[profile.release]
|
|
lto = "thin"
|
|
strip = "symbols"
|
|
|
|
# 개발 빌드에서도 의존성(이미지 디코더, 해시, sqlite 등)은 최적화한다.
|
|
# 자체 크레이트만 디버그 빌드 — 이미지 디코드가 10배 이상 빨라진다.
|
|
#
|
|
# 다만 **디버그 정보는 넣지 않는다.** rustls나 tokio 안으로 들어가 단계 실행할 일이 없는데,
|
|
# 의존성 200여 개의 PDB를 만드는 데 빌드 시간과 디스크가 크게 든다(target이 수십 GB로 불어난
|
|
# 주된 이유였다). 백트레이스에 의존성 프레임의 줄번호가 안 나오는 것이 유일한 대가다.
|
|
[profile.dev.package."*"]
|
|
opt-level = 2
|
|
debug = false
|
|
|
|
# 자체 크레이트는 줄번호까지만. 패닉 위치를 아는 데는 충분하고,
|
|
# 전체 타입 정보를 담은 PDB보다 훨씬 작고 빠르다.
|
|
[profile.dev]
|
|
debug = "line-tables-only"
|