Skip to content

Commit

Permalink
add support for using ahash internally & for redis values
Browse files Browse the repository at this point in the history
  • Loading branch information
utkarshgupta137 authored and jaymell committed Jun 20, 2022
1 parent bb329dd commit 624a59a
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 16 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Expand Up @@ -57,6 +57,9 @@ native-tls = { version = "0.2", optional = true }
tokio-native-tls = { version = "0.3", optional = true }
async-native-tls = { version = "0.4", optional = true }

# Optional aHash support
ahash = { version = "0.7.6", optional = true }

[features]
default = ["acl", "streams", "geospatial", "script"]
acl = []
Expand Down
8 changes: 5 additions & 3 deletions src/cluster.rs
Expand Up @@ -39,7 +39,7 @@
//! .query(&mut connection).unwrap();
//! ```
use std::cell::RefCell;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::BTreeMap;
use std::iter::Iterator;
use std::thread;
use std::time::Duration;
Expand All @@ -50,8 +50,10 @@ use rand::{
};

use super::{
cmd, parse_redis_value, Cmd, Connection, ConnectionAddr, ConnectionInfo, ConnectionLike,
ErrorKind, IntoConnectionInfo, RedisError, RedisResult, Value,
cmd, parse_redis_value,
types::{HashMap, HashSet},
Cmd, Connection, ConnectionAddr, ConnectionInfo, ConnectionLike, ErrorKind, IntoConnectionInfo,
RedisError, RedisResult, Value,
};

pub use crate::cluster_client::{ClusterClient, ClusterClientBuilder};
Expand Down
5 changes: 3 additions & 2 deletions src/cluster_pipeline.rs
@@ -1,7 +1,8 @@
use crate::cluster::ClusterConnection;
use crate::cmd::{cmd, Cmd};
use crate::types::{from_redis_value, ErrorKind, FromRedisValue, RedisResult, ToRedisArgs, Value};
use std::collections::HashSet;
use crate::types::{
from_redis_value, ErrorKind, FromRedisValue, HashSet, RedisResult, ToRedisArgs, Value,
};

