Avoid unnecessary DB writes (#29417)
Part of https://github.com/zed-industries/zed/issues/16472 * Adds debug logging to everywhere near INSERT/UPDATEs in the DB So something like `env RUST_LOG=debug,wasmtime_cranelift=off,cranelift_codegen=off,vte=off cargo run` could be used to view these (current zlog seems to process the exclusions odd, so not sure this is the optimal RUST_LOG line) can be used to debug any further writes. * Removes excessive window stack serialization Previously, it serialized unconditionally every 100ms. Now, only if the stack had changed, which is now check every 500ms. * Removes excessive terminal serialization Previously, it serialized its `cwd` on every `ItemEvent::UpdateTab` which was caused by e.g. any character output. Now, only if the `cwd` has changed at the next event processing time. Release Notes: - Fixed more excessive DB writes
This commit is contained in:
parent
37fa437990
commit
f106dfca42
16 changed files with 224 additions and 168 deletions
|
@ -429,6 +429,9 @@ impl TerminalDb {
|
|||
workspace_id: WorkspaceId,
|
||||
working_directory: PathBuf,
|
||||
) -> Result<()> {
|
||||
log::debug!(
|
||||
"Saving working directory {working_directory:?} for item {item_id} in workspace {workspace_id:?}"
|
||||
);
|
||||
let query =
|
||||
"INSERT INTO terminals(item_id, workspace_id, working_directory, working_directory_path)
|
||||
VALUES (?1, ?2, ?3, ?4)
|
||||
|
|
|
@ -112,6 +112,7 @@ pub struct TerminalView {
|
|||
cursor_shape: CursorShape,
|
||||
blink_state: bool,
|
||||
blinking_terminal_enabled: bool,
|
||||
cwd_serialized: bool,
|
||||
blinking_paused: bool,
|
||||
blink_epoch: usize,
|
||||
hover_target_tooltip: Option<String>,
|
||||
|
@ -207,6 +208,7 @@ impl TerminalView {
|
|||
scroll_handle,
|
||||
show_scrollbar: !Self::should_autohide_scrollbar(cx),
|
||||
hide_scrollbar_task: None,
|
||||
cwd_serialized: false,
|
||||
_subscriptions: vec![
|
||||
focus_in,
|
||||
focus_out,
|
||||
|
@ -843,167 +845,176 @@ fn subscribe_for_terminal_events(
|
|||
cx: &mut Context<TerminalView>,
|
||||
) -> Vec<Subscription> {
|
||||
let terminal_subscription = cx.observe(terminal, |_, _, cx| cx.notify());
|
||||
let mut previous_cwd = None;
|
||||
let terminal_events_subscription = cx.subscribe_in(
|
||||
terminal,
|
||||
window,
|
||||
move |terminal_view, _, event, window, cx| match event {
|
||||
Event::Wakeup => {
|
||||
cx.notify();
|
||||
cx.emit(Event::Wakeup);
|
||||
cx.emit(ItemEvent::UpdateTab);
|
||||
cx.emit(SearchEvent::MatchesInvalidated);
|
||||
move |terminal_view, terminal, event, window, cx| {
|
||||
let current_cwd = terminal.read(cx).working_directory();
|
||||
if current_cwd != previous_cwd {
|
||||
previous_cwd = current_cwd;
|
||||
terminal_view.cwd_serialized = false;
|
||||
}
|
||||
|
||||
Event::Bell => {
|
||||
terminal_view.has_bell = true;
|
||||
cx.emit(Event::Wakeup);
|
||||
}
|
||||
|
||||
Event::BlinkChanged(blinking) => {
|
||||
if matches!(
|
||||
TerminalSettings::get_global(cx).blinking,
|
||||
TerminalBlink::TerminalControlled
|
||||
) {
|
||||
terminal_view.blinking_terminal_enabled = *blinking;
|
||||
match event {
|
||||
Event::Wakeup => {
|
||||
cx.notify();
|
||||
cx.emit(Event::Wakeup);
|
||||
cx.emit(ItemEvent::UpdateTab);
|
||||
cx.emit(SearchEvent::MatchesInvalidated);
|
||||
}
|
||||
}
|
||||
|
||||
Event::TitleChanged => {
|
||||
cx.emit(ItemEvent::UpdateTab);
|
||||
}
|
||||
Event::Bell => {
|
||||
terminal_view.has_bell = true;
|
||||
cx.emit(Event::Wakeup);
|
||||
}
|
||||
|
||||
Event::NewNavigationTarget(maybe_navigation_target) => {
|
||||
match maybe_navigation_target.as_ref() {
|
||||
None => {
|
||||
terminal_view.hover_target_tooltip = None;
|
||||
terminal_view.hover_tooltip_update = Task::ready(());
|
||||
}
|
||||
Some(MaybeNavigationTarget::Url(url)) => {
|
||||
terminal_view.hover_target_tooltip = Some(url.clone());
|
||||
terminal_view.hover_tooltip_update = Task::ready(());
|
||||
}
|
||||
Some(MaybeNavigationTarget::PathLike(path_like_target)) => {
|
||||
let valid_files_to_open_task = possible_open_target(
|
||||
&workspace,
|
||||
&path_like_target.terminal_dir,
|
||||
&path_like_target.maybe_path,
|
||||
cx,
|
||||
);
|
||||
|
||||
terminal_view.hover_tooltip_update =
|
||||
cx.spawn(async move |terminal_view, cx| {
|
||||
let file_to_open = valid_files_to_open_task.await;
|
||||
terminal_view
|
||||
.update(cx, |terminal_view, _| match file_to_open {
|
||||
Some(
|
||||
OpenTarget::File(path, _)
|
||||
| OpenTarget::Worktree(path, _),
|
||||
) => {
|
||||
terminal_view.hover_target_tooltip =
|
||||
Some(path.to_string(|path| {
|
||||
path.to_string_lossy().to_string()
|
||||
}));
|
||||
}
|
||||
None => {
|
||||
terminal_view.hover_target_tooltip = None;
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
Event::BlinkChanged(blinking) => {
|
||||
if matches!(
|
||||
TerminalSettings::get_global(cx).blinking,
|
||||
TerminalBlink::TerminalControlled
|
||||
) {
|
||||
terminal_view.blinking_terminal_enabled = *blinking;
|
||||
}
|
||||
}
|
||||
|
||||
cx.notify()
|
||||
}
|
||||
Event::TitleChanged => {
|
||||
cx.emit(ItemEvent::UpdateTab);
|
||||
}
|
||||
|
||||
Event::Open(maybe_navigation_target) => match maybe_navigation_target {
|
||||
MaybeNavigationTarget::Url(url) => cx.open_url(url),
|
||||
Event::NewNavigationTarget(maybe_navigation_target) => {
|
||||
match maybe_navigation_target.as_ref() {
|
||||
None => {
|
||||
terminal_view.hover_target_tooltip = None;
|
||||
terminal_view.hover_tooltip_update = Task::ready(());
|
||||
}
|
||||
Some(MaybeNavigationTarget::Url(url)) => {
|
||||
terminal_view.hover_target_tooltip = Some(url.clone());
|
||||
terminal_view.hover_tooltip_update = Task::ready(());
|
||||
}
|
||||
Some(MaybeNavigationTarget::PathLike(path_like_target)) => {
|
||||
let valid_files_to_open_task = possible_open_target(
|
||||
&workspace,
|
||||
&path_like_target.terminal_dir,
|
||||
&path_like_target.maybe_path,
|
||||
cx,
|
||||
);
|
||||
|
||||
MaybeNavigationTarget::PathLike(path_like_target) => {
|
||||
if terminal_view.hover_target_tooltip.is_none() {
|
||||
return;
|
||||
terminal_view.hover_tooltip_update =
|
||||
cx.spawn(async move |terminal_view, cx| {
|
||||
let file_to_open = valid_files_to_open_task.await;
|
||||
terminal_view
|
||||
.update(cx, |terminal_view, _| match file_to_open {
|
||||
Some(
|
||||
OpenTarget::File(path, _)
|
||||
| OpenTarget::Worktree(path, _),
|
||||
) => {
|
||||
terminal_view.hover_target_tooltip =
|
||||
Some(path.to_string(|path| {
|
||||
path.to_string_lossy().to_string()
|
||||
}));
|
||||
}
|
||||
None => {
|
||||
terminal_view.hover_target_tooltip = None;
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
}
|
||||
}
|
||||
let task_workspace = workspace.clone();
|
||||
let path_like_target = path_like_target.clone();
|
||||
cx.spawn_in(window, async move |terminal_view, cx| {
|
||||
let open_target = terminal_view
|
||||
.update(cx, |_, cx| {
|
||||
possible_open_target(
|
||||
&task_workspace,
|
||||
&path_like_target.terminal_dir,
|
||||
&path_like_target.maybe_path,
|
||||
cx,
|
||||
)
|
||||
})?
|
||||
.await;
|
||||
if let Some(open_target) = open_target {
|
||||
let path_to_open = open_target.path();
|
||||
let opened_items = task_workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_paths(
|
||||
vec![path_to_open.path.clone()],
|
||||
OpenOptions {
|
||||
visible: Some(OpenVisible::OnlyDirectories),
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
window,
|
||||
|
||||
cx.notify()
|
||||
}
|
||||
|
||||
Event::Open(maybe_navigation_target) => match maybe_navigation_target {
|
||||
MaybeNavigationTarget::Url(url) => cx.open_url(url),
|
||||
|
||||
MaybeNavigationTarget::PathLike(path_like_target) => {
|
||||
if terminal_view.hover_target_tooltip.is_none() {
|
||||
return;
|
||||
}
|
||||
let task_workspace = workspace.clone();
|
||||
let path_like_target = path_like_target.clone();
|
||||
cx.spawn_in(window, async move |terminal_view, cx| {
|
||||
let open_target = terminal_view
|
||||
.update(cx, |_, cx| {
|
||||
possible_open_target(
|
||||
&task_workspace,
|
||||
&path_like_target.terminal_dir,
|
||||
&path_like_target.maybe_path,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.context("workspace update")?
|
||||
})?
|
||||
.await;
|
||||
if opened_items.len() != 1 {
|
||||
debug_panic!(
|
||||
"Received {} items for one path {path_to_open:?}",
|
||||
opened_items.len(),
|
||||
);
|
||||
}
|
||||
if let Some(open_target) = open_target {
|
||||
let path_to_open = open_target.path();
|
||||
let opened_items = task_workspace
|
||||
.update_in(cx, |workspace, window, cx| {
|
||||
workspace.open_paths(
|
||||
vec![path_to_open.path.clone()],
|
||||
OpenOptions {
|
||||
visible: Some(OpenVisible::OnlyDirectories),
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.context("workspace update")?
|
||||
.await;
|
||||
if opened_items.len() != 1 {
|
||||
debug_panic!(
|
||||
"Received {} items for one path {path_to_open:?}",
|
||||
opened_items.len(),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(opened_item) = opened_items.first() {
|
||||
if open_target.is_file() {
|
||||
if let Some(Ok(opened_item)) = opened_item {
|
||||
if let Some(row) = path_to_open.row {
|
||||
let col = path_to_open.column.unwrap_or(0);
|
||||
if let Some(active_editor) =
|
||||
opened_item.downcast::<Editor>()
|
||||
{
|
||||
active_editor
|
||||
.downgrade()
|
||||
.update_in(cx, |editor, window, cx| {
|
||||
editor.go_to_singleton_buffer_point(
|
||||
language::Point::new(
|
||||
row.saturating_sub(1),
|
||||
col.saturating_sub(1),
|
||||
),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.log_err();
|
||||
if let Some(opened_item) = opened_items.first() {
|
||||
if open_target.is_file() {
|
||||
if let Some(Ok(opened_item)) = opened_item {
|
||||
if let Some(row) = path_to_open.row {
|
||||
let col = path_to_open.column.unwrap_or(0);
|
||||
if let Some(active_editor) =
|
||||
opened_item.downcast::<Editor>()
|
||||
{
|
||||
active_editor
|
||||
.downgrade()
|
||||
.update_in(cx, |editor, window, cx| {
|
||||
editor.go_to_singleton_buffer_point(
|
||||
language::Point::new(
|
||||
row.saturating_sub(1),
|
||||
col.saturating_sub(1),
|
||||
),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if open_target.is_dir() {
|
||||
task_workspace.update(cx, |workspace, cx| {
|
||||
workspace.project().update(cx, |_, cx| {
|
||||
cx.emit(project::Event::ActivateProjectPanel);
|
||||
})
|
||||
})?;
|
||||
}
|
||||
} else if open_target.is_dir() {
|
||||
task_workspace.update(cx, |workspace, cx| {
|
||||
workspace.project().update(cx, |_, cx| {
|
||||
cx.emit(project::Event::ActivateProjectPanel);
|
||||
})
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx)
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx)
|
||||
}
|
||||
},
|
||||
Event::BreadcrumbsChanged => cx.emit(ItemEvent::UpdateBreadcrumbs),
|
||||
Event::CloseTerminal => cx.emit(ItemEvent::CloseItem),
|
||||
Event::SelectionsChanged => {
|
||||
window.invalidate_character_coordinates();
|
||||
cx.emit(SearchEvent::ActiveMatchChanged)
|
||||
}
|
||||
},
|
||||
Event::BreadcrumbsChanged => cx.emit(ItemEvent::UpdateBreadcrumbs),
|
||||
Event::CloseTerminal => cx.emit(ItemEvent::CloseItem),
|
||||
Event::SelectionsChanged => {
|
||||
window.invalidate_character_coordinates();
|
||||
cx.emit(SearchEvent::ActiveMatchChanged)
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -1539,6 +1550,9 @@ impl Item for TerminalView {
|
|||
) {
|
||||
if self.terminal().read(cx).task().is_none() {
|
||||
if let Some((new_id, old_id)) = workspace.database_id().zip(self.workspace_id) {
|
||||
log::debug!(
|
||||
"Updating workspace id for the terminal, old: {old_id:?}, new: {new_id:?}",
|
||||
);
|
||||
cx.background_spawn(TERMINAL_DB.update_workspace_id(
|
||||
new_id,
|
||||
old_id,
|
||||
|
@ -1587,6 +1601,7 @@ impl SerializableItem for TerminalView {
|
|||
}
|
||||
|
||||
if let Some((cwd, workspace_id)) = terminal.working_directory().zip(self.workspace_id) {
|
||||
self.cwd_serialized = true;
|
||||
Some(cx.background_spawn(async move {
|
||||
TERMINAL_DB
|
||||
.save_working_directory(item_id, workspace_id, cwd)
|
||||
|
@ -1597,8 +1612,8 @@ impl SerializableItem for TerminalView {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_serialize(&self, event: &Self::Event) -> bool {
|
||||
matches!(event, ItemEvent::UpdateTab)
|
||||
fn should_serialize(&self, _: &Self::Event) -> bool {
|
||||
!self.cwd_serialized
|
||||
}
|
||||
|
||||
fn deserialize(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue