Separate repository state synchronization from worktree synchronization (#27140)
This PR updates our DB schemas and wire protocol to separate the synchronization of git statuses and other repository state from the synchronization of worktrees. This paves the way for moving the code that executes git status updates out of the `worktree` crate and onto the new `GitStore`. That end goal is motivated by two (related) points: - Disentangling git status updates from the worktree's `BackgroundScanner` will allow us to implement a simpler concurrency story for those updates, hopefully fixing some known but elusive bugs (upstream state not updating after push; statuses getting out of sync in remote projects). - By moving git repository state to the project-scoped `GitStore`, we can get rid of the duplication that currently happens when two worktrees are associated with the same git repository. Co-authored-by: Max <max@zed.dev> Release Notes: - N/A --------- Co-authored-by: Max <max@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
700af63c45
commit
bc1c0a2297
21 changed files with 1147 additions and 535 deletions
|
@ -355,9 +355,10 @@ message Envelope {
|
|||
RefreshCodeLens refresh_code_lens = 325;
|
||||
|
||||
ToggleBreakpoint toggle_breakpoint = 326;
|
||||
BreakpointsForFile breakpoints_for_file = 327; // current max
|
||||
|
||||
BreakpointsForFile breakpoints_for_file = 327;
|
||||
|
||||
UpdateRepository update_repository = 328;
|
||||
RemoveRepository remove_repository = 329; // current max
|
||||
}
|
||||
|
||||
reserved 87 to 88;
|
||||
|
@ -455,6 +456,7 @@ message RejoinRemoteProjectsResponse {
|
|||
message RejoinProject {
|
||||
uint64 id = 1;
|
||||
repeated RejoinWorktree worktrees = 2;
|
||||
repeated RejoinRepository repositories = 3;
|
||||
}
|
||||
|
||||
message RejoinWorktree {
|
||||
|
@ -462,6 +464,11 @@ message RejoinWorktree {
|
|||
uint64 scan_id = 2;
|
||||
}
|
||||
|
||||
message RejoinRepository {
|
||||
uint64 id = 1;
|
||||
uint64 scan_id = 2;
|
||||
}
|
||||
|
||||
message RejoinRoomResponse {
|
||||
Room room = 1;
|
||||
repeated ResharedProject reshared_projects = 2;
|
||||
|
@ -637,8 +644,8 @@ message UpdateWorktree {
|
|||
string root_name = 3;
|
||||
repeated Entry updated_entries = 4;
|
||||
repeated uint64 removed_entries = 5;
|
||||
repeated RepositoryEntry updated_repositories = 6;
|
||||
repeated uint64 removed_repositories = 7;
|
||||
repeated RepositoryEntry updated_repositories = 6; // deprecated
|
||||
repeated uint64 removed_repositories = 7; // deprecated
|
||||
uint64 scan_id = 8;
|
||||
bool is_last_update = 9;
|
||||
string abs_path = 10;
|
||||
|
@ -1900,13 +1907,29 @@ message Entry {
|
|||
|
||||
message RepositoryEntry {
|
||||
uint64 work_directory_id = 1;
|
||||
optional string branch = 2; // deprecated
|
||||
optional Branch branch_summary = 6;
|
||||
reserved 2;
|
||||
repeated StatusEntry updated_statuses = 3;
|
||||
repeated string removed_statuses = 4;
|
||||
repeated string current_merge_conflicts = 5;
|
||||
optional Branch branch_summary = 6;
|
||||
}
|
||||
|
||||
message UpdateRepository {
|
||||
uint64 project_id = 1;
|
||||
uint64 id = 2;
|
||||
string abs_path = 3;
|
||||
repeated uint64 entry_ids = 4;
|
||||
optional Branch branch_summary = 5;
|
||||
repeated StatusEntry updated_statuses = 6;
|
||||
repeated string removed_statuses = 7;
|
||||
repeated string current_merge_conflicts = 8;
|
||||
uint64 scan_id = 9;
|
||||
}
|
||||
|
||||
message RemoveRepository {
|
||||
uint64 project_id = 1;
|
||||
uint64 id = 2;
|
||||
}
|
||||
|
||||
message StatusEntry {
|
||||
string repo_path = 1;
|
||||
|
|
|
@ -445,6 +445,8 @@ messages!(
|
|||
(UpdateUserPlan, Foreground),
|
||||
(UpdateWorktree, Foreground),
|
||||
(UpdateWorktreeSettings, Foreground),
|
||||
(UpdateRepository, Foreground),
|
||||
(RemoveRepository, Foreground),
|
||||
(UsersResponse, Foreground),
|
||||
(GitReset, Background),
|
||||
(GitCheckoutFiles, Background),
|
||||
|
@ -573,6 +575,8 @@ request_messages!(
|
|||
(UpdateParticipantLocation, Ack),
|
||||
(UpdateProject, Ack),
|
||||
(UpdateWorktree, Ack),
|
||||
(UpdateRepository, Ack),
|
||||
(RemoveRepository, Ack),
|
||||
(LspExtExpandMacro, LspExtExpandMacroResponse),
|
||||
(LspExtOpenDocs, LspExtOpenDocsResponse),
|
||||
(SetRoomParticipantRole, Ack),
|
||||
|
@ -689,6 +693,8 @@ entity_messages!(
|
|||
UpdateProject,
|
||||
UpdateProjectCollaborator,
|
||||
UpdateWorktree,
|
||||
UpdateRepository,
|
||||
RemoveRepository,
|
||||
UpdateWorktreeSettings,
|
||||
LspExtExpandMacro,
|
||||
LspExtOpenDocs,
|
||||
|
@ -783,6 +789,31 @@ pub const MAX_WORKTREE_UPDATE_MAX_CHUNK_SIZE: usize = 2;
|
|||
#[cfg(not(any(test, feature = "test-support")))]
|
||||
pub const MAX_WORKTREE_UPDATE_MAX_CHUNK_SIZE: usize = 256;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum WorktreeRelatedMessage {
|
||||
UpdateWorktree(UpdateWorktree),
|
||||
UpdateRepository(UpdateRepository),
|
||||
RemoveRepository(RemoveRepository),
|
||||
}
|
||||
|
||||
impl From<UpdateWorktree> for WorktreeRelatedMessage {
|
||||
fn from(value: UpdateWorktree) -> Self {
|
||||
Self::UpdateWorktree(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UpdateRepository> for WorktreeRelatedMessage {
|
||||
fn from(value: UpdateRepository) -> Self {
|
||||
Self::UpdateRepository(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RemoveRepository> for WorktreeRelatedMessage {
|
||||
fn from(value: RemoveRepository) -> Self {
|
||||
Self::RemoveRepository(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split_worktree_update(mut message: UpdateWorktree) -> impl Iterator<Item = UpdateWorktree> {
|
||||
let mut done = false;
|
||||
|
||||
|
@ -817,7 +848,6 @@ pub fn split_worktree_update(mut message: UpdateWorktree) -> impl Iterator<Item
|
|||
|
||||
updated_repositories.push(RepositoryEntry {
|
||||
work_directory_id: repo.work_directory_id,
|
||||
branch: repo.branch.clone(),
|
||||
branch_summary: repo.branch_summary.clone(),
|
||||
updated_statuses: repo
|
||||
.updated_statuses
|
||||
|
@ -863,6 +893,47 @@ pub fn split_worktree_update(mut message: UpdateWorktree) -> impl Iterator<Item
|
|||
})
|
||||
}
|
||||
|
||||
pub fn split_repository_update(
|
||||
mut update: UpdateRepository,
|
||||
) -> impl Iterator<Item = UpdateRepository> {
|
||||
let mut updated_statuses_iter = mem::take(&mut update.updated_statuses).into_iter().fuse();
|
||||
let mut removed_statuses_iter = mem::take(&mut update.removed_statuses).into_iter().fuse();
|
||||
let mut is_first = true;
|
||||
std::iter::from_fn(move || {
|
||||
let updated_statuses = updated_statuses_iter
|
||||
.by_ref()
|
||||
.take(MAX_WORKTREE_UPDATE_MAX_CHUNK_SIZE)
|
||||
.collect::<Vec<_>>();
|
||||
let removed_statuses = removed_statuses_iter
|
||||
.by_ref()
|
||||
.take(MAX_WORKTREE_UPDATE_MAX_CHUNK_SIZE)
|
||||
.collect::<Vec<_>>();
|
||||
if updated_statuses.is_empty() && removed_statuses.is_empty() && !is_first {
|
||||
return None;
|
||||
}
|
||||
is_first = false;
|
||||
Some(UpdateRepository {
|
||||
updated_statuses,
|
||||
removed_statuses,
|
||||
..update.clone()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn split_worktree_related_message(
|
||||
message: WorktreeRelatedMessage,
|
||||
) -> Box<dyn Iterator<Item = WorktreeRelatedMessage> + Send> {
|
||||
match message {
|
||||
WorktreeRelatedMessage::UpdateWorktree(message) => {
|
||||
Box::new(split_worktree_update(message).map(WorktreeRelatedMessage::UpdateWorktree))
|
||||
}
|
||||
WorktreeRelatedMessage::UpdateRepository(message) => {
|
||||
Box::new(split_repository_update(message).map(WorktreeRelatedMessage::UpdateRepository))
|
||||
}
|
||||
WorktreeRelatedMessage::RemoveRepository(update) => Box::new([update.into()].into_iter()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue