I plan to have a application which uses Sqlite databases as data files. Because different files can be opended more often, I want to cache the connections.
I'm very new to Rust; this is my first project... My problem is: Somewhen I run out of file handles, and I cannot create new database files.
What I tried so far:
- test1(), will only work, if I implement Drop for MyPool. Drop will close the connection-pool. By doing this, I'm sure the file handles gets free again.
- test2(), is the async version which I would need for my project (it will be a Rocket app). Here I'm not successful at all.
If you run the code, you would have to delete all db.* files afterwards.
// 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;
}