pub(crate) const UNROUTABLE_ERROR: (ErrorKind, &str) = (
ErrorKind::ClientError,
Expand Down
4 changes: 3 additions & 1 deletion src/connection.rs
Expand Up @@ -13,6 +13,8 @@ use crate::types::{
from_redis_value, ErrorKind, FromRedisValue, RedisError, RedisResult, ToRedisArgs, Value,
};

#[cfg(unix)]
use crate::types::HashMap;
#[cfg(unix)]
use std::os::unix::net::UnixStream;

Expand Down Expand Up @@ -235,7 +237,7 @@ fn url_to_tcp_connection_info(url: url::Url) -> RedisResult<ConnectionInfo> {

#[cfg(unix)]
fn url_to_unix_connection_info(url: url::Url) -> RedisResult<ConnectionInfo> {
let query: std::collections::HashMap<_, _> = url.query_pairs().collect();
let query: HashMap<_, _> = url.query_pairs().collect();
Ok(ConnectionInfo {
addr: ConnectionAddr::Unix(unwrap_or!(
url.to_file_path().ok(),
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Expand Up @@ -57,6 +57,7 @@
//! * `geospatial`: enables geospatial support (enabled by default)
//! * `script`: enables script support (enabled by default)
//! * `r2d2`: enables r2d2 connection pool support (optional)
//! * `ahash`: enables ahash map/set support & uses ahash internally (+7-10% performance) (optional)
//! * `cluster`: enables redis cluster support (optional)
//! * `tokio-comp`: enables support for tokio (optional)
//! * `connection-manager`: enables support for automatic reconnection (optional)
Expand Down
5 changes: 3 additions & 2 deletions src/pipeline.rs
Expand Up @@ -2,8 +2,9 @@

use crate::cmd::{cmd, cmd_len, Cmd};
use crate::connection::ConnectionLike;
use crate::types::{from_redis_value, ErrorKind, FromRedisValue, RedisResult, ToRedisArgs, Value};
use std::collections::HashSet;
use crate::types::{
from_redis_value, ErrorKind, FromRedisValue, HashSet, RedisResult, ToRedisArgs, Value,
};

/// Represents a redis command pipeline.
#[derive(Clone)]
Expand Down
5 changes: 3 additions & 2 deletions src/streams.rs
@@ -1,8 +1,9 @@
//! Defines types to use with the streams commands.

use crate::{from_redis_value, FromRedisValue, RedisResult, RedisWrite, ToRedisArgs, Value};
use crate::{
from_redis_value, types::HashMap, FromRedisValue, RedisResult, RedisWrite, ToRedisArgs, Value,
};

use std::collections::HashMap;
use std::io::{Error, ErrorKind};

// Stream Maxlen Enum
Expand Down
61 changes: 55 additions & 6 deletions src/types.rs
@@ -1,5 +1,4 @@
use std::collections::{BTreeMap, BTreeSet};
use std::collections::{HashMap, HashSet};
use std::convert::From;
use std::default::Default;
use std::error;
Expand All @@ -9,6 +8,11 @@ use std::io;
use std::str::{from_utf8, Utf8Error};
use std::string::FromUtf8Error;

#[cfg(feature = "ahash")]
pub(crate) use ahash::{AHashMap as HashMap, AHashSet as HashSet};
#[cfg(not(feature = "ahash"))]
pub(crate) use std::collections::{HashMap, HashSet};

macro_rules! invalid_type_error {
($v:expr, $det:expr) => {{
fail!(invalid_type_error_inner!($v, $det))
Expand Down Expand Up @@ -899,7 +903,26 @@ impl<T: ToRedisArgs> ToRedisArgs for &T {
/// @note: Redis cannot store empty sets so the application has to
/// check whether the set is empty and if so, not attempt to use that
/// result
impl<T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default> ToRedisArgs for HashSet<T, S> {
impl<T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default> ToRedisArgs
for std::collections::HashSet<T, S>
{
fn write_redis_args<W>(&self, out: &mut W)
where
W: ?Sized + RedisWrite,
{
ToRedisArgs::make_arg_iter_ref(self.iter(), out)
}

fn is_single_arg(&self) -> bool {
self.len() <= 1
}
}

/// @note: Redis cannot store empty sets so the application has to
/// check whether the set is empty and if so, not attempt to use that
/// result
#[cfg(feature = "ahash")]
impl<T: ToRedisArgs + Hash + Eq, S: BuildHasher + Default> ToRedisArgs for ahash::AHashSet<T, S> {
fn write_redis_args<W>(&self, out: &mut W)
where
W: ?Sized + RedisWrite,
Expand Down Expand Up @@ -1148,9 +1171,21 @@ impl<T: FromRedisValue> FromRedisValue for Vec<T> {
}

impl<K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default> FromRedisValue
for HashMap<K, V, S>
for std::collections::HashMap<K, V, S>
{
fn from_redis_value(v: &Value) -> RedisResult<HashMap<K, V, S>> {
fn from_redis_value(v: &Value) -> RedisResult<std::collections::HashMap<K, V, S>> {
v.as_map_iter()
.ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashmap compatible"))?
.map(|(k, v)| Ok((from_redis_value(k)?, from_redis_value(v)?)))
.collect()
}
}

#[cfg(feature = "ahash")]
impl<K: FromRedisValue + Eq + Hash, V: FromRedisValue, S: BuildHasher + Default> FromRedisValue
for ahash::AHashMap<K, V, S>
{
fn from_redis_value(v: &Value) -> RedisResult<ahash::AHashMap<K, V, S>> {
v.as_map_iter()
.ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashmap compatible"))?
.map(|(k, v)| Ok((from_redis_value(k)?, from_redis_value(v)?)))
Expand All @@ -1170,8 +1205,22 @@ where
}
}

impl<T: FromRedisValue + Eq + Hash, S: BuildHasher + Default> FromRedisValue for HashSet<T, S> {
fn from_redis_value(v: &Value) -> RedisResult<HashSet<T, S>> {
impl<T: FromRedisValue + Eq + Hash, S: BuildHasher + Default> FromRedisValue
for std::collections::HashSet<T, S>
{
fn from_redis_value(v: &Value) -> RedisResult<std::collections::HashSet<T, S>> {
let items = v
.as_sequence()
.ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashset compatible"))?;
items.iter().map(|item| from_redis_value(item)).collect()
}
}

#[cfg(feature = "ahash")]
impl<T: FromRedisValue + Eq + Hash, S: BuildHasher + Default> FromRedisValue
for ahash::AHashSet<T, S>
{
fn from_redis_value(v: &Value) -> RedisResult<ahash::AHashSet<T, S>> {
let items = v
.as_sequence()
.ok_or_else(|| invalid_type_error_inner!(v, "Response type not hashset compatible"))?;
Expand Down

0 comments on commit 624a59a

Please sign in to comment.