Skip to content

Commit

Permalink
feat: introduce basic memory cache framework (#64)
Browse files Browse the repository at this point in the history
Signed-off-by: MrCroxx <mrcroxx@outlook.com>
  • Loading branch information
MrCroxx committed Jul 12, 2023
1 parent 2fe1e82 commit 0792d14
Show file tree
Hide file tree
Showing 9 changed files with 437 additions and 11 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"foyer",
"foyer-common",
"foyer-intrusive",
"foyer-memory",
"foyer-storage",
"foyer-storage-bench",
]
Expand Down
12 changes: 12 additions & 0 deletions foyer-common/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub trait Key:
+ Clone
+ std::fmt::Debug
{
fn weight(&self) -> usize {
std::mem::size_of::<Self>()
}

fn serialized_len(&self) -> usize {
panic!("Method `serialized_len` must be implemented for `Key` if storage is used.")
}
Expand All @@ -44,6 +48,10 @@ pub trait Key:

#[allow(unused)]
pub trait Value: Sized + Send + Sync + 'static + std::fmt::Debug {
fn weight(&self) -> usize {
std::mem::size_of::<Self>()
}

fn serialized_len(&self) -> usize {
panic!("Method `serialized_len` must be implemented for `Value` if storage is used.")
}
Expand Down Expand Up @@ -114,6 +122,10 @@ for_all_primitives! { impl_key }
for_all_primitives! { impl_value }

impl Value for Vec<u8> {
fn weight(&self) -> usize {
self.len()
}

fn serialized_len(&self) -> usize {
self.len()
}
Expand Down
33 changes: 32 additions & 1 deletion foyer-intrusive/src/collections/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,14 @@ where
let slot = (self.slots.len() - 1) & hash as usize;

let res = self.remove_inner(key_new, slot);
if res.is_some() {
self.len -= 1;
}

self.slots[slot].push_front(link_new);

self.len += 1;

res
}
}
Expand All @@ -130,7 +135,11 @@ where
let hash = self.hash_key(key);
let slot = (self.slots.len() - 1) & hash as usize;

self.remove_inner(key, slot)
let res = self.remove_inner(key, slot);
if res.is_some() {
self.len -= 1;
}
res
}
}

Expand Down Expand Up @@ -162,6 +171,25 @@ where
HashMapIter::new(self)
}

/// # Safety
///
/// `link` MUST be in this [`HashMap`].
pub unsafe fn remove_in_place(
&mut self,
link: NonNull<HashMapLink>,
) -> <A::PointerOps as PointerOps>::Pointer {
assert!(link.as_ref().is_linked());
let item = self.adapter.link2item(link.as_ptr());
let key = &*self.adapter.item2key(item);
let hash = self.hash_key(key);
let slot = (self.slots.len() - 1) & hash as usize;
self.slots[slot]
.iter_mut_from_raw(link.as_ref().dlist_link.raw())
.remove();
self.len -= 1;
self.adapter.pointer_ops().from_raw(item)
}

/// # Safety
///
/// there must be at most one matches in the slot
Expand Down Expand Up @@ -394,6 +422,9 @@ mod tests {
assert_eq!(item.value, i);
}

unsafe { map.remove_in_place(items[0].link.raw()) };
assert!(map.lookup(&0).is_none());

drop(map);

for item in items {
Expand Down
19 changes: 16 additions & 3 deletions foyer-intrusive/src/eviction/fifo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ where
config: FifoConfig,
total_ratio: usize,

len: usize,

adapter: A,
}

Expand Down Expand Up @@ -150,6 +152,8 @@ where
config,
total_ratio,

len: 0,

adapter: A::new(),
}
}
Expand All @@ -167,6 +171,8 @@ where
self.segments[priority.into()].push_back(link);

self.rebalance();

self.len += 1;
}
}

Expand All @@ -188,12 +194,18 @@ where

self.rebalance();

self.len -= 1;

self.adapter.pointer_ops().from_raw(item)
}
}

fn access(&mut self, _ptr: &<A::PointerOps as PointerOps>::Pointer) {}

fn len(&self) -> usize {
self.len
}

fn rebalance(&mut self) {
unsafe {
let total: usize = self.segments.iter().map(|queue| queue.len()).sum();
Expand Down Expand Up @@ -350,23 +362,24 @@ where
}

fn insert(&mut self, ptr: <<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer) {
tracing::debug!("[lfu] insert {:?}", ptr);
self.insert(ptr)
}

fn remove(
&mut self,
ptr: &<<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer,
) -> <<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer {
tracing::debug!("[lfu] remove {:?}", ptr);
self.remove(ptr)
}

fn access(&mut self, ptr: &<<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer) {
tracing::debug!("[lfu] access {:?}", ptr);
self.access(ptr)
}

fn len(&self) -> usize {
self.len()
}

fn iter(&self) -> Self::E<'_> {
self.iter()
}
Expand Down
19 changes: 16 additions & 3 deletions foyer-intrusive/src/eviction/lfu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ where
/// the counts are halved every time the max_window_len is hit
frequencies: CMSketchUsize,

len: usize,

config: LfuConfig,

adapter: A,
Expand Down Expand Up @@ -187,6 +189,8 @@ where
// A dummy size, will be updated later.
frequencies: CMSketchUsize::new_with_size(1, 1),

