Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/deadpool-memcached/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["tcp"]
serde = ["deadpool/serde", "dep:serde"]

# Re-export of async-memcached features
polonius = ["async-memcached/polonius"]
Expand All @@ -35,6 +36,9 @@ deadpool = { path = "../deadpool", version = "0.13.0", default-features = false,
# dependency. Once async-memcached is fixed this dependency can be removed
# again.
tokio = { version = "1.29", default-features = false, features = ["net"] }
serde = { package = "serde", version = "1.0", features = [
"derive",
], optional = true }

[dev-dependencies]
tokio = { version = "1.29", features = ["macros", "rt-multi-thread"] }
Expand Down
4 changes: 4 additions & 0 deletions crates/deadpool-memcached/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ use deadpool_memcached::Manager;
#[tokio::main]
async fn main() {
let manager = Manager::new("localhost:11211");
let pool = deadpool_memcached::Pool::builder(manager).build().unwrap();
let mut client = pool.get().await.unwrap();
println!("version: {:?}", client.version().await);
}
```

You can also use `deadpool_memcached::Config` to build a pool (including
optional `serde`-based config deserialization).

## License

Licensed under the MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>).
107 changes: 107 additions & 0 deletions crates/deadpool-memcached/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::convert::Infallible;

use crate::{CreatePoolError, Manager, Pool, PoolBuilder, PoolConfig};

/// Configuration object.
///
/// # Example (from environment)
///
/// By enabling the `serde` feature you can read the configuration using the
/// [`config`](https://crates.io/crates/config) crate as following:
/// ```env
/// MEMCACHED__ADDR=127.0.0.1:11211
/// MEMCACHED__POOL__MAX_SIZE=16
/// MEMCACHED__POOL__TIMEOUTS__WAIT__SECS=5
/// MEMCACHED__POOL__TIMEOUTS__WAIT__NANOS=0
/// ```
/// ```rust,ignore
/// #[derive(serde::Deserialize, serde::Serialize)]
/// struct Config {
/// memcached: deadpool_memcached::Config,
/// }
/// impl Config {
/// pub fn from_env() -> Result<Self, config::ConfigError> {
/// let mut cfg = config::Config::builder()
/// .add_source(config::Environment::default().separator("__"))
/// .build()?;
/// cfg.try_deserialize()
/// }
/// }
/// ```
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Config {
/// Memcached address.
pub addr: Option<String>,

/// [`Pool`] configuration.
pub pool: Option<PoolConfig>,
}

impl Config {
/// Creates a new [`Config`] with the given Memcached address.
#[must_use]
pub fn new(addr: impl Into<String>) -> Self {
Self {
addr: Some(addr.into()),
pool: None,
}
}

/// Creates a new [`Pool`] using this [`Config`].
///
/// # Errors
///
/// See [`CreatePoolError`] for details.
pub fn create_pool(&self) -> Result<Pool, CreatePoolError> {
self.builder()
.map_err(CreatePoolError::Config)?
.build()
.map_err(CreatePoolError::Build)
}

/// Creates a new [`PoolBuilder`] using this [`Config`].
///
/// # Errors
///
/// See [`ConfigError`] for details.
pub fn builder(&self) -> Result<PoolBuilder, ConfigError> {
let manager = Manager::new(self.get_addr());
Ok(Pool::builder(manager).config(self.get_pool_config()))
}

/// Returns address used to connect to the Memcached server.
pub fn get_addr(&self) -> &str {
self.addr.as_deref().unwrap_or("127.0.0.1:11211")
}

/// Returns [`deadpool::managed::PoolConfig`] which can be used to construct
/// a [`deadpool::managed::Pool`] instance.
#[must_use]
pub fn get_pool_config(&self) -> PoolConfig {
self.pool.unwrap_or_default()
}
}

/// This error is returned if there is something wrong with the Memcached configuration.
///
/// This is just a type alias to [`Infallible`] at the moment as there
/// is no validation happening at the configuration phase.
pub type ConfigError = Infallible;

#[cfg(test)]
mod tests {
use super::Config;

#[test]
fn default_addr_is_localhost() {
let cfg = Config::default();
assert_eq!(cfg.get_addr(), "127.0.0.1:11211");
}

#[test]
fn new_sets_addr() {
let cfg = Config::new("cache.internal:11211");
assert_eq!(cfg.get_addr(), "cache.internal:11211");
}
}
6 changes: 2 additions & 4 deletions crates/deadpool-memcached/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
//! connect via TCP as there is no existing mechanism to parameterize how to deal with different
//! unerlying connection types at the moment.
#![deny(warnings, missing_docs)]
use std::convert::Infallible;

use async_memcached::{Client, Error};
mod config;

/// Type alias for using [`deadpool::managed::RecycleResult`] with [`redis`].
type RecycleResult = deadpool::managed::RecycleResult<Error>;

type ConfigError = Infallible;

pub use self::config::{Config, ConfigError};
pub use deadpool::managed::reexports::*;
deadpool::managed_reexports!(
"memcached",
Expand Down
11 changes: 7 additions & 4 deletions crates/deadpool-memcached/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ use std::env;
use async_memcached::AsciiProtocol;
use deadpool_memcached::{Manager, Pool};

fn create_pool() -> Pool {
let addr = env::var("MEMCACHED__ADDR").unwrap();
fn create_pool() -> Option<Pool> {
let addr = env::var("MEMCACHED__ADDR").ok()?;
let manager = Manager::new(addr);
Pool::builder(manager).build().unwrap()
Some(Pool::builder(manager).build().unwrap())
}

#[tokio::test]
async fn test_set_get() {
let Some(pool) = create_pool() else {
// Skip test when no Memcached server is configured.
return;
};
let test_key = "test:basic:test_set_get";
let test_value = "answer_42";
let pool = create_pool();
let mut conn = pool.get().await.unwrap();
let _ = conn.delete(test_key).await;
assert_eq!(conn.get(test_key).await.unwrap(), None);
Expand Down
Loading