Skip to content

Commit e8659a7

Browse files
committed
Add typed stores; use a dynamic Error type
1 parent 9818f68 commit e8659a7

File tree

10 files changed

+472
-148
lines changed

10 files changed

+472
-148
lines changed

Cargo.lock

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ keywords = ["key-value", "persistent", "store"]
77
description = "A lean, efficient and fast peristent in-process key-value store"
88

99
[dependencies]
10+
databuf = "0.5.0"
1011
memmap = "0.7.0"
1112
simd-itertools = "0.2.3"
1213
siphasher = "1.0.1"

examples/typed.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::sync::Arc;
2+
3+
use vicky_store::{Config, Result, VickyStore, VickyTypedStore};
4+
5+
fn main() -> Result<()> {
6+
let db = Arc::new(VickyStore::open("/tmp/vicky-dir", Config::default())?);
7+
8+
let typed = VickyTypedStore::<String, Vec<u32>>::new(db);
9+
typed.insert("hello".into(), vec![1, 2, 3])?;
10+
11+
println!("{:?}", typed.get("hello")?); // Some([1, 2, 3])
12+
13+
typed.remove("hello")?;
14+
15+
println!("{:?}", typed.contains("hello")?); // false
16+
17+
Ok(())
18+
}

src/hashing.rs

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::hash::Hasher;
22

3-
use siphasher::sip128::SipHasher24;
3+
use siphasher::sip128::{Hash128, Hasher128, SipHasher24};
44

5-
use crate::{Error, Result};
5+
use crate::{Result, VickyError};
66

