ADBCPool::connect is an async fn but calls r2d2::Pool::get() directly on the async executor. get() is synchronous and may block indefinitely when the pool is exhausted or while opening a new connection.
|
async fn connect( |
|
&self, |
|
) -> Result<Box<dyn DbConnection<r2d2::PooledConnection<AdbcConnectionManager<D>>, RecordBatch>>> |
|
{ |
|
let pool = Arc::clone(&self.pool); |
|
let conn: r2d2::PooledConnection<AdbcConnectionManager<D>> = |
|
pool.get().context(ConnectionPoolSnafu)?; |
|
|
|
Ok(Box::new(AdbcDbConnection::new(conn))) |
|
} |
When many callers await connect() concurrently (e.g. during parallel table/schema initialization in a host runtime), waiters block Tokio worker threads instead of yielding. That can stall unrelated async work on the same runtime, including health checks and other I/O.
Expected: blocking pool acquisition should run off the async executor (e.g. tokio::task::spawn_blocking) so connect().await yields while waiting for a connection.
Actual: pool.get() runs inline in the async task, blocking the executor thread until a connection is available.
ADBCPool::connectis anasync fnbut callsr2d2::Pool::get()directly on the async executor.get()is synchronous and may block indefinitely when the pool is exhausted or while opening a new connection.datafusion-table-providers/core/src/sql/db_connection_pool/adbcpool.rs
Lines 199 to 208 in 4547bee
When many callers await
connect()concurrently (e.g. during parallel table/schema initialization in a host runtime), waiters block Tokio worker threads instead of yielding. That can stall unrelated async work on the same runtime, including health checks and other I/O.Expected: blocking pool acquisition should run off the async executor (e.g.
tokio::task::spawn_blocking) soconnect().awaityields while waiting for a connection.Actual:
pool.get()runs inline in the async task, blocking the executor thread until a connection is available.