In my Rust application I am using Diesel
to interact with an SQLite
database. I have multiple threads that may query at the same time the database, and I am using the crate r2d2
to create a pool of connections.
The issue that I am seeing is that I am not able to concurrently query the database. If I try to do that, I always get the error database is locked
, which is unrecoverable (any following request will fail from the same error even if only a single thread is querying).
The following code reproduces the issue.
# Cargo.toml
[dependencies]
crossbeam = { version = "0.7.1" }
diesel = { version = "1.4.2", features = ["sqlite", "r2d2"] }
-- The database table
CREATE TABLE users (
name TEXT PRIMARY KEY NOT NULL
);
#[macro_use]
extern crate diesel;
mod schema;
use crate::schema::*;
use crossbeam;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::RunQueryDsl;
use diesel::{ExpressionMethods, SqliteConnection};
#[derive(Insertable, Queryable, Debug, Clone)]
#[table_name = "users"]
struct User {
name: String,
}
fn main() {
let db_url = "test.sqlite3";
let pool = Pool::builder()
.build(ConnectionManager::<SqliteConnection>::new(db_url))
.unwrap();
crossbeam::scope(|scope| {
let pool2 = pool.clone();
scope.spawn(move |_| {
let conn = pool2.get().unwrap();
for i in 0..100 {
let name = format!("John{}", i);
diesel::delete(users::table)
.filter(users::name.eq(&name))
.execute(&conn)
.unwrap();
}
});
let conn = pool.get().unwrap();
for i in 0..100 {
let name = format!("John{}", i);
diesel::insert_into(users::table)
.values(User { name })
.execute(&conn)
.unwrap();
}
})
.unwrap();
}
This is the error as shown when the application panics:
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: DatabaseError(__Unknown, "database is locked")'
AFAIK, I should be able to use the connection pool with multiple threads (that is, multiple connections for multiple threads), as shown in the r2d2_sqlite
crate example.
Moreover, the sqlite3 library I have installed in my system supports the Serialized threading model, which from here:
In serialized mode, SQLite can be safely used by multiple threads with no restriction.
How can I avoid the database is locked
errors? Also, if these errors are not avoidable for any reason, how can I unlock the database?