-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
59afbd3
commit a6adf78
Showing
7 changed files
with
261 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "aptos-in-memory-cache" | ||
description = "In-Memory cache" | ||
version = "0.1.0" | ||
|
||
# Workspace inherited keys | ||
authors = { workspace = true } | ||
edition = { workspace = true } | ||
homepage = { workspace = true } | ||
license = { workspace = true } | ||
publish = { workspace = true } | ||
repository = { workspace = true } | ||
rust-version = { workspace = true } | ||
|
||
[dependencies] | ||
dashmap = { workspace = true } | ||
quick_cache = { workspace = true } | ||
tokio = { workspace = true } | ||
tokio-util = { workspace = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright © Aptos Foundation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::{Cache, Incrementable, Ordered, Weighted}; | ||
use dashmap::DashMap; | ||
use std::hash::Hash; | ||
|
||
#[derive(Debug, Clone, Copy)] | ||
struct CacheMetadata<K> | ||
where | ||
K: Hash + Eq + PartialEq + Incrementable + Send + Sync + Clone, | ||
{ | ||
max_size_in_bytes: u64, | ||
total_size_in_bytes: u64, | ||
last_key: Option<K>, | ||
first_key: Option<K>, | ||
} | ||
|
||
/// FIFO is a simple in-memory cache with a deterministic FIFO eviction policy. | ||
pub struct FIFOCache<K, V> | ||
where | ||
K: Hash + Eq + PartialEq + Incrementable + Send + Sync + Clone, | ||
V: Weighted + Send + Sync + Clone, | ||
{ | ||
/// Cache maps the cache key to the deserialized Transaction. | ||
items: DashMap<K, V>, | ||
cache_metadata: CacheMetadata<K>, | ||
} | ||
|
||
impl<K, V> FIFOCache<K, V> | ||
where | ||
K: Hash + Eq + PartialEq + Incrementable + Send + Sync + Clone, | ||
V: Weighted + Send + Sync + Clone, | ||
{ | ||
pub fn new(max_size_in_bytes: u64) -> Self { | ||
FIFOCache { | ||
items: DashMap::new(), | ||
cache_metadata: CacheMetadata { | ||
max_size_in_bytes, | ||
total_size_in_bytes: 0, | ||
last_key: None, | ||
first_key: None, | ||
}, | ||
} | ||
} | ||
|
||
fn pop(&mut self) -> Option<u64> { | ||
if let Some(first_key) = self.cache_metadata.first_key.clone() { | ||
let next_key = first_key.next(); | ||
return self.items.remove(&first_key).map(|(_, v)| { | ||
let weight = v.weight(); | ||
self.cache_metadata.first_key = Some(next_key); | ||
self.cache_metadata.total_size_in_bytes -= weight; | ||
weight | ||
}); | ||
} | ||
None | ||
} | ||
|
||
fn evict(&mut self, new_value_weight: u64) -> (u64, u64) { | ||
let mut garbage_collection_count = 0; | ||
let mut garbage_collection_size = 0; | ||
while self.cache_metadata.total_size_in_bytes + new_value_weight | ||
> self.cache_metadata.max_size_in_bytes | ||
{ | ||
if let Some(weight) = self.pop() { | ||
garbage_collection_count += 1; | ||
garbage_collection_size += weight; | ||
} | ||
} | ||
(garbage_collection_count, garbage_collection_size) | ||
} | ||
|
||
fn insert_impl(&mut self, key: K, value: V) { | ||
self.cache_metadata.last_key = Some(key.clone()); | ||
self.cache_metadata.total_size_in_bytes += value.weight(); | ||
self.items.insert(key, value); | ||
} | ||
} | ||
|
||
impl<K, V> Cache<K, V> for FIFOCache<K, V> | ||
where | ||
K: Hash + Eq + PartialEq + Incrementable + Send + Sync + Clone, | ||
V: Weighted + Send + Sync + Clone, | ||
{ | ||
fn get(&self, key: &K) -> Option<V> { | ||
self.items.get(key).map(|v| v.value().clone()) | ||
} | ||
|
||
fn insert(&mut self, key: K, value: V) -> (u64, u64) { | ||
// If cache is empty, set the first to the new key. | ||
if self.items.is_empty() { | ||
self.cache_metadata.first_key = Some(key.clone()); | ||
} | ||
|
||
// Evict until enough space is available for next value. | ||
let (garbage_collection_count, garbage_collection_size) = self.evict(value.weight()); | ||
self.insert_impl(key, value); | ||
|
||
return (garbage_collection_count, garbage_collection_size); | ||
} | ||
} | ||
|
||
impl<K, V> Ordered<K, V> for FIFOCache<K, V> | ||
where | ||
K: Hash + Eq + PartialEq + Incrementable + Send + Sync + Clone, | ||
V: Weighted + Send + Sync + Clone, | ||
{ | ||
fn first_key(&self) -> Option<K> { | ||
self.cache_metadata.first_key.clone() | ||
} | ||
|
||
fn last_key(&self) -> Option<K> { | ||
self.cache_metadata.last_key.clone() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Copyright © Aptos Foundation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
pub mod fifo; | ||
pub mod s3fifo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Copyright © Aptos Foundation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::{Cache, Ordered}; | ||
use quick_cache::{sync::Cache as S3FIFOCache, Lifecycle, Weighter}; | ||
use std::hash::{BuildHasher, Hash}; | ||
|
||
impl<K, V, We, B, L> Cache<K, V> for S3FIFOCache<K, V, We, B, L> | ||
where | ||
K: Eq + Hash + Clone + Send + Sync, | ||
V: Clone + Send + Sync, | ||
We: Weighter<K, V> + Clone + Send + Sync, | ||
B: BuildHasher + Clone + Send + Sync, | ||
L: Lifecycle<K, V> + Clone + Send + Sync, | ||
{ | ||
fn get(&self, key: &K) -> Option<V> { | ||
S3FIFOCache::get(self, key) | ||
} | ||
|
||
fn insert(&mut self, key: K, value: V) -> (u64, u64) { | ||
S3FIFOCache::insert(self, key, value); | ||
(0, 0) | ||
} | ||
} | ||
|
||
impl<K, V, We, B, L> Ordered<K, V> for S3FIFOCache<K, V, We, B, L> | ||
where | ||
K: Eq + Hash + Clone + Send + Sync, | ||
V: Clone + Send + Sync, | ||
We: Weighter<K, V> + Clone + Send + Sync, | ||
B: BuildHasher + Clone + Send + Sync, | ||
L: Lifecycle<K, V> + Clone + Send + Sync, | ||
{ | ||
fn first_key(&self) -> Option<K> { | ||
unimplemented!(); | ||
} | ||
|
||
fn last_key(&self) -> Option<K> { | ||
unimplemented!(); | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use quick_cache::sync::Cache as S3FIFOCache; | ||
|
||
fn get_s3fifo_cache() -> S3FIFOCache<i32, i32> { | ||
S3FIFOCache::<i32, i32>::new(10) | ||
} | ||
|
||
#[test] | ||
fn test_s3fifo_cache() { | ||
let mut cache: Box<dyn Cache<i32, i32>> = Box::new(get_s3fifo_cache()); | ||
cache.insert(1, 1); | ||
assert_eq!(cache.get(&1), Some(1)); | ||
assert_eq!(cache.get(&2), None); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright © Aptos Foundation | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::hash::Hash; | ||
|
||
pub mod caches; | ||
|
||
/// A trait for a cache that can be used to store key-value pairs. | ||
pub trait Cache<K, V>: Send + Sync | ||
where | ||
K: Eq + Hash + Clone + Send + Sync, | ||
V: Clone + Send + Sync, | ||
{ | ||
/// Get the value for a given key. Return [`None`] if the key is not in the cache. | ||
fn get(&self, key: &K) -> Option<V>; | ||
|
||
/// Inserts a given key-value pair in cache. Panics if the insert fails. | ||
fn insert(&mut self, key: K, value: V) -> (u64, u64); | ||
} | ||
|
||
pub trait Ordered<K, V>: Send + Sync { | ||
/// Returns the first key in the cache. Returns [`None`] if the cache is empty. | ||
fn first_key(&self) -> Option<K>; | ||
|
||
/// Returns the last key in the cache. Returns [`None`] if the cache is empty. | ||
fn last_key(&self) -> Option<K>; | ||
} | ||
|
||
pub trait Weighted { | ||
/// Returns the size of the value in bytes. | ||
fn weight(&self) -> u64; | ||
} | ||
|
||
pub trait Incrementable { | ||
/// Increments the value. | ||
fn next(&self) -> Self; | ||
} |