@@ -27,6 +27,7 @@ use std::path::PathBuf;
2727use std:: sync:: Arc ;
2828use std:: sync:: atomic:: { AtomicBool , AtomicUsize , Ordering } ;
2929
30+ use libc:: unsetenv;
3031use tracing:: { error, info} ;
3132
3233use crate :: FileSync ;
@@ -58,7 +59,7 @@ pub(crate) struct ScanSignals {
5859}
5960
6061/// Which optional phases a scan should run.
61- #[ derive( Clone , Copy , Default ) ]
62+ #[ derive( Clone , Copy , Default , Debug ) ]
6263pub ( crate ) struct ScanConfig {
6364 pub ( crate ) warmup : bool ,
6465 pub ( crate ) content_indexing : bool ,
@@ -232,26 +233,26 @@ impl ScanJob {
232233 None
233234 } ;
234235
235- // 3. Apply git status + frecency off-lock (joins the git thread).
236- // Done BEFORE the bigram/warmup pass so `FileItem::git_status` is
237- // populated when the indexer decides which files to pin in the
238- // mmap cache (dirty files stay hot in the page cache on their own).
239- if !signals. cancelled . load ( Ordering :: Acquire )
240- && let Some ( status_handle) = status_handle
241- && let Some ( snap) = snapshot. as_mut ( )
242- {
243- apply_git_status_and_frecency ( & shared_frecency, status_handle, mode, snap) ;
244- }
245-
246- // 4. Post-scan warmup + bigram build.
236+ // 3. Post-scan warmup + bigram build — runs in parallel with the
237+ // git-status thread to overlap the two expensive phases.
247238 if ( config. warmup || config. content_indexing )
248239 && !signals. cancelled . load ( Ordering :: Acquire )
249240 && let Some ( snap) = snapshot. as_ref ( )
250241 {
251242 Self :: run_post_scan ( & shared_picker, & signals, & config, snap) ;
252243 }
253244
254- drop ( snapshot) ;
245+ // 4. Join and git status, this HAS to be done after the post scan
246+ if !signals. cancelled . load ( Ordering :: Acquire )
247+ && let Some ( status_handle) = status_handle
248+ && let Some ( snapshot) = snapshot. as_mut ( )
249+ {
250+ if let Ok ( Some ( git_status) ) = status_handle. join ( ) {
251+ apply_git_status_and_frecency ( git_status, & shared_frecency, mode, snapshot) ;
252+ }
253+ }
254+
255+ drop ( snapshot) ; // SNAPSHOT SHOULD NOT BE USED AFTER THIS POINT
255256
256257 // 5. Install filesystem watcher (initial scan only).
257258 if config. install_watcher && config. watch && !signals. cancelled . load ( Ordering :: Acquire ) {
@@ -300,7 +301,7 @@ impl ScanJob {
300301 }
301302 }
302303
303- #[ tracing:: instrument( skip_all) ]
304+ #[ tracing:: instrument( skip_all, fields ( warmup = ?config . warmup , indexing = ?config . content_indexing ) ) ]
304305 fn run_post_scan (
305306 shared_picker : & SharedFilePicker ,
306307 signals : & ScanSignals ,
@@ -314,24 +315,27 @@ impl ScanJob {
314315 . unwrap_or ( ArenaPtr :: null ( ) ) ;
315316 let budget: & ContentCacheBudget = & unsafe_snapshot. budget ;
316317 let files: & [ crate :: types:: FileItem ] = & unsafe_snapshot. files [ ..unsafe_snapshot. base_count ] ;
318+ if !signals. cancelled . load ( Ordering :: Acquire ) {
319+ return ;
320+ }
317321
318322 // unified bigram and warmup_mmaps in one go, it's important to reuse open files as much as possible
319- if config. content_indexing && !signals . cancelled . load ( Ordering :: Acquire ) {
323+ if config. content_indexing {
320324 let indexable_files = & files[ ..unsafe_snapshot. indexable_count . min ( files. len ( ) ) ] ;
321325 let index = build_bigram_index (
322326 indexable_files,
323327 budget,
324328 & unsafe_snapshot. base_path ,
325329 arena,
326- config. warmup ,
330+ config. warmup , // can be optionally skipped
327331 ) ;
328332
329333 if let Ok ( mut guard) = shared_picker. write ( )
330334 && let Some ( picker) = guard. as_mut ( )
331335 {
332- picker. set_bigram_index ( index, BigramOverlay :: new ( unsafe_snapshot . indexable_count ) ) ;
336+ picker. set_bigram_index ( index) ;
333337 }
334- } else if config. warmup && !signals . cancelled . load ( Ordering :: Acquire ) {
338+ } else if config. warmup {
335339 // Warmup-only: no bigram indexing, just fill the mmap cache.
336340 warmup_mmaps ( files, budget, & unsafe_snapshot. base_path , arena) ;
337341 }
@@ -386,21 +390,17 @@ fn rescubscribe_watcher_post_scan(shared_picker: &SharedFilePicker) {
386390 } ) ;
387391}
388392
393+ #[ tracing:: instrument(
394+ level = "debug" ,
395+ skip_all,
396+ fields( file_count = tracing:: field:: Empty , dirty_count = tracing:: field:: Empty ) ,
397+ ) ]
389398fn apply_git_status_and_frecency (
399+ git_cache : GitStatusCache ,
390400 shared_frecency : & SharedFrecency ,
391- git_handle : std:: thread:: JoinHandle < Option < GitStatusCache > > ,
392401 mode : FFFMode ,
393402 unsafe_snapshot : & mut crate :: file_picker:: PostScanUnsafeSnapshot ,
394403) {
395- let git_cache = match git_handle. join ( ) {
396- Ok ( Some ( cache) ) => cache,
397- Ok ( None ) => return ,
398- Err ( _) => {
399- error ! ( "Git status thread panicked" ) ;
400- return ;
401- }
402- } ;
403-
404404 let frecency = shared_frecency. read ( ) . ok ( ) ;
405405 let frecency_ref = frecency. as_ref ( ) . and_then ( |f| f. as_ref ( ) ) ;
406406
@@ -445,11 +445,7 @@ fn apply_git_status_and_frecency(
445445 }
446446 } ) ;
447447 } ) ;
448- drop ( frecency) ;
449448
450- info ! (
451- "SCAN: Applied git status to {} files ({} dirty)" ,
452- unsafe_snapshot. base_count,
453- git_cache. statuses_len( ) ,
454- ) ;
449+ let span = tracing:: Span :: current ( ) ;
450+ span. record ( "dirty_count" , git_cache. statuses_len ( ) ) ;
455451}
0 commit comments