77
#[derive(Debug, Clone, Copy)]
88
pub struct SecretKey([u8; 16]);
@@ -17,7 +17,7 @@ impl SecretKey {
1717
pub fn new<B: AsRef<[u8]> + ?Sized>(key: &B) -> Result<Self> {
1818
let key = key.as_ref();
1919
if key.len() != Self::LEN {
20-
return Err(Error::WrongSecretKeyLength);
20+
return Err(Box::new(VickyError::WrongSecretKeyLength));
2121
}
2222
let mut bytes = [0u8; Self::LEN];
2323
bytes.copy_from_slice(&key);
@@ -34,14 +34,10 @@ pub(crate) struct PartedHash {
3434

3535
pub(crate) const INVALID_SIG: u32 = 0;
3636
pub(crate) const USER_NAMESPACE: u8 = 1;
37+
//pub(crate) const TYPED_NAMESPACE: u8 = 2;
3738

3839
impl PartedHash {
39-
pub fn from_buffer(namespace: u8, key: &SecretKey, buf: &[u8]) -> Self {
40-
// maybe use blake3?
41-
let mut hasher = SipHasher24::new_with_key(&key.0);
42-
hasher.write_u8(namespace);
43-
hasher.write(buf);
44-
let h = hasher.hash(buf);
40+
fn from_hash(h: Hash128) -> Self {
4541
let mut signature = h.h1 as u32;
4642
if signature == INVALID_SIG {
4743
signature = h.h2 as u32;
@@ -58,27 +54,72 @@ impl PartedHash {
5854
signature,
5955
}
6056
}
57+
pub fn from_buffer(namespace: u8, key: &SecretKey, buf: &[u8]) -> Self {
58+
// maybe use blake3?
59+
let mut hasher = SipHasher24::new_with_key(&key.0);
60+
hasher.write_u8(namespace);
61+
hasher.write(buf);
62+
Self::from_hash(hasher.finish128())
63+
}
64+
65+
#[allow(dead_code)]
66+
pub fn builder(key: &SecretKey) -> PartedHashBuilder {
67+
PartedHashBuilder(SipHasher24::new_with_key(&key.0))
68+
}
69+
70+
#[allow(dead_code)]
71+
pub fn to_u64(&self) -> u64 {
72+
((self.shard_selector as u64) << 48)
73+
| ((self.row_selector as u64) << 32)
74+
| (self.signature as u64)
75+
}
76+
}
77+
78+
#[allow(dead_code)]
79+
pub(crate) struct PartedHashBuilder(SipHasher24);
80+
81+
impl PartedHashBuilder {
82+
#[allow(dead_code)]
83+
pub fn write(mut self, bytes: &[u8]) -> Self {
84+
self.0.write(bytes);
85+
self
86+
}
87+
#[allow(dead_code)]
88+
pub fn write_u32(mut self, v: u32) -> Self {
89+
self.0.write_u32(v);
90+
self
91+
}
92+
#[allow(dead_code)]
93+
pub fn write_u8(mut self, v: u8) -> Self {
94+
self.0.write_u8(v);
95+
self
96+
}
97+
#[allow(dead_code)]
98+
pub fn finish(self) -> PartedHash {
99+
PartedHash::from_hash(self.0.finish128())
100+
}
61101
}
62102

63103
#[test]
64104
fn test_parted_hash() -> Result<()> {
65-
assert!(matches!(
66-
SecretKey::new("1234"),
67-
Err(Error::WrongSecretKeyLength)
68-
));
69-
assert!(matches!(
70-
SecretKey::new("12341234123412341"),
71-
Err(Error::WrongSecretKeyLength)
72-
));
105+
SecretKey::new("1234").expect_err("shouldn't work");
106+
SecretKey::new("12341234123412341").expect_err("shouldn't work");
107+
73108
let key = SecretKey::new("aaaabbbbccccdddd")?;
74109

75110
assert_eq!(
76-
PartedHash::from_buffer(USER_NAMESPACE, &key, b"hello world"),
77-
PartedHash {
78-
shard_selector: 62379,
79-
row_selector: 17802,
80-
signature: 3217405680
81-
}
111+
PartedHash::from_buffer(USER_NAMESPACE, &key, b"hello world").to_u64(),
112+
12143172433256666175,
82113
);
114+
115+
assert_eq!(
116+
PartedHash::builder(&key)
117+
.write_u8(USER_NAMESPACE)
118+
.write(b"hello world")
119+
.finish()
120+
.to_u64(),
121+
12143172433256666175,
122+
);
123+
83124
Ok(())
84125
}

src/lib.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,37 @@
33
mod hashing;
44
mod shard;
55
mod store;
6+
mod typed;
67

78
pub use hashing::SecretKey;
89
use std::fmt::{Display, Formatter};
910
pub use store::{Stats, VickyStore};
11+
pub use typed::{VickyTypedKey, VickyTypedStore};
1012

1113
#[derive(Debug)]
12-
pub enum Error {
14+
pub enum VickyError {
1315
WrongSecretKeyLength,
1416
KeyTooLong,
1517
ValueTooLong,
1618
KeyNotFound,
17-
IOError(std::io::Error),
1819
}
1920

20-
impl From<std::io::Error> for Error {
21-
fn from(value: std::io::Error) -> Self {
22-
Self::IOError(value)
23-
}
24-
}
25-
26-
impl Display for Error {
21+
impl Display for VickyError {
2722
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
2823
match self {
29-
Error::WrongSecretKeyLength => write!(f, "wrong secret length"),
30-
Error::KeyTooLong => write!(f, "key too long"),
31-
Error::KeyNotFound => write!(f, "key not found"),
32-
Error::ValueTooLong => write!(f, "value too long"),
33-
Error::IOError(err) => write!(f, "IO error: {err}"),
24+
Self::WrongSecretKeyLength => write!(f, "wrong secret length"),
25+
Self::KeyTooLong => write!(f, "key too long"),
26+
Self::KeyNotFound => write!(f, "key not found"),
27+
Self::ValueTooLong => write!(f, "value too long"),
3428
}
3529
}
3630
}
3731

38-
impl std::error::Error for Error {}
32+
impl std::error::Error for VickyError {}
3933

40-
pub type Result<T> = std::result::Result<T, Error>;
34+
/// It is an alias for a boxed [std::error::Error].
35+
pub type Error = Box<dyn std::error::Error + Send + Sync>;
36+
pub type Result<T, E = Error> = std::result::Result<T, E>;
4137

4238
/// The configuration options for VickyStore. Comes with sane defaults, feel free to use them
4339
#[derive(Debug, Clone)]

0 commit comments

Comments
 (0)