diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-07 15:34:26 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-07 15:35:20 +0300 |
| commit | b425260f9d86bb7e0bbea1d1e557ee75ba22443e (patch) | |
| tree | d67a0896bdfa5ce027fc85982d547ed995936265 /src/app/mod.rs | |
| parent | b017d212905b4de04770100ad993cb5c0b7855ca (diff) | |
perf: move session autosaves off main loop
Diffstat (limited to 'src/app/mod.rs')
| -rw-r--r-- | src/app/mod.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs index 8f33e23a..51bdd33e 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -128,6 +128,7 @@ pub struct App { pub(crate) selection_autoscroll_deadline: Option<Instant>, pub(crate) selection_highlight_clear_deadline: Option<Instant>, pub(crate) session_save_deadline: Option<Instant>, + pub(crate) session_save_thread: Option<std::thread::JoinHandle<()>>, pub(crate) persist_pane_history: bool, pub(crate) last_render_at: Option<Instant>, pub(crate) suppressed_repeat_keys: @@ -719,6 +720,7 @@ impl App { agent_metadata_deadline: None, pending_agent_resume_deadline: None, session_save_deadline: None, + session_save_thread: None, selection_autoscroll_deadline: None, selection_highlight_clear_deadline: None, persist_pane_history: config.experimental.pane_history, @@ -1739,6 +1741,14 @@ mod tests { ) } + fn unique_temp_path(name: &str) -> std::path::PathBuf { + let stamp = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + std::env::temp_dir().join(format!("herdr-{name}-{}-{stamp}", std::process::id())) + } + #[cfg(windows)] fn exiting_test_command() -> &'static str { "C:\\Windows\\System32\\whoami.exe" @@ -4076,6 +4086,71 @@ mod tests { } #[test] + fn due_session_save_starts_background_writer() { + let _guard = crate::config::test_config_env_lock().lock().unwrap(); + let config_home = unique_temp_path("background-session-save"); + std::env::set_var("XDG_CONFIG_HOME", &config_home); + std::env::remove_var(crate::session::SESSION_ENV_VAR); + + let mut app = test_app(); + app.no_session = false; + app.state.workspaces = vec![Workspace::test_new("autosave")]; + app.state.ensure_test_terminals(); + app.session_save_deadline = Some(Instant::now() - Duration::from_secs(1)); + + app.handle_scheduled_tasks(Instant::now(), false); + + assert!(app.session_save_thread.is_some()); + assert!(app.session_save_deadline.is_none()); + app.save_session_now(); + assert!(crate::session::data_dir().join("session.json").exists()); + + std::env::remove_var("XDG_CONFIG_HOME"); + let _ = std::fs::remove_dir_all(config_home); + } + + #[test] + fn background_session_save_reschedules_when_writer_is_busy() { + let mut app = test_app(); + app.no_session = false; + let (release_tx, release_rx) = std::sync::mpsc::channel(); + app.session_save_thread = Some(std::thread::spawn(move || { + let _ = release_rx.recv(); + })); + + app.start_background_session_save(); + + assert!(app.session_save_thread.is_some()); + assert!(app.session_save_deadline.is_some()); + + release_tx.send(()).unwrap(); + app.no_session = true; + app.save_session_now(); + } + + #[test] + fn final_session_save_joins_background_writer_before_returning() { + let mut app = test_app(); + app.no_session = true; + let (release_tx, release_rx) = std::sync::mpsc::channel(); + let (done_tx, done_rx) = std::sync::mpsc::channel(); + app.session_save_thread = Some(std::thread::spawn(move || { + let _ = release_rx.recv(); + done_tx.send(()).unwrap(); + })); + let releaser = std::thread::spawn(move || { + std::thread::sleep(Duration::from_millis(30)); + release_tx.send(()).unwrap(); + }); + + app.save_session_now(); + + releaser.join().unwrap(); + done_rx.try_recv().unwrap(); + assert!(app.session_save_thread.is_none()); + } + + #[test] fn next_loop_deadline_includes_selection_autoscroll_deadline() { let mut app = test_app(); let now = Instant::now(); |
