Skip to content

Commit 5ca2f20

Browse files
committed
breaking(sdk): Rename several options & add more flags to control
1 parent cebacb3 commit 5ca2f20

24 files changed

Lines changed: 636 additions & 60 deletions

crates/fff-c/include/fff.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ typedef struct FffScanProgress {
241241
* * `frecency_db_path` – path to frecency LMDB database (NULL/empty to skip)
242242
* * `history_db_path` – path to query history LMDB database (NULL/empty to skip)
243243
* * `use_unsafe_no_lock` – use MDB_NOLOCK for LMDB (useful in single-process setups)
244-
* * `warmup_mmap_cache` – pre-populate mmap caches after the initial scan
244+
* * `enable_mmap_cache` – pre-populate mmap caches after the initial scan
245245
* * `ai_mode` – enable AI-agent optimizations (auto-track frecency on modifications)
246246
*
247247
* ## Safety
@@ -251,7 +251,7 @@ struct FffResult *fff_create_instance(const char *base_path,
251251
const char *frecency_db_path,
252252
const char *history_db_path,
253253
bool use_unsafe_no_lock,
254-
bool warmup_mmap_cache,
254+
bool enable_mmap_cache,
255255
bool ai_mode);
256256

257257
/**

crates/fff-c/src/lib.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ fn default_i32(val: i32, default: i32) -> i32 {
113113
/// * `frecency_db_path` – path to frecency LMDB database (NULL/empty to skip)
114114
/// * `history_db_path` – path to query history LMDB database (NULL/empty to skip)
115115
/// * `use_unsafe_no_lock` – use MDB_NOLOCK for LMDB (useful in single-process setups)
116-
/// * `warmup_mmap_cache` – pre-populate mmap caches after the initial scan
116+
/// * `enable_mmap_cache` – pre-populate mmap caches after the initial scan
117117
/// * `ai_mode` – enable AI-agent optimizations (auto-track frecency on modifications)
118118
///
119119
/// ## Safety
@@ -124,7 +124,7 @@ pub unsafe extern "C" fn fff_create_instance(
124124
frecency_db_path: *const c_char,
125125
history_db_path: *const c_char,
126126
use_unsafe_no_lock: bool,
127-
warmup_mmap_cache: bool,
127+
enable_mmap_cache: bool,
128128
ai_mode: bool,
129129
) -> *mut FffResult {
130130
let base_path_str = match unsafe { cstr_to_str(base_path) } {
@@ -185,7 +185,8 @@ pub unsafe extern "C" fn fff_create_instance(
185185
shared_frecency.clone(),
186186
fff::FilePickerOptions {
187187
base_path: base_path_str,
188-
warmup_mmap_cache,
188+
enable_mmap_cache,
189+
enable_content_indexing: enable_mmap_cache,
189190
mode,
190191
cache_budget: None,
191192
..Default::default()
@@ -671,13 +672,14 @@ pub unsafe extern "C" fn fff_restart_index(
671672
Err(e) => return FffResult::err(&format!("Failed to acquire file picker lock: {}", e)),
672673
};
673674

674-
let (warmup_caches, mode) = if let Some(mut picker) = guard.take() {
675-
let warmup = picker.need_warmup_mmap_cache();
675+
let (warmup_caches, content_indexing, mode) = if let Some(mut picker) = guard.take() {
676+
let warmup = picker.need_enable_mmap_cache();
677+
let ci = picker.need_enable_content_indexing();
676678
let mode = picker.mode();
677679
picker.stop_background_monitor();
678-
(warmup, mode)
680+
(warmup, ci, mode)
679681
} else {
680-
(false, FFFMode::default())
682+
(false, false, FFFMode::default())
681683
};
682684

683685
drop(guard);
@@ -687,7 +689,8 @@ pub unsafe extern "C" fn fff_restart_index(
687689
inst.frecency.clone(),
688690
fff::FilePickerOptions {
689691
base_path: canonical_path.to_string_lossy().to_string(),
690-
warmup_mmap_cache: warmup_caches,
692+
enable_mmap_cache: warmup_caches,
693+
enable_content_indexing: content_indexing,
691694
mode,
692695
cache_budget: None,
693696
..Default::default()

crates/fff-core/src/background_watcher.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,9 @@ fn trigger_full_rescan(shared_picker: &SharedPicker, shared_frecency: &SharedFre
520520
// Spawn background warmup + bigram rebuild (mirrors the initial scan's
521521
// post-scan phase). The write lock is still held here but the spawned
522522
// thread re-acquires it later — safe because the guard drops at function end.
523-
picker.spawn_post_rescan_rebuild(shared_picker.clone());
523+
if shared_picker.need_complex_rebuild() {
524+
picker.spawn_post_rescan_rebuild(shared_picker.clone());
525+
}
524526
}
525527

526528
fn should_include_file(path: &Path, repo: &Option<Repository>) -> bool {

crates/fff-core/src/file_picker.rs

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -388,21 +388,25 @@ impl FileItem {
388388
/// Options for creating a [`FilePicker`].
389389
pub struct FilePickerOptions {
390390
pub base_path: String,
391-
pub warmup_mmap_cache: bool,
391+
/// Pre-populate mmap caches for top-frecency files after the initial scan.
392+
pub enable_mmap_cache: bool,
393+
/// Build bigram content index after the initial scan for faster
394+
/// content-aware filtering. Independent of `enable_mmap_cache`.
395+
pub enable_content_indexing: bool,
392396
pub mode: FFFMode,
393397
/// Explicit cache budget. When `None`, the budget is auto-computed from
394398
/// the repo size after the initial scan completes.
395399
pub cache_budget: Option<ContentCacheBudget>,
396400
/// When `false`, `new_with_shared_state` skips the background file watcher.
397-
/// Files are still scanned, warmed up, and bigram-indexed.
398401
pub watch: bool,
399402
}
400403

401404
impl Default for FilePickerOptions {
402405
fn default() -> Self {
403406
Self {
404407
base_path: ".".into(),
405-
warmup_mmap_cache: false,
408+
enable_mmap_cache: false,
409+
enable_content_indexing: false,
406410
mode: FFFMode::default(),
407411
cache_budget: None,
408412
watch: true,
@@ -420,7 +424,8 @@ pub struct FilePicker {
420424
watcher_ready: Arc<AtomicBool>,
421425
scanned_files_count: Arc<AtomicUsize>,
422426
background_watcher: Option<BackgroundWatcher>,
423-
warmup_mmap_cache: bool,
427+
enable_mmap_cache: bool,
428+
enable_content_indexing: bool,
424429
watch: bool,
425430
cancelled: Arc<AtomicBool>,
426431
// This is a soft lock that we use to prevent rescan be triggered while the
@@ -478,8 +483,12 @@ impl FilePicker {
478483
.and_then(|p| p.to_str())
479484
}
480485

481-
pub fn need_warmup_mmap_cache(&self) -> bool {
482-
self.warmup_mmap_cache
486+
pub fn need_enable_mmap_cache(&self) -> bool {
487+
self.enable_mmap_cache
488+
}
489+
490+
pub fn need_enable_content_indexing(&self) -> bool {
491+
self.enable_content_indexing
483492
}
484493

485494
pub fn mode(&self) -> FFFMode {
@@ -631,7 +640,8 @@ impl FilePicker {
631640
post_scan_busy: Arc::new(AtomicBool::new(false)),
632641
scanned_files_count: Arc::new(AtomicUsize::new(0)),
633642
sync_data: FileSync::new(),
634-
warmup_mmap_cache: options.warmup_mmap_cache,
643+
enable_mmap_cache: options.enable_mmap_cache,
644+
enable_content_indexing: options.enable_content_indexing,
635645
watch: options.watch,
636646
watcher_ready: Arc::new(AtomicBool::new(false)),
637647
})
@@ -647,13 +657,15 @@ impl FilePicker {
647657
let picker = Self::new(options)?;
648658

649659
info!(
650-
"Spawning background threads: base_path={}, warmup={}, mode={:?}",
660+
"Spawning background threads: base_path={}, warmup={}, content_indexing={}, mode={:?}",
651661
picker.base_path.display(),
652-
picker.warmup_mmap_cache,
662+
picker.enable_mmap_cache,
663+
picker.enable_content_indexing,
653664
picker.mode,
654665
);
655666

656-
let warmup = picker.warmup_mmap_cache;
667+
let warmup = picker.enable_mmap_cache;
668+
let content_indexing = picker.enable_content_indexing;
657669
let watch = picker.watch;
658670
let mode = picker.mode;
659671

@@ -677,6 +689,7 @@ impl FilePicker {
677689
watcher_ready,
678690
synced_files_count,
679691
warmup,
692+
content_indexing,
680693
watch,
681694
mode,
682695
shared_picker,
@@ -1199,13 +1212,15 @@ impl FilePicker {
11991212

12001213
/// Spawn a background thread to rebuild the bigram index after rescan.
12011214
pub(crate) fn spawn_post_rescan_rebuild(&self, shared_picker: SharedPicker) -> bool {
1202-
if !self.warmup_mmap_cache || self.cancelled.load(Ordering::Relaxed) {
1215+
if self.cancelled.load(Ordering::Relaxed) {
12031216
return false;
12041217
}
12051218

12061219
let post_scan_busy = Arc::clone(&self.post_scan_busy);
12071220
let cancelled = Arc::clone(&self.cancelled);
12081221
let auto_budget = !self.has_explicit_cache_budget;
1222+
let do_warmup = self.enable_mmap_cache;
1223+
let do_content_indexing = self.enable_content_indexing;
12091224

12101225
post_scan_busy.store(true, Ordering::Release);
12111226

@@ -1249,7 +1264,7 @@ impl FilePicker {
12491264

12501265
if let Some((files, budget, bp, arena)) = files_snapshot {
12511266
// Warmup mmap caches.
1252-
if !cancelled.load(Ordering::Acquire) {
1267+
if do_warmup && !cancelled.load(Ordering::Acquire) {
12531268
let t = std::time::Instant::now();
12541269
warmup_mmaps(files, &budget, &bp, arena);
12551270
info!(
@@ -1261,7 +1276,7 @@ impl FilePicker {
12611276
}
12621277

12631278
// Build bigram index (lock-free).
1264-
if !cancelled.load(Ordering::Acquire) {
1279+
if do_content_indexing && !cancelled.load(Ordering::Acquire) {
12651280
let t = std::time::Instant::now();
12661281
info!(
12671282
"Rescan: starting bigram index build for {} files...",
@@ -1294,8 +1309,10 @@ impl FilePicker {
12941309

12951310
post_scan_busy.store(false, Ordering::Release);
12961311
info!(
1297-
"Rescan post-scan warmup + bigram total: {:.2}s",
1312+
"Rescan post-scan phase total: {:.2}s (warmup={}, content_indexing={})",
12981313
phase_start.elapsed().as_secs_f64(),
1314+
do_warmup,
1315+
do_content_indexing,
12991316
);
13001317
});
13011318

@@ -1401,7 +1418,8 @@ fn spawn_scan_and_watcher(
14011418
scan_signal: Arc<AtomicBool>,
14021419
watcher_ready: Arc<AtomicBool>,
14031420
synced_files_count: Arc<AtomicUsize>,
1404-
warmup_mmap_cache: bool,
1421+
enable_mmap_cache: bool,
1422+
enable_content_indexing: bool,
14051423
watch: bool,
14061424
mode: FFFMode,
14071425
shared_picker: SharedPicker,
@@ -1505,7 +1523,10 @@ fn spawn_scan_and_watcher(
15051523

15061524
watcher_ready.store(true, Ordering::Release);
15071525

1508-
if warmup_mmap_cache && !cancelled.load(Ordering::Acquire) {
1526+
let need_post_scan =
1527+
(enable_mmap_cache || enable_content_indexing) && !cancelled.load(Ordering::Acquire);
1528+
1529+
if need_post_scan {
15091530
post_scan_busy.store(true, Ordering::Release);
15101531
let phase_start = std::time::Instant::now();
15111532

@@ -1548,9 +1569,11 @@ fn spawn_scan_and_watcher(
15481569
None
15491570
};
15501571

1572+
// both of this is using a custom soft lock not guaranteed by compiler
1573+
// this is required to keep the picker functioning if someone opened a really crazy
1574+
// e.g 10m files directory but potentially unsafe
15511575
if let Some((files, budget, arena)) = files_snapshot {
1552-
// Warmup: populate mmap caches for top-frecency files.
1553-
if !cancelled.load(Ordering::Acquire) {
1576+
if enable_mmap_cache && !cancelled.load(Ordering::Acquire) {
15541577
let warmup_start = std::time::Instant::now();
15551578
warmup_mmaps(files, &budget, &base_path, arena);
15561579
info!(
@@ -1561,16 +1584,9 @@ fn spawn_scan_and_watcher(
15611584
);
15621585
}
15631586

1564-
// Build bigram index — entirely lock-free.
1565-
if !cancelled.load(Ordering::Acquire) {
1566-
let bigram_start = std::time::Instant::now();
1567-
info!("Starting bigram index build for {} files...", files.len());
1587+
if enable_content_indexing && !cancelled.load(Ordering::Acquire) {
15681588
let (index, content_binary) =
15691589
build_bigram_index(files, &budget, &base_path, arena);
1570-
info!(
1571-
"Bigram index ready in {:.2}s",
1572-
bigram_start.elapsed().as_secs_f64(),
1573-
);
15741590

15751591
if let Ok(mut guard) = shared_picker.write()
15761592
&& let Some(ref mut picker) = *guard
@@ -1593,8 +1609,10 @@ fn spawn_scan_and_watcher(
15931609
post_scan_busy.store(false, Ordering::Release);
15941610

15951611
info!(
1596-
"Post-scan warmup + bigram total: {:.2}s",
1612+
"Post-scan phase total: {:.2}s (warmup={}, content_indexing={})",
15971613
phase_start.elapsed().as_secs_f64(),
1614+
enable_mmap_cache,
1615+
enable_content_indexing,
15981616
);
15991617
}
16001618

@@ -1677,6 +1695,7 @@ pub(crate) fn warmup_mmaps(
16771695
/// so reading further adds no new information to the index.
16781696
pub const BIGRAM_CONTENT_CAP: usize = 64 * 1024;
16791697

1698+
#[tracing::instrument(skip_all, name = "Building Bigram Index", level = Level::DEBUG)]
16801699
pub(crate) fn build_bigram_index(
16811700
files: &[FileItem],
16821701
budget: &ContentCacheBudget,

crates/fff-core/src/shared.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,15 @@ impl SharedPicker {
3434
Ok(self.0.write())
3535
}
3636

37+
/// Return `true` if this is an instnace of the picker that requires a complicated post-scan
38+
/// indexing/cache warmup job. The indexing is not crazy but it takes time.
39+
pub fn need_complex_rebuild(&self) -> bool {
40+
let guard = self.0.read();
41+
guard
42+
.as_ref()
43+
.is_some_and(|p| p.need_enable_mmap_cache() || p.need_enable_content_indexing())
44+
}
45+
3746
/// Block until the background filesystem scan finishes.
3847
/// Returns `true` if scan completed, `false` on timeout.
3948
pub fn wait_for_scan(&self, timeout: Duration) -> bool {

crates/fff-core/tests/bigram_overlay_coherence_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1435,7 +1435,8 @@ fn make_picker(base: &Path) -> (SharedPicker, SharedFrecency) {
14351435
shared_frecency.clone(),
14361436
FilePickerOptions {
14371437
base_path: base.to_string_lossy().to_string(),
1438-
warmup_mmap_cache: true,
1438+
enable_mmap_cache: true,
1439+
enable_content_indexing: true,
14391440
mode: FFFMode::Neovim,
14401441
watch: false, // we drive events manually
14411442
..Default::default()

crates/fff-core/tests/bigram_overlay_integration.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ fn modified_file_findable_via_overlay() {
3333
shared_frecency.clone(),
3434
FilePickerOptions {
3535
base_path: base.to_string_lossy().to_string(),
36-
warmup_mmap_cache: true,
36+
enable_mmap_cache: true,
37+
enable_content_indexing: true,
3738
mode: FFFMode::Neovim,
3839
..Default::default()
3940
},
@@ -182,7 +183,8 @@ fn deleted_file_excluded_via_overlay() {
182183
shared_frecency.clone(),
183184
FilePickerOptions {
184185
base_path: base.to_string_lossy().to_string(),
185-
warmup_mmap_cache: true,
186+
enable_mmap_cache: true,
187+
enable_content_indexing: true,
186188
mode: FFFMode::Neovim,
187189
..Default::default()
188190
},
@@ -250,7 +252,8 @@ fn new_file_findable_after_add() {
250252
shared_frecency.clone(),
251253
FilePickerOptions {
252254
base_path: base.to_string_lossy().to_string(),
253-
warmup_mmap_cache: true,
255+
enable_mmap_cache: true,
256+
enable_content_indexing: true,
254257
mode: FFFMode::Neovim,
255258
..Default::default()
256259
},
@@ -319,7 +322,8 @@ fn modified_file_findable_via_regex_overlay() {
319322
shared_frecency.clone(),
320323
FilePickerOptions {
321324
base_path: base.to_string_lossy().to_string(),
322-
warmup_mmap_cache: true,
325+
enable_mmap_cache: true,
326+
enable_content_indexing: true,
323327
mode: FFFMode::Neovim,
324328
..Default::default()
325329
},

crates/fff-core/tests/fuzz_file_operations.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,8 @@ fn fuzz_file_operations_stress() {
316316
FilePickerOptions {
317317
watch: false, // we do not need the backgrodun monitor
318318
base_path: base.to_string_lossy().to_string(),
319-
warmup_mmap_cache: true,
319+
enable_mmap_cache: true,
320+
enable_content_indexing: true,
320321
mode: FFFMode::Neovim,
321322
..Default::default()
322323
},

crates/fff-core/tests/grep_integration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ fn create_picker(base: &Path, specs: &[(&str, &str)]) -> FilePicker {
1717
}
1818
let mut picker = FilePicker::new(FilePickerOptions {
1919
base_path: base.to_string_lossy().to_string(),
20-
warmup_mmap_cache: false,
20+
enable_mmap_cache: false,
2121
watch: false,
2222
..Default::default()
2323
})

0 commit comments

Comments
 (0)