-
Notifications
You must be signed in to change notification settings - Fork 9
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
Showing
7 changed files
with
208 additions
and
13 deletions.
There are no files selected for viewing
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
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
85 changes: 85 additions & 0 deletions
85
src/array/chunk_cache/chunk_cache_lru_chunk_limit_thread_local.rs
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,85 @@ | ||
use std::{ | ||
num::NonZeroUsize, | ||
sync::{Arc, Mutex}, | ||
}; | ||
|
||
use lru::LruCache; | ||
use thread_local::ThreadLocal; | ||
|
||
use crate::array::{ArrayError, ArrayIndices}; | ||
|
||
use super::{ChunkCache, ChunkCacheType, ChunkCacheTypeDecoded, ChunkCacheTypeEncoded}; | ||
type ChunkIndices = ArrayIndices; | ||
|
||
/// A thread local chunk cache with a fixed chunk capacity per thread. | ||
pub struct ChunkCacheLruChunkLimitThreadLocal<T: ChunkCacheType> { | ||
cache: ThreadLocal<Mutex<LruCache<ChunkIndices, Arc<T>>>>, | ||
capacity: u64, | ||
} | ||
|
||
/// An LRU (least recently used) encoded chunk cache with a fixed chunk capacity. | ||
pub type ChunkCacheEncodedLruChunkLimitThreadLocal = | ||
ChunkCacheLruChunkLimitThreadLocal<ChunkCacheTypeEncoded>; | ||
|
||
/// An LRU (least recently used) decoded chunk cache with a fixed chunk capacity. | ||
pub type ChunkCacheDecodedLruChunkLimitThreadLocal = | ||
ChunkCacheLruChunkLimitThreadLocal<ChunkCacheTypeDecoded>; | ||
|
||
impl<CT: ChunkCacheType> ChunkCacheLruChunkLimitThreadLocal<CT> { | ||
/// Create a new [`ChunkCacheLruChunkLimitThreadLocal`] with a capacity in bytes of `capacity`. | ||
#[must_use] | ||
pub fn new(capacity: u64) -> Self { | ||
let cache = ThreadLocal::new(); | ||
Self { cache, capacity } | ||
} | ||
|
||
fn cache(&self) -> &Mutex<LruCache<ChunkIndices, Arc<CT>>> { | ||
self.cache.get_or(|| { | ||
Mutex::new(LruCache::new( | ||
NonZeroUsize::new(usize::try_from(self.capacity).unwrap_or(usize::MAX).max(1)) | ||
.unwrap(), | ||
)) | ||
}) | ||
} | ||
} | ||
|
||
macro_rules! impl_ChunkCacheLruChunkLimitThreadLocal { | ||
($t:ty) => { | ||
impl<CT: ChunkCacheType> ChunkCache<CT> for $t { | ||
fn get(&self, chunk_indices: &[u64]) -> Option<Arc<CT>> { | ||
self.cache() | ||
.lock() | ||
.unwrap() | ||
.get(&chunk_indices.to_vec()) | ||
.cloned() | ||
} | ||
|
||
fn insert(&self, chunk_indices: ChunkIndices, chunk: Arc<CT>) { | ||
self.cache().lock().unwrap().push(chunk_indices, chunk); | ||
} | ||
|
||
fn try_get_or_insert_with<F, E>( | ||
&self, | ||
chunk_indices: Vec<u64>, | ||
f: F, | ||
) -> Result<Arc<CT>, Arc<ArrayError>> | ||
where | ||
F: FnOnce() -> Result<Arc<CT>, ArrayError>, | ||
{ | ||
self.cache() | ||
.lock() | ||
.unwrap() | ||
.try_get_or_insert(chunk_indices, f) | ||
.cloned() | ||
.map_err(|e| Arc::new(e)) | ||
} | ||
|
||
fn len(&self) -> usize { | ||
self.cache().lock().unwrap().len() | ||
} | ||
} | ||
}; | ||
} | ||
|
||
impl_ChunkCacheLruChunkLimitThreadLocal!(ChunkCacheLruChunkLimitThreadLocal<CT>); | ||
impl_ChunkCacheLruChunkLimitThreadLocal!(&ChunkCacheLruChunkLimitThreadLocal<CT>); |
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
89 changes: 89 additions & 0 deletions
89
src/array/chunk_cache/chunk_cache_lru_size_limit_thread_local.rs
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,89 @@ | ||
use std::sync::{ | ||
atomic::{self, AtomicUsize}, | ||
Arc, Mutex, | ||
}; | ||
|
||
use lru::LruCache; | ||
use thread_local::ThreadLocal; | ||
|
||
use crate::array::ArrayIndices; | ||
|
||
use super::{ChunkCache, ChunkCacheType, ChunkCacheTypeDecoded, ChunkCacheTypeEncoded}; | ||
type ChunkIndices = ArrayIndices; | ||
|
||
/// A thread local chunk cache with a fixed chunk capacity per thread. | ||
pub struct ChunkCacheLruSizeLimitThreadLocal<T: ChunkCacheType> { | ||
cache: ThreadLocal<Mutex<LruCache<ChunkIndices, Arc<T>>>>, | ||
capacity: usize, | ||
size: ThreadLocal<AtomicUsize>, | ||
} | ||
|
||
/// An LRU (least recently used) encoded chunk cache with a fixed chunk capacity. | ||
pub type ChunkCacheEncodedLruSizeLimitThreadLocal = | ||
ChunkCacheLruSizeLimitThreadLocal<ChunkCacheTypeEncoded>; | ||
|
||
/// An LRU (least recently used) decoded chunk cache with a fixed chunk capacity. | ||
pub type ChunkCacheDecodedLruSizeLimitThreadLocal = | ||
ChunkCacheLruSizeLimitThreadLocal<ChunkCacheTypeDecoded>; | ||
|
||
impl<CT: ChunkCacheType> ChunkCacheLruSizeLimitThreadLocal<CT> { | ||
/// Create a new [`ChunkCacheLruSizeLimitThreadLocal`] with a capacity in bytes of `capacity`. | ||
#[must_use] | ||
pub fn new(capacity: u64) -> Self { | ||
let cache = ThreadLocal::new(); | ||
Self { | ||
cache, | ||
capacity: usize::try_from(capacity).unwrap_or(usize::MAX), | ||
size: ThreadLocal::new(), | ||
} | ||
} | ||
|
||
fn cache(&self) -> &Mutex<LruCache<ChunkIndices, Arc<CT>>> { | ||
self.cache.get_or(|| Mutex::new(LruCache::unbounded())) | ||
} | ||
} | ||
|
||
impl<T: ChunkCacheType> ChunkCacheLruSizeLimitThreadLocal<T> { | ||
/// Return the size of the cache in bytes. | ||
#[must_use] | ||
pub fn size(&self) -> usize { | ||
self.size.get_or_default().load(atomic::Ordering::SeqCst) | ||
} | ||
} | ||
|
||
macro_rules! impl_ChunkCacheLruSizeLimitThreadLocal { | ||
($t:ty) => { | ||
impl<CT: ChunkCacheType> ChunkCache<CT> for $t { | ||
fn get(&self, chunk_indices: &[u64]) -> Option<Arc<CT>> { | ||
self.cache() | ||
.lock() | ||
.unwrap() | ||
.get(&chunk_indices.to_vec()) | ||
.cloned() | ||
} | ||
|
||
fn insert(&self, chunk_indices: ChunkIndices, chunk: Arc<CT>) { | ||
let size = self.size.get_or_default(); | ||
let size_old = size.fetch_add(chunk.size(), atomic::Ordering::SeqCst); | ||
if size_old + chunk.size() > self.capacity { | ||
let old = self.cache().lock().unwrap().pop_lru(); | ||
if let Some(old) = old { | ||
size.fetch_sub(old.1.size(), atomic::Ordering::SeqCst); | ||
} | ||
} | ||
|
||
let old = self.cache().lock().unwrap().push(chunk_indices, chunk); | ||
if let Some(old) = old { | ||
size.fetch_sub(old.1.size(), atomic::Ordering::SeqCst); | ||
} | ||
} | ||
|
||
fn len(&self) -> usize { | ||
self.cache().lock().unwrap().len() | ||
} | ||
} | ||
}; | ||
} | ||
|
||
impl_ChunkCacheLruSizeLimitThreadLocal!(ChunkCacheLruSizeLimitThreadLocal<CT>); | ||
impl_ChunkCacheLruSizeLimitThreadLocal!(&ChunkCacheLruSizeLimitThreadLocal<CT>); |