diff --git a/Cargo.lock b/Cargo.lock index 11d373e..4cd4528 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,9 +17,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -42,6 +42,17 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -80,20 +91,18 @@ dependencies = [ [[package]] name = "bson" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c1c1044eb5689370b9da714b543a4a8d15601f4a68538dcadcf9c41b916aff" +checksum = "b3f109694c4f45353972af96bf97d8a057f82e2d6e496457f4d135b9867a518c" dependencies = [ "ahash", "base64", "bitvec", - "getrandom 0.2.16", "getrandom 0.3.4", "hex", "indexmap", "js-sys", - "once_cell", - "rand", + "rand 0.9.2", "serde_bytes", "simdutf8", "thiserror", @@ -115,9 +124,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cast" @@ -160,18 +169,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstyle", "clap_lex", @@ -288,6 +297,7 @@ checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" name = "forceps" version = "0.4.1" dependencies = [ + "async-trait", "bson", "bytes", "criterion", @@ -295,9 +305,11 @@ dependencies = [ "lru", "md5", "parking_lot 0.12.5", - "rand", + "rand 0.9.2", + "serde", "sled", "tokio", + "twox-hash", ] [[package]] @@ -332,10 +344,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", ] [[package]] @@ -365,9 +375,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", @@ -382,9 +392,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "indexmap" -version = "2.12.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", "hashbrown", @@ -416,9 +426,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -426,9 +436,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "lock_api" @@ -441,9 +451,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru" @@ -612,9 +622,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -631,14 +641,35 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -648,7 +679,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -809,9 +849,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" dependencies = [ "libc", ] @@ -854,11 +894,17 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "syn" -version = "2.0.108" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -960,21 +1006,32 @@ dependencies = [ "syn", ] +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand 0.8.5", + "static_assertions", +] + [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -1011,9 +1068,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -1022,25 +1079,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1048,31 +1091,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -1215,18 +1258,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 22b9c65..9080c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,18 +16,26 @@ categories = [ ] edition = "2024" +[features] +default = ["md5"] +md5 = ["dep:md5"] +xxhash = ["dep:twox-hash"] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +async-trait = "0.1.50" bson = "3.0.0" -sled = "0.34.7" -hex = "0.4.3" -md5 = "0.8.0" -rand = "0.9.2" -tokio = { version = "1.48.0", features = ["fs", "io-util"] } bytes = "1.10.1" +hex = "0.4.3" lru = "0.16.2" +md5 = { version = "0.8.0", optional = true } parking_lot = "0.12.5" +rand = { version = "0.9.2", features = ["small_rng"], default-features = false} +serde = {version = "1.0.125", features = ["derive"]} +sled = "0.34.7" +tokio = {version = "1.48.0", features = ["fs", "io-util"]} +twox-hash = { version = "1.6.3", optional = true } [dev-dependencies] tokio = { version = "1.48.0", features = ["full"] } diff --git a/src/cache.rs b/src/cache.rs index aebf748..ef24dc7 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -3,6 +3,7 @@ pub use builder::CacheBuilder; use crate::{ForcepError, MetaDb, Metadata, Result, mem_cache::MemCache}; use bytes::Bytes; +use sled::Db; use std::io; use std::path; use std::result; @@ -116,6 +117,11 @@ impl Cache { }) } + /// Gets a reference to the underlying meta database. + pub fn get_meta_db_ref(&self) -> &Db { + self.meta.get_db_ref() + } + /// Creates a PathBuf based on the key provided fn path_from_key(&self, key: &[u8]) -> path::PathBuf { let hex = hex::encode(key); diff --git a/src/evictors.rs b/src/evictors.rs index 1efcecd..35c8850 100644 --- a/src/evictors.rs +++ b/src/evictors.rs @@ -273,14 +273,14 @@ impl LruEvictor { impl MinSzEvictor for LruEvictor { type Candidate = LruEc; - #[inline] - fn min_size(&self) -> u64 { - self.min_sz - } #[inline] fn batch_size(&self) -> usize { self.batch_size } + #[inline] + fn min_size(&self) -> u64 { + self.min_sz + } } impl Evictor for LruEvictor { type Err = ForcepError; diff --git a/src/lib.rs b/src/lib.rs index 922042f..e8be7bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,9 @@ #![warn(missing_docs)] #![warn(rustdoc::broken_intra_doc_links)] +#[cfg(all(feature = "md5", feature = "xxhash"))] +compile_error!("feature \"md5\" and feature \"xxhash\" cannot be enabled at the same time"); + use std::error; use std::io; @@ -112,7 +115,7 @@ pub use cache::{Cache, CacheBuilder}; mod metadata; pub(crate) use metadata::MetaDb; -pub use metadata::{Md5Bytes, Metadata}; +pub use metadata::{HashBytes, Metadata}; /// A collection of [`Cache`] eviction algorithms and generics /// diff --git a/src/mem_cache.rs b/src/mem_cache.rs index 5c329d3..fb01531 100644 --- a/src/mem_cache.rs +++ b/src/mem_cache.rs @@ -1,16 +1,23 @@ -use crate::Md5Bytes; +use crate::HashBytes; use bytes::Bytes; use lru::LruCache; use parking_lot::Mutex; use std::sync::atomic::{AtomicUsize, Ordering}; -type Lru = LruCache; +type Lru = LruCache; +#[cfg(feature = "md5")] #[inline] -fn hash_key(k: &[u8]) -> Md5Bytes { +fn hash_key(k: &[u8]) -> HashBytes { md5::compute(k).into() } +#[cfg(feature = "xxhash")] +#[inline] +fn hash_key(k: &[u8]) -> HashBytes { + twox_hash::xxh3::hash128(k).to_be_bytes() +} + #[derive(Debug)] struct MemCacheInner { cache: Mutex, diff --git a/src/metadata.rs b/src/metadata.rs index a21b181..697b9a9 100644 --- a/src/metadata.rs +++ b/src/metadata.rs @@ -2,8 +2,8 @@ use crate::{ForcepError, Result}; use std::path; use std::time; -/// Type definition for an array of bytes that make up an `md5` hash. -pub type Md5Bytes = [u8; 16]; +/// Type definition for an array of bytes that make up an 16-byte hash (e.g., md5, xx3, etc.). +pub type HashBytes = [u8; 16]; /// Metadata information about a certain entry in the cache /// @@ -38,7 +38,7 @@ pub struct Metadata { /// Number of times this entry has been HIT (total accesses) hits: u64, /// Md5 hash of the underlying data - integrity: Md5Bytes, + integrity: HashBytes, } /// Database for cache entry metadata @@ -58,12 +58,21 @@ fn now_since_epoch() -> u64 { impl Metadata { /// Creates a new instance of [`Metadata`] from the given `data` pub(crate) fn new(data: &[u8]) -> Self { + #[cfg(feature = "md5")] + let hash = md5::compute(data).0; + #[cfg(feature = "xxhash")] + let hash = twox_hash::xxh3::hash128(data).to_be_bytes(); + + Self::new_with_hash(data, hash) + } + + pub(crate) fn new_with_hash(data: &[u8], hash: HashBytes) -> Self { Self { size: data.len() as u64, last_modified: now_since_epoch(), last_accessed: now_since_epoch(), hits: 0, - integrity: md5::compute(data).into(), + integrity: hash, } } @@ -199,16 +208,20 @@ impl Metadata { self.last_accessed } - /// Retrieves the internal [`Md5Bytes`] integrity of the corresponding metadata entry. + /// Retrieves the internal [`HashBytes`] integrity of the corresponding metadata entry. #[inline] - pub fn get_integrity(&self) -> &Md5Bytes { + pub fn get_integrity(&self) -> &HashBytes { &self.integrity } /// Verifies that the metadata integrity matches the integrity of the data provided. #[inline] pub fn check_integrity_of(&self, data: &[u8]) -> bool { - let other_integrity: Md5Bytes = md5::compute(data).into(); + #[cfg(feature = "md5")] + let other_integrity: HashBytes = md5::compute(data).into(); + #[cfg(feature = "xxhash")] + let other_integrity: HashBytes = twox_hash::xxh3::hash128(data).to_be_bytes(); + other_integrity == self.integrity } } @@ -221,6 +234,10 @@ impl MetaDb { .map(|db| Self { db }) } + pub fn get_db_ref(&self) -> &sled::Db { + &self.db + } + /// Retrieves an entry in the metadata database with the corresponding key. pub fn get_metadata(&self, key: &[u8]) -> Result { let data = match self.db.get(key) {