bikeshedder / deadpool

Dead simple pool implementation for rust with async-await
Apache License 2.0
1.04k stars 134 forks source link

Block on dropping SyncWrapper. #330

Open xuxiaocheng0201 opened 3 months ago

xuxiaocheng0201 commented 3 months ago

When I removing the sqlite db file, I occurred an os error 32. Error: 另一个程序正在使用此文件,进程无法访问。 (os error 32) It means Another program is using this file and the process cannot access it. This is a common error in windows.

I have found the code that caused this problem. In SyncWrapper, the connection resource will be dropped in a background task. However, I have no way of knowing whether this task has been completed or not. So if I remove the db file immediately after dropping the pool, this error will occur.

So is there any way to ensure the connections is completely dropped? or block on when the SyncWrapper is dropping?

Reproduce: Cargo.toml:

anyhow = "^1.0"
tokio = { version = "^1.0", features = ["macros", "rt-multi-thread"] }
rusqlite = { version = "~0.31", features = ["bundled"] }
r2d2_sqlite = "~0.24"
r2d2 = "~0.8"
deadpool-r2d2 = "~0.4"

main.rs:

use std::fs::remove_file;
use anyhow::Result;
use deadpool_r2d2::Runtime;
use r2d2_sqlite::SqliteConnectionManager;

pub type Manager = deadpool_r2d2::Manager<SqliteConnectionManager>;
pub type Pool = deadpool_r2d2::Pool<Manager>;

#[tokio::main]
async fn main() -> Result<()> {
    // Create the sqlite database pool.
    let pool = Pool::builder(Manager::new(SqliteConnectionManager::file("1.db"), Runtime::Tokio1)).build()?;

    // Perform a simple query.
    pool.get().await?.interact(|c| c.execute("CREATE TABLE db(id INTEGER);", [])).await.unwrap()?;

    // Close the pool.
    pool.close();
    drop(pool);

    // Remove the database file.
    remove_file("1.db")?; // Error here.
    Ok(())
}
xuxiaocheng0201 commented 3 months ago

I tried my best to resolve the question:

while let Err(e) = tokio::fs::remove_file("1.db").await {
    tokio::task::yield_now().await;
}

But it's not perfect.

bikeshedder commented 3 months ago

I've never thought about that but it makes perfect sense to have that feature. You basically want to wait for all objects returned from the pool to be dropped.

I'm currently thinking of adding a return value to Pool::close which gives you the ability to .await it.

I can think of two ways to implement this:

Even though it's a lot more involved I'm almost leaning towards the second implementation. It always bugged me a bit that deadpool-postgres keeps track of the StatementCaches and not the entire object. e.g. It would be nice if it was also possible to access the Metrics of objects which are currently not living inside the pool.

bikeshedder commented 3 months ago

Related to: