|
@@ -120,9 +120,11 @@ impl Db {
|
|
|
keys.iter()
|
|
|
.map(|key| {
|
|
|
let mut entries = self.entries[self.get_slot(key)].write().unwrap();
|
|
|
- if entries.remove(key).is_some() {
|
|
|
- expirations.remove(&key);
|
|
|
- deleted += 1;
|
|
|
+ if let Some(entry) = entries.remove(key) {
|
|
|
+ expirations.remove(key);
|
|
|
+ if entry.is_valid() {
|
|
|
+ deleted += 1;
|
|
|
+ }
|
|
|
}
|
|
|
})
|
|
|
.for_each(drop);
|
|
@@ -164,7 +166,7 @@ impl Db {
|
|
|
|
|
|
pub fn getset(&self, key: &Bytes, value: &Value) -> Value {
|
|
|
let mut entries = self.entries[self.get_slot(key)].write().unwrap();
|
|
|
- self.expirations.lock().unwrap().remove(&key);
|
|
|
+ self.expirations.lock().unwrap().remove(key);
|
|
|
entries
|
|
|
.insert(key.clone(), Entry::new(value.clone(), None))
|
|
|
.filter(|x| x.is_valid())
|
|
@@ -174,7 +176,7 @@ impl Db {
|
|
|
pub fn getdel(&self, key: &Bytes) -> Value {
|
|
|
let mut entries = self.entries[self.get_slot(key)].write().unwrap();
|
|
|
entries.remove(key).map_or(Value::Null, |x| {
|
|
|
- self.expirations.lock().unwrap().remove(&key);
|
|
|
+ self.expirations.lock().unwrap().remove(key);
|
|
|
x.get().clone()
|
|
|
})
|
|
|
}
|
|
@@ -184,7 +186,7 @@ impl Db {
|
|
|
let expires_at = expires_in.map(|duration| Instant::now() + duration);
|
|
|
|
|
|
if let Some(expires_at) = expires_at {
|
|
|
- self.expirations.lock().unwrap().add(&key, expires_at);
|
|
|
+ self.expirations.lock().unwrap().add(key, expires_at);
|
|
|
}
|
|
|
entries.insert(key.clone(), Entry::new(value.clone(), expires_at));
|
|
|
Value::OK
|
|
@@ -227,30 +229,133 @@ mod test {
|
|
|
use crate::bytes;
|
|
|
|
|
|
#[test]
|
|
|
+ fn incr_wrong_type() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(&bytes!(b"num"), &Value::Blob(bytes!("some string")), None);
|
|
|
+
|
|
|
+ let r = db.incr(&bytes!("num"), 1);
|
|
|
+
|
|
|
+ assert!(r.is_err());
|
|
|
+ assert_eq!(Error::NotANumber, r.expect_err("should fail"));
|
|
|
+ assert_eq!(Value::Blob(bytes!("some string")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn incr_blob_float() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(&bytes!(b"num"), &Value::Blob(bytes!("1.1")), None);
|
|
|
+
|
|
|
+ assert_eq!(Value::Float(2.2), db.incr(&bytes!("num"), 1.1).unwrap());
|
|
|
+ assert_eq!(Value::Blob(bytes!("2.2")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn incr_blob_int_float() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(&bytes!(b"num"), &Value::Blob(bytes!("1")), None);
|
|
|
+
|
|
|
+ assert_eq!(Value::Float(2.1), db.incr(&bytes!("num"), 1.1).unwrap());
|
|
|
+ assert_eq!(Value::Blob(bytes!("2.1")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn incr_blob_int() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(&bytes!(b"num"), &Value::Blob(bytes!("1")), None);
|
|
|
+
|
|
|
+ assert_eq!(Value::Integer(2), db.incr(&bytes!("num"), 1).unwrap());
|
|
|
+ assert_eq!(Value::Blob(bytes!("2")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn incr_blob_int_set() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ assert_eq!(Value::Integer(1), db.incr(&bytes!("num"), 1).unwrap());
|
|
|
+ assert_eq!(Value::Blob(bytes!("1")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn incr_blob_float_set() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ assert_eq!(Value::Float(1.1), db.incr(&bytes!("num"), 1.1).unwrap());
|
|
|
+ assert_eq!(Value::Blob(bytes!("1.1")), db.get(&bytes!("num")));
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn del() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(
|
|
|
+ &bytes!(b"expired"),
|
|
|
+ &Value::OK,
|
|
|
+ Some(Duration::from_secs(0)),
|
|
|
+ );
|
|
|
+ db.set(&bytes!(b"valid"), &Value::OK, None);
|
|
|
+ db.set(
|
|
|
+ &bytes!(b"expiring"),
|
|
|
+ &Value::OK,
|
|
|
+ Some(Duration::from_secs(5)),
|
|
|
+ );
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ Value::Integer(2),
|
|
|
+ db.del(&[
|
|
|
+ bytes!(b"expired"),
|
|
|
+ bytes!(b"valid"),
|
|
|
+ bytes!(b"expiring"),
|
|
|
+ bytes!(b"not_existing_key")
|
|
|
+ ])
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
+ fn ttl() {
|
|
|
+ let db = Db::new(100);
|
|
|
+ db.set(
|
|
|
+ &bytes!(b"expired"),
|
|
|
+ &Value::OK,
|
|
|
+ Some(Duration::from_secs(0)),
|
|
|
+ );
|
|
|
+ db.set(&bytes!(b"valid"), &Value::OK, None);
|
|
|
+ db.set(
|
|
|
+ &bytes!(b"expiring"),
|
|
|
+ &Value::OK,
|
|
|
+ Some(Duration::from_secs(5)),
|
|
|
+ );
|
|
|
+
|
|
|
+ assert_eq!(None, db.ttl(&bytes!(b"expired")));
|
|
|
+ assert_eq!(None, db.ttl(&bytes!(b"not_existing_key")));
|
|
|
+ assert_eq!(Some(None), db.ttl(&bytes!(b"valid")));
|
|
|
+ assert!(match db.ttl(&bytes!(b"expiring")) {
|
|
|
+ Some(Some(_)) => true,
|
|
|
+ _ => false,
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ #[test]
|
|
|
fn purge_keys() {
|
|
|
let db = Db::new(100);
|
|
|
- db.set(& bytes!(b"one"), &Value::OK, Some(Duration::from_secs(0)));
|
|
|
+ db.set(&bytes!(b"one"), &Value::OK, Some(Duration::from_secs(0)));
|
|
|
// Expired keys should not be returned, even if they are not yet
|
|
|
// removed by the purge process.
|
|
|
- assert_eq!(Value::Null, db.get(& bytes!(b"one")));
|
|
|
+ assert_eq!(Value::Null, db.get(&bytes!(b"one")));
|
|
|
|
|
|
// Purge twice
|
|
|
assert_eq!(1, db.purge());
|
|
|
assert_eq!(0, db.purge());
|
|
|
|
|
|
- assert_eq!(Value::Null, db.get(& bytes!(b"one")));
|
|
|
+ assert_eq!(Value::Null, db.get(&bytes!(b"one")));
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
fn replace_purge_keys() {
|
|
|
let db = Db::new(100);
|
|
|
- db.set(& bytes!(b"one"), &Value::OK, Some(Duration::from_secs(0)));
|
|
|
+ db.set(&bytes!(b"one"), &Value::OK, Some(Duration::from_secs(0)));
|
|
|
// Expired keys should not be returned, even if they are not yet
|
|
|
// removed by the purge process.
|
|
|
- assert_eq!(Value::Null, db.get(& bytes!(b"one")));
|
|
|
+ assert_eq!(Value::Null, db.get(&bytes!(b"one")));
|
|
|
|
|
|
- db.set(& bytes!(b"one"), &Value::OK, Some(Duration::from_secs(5)));
|
|
|
- assert_eq!(Value::OK, db.get(& bytes!(b"one")));
|
|
|
+ db.set(&bytes!(b"one"), &Value::OK, Some(Duration::from_secs(5)));
|
|
|
+ assert_eq!(Value::OK, db.get(&bytes!(b"one")));
|
|
|
|
|
|
// Purge should return 0 as the expired key has been removed already
|
|
|
assert_eq!(0, db.purge());
|