len: 0,

config,

adapter: A::new(),
Expand Down Expand Up @@ -220,6 +224,8 @@ where

// If the number of counters are too small for the cache size, double them.
self.maybe_grow_access_counters();

self.len += 1;
}
}

Expand All @@ -235,6 +241,8 @@ where

self.remove_from_lru(link);

self.len -= 1;

self.adapter.pointer_ops().from_raw(item)
}
}
Expand All @@ -252,6 +260,10 @@ where
}
}

fn len(&self) -> usize {
self.len
}

fn iter(&self) -> LfuIter<A> {
let mut iter_main = self.lru_main.iter();
let mut iter_tiny = self.lru_tiny.iter();
Expand Down Expand Up @@ -527,23 +539,24 @@ where
}

fn insert(&mut self, ptr: <<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer) {
tracing::debug!("[lfu] insert {:?}", ptr);
self.insert(ptr)
}

fn remove(
&mut self,
ptr: &<<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer,
) -> <<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer {
tracing::debug!("[lfu] remove {:?}", ptr);
self.remove(ptr)
}

fn access(&mut self, ptr: &<<A>::PointerOps as crate::core::pointer::PointerOps>::Pointer) {
tracing::debug!("[lfu] access {:?}", ptr);
self.access(ptr)
}

fn len(&self) -> usize {
self.len()
}

fn iter(&self) -> Self::E<'_> {
self.iter()
}
Expand Down
19 changes: 16 additions & 3 deletions foyer-intrusive/src/eviction/lru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ where
/// length of tail after insertion point
tail_len: usize,

len: usize,

config: LruConfig,

adapter: A,
Expand Down Expand Up @@ -114,6 +116,8 @@ where

tail_len: 0,

len: 0,

config,

adapter: A::new(),
Expand All @@ -130,6 +134,8 @@ where
self.insert_lru(link);

self.update_lru_insertion_point();

self.len += 1;
}
}

Expand All @@ -153,6 +159,8 @@ where
self.tail_len -= 1;
}

self.len -= 1;

self.adapter.pointer_ops().from_raw(item)
}
}
Expand All @@ -176,6 +184,10 @@ where
}
}

fn len(&self) -> usize {
self.len
}

fn iter(&self) -> LruIter<'_, A> {
let mut iter = self.lru.iter();
iter.back();
Expand Down Expand Up @@ -379,23 +391,24 @@ where
}

fn insert(&mut self, ptr: <<A>::PointerOps as PointerOps>::Pointer) {
tracing::debug!("[lru] insert {:?}", ptr);
self.insert(ptr)
}

fn remove(
&mut self,
ptr: &<<A>::PointerOps as PointerOps>::Pointer,
) -> <<A>::PointerOps as PointerOps>::Pointer {
tracing::debug!("[lru] remove {:?}", ptr);
self.remove(ptr)
}

fn access(&mut self, ptr: &<<A>::PointerOps as PointerOps>::Pointer) {
tracing::debug!("[lru] access {:?}", ptr);
self.access(ptr)
}

fn len(&self) -> usize {
self.len()
}

fn iter(&self) -> Self::E<'_> {
self.iter()
}
Expand Down
8 changes: 7 additions & 1 deletion foyer-intrusive/src/eviction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::core::{

use std::fmt::Debug;

pub trait Config = Send + Sync + 'static + Debug;
pub trait Config = Send + Sync + 'static + Debug + Clone;

pub trait EvictionPolicy<A>: Send + Sync + 'static
where
Expand All @@ -41,6 +41,12 @@ where

fn access(&mut self, ptr: &<A::PointerOps as PointerOps>::Pointer);

fn len(&self) -> usize;

fn is_empty(&self) -> bool {
self.len() == 0
}

fn iter(&self) -> Self::E<'_>;

fn push(&mut self, ptr: <A::PointerOps as PointerOps>::Pointer) {
Expand Down
48 changes: 48 additions & 0 deletions foyer-memory/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[package]
name = "foyer-memory"
version = "0.1.0"
edition = "2021"
authors = ["MrCroxx <mrcroxx@outlook.com>"]
description = "Hybrid cache for Rust"
license = "Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-channel = "1.8"
async-trait = "0.1"
bitflags = "2.3.1"
bytes = "1"
cmsketch = "0.1"
foyer-common = { path = "../foyer-common" }
foyer-intrusive = { path = "../foyer-intrusive" }
futures = "0.3"
itertools = "0.10.5"
libc = "0.2"
memoffset = "0.8"
nix = { version = "0.26", features = ["fs", "mman"] }
parking_lot = "0.12"
paste = "1.0"
pin-project = "1"
prometheus = "0.13"
rand = "0.8.5"
thiserror = "1"
tokio = { version = "1", features = [
"rt",
"rt-multi-thread",
"sync",
"macros",
"time",
"signal",
] }
tracing = "0.1"
twox-hash = "1"

[dev-dependencies]
bytesize = "1"
clap = { version = "4", features = ["derive"] }
hdrhistogram = "7"
rand_mt = "4.2.1"
tempfile = "3"

[features]
deadlock = ["parking_lot/deadlock_detection"]
Loading

0 comments on commit 0792d14

Please sign in to comment.