From cad0dcbed15b1d0befcd6d469614163db903093a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Mon, 22 Nov 2021 00:01:23 +0100 Subject: [PATCH] await the mutex in db_run and use block_in_place for it's contents --- src/db/mod.rs | 99 +++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 71 deletions(-) diff --git a/src/db/mod.rs b/src/db/mod.rs index aeceda5a..6fcb63e5 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -206,87 +206,44 @@ macro_rules! db_run { // Different code for each db ( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{ #[allow(unused)] use diesel::prelude::*; + #[allow(unused)] use crate::db::FromDb; - // It is important that this inner Arc> (or the OwnedMutexGuard - // derived from it) never be a variable on the stack at an await point, - // where Drop might be called at any time. This causes (synchronous) - // Drop to be called from asynchronous code, which some database - // wrappers do not or can not handle. let conn = $conn.conn.clone(); + let mut conn = conn.lock_owned().await; + match conn.as_mut().expect("internal invariant broken: self.connection is Some") { + $($( + #[cfg($db)] + crate::db::DbConnInner::$db($conn) => { + paste::paste! { + #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *}; + #[allow(unused)] use [<__ $db _model>]::*; + } - // Since connection can't be on the stack in an async fn during an - // await, we have to spawn a new blocking-safe thread... - /* - run_blocking(move || { - // And then re-enter the runtime to wait on the async mutex, but in - // a blocking fashion. - let mut conn = tokio::runtime::Handle::current().block_on(conn.lock_owned()); - let conn = conn.as_mut().expect("internal invariant broken: self.connection is Some"); - */ - let mut __conn_mutex = conn.try_lock_owned().unwrap(); - let conn = __conn_mutex.as_mut().unwrap(); - match conn { - $($( - #[cfg($db)] - crate::db::DbConnInner::$db($conn) => { - paste::paste! { - #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *}; - #[allow(unused)] use [<__ $db _model>]::*; - #[allow(unused)] use crate::db::FromDb; - } - - /* - // Since connection can't be on the stack in an async fn during an - // await, we have to spawn a new blocking-safe thread... - run_blocking(move || { - // And then re-enter the runtime to wait on the async mutex, but in - // a blocking fashion. - let mut conn = tokio::runtime::Handle::current().block_on(async { - conn.lock_owned().await - }); - - let conn = conn.as_mut().expect("internal invariant broken: self.connection is Some"); - f(conn) - }).await;*/ - - $body - }, - )+)+ - } - // }).await + tokio::task::block_in_place(move || { $body }) // Run blocking can't be used due to the 'static limitation, use block_in_place instead + }, + )+)+ + } }}; ( @raw $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{ #[allow(unused)] use diesel::prelude::*; + #[allow(unused)] use crate::db::FromDb; - // It is important that this inner Arc> (or the OwnedMutexGuard - // derived from it) never be a variable on the stack at an await point, - // where Drop might be called at any time. This causes (synchronous) - // Drop to be called from asynchronous code, which some database - // wrappers do not or can not handle. let conn = $conn.conn.clone(); + let mut conn = conn.lock_owned().await; + match conn.as_mut().expect("internal invariant broken: self.connection is Some") { + $($( + #[cfg($db)] + crate::db::DbConnInner::$db($conn) => { + paste::paste! { + #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *}; + // @ RAW: #[allow(unused)] use [<__ $db _model>]::*; + } - // Since connection can't be on the stack in an async fn during an - // await, we have to spawn a new blocking-safe thread... - run_blocking(move || { - // And then re-enter the runtime to wait on the async mutex, but in - // a blocking fashion. - let mut conn = tokio::runtime::Handle::current().block_on(conn.lock_owned()); - match conn.as_mut().expect("internal invariant broken: self.connection is Some") { - $($( - #[cfg($db)] - crate::db::DbConnInner::$db($conn) => { - paste::paste! { - #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *}; - // @RAW: #[allow(unused)] use [<__ $db _model>]::*; - #[allow(unused)] use crate::db::FromDb; - } - - $body - }, - )+)+ - } - }).await + tokio::task::block_in_place(move || { $body }) // Run blocking can't be used due to the 'static limitation, use block_in_place instead + }, + )+)+ + } }}; }