Merge switching SQLite connection pool from FIFO to LIFO

This commit is contained in:
link2xt
2023-02-20 16:43:19 +00:00
4 changed files with 23 additions and 14 deletions

View File

@@ -1,10 +1,18 @@
//! Connection pool.
//! # SQLite connection pool.
//!
//! The connection pool holds a number of SQLite connections and allows to allocate them.
//! When allocated connection is dropped, underlying connection is returned back to the pool.
//!
//! The pool is organized as a stack. It always allocates the most recently used connection.
//! Each SQLite connection has its own page cache, so allocating recently used connections
//! improves the performance compared to, for example, organizing the pool as a queue
//! and returning the least recently used connection each time.
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Weak};
use anyhow::{Context, Result};
use crossbeam_queue::ArrayQueue;
use parking_lot::Mutex;
use rusqlite::Connection;
use tokio::sync::{OwnedSemaphorePermit, Semaphore};
@@ -12,7 +20,7 @@ use tokio::sync::{OwnedSemaphorePermit, Semaphore};
#[derive(Debug)]
struct InnerPool {
/// Available connections.
connections: ArrayQueue<Connection>,
connections: Mutex<Vec<Connection>>,
/// Counts the number of available connections.
semaphore: Arc<Semaphore>,
@@ -23,7 +31,9 @@ impl InnerPool {
///
/// The connection could be new or returned back.
fn put(&self, connection: Connection) {
self.connections.force_push(connection);
let mut connections = self.connections.lock();
connections.push(connection);
drop(connections);
}
}
@@ -74,22 +84,19 @@ pub struct Pool {
impl Pool {
/// Creates a new connection pool.
pub fn new(connections: Vec<Connection>) -> Self {
let semaphore = Arc::new(Semaphore::new(connections.len()));
let inner = Arc::new(InnerPool {
connections: ArrayQueue::new(connections.len()),
semaphore: Arc::new(Semaphore::new(connections.len())),
connections: Mutex::new(connections),
semaphore,
});
for connection in connections {
inner.connections.force_push(connection);
}
Pool { inner }
}
/// Retrieves a connection from the pool.
pub async fn get(&self) -> Result<PooledConnection> {
let permit = self.inner.semaphore.clone().acquire_owned().await?;
let conn = self
.inner
.connections
let mut connections = self.inner.connections.lock();
let conn = connections
.pop()
.context("got a permit when there are no connections in the pool")?;
let conn = PooledConnection {