From 639cd71a3b3d49e7850d0ca2c9ffcbf978b011f3 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 29 Jun 2022 16:58:19 +0200 Subject: [PATCH] Record worktree extensions every 5 minutes Co-Authored-By: Nathan Sobo --- crates/collab/src/db.rs | 8 +-- crates/collab/src/rpc.rs | 30 ++++++-- crates/collab/src/rpc/store.rs | 57 ++------------- crates/project/src/project.rs | 49 ++++++++++++- crates/project/src/worktree.rs | 4 ++ crates/rpc/proto/zed.proto | 126 ++++++++++++++++++--------------- crates/rpc/src/proto.rs | 2 + 7 files changed, 151 insertions(+), 125 deletions(-) diff --git a/crates/collab/src/db.rs b/crates/collab/src/db.rs index ef91bb03ac..09e6245e43 100644 --- a/crates/collab/src/db.rs +++ b/crates/collab/src/db.rs @@ -52,7 +52,7 @@ pub trait Db: Send + Sync { &self, project_id: ProjectId, worktree_id: u64, - extensions: HashMap, + extensions: HashMap, ) -> Result<()>; /// Get the file counts on the given project keyed by their worktree and extension. @@ -506,7 +506,7 @@ impl Db for PostgresDb { &self, project_id: ProjectId, worktree_id: u64, - extensions: HashMap, + extensions: HashMap, ) -> Result<()> { if extensions.is_empty() { return Ok(()); @@ -2255,7 +2255,7 @@ pub mod tests { background: Arc, pub users: Mutex>, pub projects: Mutex>, - pub worktree_extensions: Mutex>, + pub worktree_extensions: Mutex>, pub orgs: Mutex>, pub org_memberships: Mutex>, pub channels: Mutex>, @@ -2442,7 +2442,7 @@ pub mod tests { &self, project_id: ProjectId, worktree_id: u64, - extensions: HashMap, + extensions: HashMap, ) -> Result<()> { self.background.simulate_random_delay().await; if !self.projects.lock().contains_key(&project_id) { diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 1aa2e5c4af..2a5aeb459e 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -164,6 +164,7 @@ impl Server { .add_message_handler(Server::update_project) .add_message_handler(Server::register_project_activity) .add_request_handler(Server::update_worktree) + .add_message_handler(Server::update_worktree_extensions) .add_message_handler(Server::start_language_server) .add_message_handler(Server::update_language_server) .add_message_handler(Server::update_diagnostic_summary) @@ -996,9 +997,9 @@ impl Server { ) -> Result<()> { let project_id = ProjectId::from_proto(request.payload.project_id); let worktree_id = request.payload.worktree_id; - let (connection_ids, metadata_changed, extension_counts) = { + let (connection_ids, metadata_changed) = { let mut store = self.store_mut().await; - let (connection_ids, metadata_changed, extension_counts) = store.update_worktree( + let (connection_ids, metadata_changed) = store.update_worktree( request.sender_id, project_id, worktree_id, @@ -1007,12 +1008,8 @@ impl Server { &request.payload.updated_entries, request.payload.scan_id, )?; - (connection_ids, metadata_changed, extension_counts.clone()) + (connection_ids, metadata_changed) }; - self.app_state - .db - .update_worktree_extensions(project_id, worktree_id, extension_counts) - .await?; broadcast(request.sender_id, connection_ids, |connection_id| { self.peer @@ -1029,6 +1026,25 @@ impl Server { Ok(()) } + async fn update_worktree_extensions( + self: Arc, + request: TypedEnvelope, + ) -> Result<()> { + let project_id = ProjectId::from_proto(request.payload.project_id); + let worktree_id = request.payload.worktree_id; + let extensions = request + .payload + .extensions + .into_iter() + .zip(request.payload.counts) + .collect(); + self.app_state + .db + .update_worktree_extensions(project_id, worktree_id, extensions) + .await?; + Ok(()) + } + async fn update_diagnostic_summary( self: Arc, request: TypedEnvelope, diff --git a/crates/collab/src/rpc/store.rs b/crates/collab/src/rpc/store.rs index 7a327e4d35..2ae7036ccb 100644 --- a/crates/collab/src/rpc/store.rs +++ b/crates/collab/src/rpc/store.rs @@ -3,12 +3,7 @@ use anyhow::{anyhow, Result}; use collections::{btree_map, hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}; use rpc::{proto, ConnectionId, Receipt}; use serde::Serialize; -use std::{ - mem, - path::{Path, PathBuf}, - str, - time::Duration, -}; +use std::{mem, path::PathBuf, str, time::Duration}; use time::OffsetDateTime; use tracing::instrument; @@ -59,8 +54,6 @@ pub struct Worktree { #[serde(skip)] pub entries: BTreeMap, #[serde(skip)] - pub extension_counts: HashMap, - #[serde(skip)] pub diagnostic_summaries: BTreeMap, pub scan_id: u64, } @@ -401,7 +394,6 @@ impl Store { for worktree in project.worktrees.values_mut() { worktree.diagnostic_summaries.clear(); worktree.entries.clear(); - worktree.extension_counts.clear(); } Ok(Some(UnsharedProject { @@ -632,7 +624,6 @@ impl Store { for worktree in project.worktrees.values_mut() { worktree.diagnostic_summaries.clear(); worktree.entries.clear(); - worktree.extension_counts.clear(); } } @@ -655,7 +646,7 @@ impl Store { removed_entries: &[u64], updated_entries: &[proto::Entry], scan_id: u64, - ) -> Result<(Vec, bool, HashMap)> { + ) -> Result<(Vec, bool)> { let project = self.write_project(project_id, connection_id)?; if !project.online { return Err(anyhow!("project is not online")); @@ -667,45 +658,15 @@ impl Store { worktree.root_name = worktree_root_name.to_string(); for entry_id in removed_entries { - if let Some(entry) = worktree.entries.remove(&entry_id) { - if !entry.is_ignored { - if let Some(extension) = extension_for_entry(&entry) { - if let Some(count) = worktree.extension_counts.get_mut(extension) { - *count = count.saturating_sub(1); - } - } - } - } + worktree.entries.remove(&entry_id); } for entry in updated_entries { - if let Some(old_entry) = worktree.entries.insert(entry.id, entry.clone()) { - if !old_entry.is_ignored { - if let Some(extension) = extension_for_entry(&old_entry) { - if let Some(count) = worktree.extension_counts.get_mut(extension) { - *count = count.saturating_sub(1); - } - } - } - } - - if !entry.is_ignored { - if let Some(extension) = extension_for_entry(&entry) { - if let Some(count) = worktree.extension_counts.get_mut(extension) { - *count += 1; - } else { - worktree.extension_counts.insert(extension.into(), 1); - } - } - } + worktree.entries.insert(entry.id, entry.clone()); } worktree.scan_id = scan_id; - Ok(( - connection_ids, - metadata_changed, - worktree.extension_counts.clone(), - )) + Ok((connection_ids, metadata_changed)) } pub fn project_connection_ids( @@ -894,11 +855,3 @@ impl Channel { self.connection_ids.iter().copied().collect() } } - -fn extension_for_entry(entry: &proto::Entry) -> Option<&str> { - str::from_utf8(&entry.path) - .ok() - .map(Path::new) - .and_then(|p| p.extension()) - .and_then(|e| e.to_str()) -} diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 2658adaa6d..520d743f46 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -52,7 +52,7 @@ use std::{ atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst}, Arc, }, - time::Instant, + time::{Duration, Instant}, }; use thiserror::Error; use util::{post_inc, ResultExt, TryFutureExt as _}; @@ -403,13 +403,22 @@ impl Project { }); let (online_tx, online_rx) = watch::channel_with(online); + let mut send_extension_counts = None; let _maintain_online_status = cx.spawn_weak({ let mut online_rx = online_rx.clone(); move |this, mut cx| async move { - while online_rx.recv().await.is_some() { + while let Some(online) = online_rx.recv().await { let this = this.upgrade(&cx)?; + if online { + send_extension_counts = Some( + this.update(&mut cx, |this, cx| this.send_extension_counts(cx)), + ); + } else { + send_extension_counts.take(); + } + this.update(&mut cx, |this, cx| { - if !this.is_online() { + if !online { this.unshared(cx); } this.metadata_changed(false, cx) @@ -463,6 +472,40 @@ impl Project { }) } + fn send_extension_counts(&self, cx: &mut ModelContext) -> Task> { + cx.spawn_weak(|this, cx| async move { + loop { + let this = this.upgrade(&cx)?; + this.read_with(&cx, |this, cx| { + if let Some(project_id) = this.remote_id() { + for worktree in this.visible_worktrees(cx) { + if let Some(worktree) = worktree.read(cx).as_local() { + let mut extensions = Vec::new(); + let mut counts = Vec::new(); + + for (extension, count) in worktree.extension_counts() { + extensions.push(extension.to_string_lossy().to_string()); + counts.push(*count as u32); + } + + this.client + .send(proto::UpdateWorktreeExtensions { + project_id, + worktree_id: worktree.id().to_proto(), + extensions, + counts, + }) + .log_err(); + } + } + } + }); + + cx.background().timer(Duration::from_secs(60 * 5)).await; + } + }) + } + pub async fn remote( remote_id: u64, client: Arc, diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 2184f4c1cd..5900c9b079 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -1327,6 +1327,10 @@ impl LocalSnapshot { &self.abs_path } + pub fn extension_counts(&self) -> &HashMap { + &self.extension_counts + } + #[cfg(test)] pub(crate) fn to_proto( &self, diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 1cfbb6cea4..10810d7a6b 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -38,72 +38,73 @@ message Envelope { UpdateProject update_project = 30; RegisterProjectActivity register_project_activity = 31; UpdateWorktree update_worktree = 32; + UpdateWorktreeExtensions update_worktree_extensions = 33; - CreateProjectEntry create_project_entry = 33; - RenameProjectEntry rename_project_entry = 34; - CopyProjectEntry copy_project_entry = 35; - DeleteProjectEntry delete_project_entry = 36; - ProjectEntryResponse project_entry_response = 37; + CreateProjectEntry create_project_entry = 34; + RenameProjectEntry rename_project_entry = 35; + CopyProjectEntry copy_project_entry = 36; + DeleteProjectEntry delete_project_entry = 37; + ProjectEntryResponse project_entry_response = 38; - UpdateDiagnosticSummary update_diagnostic_summary = 38; - StartLanguageServer start_language_server = 39; - UpdateLanguageServer update_language_server = 40; + UpdateDiagnosticSummary update_diagnostic_summary = 39; + StartLanguageServer start_language_server = 40; + UpdateLanguageServer update_language_server = 41; - OpenBufferById open_buffer_by_id = 41; - OpenBufferByPath open_buffer_by_path = 42; - OpenBufferResponse open_buffer_response = 43; - UpdateBuffer update_buffer = 44; - UpdateBufferFile update_buffer_file = 45; - SaveBuffer save_buffer = 46; - BufferSaved buffer_saved = 47; - BufferReloaded buffer_reloaded = 48; - ReloadBuffers reload_buffers = 49; - ReloadBuffersResponse reload_buffers_response = 50; - FormatBuffers format_buffers = 51; - FormatBuffersResponse format_buffers_response = 52; - GetCompletions get_completions = 53; - GetCompletionsResponse get_completions_response = 54; - ApplyCompletionAdditionalEdits apply_completion_additional_edits = 55; - ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 56; - GetCodeActions get_code_actions = 57; - GetCodeActionsResponse get_code_actions_response = 58; - GetHover get_hover = 59; - GetHoverResponse get_hover_response = 60; - ApplyCodeAction apply_code_action = 61; - ApplyCodeActionResponse apply_code_action_response = 62; - PrepareRename prepare_rename = 63; - PrepareRenameResponse prepare_rename_response = 64; - PerformRename perform_rename = 65; - PerformRenameResponse perform_rename_response = 66; - SearchProject search_project = 67; - SearchProjectResponse search_project_response = 68; + OpenBufferById open_buffer_by_id = 42; + OpenBufferByPath open_buffer_by_path = 43; + OpenBufferResponse open_buffer_response = 44; + UpdateBuffer update_buffer = 45; + UpdateBufferFile update_buffer_file = 46; + SaveBuffer save_buffer = 47; + BufferSaved buffer_saved = 48; + BufferReloaded buffer_reloaded = 49; + ReloadBuffers reload_buffers = 50; + ReloadBuffersResponse reload_buffers_response = 51; + FormatBuffers format_buffers = 52; + FormatBuffersResponse format_buffers_response = 53; + GetCompletions get_completions = 54; + GetCompletionsResponse get_completions_response = 55; + ApplyCompletionAdditionalEdits apply_completion_additional_edits = 56; + ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 57; + GetCodeActions get_code_actions = 58; + GetCodeActionsResponse get_code_actions_response = 59; + GetHover get_hover = 60; + GetHoverResponse get_hover_response = 61; + ApplyCodeAction apply_code_action = 62; + ApplyCodeActionResponse apply_code_action_response = 63; + PrepareRename prepare_rename = 64; + PrepareRenameResponse prepare_rename_response = 65; + PerformRename perform_rename = 66; + PerformRenameResponse perform_rename_response = 67; + SearchProject search_project = 68; + SearchProjectResponse search_project_response = 69; - GetChannels get_channels = 69; - GetChannelsResponse get_channels_response = 70; - JoinChannel join_channel = 71; - JoinChannelResponse join_channel_response = 72; - LeaveChannel leave_channel = 73; - SendChannelMessage send_channel_message = 74; - SendChannelMessageResponse send_channel_message_response = 75; - ChannelMessageSent channel_message_sent = 76; - GetChannelMessages get_channel_messages = 77; - GetChannelMessagesResponse get_channel_messages_response = 78; + GetChannels get_channels = 70; + GetChannelsResponse get_channels_response = 71; + JoinChannel join_channel = 72; + JoinChannelResponse join_channel_response = 73; + LeaveChannel leave_channel = 74; + SendChannelMessage send_channel_message = 75; + SendChannelMessageResponse send_channel_message_response = 76; + ChannelMessageSent channel_message_sent = 77; + GetChannelMessages get_channel_messages = 78; + GetChannelMessagesResponse get_channel_messages_response = 79; - UpdateContacts update_contacts = 79; - UpdateInviteInfo update_invite_info = 80; - ShowContacts show_contacts = 81; + UpdateContacts update_contacts = 80; + UpdateInviteInfo update_invite_info = 81; + ShowContacts show_contacts = 82; - GetUsers get_users = 82; - FuzzySearchUsers fuzzy_search_users = 83; - UsersResponse users_response = 84; - RequestContact request_contact = 85; - RespondToContactRequest respond_to_contact_request = 86; - RemoveContact remove_contact = 87; + GetUsers get_users = 83; + FuzzySearchUsers fuzzy_search_users = 84; + UsersResponse users_response = 85; + RequestContact request_contact = 86; + RespondToContactRequest respond_to_contact_request = 87; + RemoveContact remove_contact = 88; - Follow follow = 88; - FollowResponse follow_response = 89; - UpdateFollowers update_followers = 90; - Unfollow unfollow = 91; + Follow follow = 89; + FollowResponse follow_response = 90; + UpdateFollowers update_followers = 91; + Unfollow unfollow = 92; } } @@ -200,6 +201,13 @@ message UpdateWorktree { uint64 scan_id = 6; } +message UpdateWorktreeExtensions { + uint64 project_id = 1; + uint64 worktree_id = 2; + repeated string extensions = 3; + repeated uint32 counts = 4; +} + message CreateProjectEntry { uint64 project_id = 1; uint64 worktree_id = 2; diff --git a/crates/rpc/src/proto.rs b/crates/rpc/src/proto.rs index 8b7c5e302b..9429d9a6eb 100644 --- a/crates/rpc/src/proto.rs +++ b/crates/rpc/src/proto.rs @@ -162,6 +162,7 @@ messages!( (UpdateLanguageServer, Foreground), (UpdateProject, Foreground), (UpdateWorktree, Foreground), + (UpdateWorktreeExtensions, Background), ); request_messages!( @@ -254,6 +255,7 @@ entity_messages!( UpdateLanguageServer, UpdateProject, UpdateWorktree, + UpdateWorktreeExtensions, ); entity_messages!(channel_id, ChannelMessageSent);