Rust 缓存sqlx池会导致文件句柄溢出

Rust 缓存sqlx池会导致文件句柄溢出,rust,rust-sqlx,Rust,Rust Sqlx,我计划有一个使用Sqlite数据库作为数据文件的应用程序。 因为可以更频繁地打开不同的文件,所以我希望缓存连接 我对生锈很陌生;这是我的第一个项目。。。 我的问题是:当我用完文件句柄时,我无法创建新的数据库文件 到目前为止,我尝试的是: test1(),只有在我为MyPool实现Drop时才起作用。Drop将关闭连接池。通过这样做,我确信文件句柄可以再次释放 test2()是我的项目需要的异步版本(它将是一个火箭应用程序)。在这里,我一点也不成功 如果您运行该代码,则必须在之后删除所有db.

我计划有一个使用Sqlite数据库作为数据文件的应用程序。 因为可以更频繁地打开不同的文件,所以我希望缓存连接

我对生锈很陌生;这是我的第一个项目。。。 我的问题是:当我用完文件句柄时,我无法创建新的数据库文件

到目前为止,我尝试的是:

  • test1(),只有在我为MyPool实现Drop时才起作用。Drop将关闭连接池。通过这样做,我确信文件句柄可以再次释放
  • test2()是我的项目需要的异步版本(它将是一个火箭应用程序)。在这里,我一点也不成功
如果您运行该代码,则必须在之后删除所有db.*文件

// Cargo.toml
// tokio = { version = "1", features = ["rt-multi-thread", "macros" ] }
// futures = "0.3"
// sqlx = { version = "0.5", features = [ "runtime-tokio-native-tls", "sqlite", "migrate" ] }

use sqlx::{migrate::MigrateDatabase, sqlite::SqlitePoolOptions, Pool, Sqlite};
use futures::executor::block_on;
use std::sync::{Arc, Mutex};

#[derive(Clone)]
struct MyPool(Pool<Sqlite>);

impl Drop for MyPool {
    fn drop(&mut self) {
        println!("**** drop");
        block_on(
            self.0.close()
        );
    }
}

#[tokio::main]
async fn main() {
    test1().await;
    //test2().await;
}

async fn test1() {
    let mut pool: Vec<MyPool> = Vec::new();

    for i in 1..1000 {

        let db_name = format!("./db.{}.db", i);

        Sqlite::create_database(&db_name)
            .await.expect(format!("create {} failed", i).as_str());

        let conn = SqlitePoolOptions::new()
            .max_connections(5)
            .connect(&db_name).await.expect(format!("connect {} failed", i).as_str());

        if pool.len() == 10 {
            println!("Clenup");
            pool.clear();
        }

        println!("{}", i);
        pool.push(MyPool(conn));
    }
}

async fn test2() {
    let pool: Arc<Mutex<Vec<MyPool>>> = Arc::new(Mutex::new(Vec::new()));

    let tasks: Vec<_> = (0..1000)
    .map(|i| {
        let my_pool = pool.clone();

        tokio::spawn(async move {

            let db_name = format!("./db.{}.db", i);

            Sqlite::create_database(&db_name)
                .await.expect(format!("create {} failed", i).as_str());

            let conn = SqlitePoolOptions::new()
                .max_connections(5)
                .connect(&db_name).await.expect(format!("connect {} failed", i).as_str());

            {
                let mut locked_pool = my_pool.lock().expect("locked");
                if locked_pool.len() == 10 {
                    println!("Clenup");
                    locked_pool.clear();
                }

                println!("{}", i);
                locked_pool.push(MyPool(conn));
            }

        })
    }).collect();

    // Wait for all tasks to complete.
    futures::future::join_all(tasks).await;
}
//Cargo.toml
//tokio={version=“1”,功能=[“rt多线程”,“宏”]}
//期货=“0.3”
//sqlx={version=“0.5”,功能=[“运行时东京本地tls”、“sqlite”、“迁移”]}
使用sqlx::{migrate::MigrateDatabase,sqlite::SqlitePoolOptions,Pool,sqlite};
使用futures::executor::block_on;
使用std::sync::{Arc,Mutex};
#[衍生(克隆)]
结构MyPool(Pool);
MyPool的impl Drop{
fn下降(&mut自我){
println!(“****下降”);
封锁(
self.0.close()
);
}
}
#[tokio::main]
异步fn main(){
test1()等待;
//test2()等待;
}
异步fn test1(){
让mut pool:Vec=Vec::new();
因为我在1..1000{
让db_name=format!(“/db.{}.db”,i);
Sqlite::创建数据库(&db\U名称)
.await.expect(格式!(“创建{}失败”,i).as_str());
让conn=SqlitePoolOptions::new()
.最大连接数(5)
.connect(&db_name).await.expect(格式!(“连接{}失败”,i).as_str());
如果pool.len()==10{
println!(“Clenup”);
pool.clear();
}
println!(“{}”,i);
推球(康涅狄格州米池);
}
}
异步fn test2(){
让池:Arc=Arc::new(Mutex::new(Vec::new());
let任务:Vec=(0..1000)
.map(|i|{
让my_pool=pool.clone();
东京:产卵(异步移动){
让db_name=format!(“/db.{}.db”,i);
Sqlite::创建数据库(&db\U名称)
.await.expect(格式!(“创建{}失败”,i).as_str());
让conn=SqlitePoolOptions::new()
.最大连接数(5)
.connect(&db_name).await.expect(格式!(“连接{}失败”,i).as_str());
{
让mut locked_pool=my_pool.lock().expect(“locked”);
如果已锁定\u pool.len()==10{
println!(“Clenup”);
锁定池。清除();
}
println!(“{}”,i);
锁定池。推(我的池(康涅狄格州));
}
})
}).收集();
//等待所有任务完成。
未来::未来::加入所有(任务)。等待;
}

在异步版本中,所有1000个任务都会立即开始运行*,因此有机会在池有机会删除它们之前创建所有1000个任务。我已经在Rocket应用程序中实现了这一点。当我创建1000个curl请求时,我看到了同样的问题。在这种情况下,应该有一些延迟,并且不是所有的延迟都应该同时运行。但我确信这是一个多线程问题……当我锁定互斥锁时,这不是其他任务等待的信号吗?这意味着第11个任务将清理缓存,并将是随后缓存中的第一个任务。所以从理论上讲,这个问题应该没有问题。不,等等。。。在锁定互斥锁之前,连接已打开。所有其他线程也是如此。在下一步中,缓存将被释放,但这已经太晚了。这意味着我必须先锁定互斥体?现在尝试将
let conn=SqlitePoolOptions::new()
部分移到块内,在块内锁定互斥体。但这不起作用,因为没有为互斥实现
std::marker::Send
。如何解决这个问题?