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:
Nathan Sobo 2023-01-04 12:33:48 -07:00
parent 1dd085fc92
commit 789bbf15b7
5 changed files with 35 additions and 16 deletions

View file

@ -580,7 +580,7 @@ impl Server {
drop(foreground_message_handlers);
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");
}
@ -781,7 +781,7 @@ pub async fn handle_metrics(Extension(server): Extension<Arc<Server>>) -> Result
}
#[instrument(err, skip(executor))]
async fn sign_out(
async fn connection_lost(
session: Session,
mut teardown: watch::Receiver<()>,
executor: Executor,

View file

@ -314,6 +314,7 @@ async fn test_random_collaboration(
.read_with(client_cx, |project, _| project.remote_id())
.unwrap()
};
let guest_user_id = client.user_id().unwrap();
let host_project = clients.iter().find_map(|(client, cx)| {
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)
})
})?;
Some((project, cx))
Some((client.user_id().unwrap(), project, cx))
});
let (host_project, host_cx) = if let Some((host_project, host_cx)) = host_project {
(host_project, host_cx)
} else {
continue;
};
let (host_user_id, host_project, host_cx) =
if let Some((host_user_id, host_project, host_cx)) = host_project {
(host_user_id, host_project, host_cx)
} else {
continue;
};
for guest_buffer in guest_buffers {
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());
match (host_file, guest_file) {
(Some(host_file), Some(guest_file)) => {
assert_eq!(host_file.mtime(), guest_file.mtime());
assert_eq!(host_file.path(), guest_file.path());
assert_eq!(host_file.is_deleted(), guest_file.is_deleted());
assert_eq!(guest_file.path(), host_file.path());
assert_eq!(guest_file.is_deleted(), host_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, _) => panic!("host's file is None, guest's isn't "),

View file

@ -327,8 +327,6 @@ mod tests {
.path();
corrupted_backup_dir.push(DB_FILE_NAME);
dbg!(&corrupted_backup_dir);
let backup = Connection::open_file(&corrupted_backup_dir.to_string_lossy());
assert!(backup.select_row::<usize>("SELECT * FROM test").unwrap()()
.unwrap()

View file

@ -359,7 +359,7 @@ impl FormatTrigger {
impl Project {
pub fn init(client: &Arc<Client>) {
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_buffer_reloaded);
client.add_model_message_handler(Self::handle_buffer_saved);
@ -4617,7 +4617,7 @@ impl Project {
Ok(())
}
async fn handle_update_collaborator(
async fn handle_update_project_collaborator(
this: ModelHandle<Self>,
envelope: TypedEnvelope<proto::UpdateProjectCollaborator>,
_: Arc<Client>,
@ -5184,9 +5184,20 @@ impl Project {
let operations = buffer.serialize_ops(Some(remote_version), cx);
let client = this.client.clone();
let file = buffer.file().cloned();
cx.background()
.spawn(
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;
for chunk in split_operations(operations) {
client

View file

@ -216,7 +216,7 @@ impl WorkspaceDb {
let mut result = Vec::new();
let mut delete_tasks = Vec::new();
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));
} else {
delete_tasks.push(self.delete_stale_workspace(id));