첫 소스 매핑 체감 속도 개선 — 열거 직후 그리드 표시(메타 대기 안 함)
증상: 파일(특히 영상)이 많으면 첫 소스 추가 시 오래 걸림. 원인은 library-changed(그리드 표시)가 스캔+이미지메타+영상메타를 모두 마친 뒤에야 발생 → 영상마다 ffprobe 프로세스를 띄우는 영상 메타가 끝날 때까지 그리드가 빈 채로. 수정: run_scan_pipeline에 on_refresh 콜백 추가. - 열거(파일 DB 삽입) 직후 썸네일 생성 시작 + library-changed 발생 → 그리드 즉시 표시 - 이미지 메타(헤더, 빠름) 후 재배치 - 영상 메타(ffprobe, 느림)는 백그라운드 진행, 완료 후 최종 재배치 watcher 재스캔도 동일 적용. 검증(영상 250개): 그리드가 300ms에 표시(메타 250 대기 중), 썸네일은 백그라운드로 채워지고 영상 메타 완료(~6.6s) 후 종횡비 재배치. 기존엔 ~6.6s 내내 빈 화면이었음. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -232,22 +232,30 @@ pub fn run_scan_pipeline(
|
|||||||
root: &Path,
|
root: &Path,
|
||||||
cancel: &std::sync::atomic::AtomicBool,
|
cancel: &std::sync::atomic::AtomicBool,
|
||||||
mut on_progress: impl FnMut(ScanProgress),
|
mut on_progress: impl FnMut(ScanProgress),
|
||||||
|
on_refresh: impl Fn(),
|
||||||
) {
|
) {
|
||||||
let result = archive_indexer::pipeline::scan_source(db, source_id, root, cancel, &mut on_progress);
|
let result = archive_indexer::pipeline::scan_source(db, source_id, root, cancel, &mut on_progress);
|
||||||
match result {
|
match result {
|
||||||
Ok(stats) => {
|
Ok(stats) => {
|
||||||
tracing::info!(?stats, source_id, "스캔 완료 — 메타데이터 추출 시작");
|
tracing::info!(?stats, source_id, "스캔(열거) 완료 — 즉시 표시 후 메타 진행");
|
||||||
|
// 열거가 끝나면 파일 행은 이미 DB에 있다. 느린 메타(특히 영상 ffprobe)를
|
||||||
|
// 기다리지 않고 ① 썸네일 생성을 시작하고 ② 그리드를 바로 띄운다.
|
||||||
|
thumbs.enqueue_pending(db, Some(source_id));
|
||||||
|
on_refresh();
|
||||||
|
// 이미지 메타는 헤더만 읽어 빠름 → 끝나면 사진 종횡비 재배치.
|
||||||
match archive_indexer::meta::extract_image_meta(db, source_id, cancel) {
|
match archive_indexer::meta::extract_image_meta(db, source_id, cancel) {
|
||||||
Ok(n) => tracing::info!(count = n, "이미지 메타 추출 완료"),
|
Ok(n) => tracing::info!(count = n, "이미지 메타 추출 완료"),
|
||||||
Err(e) => tracing::error!("이미지 메타 추출 오류: {e}"),
|
Err(e) => tracing::error!("이미지 메타 추출 오류: {e}"),
|
||||||
}
|
}
|
||||||
|
on_refresh();
|
||||||
|
// 영상 메타(ffprobe)는 파일당 프로세스라 느림 → 백그라운드에서 진행.
|
||||||
|
// 완료 후 재배치는 호출자의 최종 library-changed가 담당.
|
||||||
if let Some(t) = tools {
|
if let Some(t) = tools {
|
||||||
match archive_indexer::meta::extract_video_meta(db, source_id, cancel, t) {
|
match archive_indexer::meta::extract_video_meta(db, source_id, cancel, t) {
|
||||||
Ok(n) => tracing::info!(count = n, "영상 메타 추출 완료"),
|
Ok(n) => tracing::info!(count = n, "영상 메타 추출 완료"),
|
||||||
Err(e) => tracing::error!("영상 메타 추출 오류: {e}"),
|
Err(e) => tracing::error!("영상 메타 추출 오류: {e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thumbs.enqueue_pending(db, Some(source_id));
|
|
||||||
}
|
}
|
||||||
Err(e) => tracing::warn!("스캔 중단: {e}"),
|
Err(e) => tracing::warn!("스캔 중단: {e}"),
|
||||||
}
|
}
|
||||||
@@ -272,12 +280,26 @@ pub fn spawn_scan_thread(
|
|||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
// 스캔/메타 오케스트레이션 스레드도 저우선순위로 — UI 응답성 우선
|
// 스캔/메타 오케스트레이션 스레드도 저우선순위로 — UI 응답성 우선
|
||||||
archive_indexer::prio::set_current_thread_low();
|
archive_indexer::prio::set_current_thread_low();
|
||||||
run_scan_pipeline(&db, &tools, &thumbs, source_id, Path::new(&root), &cancel, |p| {
|
let app_refresh = app.clone();
|
||||||
|
run_scan_pipeline(
|
||||||
|
&db,
|
||||||
|
&tools,
|
||||||
|
&thumbs,
|
||||||
|
source_id,
|
||||||
|
Path::new(&root),
|
||||||
|
&cancel,
|
||||||
|
|p| {
|
||||||
if let Some(ch) = &on_progress {
|
if let Some(ch) = &on_progress {
|
||||||
let _ = ch.send(p);
|
let _ = ch.send(p);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
// 열거 직후·이미지 메타 후 그리드를 즉시 갱신 (영상 메타를 기다리지 않음)
|
||||||
|
move || {
|
||||||
|
let _ = app_refresh.emit("library-changed", source_id);
|
||||||
|
},
|
||||||
|
);
|
||||||
running.store(false, Ordering::SeqCst);
|
running.store(false, Ordering::SeqCst);
|
||||||
|
// 영상 메타까지 끝난 뒤 최종 재배치
|
||||||
let _ = app.emit("library-changed", source_id);
|
let _ = app.emit("library-changed", source_id);
|
||||||
})
|
})
|
||||||
.map_err(err_str)?;
|
.map_err(err_str)?;
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ impl WatcherManager {
|
|||||||
Path::new(&root),
|
Path::new(&root),
|
||||||
&state.scan_cancel,
|
&state.scan_cancel,
|
||||||
|_| {},
|
|_| {},
|
||||||
|
|| {
|
||||||
|
let _ = app.emit("library-changed", source_id);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
state.scan_running.store(false, Ordering::SeqCst);
|
state.scan_running.store(false, Ordering::SeqCst);
|
||||||
let _ = app.emit("library-changed", source_id);
|
let _ = app.emit("library-changed", source_id);
|
||||||
|
|||||||
Reference in New Issue
Block a user