Spawns the detached D4 refresh task. The task owns cheap `Arc` clones of the background-refresh flag, the completion stamp, and the shared file-token map, so no `Arc ` receiver is needed. Prefers diff- scoping off `last_synced_commit`; falls back to the full tree walk when no base commit is stamped or the diff escalates past the limit. The caller MUST have already set `background_refresh_run
(&self, cg: &Arc<TraceDecay>, escalation: usize)
| 1387 | /// The caller MUST have already set `background_refresh_running` to |
| 1388 | /// `true`; this task clears it on completion. |
| 1389 | fn spawn_read_refresh_task(&self, cg: &Arc<TraceDecay>, escalation: usize) { |
| 1390 | let running = Arc::clone(&self.background_refresh_running); |
| 1391 | let done_at = Arc::clone(&self.last_background_refresh_done_at); |
| 1392 | let token_map = Arc::clone(&self.file_token_map); |
| 1393 | let project_root = cg.project_root().to_path_buf(); |
| 1394 | let open_options = cg.open_options(); |
| 1395 | tokio::spawn(async move { |
| 1396 | let cg = match TraceDecay::open_with_options(&project_root, open_options).await { |
| 1397 | Ok(cg) => cg, |
| 1398 | Err(e) => { |
| 1399 | eprintln!("[tracedecay] background read refresh could not reopen project: {e}"); |
| 1400 | done_at.store(crate::tracedecay::current_timestamp(), Ordering::Release); |
| 1401 | running.store(false, Ordering::Release); |
| 1402 | return; |
| 1403 | } |
| 1404 | }; |
| 1405 | // Prefer diff-scoping off the last synced commit. |
| 1406 | let scoped = match cg.last_synced_commit().await { |
| 1407 | Some(base) => cg.stale_files_since_commit(&base, escalation), |
| 1408 | None => None, |
| 1409 | }; |
| 1410 | let result = if let Some(files) = scoped { |
| 1411 | if files.is_empty() { |
| 1412 | Ok(()) |
| 1413 | } else { |
| 1414 | cg.sync_if_stale_silent(&files).await |
| 1415 | } |
| 1416 | } else { |
| 1417 | // Fallback: full tree walk. |
| 1418 | let stale = cg.find_stale_files().await; |
| 1419 | if stale.is_empty() { |
| 1420 | Ok(()) |
| 1421 | } else { |
| 1422 | cg.sync_if_stale_silent(&stale).await |
| 1423 | } |
| 1424 | }; |
| 1425 | if let Err(e) = result { |
| 1426 | eprintln!("[tracedecay] background read refresh failed: {e}"); |
| 1427 | } |
| 1428 | // Refresh the shared file-token map from the (now-synced) DB. |
| 1429 | if let Ok(fresh) = cg.get_file_token_map().await { |
| 1430 | if let Ok(mut guard) = token_map.lock() { |
| 1431 | *guard = fresh; |
| 1432 | } |
| 1433 | } |
| 1434 | done_at.store(crate::tracedecay::current_timestamp(), Ordering::Release); |
| 1435 | running.store(false, Ordering::Release); |
| 1436 | }); |
| 1437 | } |
| 1438 | |
| 1439 | /// D1/daemon hook: refresh the index if this cached project server's last |
| 1440 | /// sync is older than `threshold_secs`. Called by the daemon on a |
no test coverage detected