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
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -3158,6 +3158,7 @@ dependencies = [
|
|||
"go_to_line",
|
||||
"gpui",
|
||||
"language",
|
||||
"log",
|
||||
"menu",
|
||||
"picker",
|
||||
"postage",
|
||||
|
@ -3208,6 +3209,7 @@ dependencies = [
|
|||
"db",
|
||||
"gpui",
|
||||
"languages",
|
||||
"log",
|
||||
"notifications",
|
||||
"project",
|
||||
"serde",
|
||||
|
@ -7100,6 +7102,7 @@ dependencies = [
|
|||
"editor",
|
||||
"file_icons",
|
||||
"gpui",
|
||||
"log",
|
||||
"project",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
|
|
@ -20,6 +20,7 @@ command_palette_hooks.workspace = true
|
|||
db.workspace = true
|
||||
fuzzy.workspace = true
|
||||
gpui.workspace = true
|
||||
log.workspace = true
|
||||
picker.workspace = true
|
||||
postage.workspace = true
|
||||
serde.workspace = true
|
||||
|
|
|
@ -67,7 +67,12 @@ impl CommandPaletteDB {
|
|||
command_name: impl Into<String>,
|
||||
user_query: impl Into<String>,
|
||||
) -> Result<()> {
|
||||
self.write_command_invocation_internal(command_name.into(), user_query.into())
|
||||
let command_name = command_name.into();
|
||||
let user_query = user_query.into();
|
||||
log::debug!(
|
||||
"Writing command invocation: command_name={command_name}, user_query={user_query}"
|
||||
);
|
||||
self.write_command_invocation_internal(command_name, user_query)
|
||||
.await
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ component.workspace = true
|
|||
gpui.workspace = true
|
||||
languages.workspace = true
|
||||
notifications.workspace = true
|
||||
log.workspace = true
|
||||
project.workspace = true
|
||||
ui.workspace = true
|
||||
ui_input.workspace = true
|
||||
|
|
|
@ -23,6 +23,9 @@ impl ComponentPreviewDb {
|
|||
workspace_id: WorkspaceId,
|
||||
active_page_id: String,
|
||||
) -> Result<()> {
|
||||
log::debug!(
|
||||
"Saving active page: item_id={item_id:?}, workspace_id={workspace_id:?}, active_page_id={active_page_id}"
|
||||
);
|
||||
let query = "INSERT INTO component_previews(item_id, workspace_id, active_page_id)
|
||||
VALUES (?1, ?2, ?3)
|
||||
ON CONFLICT DO UPDATE SET
|
||||
|
|
|
@ -18,8 +18,13 @@ impl KeyValueStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn write_kvp(&self, key: String, value: String) -> anyhow::Result<()> {
|
||||
log::debug!("Writing key-value pair for key {key}");
|
||||
self.write_kvp_inner(key, value).await
|
||||
}
|
||||
|
||||
query! {
|
||||
pub async fn write_kvp(key: String, value: String) -> Result<()> {
|
||||
async fn write_kvp_inner(key: String, value: String) -> Result<()> {
|
||||
INSERT OR REPLACE INTO kv_store(key, value) VALUES ((?), (?))
|
||||
}
|
||||
}
|
||||
|
@ -78,8 +83,13 @@ impl GlobalKeyValueStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn write_kvp(&self, key: String, value: String) -> anyhow::Result<()> {
|
||||
log::debug!("Writing global key-value pair for key {key}");
|
||||
self.write_kvp_inner(key, value).await
|
||||
}
|
||||
|
||||
query! {
|
||||
pub async fn write_kvp(key: String, value: String) -> Result<()> {
|
||||
async fn write_kvp_inner(key: String, value: String) -> Result<()> {
|
||||
INSERT OR REPLACE INTO kv_store(key, value) VALUES ((?), (?))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1251,6 +1251,7 @@ impl SerializableItem for Editor {
|
|||
language,
|
||||
mtime,
|
||||
};
|
||||
log::debug!("Serializing editor {item_id:?} in workspace {workspace_id:?}");
|
||||
DB.save_serialized_editor(item_id, workspace_id, editor)
|
||||
.await
|
||||
.context("failed to save serialized editor")
|
||||
|
|
|
@ -276,6 +276,7 @@ impl EditorDb {
|
|||
workspace_id: WorkspaceId,
|
||||
selections: Vec<(usize, usize)>,
|
||||
) -> Result<()> {
|
||||
log::debug!("Saving selections for editor {editor_id} in workspace {workspace_id:?}");
|
||||
let mut first_selection;
|
||||
let mut last_selection = 0_usize;
|
||||
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
|
||||
|
@ -327,6 +328,7 @@ VALUES {placeholders};
|
|||
workspace_id: WorkspaceId,
|
||||
folds: Vec<(usize, usize)>,
|
||||
) -> Result<()> {
|
||||
log::debug!("Saving folds for editor {editor_id} in workspace {workspace_id:?}");
|
||||
let mut first_fold;
|
||||
let mut last_fold = 0_usize;
|
||||
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
|
||||
|
|
|
@ -270,6 +270,9 @@ impl ScrollManager {
|
|||
|
||||
cx.foreground_executor()
|
||||
.spawn(async move {
|
||||
log::debug!(
|
||||
"Saving scroll position for item {item_id:?} in workspace {workspace_id:?}"
|
||||
);
|
||||
DB.save_scroll_position(
|
||||
item_id,
|
||||
workspace_id,
|
||||
|
|
|
@ -21,6 +21,7 @@ db.workspace = true
|
|||
editor.workspace = true
|
||||
file_icons.workspace = true
|
||||
gpui.workspace = true
|
||||
log.workspace = true
|
||||
project.workspace = true
|
||||
schemars.workspace = true
|
||||
serde.workspace = true
|
||||
|
|
|
@ -261,6 +261,7 @@ impl SerializableItem for ImageView {
|
|||
|
||||
Some(cx.background_spawn({
|
||||
async move {
|
||||
log::debug!("Saving image at path {image_path:?}");
|
||||
IMAGE_VIEWER
|
||||
.save_image_path(item_id, workspace_id, image_path)
|
||||
.await
|
||||
|
@ -399,18 +400,6 @@ mod persistence {
|
|||
}
|
||||
|
||||
impl ImageViewerDb {
|
||||
query! {
|
||||
pub async fn update_workspace_id(
|
||||
new_id: WorkspaceId,
|
||||
old_id: WorkspaceId,
|
||||
item_id: ItemId
|
||||
) -> Result<()> {
|
||||
UPDATE image_viewers
|
||||
SET workspace_id = ?
|
||||
WHERE workspace_id = ? AND item_id = ?
|
||||
}
|
||||
}
|
||||
|
||||
query! {
|
||||
pub async fn save_image_path(
|
||||
item_id: ItemId,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use gpui::{AnyWindowHandle, AppContext as _, Context, Subscription, Task, WindowId};
|
||||
use gpui::{App, AppContext as _, Context, Subscription, Task, WindowId};
|
||||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -59,7 +59,7 @@ impl Session {
|
|||
|
||||
pub struct AppSession {
|
||||
session: Session,
|
||||
_serialization_task: Option<Task<()>>,
|
||||
_serialization_task: Task<()>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
}
|
||||
|
||||
|
@ -67,17 +67,21 @@ impl AppSession {
|
|||
pub fn new(session: Session, cx: &Context<Self>) -> Self {
|
||||
let _subscriptions = vec![cx.on_app_quit(Self::app_will_quit)];
|
||||
|
||||
let _serialization_task = Some(cx.spawn(async move |_, cx| {
|
||||
let _serialization_task = cx.spawn(async move |_, cx| {
|
||||
let mut current_window_stack = Vec::new();
|
||||
loop {
|
||||
if let Some(windows) = cx.update(|cx| cx.window_stack()).ok().flatten() {
|
||||
store_window_stack(windows).await;
|
||||
if let Some(windows) = cx.update(|cx| window_stack(cx)).ok().flatten() {
|
||||
if windows != current_window_stack {
|
||||
store_window_stack(&windows).await;
|
||||
current_window_stack = windows;
|
||||
}
|
||||
}
|
||||
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(100))
|
||||
.timer(Duration::from_millis(500))
|
||||
.await;
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
Self {
|
||||
session,
|
||||
|
@ -87,8 +91,8 @@ impl AppSession {
|
|||
}
|
||||
|
||||
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> Task<()> {
|
||||
if let Some(windows) = cx.window_stack() {
|
||||
cx.background_spawn(store_window_stack(windows))
|
||||
if let Some(window_stack) = window_stack(cx) {
|
||||
cx.background_spawn(async move { store_window_stack(&window_stack).await })
|
||||
} else {
|
||||
Task::ready(())
|
||||
}
|
||||
|
@ -107,13 +111,17 @@ impl AppSession {
|
|||
}
|
||||
}
|
||||
|
||||
async fn store_window_stack(windows: Vec<AnyWindowHandle>) {
|
||||
let window_ids = windows
|
||||
fn window_stack(cx: &App) -> Option<Vec<u64>> {
|
||||
Some(
|
||||
cx.window_stack()?
|
||||
.into_iter()
|
||||
.map(|window| window.window_id().as_u64())
|
||||
.collect::<Vec<_>>();
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
if let Ok(window_ids_json) = serde_json::to_string(&window_ids) {
|
||||
async fn store_window_stack(windows: &[u64]) {
|
||||
if let Ok(window_ids_json) = serde_json::to_string(windows) {
|
||||
KEY_VALUE_STORE
|
||||
.write_kvp(SESSION_WINDOW_STACK_KEY.to_string(), window_ids_json)
|
||||
.await
|
||||
|
|
|
@ -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,10 +845,18 @@ 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 {
|
||||
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;
|
||||
}
|
||||
|
||||
match event {
|
||||
Event::Wakeup => {
|
||||
cx.notify();
|
||||
cx.emit(Event::Wakeup);
|
||||
|
@ -1005,6 +1015,7 @@ fn subscribe_for_terminal_events(
|
|||
window.invalidate_character_coordinates();
|
||||
cx.emit(SearchEvent::ActiveMatchChanged)
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
vec![terminal_subscription, terminal_events_subscription]
|
||||
|
@ -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(
|
||||
|
|
|
@ -1644,6 +1644,7 @@ impl VimDb {
|
|||
path: Arc<Path>,
|
||||
marks: HashMap<String, Vec<Point>>,
|
||||
) -> Result<()> {
|
||||
log::debug!("Setting path {path:?} for {} marks", marks.len());
|
||||
let result = self
|
||||
.write(move |conn| {
|
||||
let mut query = conn.exec_bound(sql!(
|
||||
|
@ -1694,6 +1695,7 @@ impl VimDb {
|
|||
mark_name: String,
|
||||
path: Arc<Path>,
|
||||
) -> Result<()> {
|
||||
log::debug!("Setting global mark path {path:?} for {mark_name}");
|
||||
self.write(move |conn| {
|
||||
conn.exec_bound(sql!(
|
||||
INSERT OR REPLACE INTO vim_global_marks_paths
|
||||
|
|
|
@ -739,6 +739,7 @@ impl WorkspaceDb {
|
|||
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
|
||||
/// that used this workspace previously
|
||||
pub(crate) async fn save_workspace(&self, workspace: SerializedWorkspace) {
|
||||
log::debug!("Saving workspace at location: {:?}", workspace.location);
|
||||
self.write(move |conn| {
|
||||
conn.with_savepoint("update_worktrees", || {
|
||||
// Clear out panes and pane_groups
|
||||
|
@ -909,6 +910,7 @@ impl WorkspaceDb {
|
|||
{
|
||||
Ok(project)
|
||||
} else {
|
||||
log::debug!("Inserting SSH project at host {host}");
|
||||
self.insert_ssh_project(host, port, paths, user)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("failed to insert ssh project"))
|
||||
|
@ -1209,6 +1211,9 @@ impl WorkspaceDb {
|
|||
pane_group: &SerializedPaneGroup,
|
||||
parent: Option<(GroupId, usize)>,
|
||||
) -> Result<()> {
|
||||
if parent.is_none() {
|
||||
log::debug!("Saving a pane group for workspace {workspace_id:?}");
|
||||
}
|
||||
match pane_group {
|
||||
SerializedPaneGroup::Group {
|
||||
axis,
|
||||
|
@ -1387,6 +1392,10 @@ impl WorkspaceDb {
|
|||
relative_worktree_path: String,
|
||||
toolchain: Toolchain,
|
||||
) -> Result<()> {
|
||||
log::debug!(
|
||||
"Setting toolchain for workspace, worktree: {worktree_id:?}, relative path: {relative_worktree_path:?}, toolchain: {}",
|
||||
toolchain.name
|
||||
);
|
||||
self.write(move |conn| {
|
||||
let mut insert = conn
|
||||
.exec_bound(sql!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue