Update buffer files when synchronizing buffers
It's possible that the host was disconnected when attempting to notify guests of a file save, so we need to transmit this in order to correctly update the file's mtime. Next failing seed OPERATIONS=200 SEED=6894
This commit is contained in:
parent
1dd085fc92
commit
789bbf15b7
5 changed files with 35 additions and 16 deletions
|
@ -580,7 +580,7 @@ impl Server {
|
||||||
|
|
||||||
drop(foreground_message_handlers);
|
drop(foreground_message_handlers);
|
||||||
tracing::info!(%user_id, %login, %connection_id, %address, "signing out");
|
tracing::info!(%user_id, %login, %connection_id, %address, "signing out");
|
||||||
if let Err(error) = sign_out(session, teardown, executor).await {
|
if let Err(error) = connection_lost(session, teardown, executor).await {
|
||||||
tracing::error!(%user_id, %login, %connection_id, %address, ?error, "error signing out");
|
tracing::error!(%user_id, %login, %connection_id, %address, ?error, "error signing out");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,7 +781,7 @@ pub async fn handle_metrics(Extension(server): Extension<Arc<Server>>) -> Result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(err, skip(executor))]
|
#[instrument(err, skip(executor))]
|
||||||
async fn sign_out(
|
async fn connection_lost(
|
||||||
session: Session,
|
session: Session,
|
||||||
mut teardown: watch::Receiver<()>,
|
mut teardown: watch::Receiver<()>,
|
||||||
executor: Executor,
|
executor: Executor,
|
||||||
|
|
|
@ -314,6 +314,7 @@ async fn test_random_collaboration(
|
||||||
.read_with(client_cx, |project, _| project.remote_id())
|
.read_with(client_cx, |project, _| project.remote_id())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
let guest_user_id = client.user_id().unwrap();
|
||||||
|
|
||||||
let host_project = clients.iter().find_map(|(client, cx)| {
|
let host_project = clients.iter().find_map(|(client, cx)| {
|
||||||
let project = client.local_projects.iter().find(|host_project| {
|
let project = client.local_projects.iter().find(|host_project| {
|
||||||
|
@ -321,14 +322,15 @@ async fn test_random_collaboration(
|
||||||
host_project.remote_id() == Some(project_id)
|
host_project.remote_id() == Some(project_id)
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
Some((project, cx))
|
Some((client.user_id().unwrap(), project, cx))
|
||||||
});
|
});
|
||||||
|
|
||||||
let (host_project, host_cx) = if let Some((host_project, host_cx)) = host_project {
|
let (host_user_id, host_project, host_cx) =
|
||||||
(host_project, host_cx)
|
if let Some((host_user_id, host_project, host_cx)) = host_project {
|
||||||
} else {
|
(host_user_id, host_project, host_cx)
|
||||||
continue;
|
} else {
|
||||||
};
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
for guest_buffer in guest_buffers {
|
for guest_buffer in guest_buffers {
|
||||||
let buffer_id = guest_buffer.read_with(client_cx, |buffer, _| buffer.remote_id());
|
let buffer_id = guest_buffer.read_with(client_cx, |buffer, _| buffer.remote_id());
|
||||||
|
@ -366,9 +368,17 @@ async fn test_random_collaboration(
|
||||||
let guest_file = guest_buffer.read_with(client_cx, |b, _| b.file().cloned());
|
let guest_file = guest_buffer.read_with(client_cx, |b, _| b.file().cloned());
|
||||||
match (host_file, guest_file) {
|
match (host_file, guest_file) {
|
||||||
(Some(host_file), Some(guest_file)) => {
|
(Some(host_file), Some(guest_file)) => {
|
||||||
assert_eq!(host_file.mtime(), guest_file.mtime());
|
assert_eq!(guest_file.path(), host_file.path());
|
||||||
assert_eq!(host_file.path(), guest_file.path());
|
assert_eq!(guest_file.is_deleted(), host_file.is_deleted());
|
||||||
assert_eq!(host_file.is_deleted(), guest_file.is_deleted());
|
assert_eq!(
|
||||||
|
guest_file.mtime(),
|
||||||
|
host_file.mtime(),
|
||||||
|
"guest {} mtime does not match host {} for path {:?} in project {}",
|
||||||
|
guest_user_id,
|
||||||
|
host_user_id,
|
||||||
|
guest_file.path(),
|
||||||
|
project_id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
(None, None) => {}
|
(None, None) => {}
|
||||||
(None, _) => panic!("host's file is None, guest's isn't "),
|
(None, _) => panic!("host's file is None, guest's isn't "),
|
||||||
|
|
|
@ -327,8 +327,6 @@ mod tests {
|
||||||
.path();
|
.path();
|
||||||
corrupted_backup_dir.push(DB_FILE_NAME);
|
corrupted_backup_dir.push(DB_FILE_NAME);
|
||||||
|
|
||||||
dbg!(&corrupted_backup_dir);
|
|
||||||
|
|
||||||
let backup = Connection::open_file(&corrupted_backup_dir.to_string_lossy());
|
let backup = Connection::open_file(&corrupted_backup_dir.to_string_lossy());
|
||||||
assert!(backup.select_row::<usize>("SELECT * FROM test").unwrap()()
|
assert!(backup.select_row::<usize>("SELECT * FROM test").unwrap()()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -359,7 +359,7 @@ impl FormatTrigger {
|
||||||
impl Project {
|
impl Project {
|
||||||
pub fn init(client: &Arc<Client>) {
|
pub fn init(client: &Arc<Client>) {
|
||||||
client.add_model_message_handler(Self::handle_add_collaborator);
|
client.add_model_message_handler(Self::handle_add_collaborator);
|
||||||
client.add_model_message_handler(Self::handle_update_collaborator);
|
client.add_model_message_handler(Self::handle_update_project_collaborator);
|
||||||
client.add_model_message_handler(Self::handle_remove_collaborator);
|
client.add_model_message_handler(Self::handle_remove_collaborator);
|
||||||
client.add_model_message_handler(Self::handle_buffer_reloaded);
|
client.add_model_message_handler(Self::handle_buffer_reloaded);
|
||||||
client.add_model_message_handler(Self::handle_buffer_saved);
|
client.add_model_message_handler(Self::handle_buffer_saved);
|
||||||
|
@ -4617,7 +4617,7 @@ impl Project {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_update_collaborator(
|
async fn handle_update_project_collaborator(
|
||||||
this: ModelHandle<Self>,
|
this: ModelHandle<Self>,
|
||||||
envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
|
envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
|
||||||
_: Arc<Client>,
|
_: Arc<Client>,
|
||||||
|
@ -5184,9 +5184,20 @@ impl Project {
|
||||||
|
|
||||||
let operations = buffer.serialize_ops(Some(remote_version), cx);
|
let operations = buffer.serialize_ops(Some(remote_version), cx);
|
||||||
let client = this.client.clone();
|
let client = this.client.clone();
|
||||||
|
let file = buffer.file().cloned();
|
||||||
cx.background()
|
cx.background()
|
||||||
.spawn(
|
.spawn(
|
||||||
async move {
|
async move {
|
||||||
|
if let Some(file) = file {
|
||||||
|
client
|
||||||
|
.send(proto::UpdateBufferFile {
|
||||||
|
project_id,
|
||||||
|
buffer_id: buffer_id as u64,
|
||||||
|
file: Some(file.to_proto()),
|
||||||
|
})
|
||||||
|
.log_err();
|
||||||
|
}
|
||||||
|
|
||||||
let operations = operations.await;
|
let operations = operations.await;
|
||||||
for chunk in split_operations(operations) {
|
for chunk in split_operations(operations) {
|
||||||
client
|
client
|
||||||
|
|
|
@ -216,7 +216,7 @@ impl WorkspaceDb {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let mut delete_tasks = Vec::new();
|
let mut delete_tasks = Vec::new();
|
||||||
for (id, location) in self.recent_workspaces()? {
|
for (id, location) in self.recent_workspaces()? {
|
||||||
if location.paths().iter().all(|path| dbg!(path).exists()) {
|
if location.paths().iter().all(|path| path.exists()) {
|
||||||
result.push((id, location));
|
result.push((id, location));
|
||||||
} else {
|
} else {
|
||||||
delete_tasks.push(self.delete_stale_workspace(id));
|
delete_tasks.push(self.delete_stale_workspace(id));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue