Reduce serializability of project delete (#11628)

Conrad Irwin created

This may reduce locks when deleting projects.

Release Notes:

- N/A

Change summary

crates/collab/src/db.rs                  |  2 
crates/collab/src/db/queries/projects.rs | 17 +++++++----
crates/collab/src/rpc.rs                 | 39 ++++++++++++++++---------
3 files changed, 37 insertions(+), 21 deletions(-)

Detailed changes

crates/collab/src/db.rs 🔗

@@ -415,7 +415,7 @@ impl Database {
         if is_serialization_error(error) && prev_attempt_count < SLEEPS.len() {
             let base_delay = SLEEPS[prev_attempt_count];
             let randomized_delay = base_delay * self.rng.lock().await.gen_range(0.5..=2.0);
-            log::info!(
+            log::warn!(
                 "retrying transaction after serialization error. delay: {} ms.",
                 randomized_delay
             );

crates/collab/src/db/queries/projects.rs 🔗

@@ -130,13 +130,21 @@ impl Database {
         .await
     }
 
+    pub async fn delete_project(&self, project_id: ProjectId) -> Result<()> {
+        self.weak_transaction(|tx| async move {
+            project::Entity::delete_by_id(project_id).exec(&*tx).await?;
+            Ok(())
+        })
+        .await
+    }
+
     /// Unshares the given project.
     pub async fn unshare_project(
         &self,
         project_id: ProjectId,
         connection: ConnectionId,
         user_id: Option<UserId>,
-    ) -> Result<TransactionGuard<(Option<proto::Room>, Vec<ConnectionId>)>> {
+    ) -> Result<TransactionGuard<(bool, Option<proto::Room>, Vec<ConnectionId>)>> {
         self.project_transaction(project_id, |tx| async move {
             let guest_connection_ids = self.project_guest_connection_ids(project_id, &tx).await?;
             let project = project::Entity::find_by_id(project_id)
@@ -149,10 +157,7 @@ impl Database {
                 None
             };
             if project.host_connection()? == connection {
-                project::Entity::delete(project.into_active_model())
-                    .exec(&*tx)
-                    .await?;
-                return Ok((room, guest_connection_ids));
+                return Ok((true, room, guest_connection_ids));
             }
             if let Some(dev_server_project_id) = project.dev_server_project_id {
                 if let Some(user_id) = user_id {
@@ -169,7 +174,7 @@ impl Database {
                     })
                     .exec(&*tx)
                     .await?;
-                    return Ok((room, guest_connection_ids));
+                    return Ok((false, room, guest_connection_ids));
                 }
             }
 

crates/collab/src/rpc.rs 🔗

@@ -2032,23 +2032,34 @@ async fn unshare_project_internal(
     user_id: Option<UserId>,
     session: &Session,
 ) -> Result<()> {
-    let (room, guest_connection_ids) = &*session
-        .db()
-        .await
-        .unshare_project(project_id, connection_id, user_id)
-        .await?;
+    let delete = {
+        let room_guard = session
+            .db()
+            .await
+            .unshare_project(project_id, connection_id, user_id)
+            .await?;
 
-    let message = proto::UnshareProject {
-        project_id: project_id.to_proto(),
+        let (delete, room, guest_connection_ids) = &*room_guard;
+
+        let message = proto::UnshareProject {
+            project_id: project_id.to_proto(),
+        };
+
+        broadcast(
+            Some(connection_id),
+            guest_connection_ids.iter().copied(),
+            |conn_id| session.peer.send(conn_id, message.clone()),
+        );
+        if let Some(room) = room {
+            room_updated(room, &session.peer);
+        }
+
+        *delete
     };
 
-    broadcast(
-        Some(connection_id),
-        guest_connection_ids.iter().copied(),
-        |conn_id| session.peer.send(conn_id, message.clone()),
-    );
-    if let Some(room) = room {
-        room_updated(room, &session.peer);
+    if delete {
+        let db = session.db().await;
+        db.delete_project(project_id).await?;
     }
 
     Ok(())