Skip to content

Commit

Permalink
Add deadpool support (#284)
Browse files Browse the repository at this point in the history
Add deadpool support and refactor r2d2 support for sharing.
  • Loading branch information
Electron100 authored Dec 8, 2024
1 parent c75ac92 commit fca9bf5
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 120 deletions.
29 changes: 28 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ chrono = { version = "0.4.25", default-features = false, features = [
"std",
] }
crossbeam-channel = "0.5"
deadpool = "0.12"
env_logger = "0.11"
fake = "2.6"
log = "0.4"
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ enabled: you will want to enable `sqlite` and/or `pg`:
* `async`: Turns on async support. This is automatically enabled for the `pg` backend, which is implemented on the `tokio-postgres` crate.
* `async-adapter`: Enables the use of `async` with the `sqlite` backend, which is not natively async.
* `debug`: Used in developing Butane, not expected to be enabled by consumers.
* `deadpool`: Connection pooling using [`deadpool`](https://crates.io/crates/deadpool).
* `datetime`: Support for timestamps (using [`chrono`](https://crates.io/crates/chrono) crate).
* `fake`: Support for the [`fake`](https://crates.io/crates/fake) crate's generation of fake data.
* `json`: Support for storing structs as JSON, including using postgres' `JSONB` field type.
* `log`: Log certain warnings to the [`log`](https://crates.io/crates/log) crate facade (target "butane").
* `pg`: Support for PostgreSQL using [`postgres`](https://crates.io/crates/postgres) crate.
* `r2d2`: Connection pooling using [`r2d2`](https://crates.io/crates/r2d2) support
* `r2d2`: Connection pooling using [`r2d2`](https://crates.io/crates/r2d2).
(See `butane::db::ConnectionManager`).
* `sqlite`: Support for SQLite using [`rusqlite`](https://crates.io/crates/rusqlite) crate.
* `sqlite-bundled`: Bundles sqlite instead of using the system version.
Expand All @@ -98,7 +99,7 @@ enabled: you will want to enable `sqlite` and/or `pg`:

## Migration of Breaking Changes
### 0.8 (not yet released)

#### Async
This is a major release which adds Async support. Effort has been made
to keep the sync experience as unchanged as possible. Async versions
of many types have been added, but the sync ones generally retain
Expand All @@ -125,6 +126,12 @@ The Ops traits are:
* `ForeignKeyOpsSync` / `ForeignKeyOpsAsync` (for use with [`ForeignKey`](https://docs.rs/butane/latest/butane/struct.ForeignKey.html))
* `ManyOpsSync` / `ManyOpsAsync` (for use with [`Many`](https://docs.rs/butane/latest/butane/struct.Many.html))

#### ConnectionManager
The `ConnectionManager` struct has moved from `butane::db::r2` to
`butane::db`. It no longer implements `ConnectionMethods` as this was
unnecessary due to `Deref`. The `butane::db::r2` module is no longer
public.

### 0.7
#### `AutoPk`
Replace model fields like
Expand Down
2 changes: 1 addition & 1 deletion async_checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
* [ ] Clean up miscellaneous TODOs
* [x] Establish soundness for unsafe sections of AsyncAdapter
* [x] Should async and/or async_adapter be under a separate feature?
* [ ] Integrate deadpool or bb8 for async connection pool
* [x] Integrate deadpool or bb8 for async connection pool
10 changes: 6 additions & 4 deletions butane/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ build = "build.rs"
[features]
async = ["butane_core/async", "butane_codegen/async"]
async-adapter = ["butane_core/async-adapter"]
deadpool = ["dep:deadpool", "async"]
default = ["datetime", "json", "uuid"]
fake = ["butane_core/fake"]
json = ["butane_codegen/json", "butane_core/json"]
Expand All @@ -24,13 +25,15 @@ pg = ["async", "butane_core/pg"]
datetime = ["butane_codegen/datetime", "butane_core/datetime"]
debug = ["butane_core/debug"]
log = ["butane_core/log"]
r2d2 = ["butane_core/r2d2"]
r2d2 = ["dep:r2d2"]
tls = ["butane_core/tls"]
uuid = ["butane_codegen/uuid", "butane_core/uuid"]

[dependencies]
butane_codegen = { workspace = true }
butane_core = { workspace = true }
r2d2 = { optional = true, workspace = true }
deadpool = { optional = true, workspace = true }

[dev-dependencies]
butane_test_helper = { workspace = true }
Expand All @@ -51,7 +54,6 @@ tokio = { workspace = true, features = ["macros"] }
tokio-postgres = { features = ["with-geo-types-0_7"], workspace = true }
tokio-test = { workspace = true }
rand = { workspace = true }
r2d2_for_test = { package = "r2d2", version = "0.8" }
rusqlite = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
Expand All @@ -74,8 +76,8 @@ name = "json"
required-features = ["json"]

[[test]]
name = "r2d2"
required-features = ["r2d2"]
name = "pool"
required-features = ["r2d2", "deadpool"]

[[test]]
name = "uuid"
Expand Down
21 changes: 21 additions & 0 deletions butane/src/db/deadpool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Deadpool support for Butane.
use super::ConnectionManager;
use crate::db::{BackendConnectionAsync, ConnectionAsync};
use crate::Result;
use deadpool::managed::{Manager, Metrics, RecycleError, RecycleResult};

impl Manager for ConnectionManager {
type Type = ConnectionAsync;
type Error = crate::Error;

async fn create(&self) -> Result<ConnectionAsync> {
crate::db::connect_async(&self.spec).await
}

async fn recycle(&self, conn: &mut ConnectionAsync, _: &Metrics) -> RecycleResult<Self::Error> {
if conn.is_closed() {
return Err(RecycleError::message("Connection is closed"));
}
Ok(())
}
}
37 changes: 37 additions & 0 deletions butane/src/db/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Types, traits, and methods for interacting with a database.
//!
//! The different ways of referring to a database handle may present
//! some initial confusion.
//! * `ConnectionMethods` is a trait containing the methods available on a database connection or a transaction.
//! Most methods on a [DataObject][crate::DataObject] or a [Query][crate::query::Query] require an
//! implementation of `ConnectionMethods`.
//! * `BackendConnection` is a trait representing a direct connection to a database backend. It is a superset
//! of `ConnectionMethods` and also includes the ability to create a transaction.
//! * `Transaction` is a struct representing a database transaction. It implements `ConnectionMethods`.
//! * `Connection` is a convenience struct containing a boxed `BackendConnection`. It cannot do anything other than
//! what a `BackendConnection` can do, but allows using a single concrete type that is not tied to a particular
//! database backend. It is returned by the `connect` method.
pub use butane_core::db::*;

#[cfg(feature = "r2d2")]
mod r2;

#[cfg(feature = "deadpool")]
mod deadpool;

/// Connection manager used with connection pooling systems such as r2d2 or deadpool.
/// With the `r2d2` feature enabled, it implements `r2d2::ManageConnection`.
/// With the `deadpool` feature enabled, it implements `deadpool::managed::Manager`.
#[cfg(any(feature = "deadpool", feature = "r2d2"))]
#[derive(Clone, Debug)]
pub struct ConnectionManager {
spec: ConnectionSpec,
}
#[cfg(any(feature = "deadpool", feature = "r2d2"))]
impl ConnectionManager {
/// Create a new ConnectionManager from a [ConnectionSpec].
pub fn new(spec: ConnectionSpec) -> Self {
ConnectionManager { spec }
}
}
23 changes: 23 additions & 0 deletions butane/src/db/r2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! R2D2 support for Butane.
use r2d2::ManageConnection;

use super::ConnectionManager;
use crate::db::{BackendConnection, Connection};
use crate::Result;

impl ManageConnection for ConnectionManager {
type Connection = Connection;
type Error = crate::Error;

fn connect(&self) -> Result<Connection> {
crate::db::connect(&self.spec)
}

fn is_valid(&self, conn: &mut Connection) -> Result<()> {
conn.execute("SELECT 1")
}

fn has_broken(&self, conn: &mut Connection) -> bool {
conn.is_closed()
}
}
5 changes: 1 addition & 4 deletions butane/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ pub use butane_core::{
PrimaryKeyType, Result, SqlType, SqlVal, SqlValRef, ToSql,
};

pub mod db {
//! Database helpers
pub use butane_core::db::*;
}
pub mod db;

/// Macro to construct a [`BoolExpr`] (for use with a [`Query`]) from
/// an expression with Rust syntax.
Expand Down
29 changes: 22 additions & 7 deletions butane/tests/r2d2.rs → butane/tests/pool.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
#[cfg(any(feature = "pg", feature = "sqlite"))]
use butane::db::r2::ConnectionManager;
#[cfg(feature = "pg")]
use butane_test_helper::pg_connspec;
use butane::db::ConnectionManager;
use butane_test_helper::*;
#[cfg(any(feature = "pg", feature = "sqlite"))]
use butane_test_helper::setup_db;
#[cfg(feature = "sqlite")]
use butane_test_helper::sqlite_connspec;
#[cfg(any(feature = "pg", feature = "sqlite"))]
use r2d2_for_test as r2d2;
use r2d2;
use std::ops::DerefMut;

#[cfg(feature = "sqlite")]
#[test]
Expand Down Expand Up @@ -49,3 +46,21 @@ fn r2d2_pq() {
}
assert_eq!(pool.state().idle_connections, 3);
}

#[tokio::test]
async fn deadpool_test_pg_async() {
let (connspec, _data) = pg_connspec().await;
let manager = ConnectionManager::new(connspec);
let pool = deadpool::managed::Pool::builder(manager).build().unwrap();
assert_eq!(pool.status().size, 0);
assert_eq!(pool.status().available, 0);
{
let mut conn: deadpool::managed::Object<ConnectionManager> = pool.get().await.unwrap();
assert_eq!(pool.status().size, 1);
assert_eq!(pool.status().available, 0);

setup_db_async(conn.deref_mut()).await;
}
assert_eq!(pool.status().size, 1);
assert_eq!(pool.status().available, 1);
}
1 change: 0 additions & 1 deletion butane_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ tokio-postgres = { optional = true, workspace = true }
postgres-native-tls = { version = "0.5", optional = true }
proc-macro2 = { workspace = true }
quote = { workspace = true }
r2d2 = { optional = true, workspace = true }
rand = { optional = true, workspace = true }
regex = { version = "1.5", features = ["std"] }
rusqlite = { workspace = true, optional = true }
Expand Down
3 changes: 0 additions & 3 deletions butane_core/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,6 @@ pub mod pg;
#[cfg(feature = "sqlite")]
pub mod sqlite;

#[cfg(feature = "r2d2")]
pub mod r2;

// Macros are always exported at the root of the crate
use crate::connection_method_wrapper;

Expand Down
Loading

0 comments on commit fca9bf5

Please sign in to comment.