-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #70 from Gifted-s/feat/block_cache
[Feat] File Descriptor and Unit tests for it
- Loading branch information
Showing
12 changed files
with
451 additions
and
3 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
use std::sync::Arc; | ||
|
||
use crate::block_cache::Either::Left; | ||
use crate::block_cache::Either::Right; | ||
use crate::{ | ||
either::Either, | ||
sst::{ | ||
block_index::{block_handle::KeyedBlockHandle, IndexBlock}, | ||
id::GlobalSegmentId, | ||
value_offset_block::ValueOffsetBlock, | ||
}, | ||
}; | ||
use quick_cache::Weighter; | ||
use quick_cache::{sync::Cache, Equivalent}; | ||
|
||
type Item = Either<Arc<ValueOffsetBlock>, Arc<IndexBlock>>; | ||
|
||
// (Type (TreeId, Segment ID), Block offset) | ||
#[derive(Eq, std::hash::Hash, PartialEq)] | ||
struct CacheKey(GlobalSegmentId, u64); | ||
|
||
impl Equivalent<CacheKey> for (GlobalSegmentId, u64) { | ||
fn equivalent(&self, key: &CacheKey) -> bool { | ||
self.0 == key.0 && self.1 == key.1 | ||
} | ||
} | ||
|
||
impl From<(GlobalSegmentId, u64)> for CacheKey { | ||
fn from((gid, bid): (GlobalSegmentId, u64)) -> Self { | ||
Self(gid, bid) | ||
} | ||
} | ||
|
||
#[derive(Clone)] | ||
struct BlockWeighter; | ||
|
||
impl Weighter<CacheKey, Item> for BlockWeighter { | ||
fn weight(&self, _: &CacheKey, block: &Item) -> u64 { | ||
// NOTE: Truncation is fine: blocks are definitely below 4 GiB | ||
#[allow(clippy::cast_possible_truncation)] | ||
match block { | ||
Either::Left(block) => block.size() as u64, | ||
Either::Right(block) => block | ||
.items | ||
.iter() | ||
.map(|x| x.end_key.len() + std::mem::size_of::<KeyedBlockHandle>()) | ||
.sum::<usize>() as u64, | ||
} | ||
} | ||
} | ||
|
||
pub struct BlockCache { | ||
data: Cache<CacheKey, Item, BlockWeighter>, | ||
capacity: u64, | ||
} | ||
|
||
impl BlockCache { | ||
#[must_use] | ||
pub fn with_capacity_bytes(bytes: u64) -> Self { | ||
Self { | ||
data: Cache::with_weighter(1_000_000, bytes, BlockWeighter), | ||
capacity: bytes, | ||
} | ||
} | ||
|
||
/// Returns the amount of cached bytes | ||
#[must_use] | ||
pub fn size(&self) -> u64 { | ||
self.data.weight() | ||
} | ||
|
||
/// Returns the cache capacity in bytes. | ||
#[must_use] | ||
pub fn capacity(&self) -> u64 { | ||
self.capacity | ||
} | ||
|
||
/// Returns the number of cached blocks. | ||
#[must_use] | ||
pub fn len(&self) -> usize { | ||
self.data.len() | ||
} | ||
|
||
/// Returns `true` if there are no cached blocks. | ||
#[must_use] | ||
pub fn is_empty(&self) -> bool { | ||
self.data.is_empty() | ||
} | ||
|
||
#[doc(hidden)] | ||
pub fn insert_disk_block(&self, sstable_id: GlobalSegmentId, offset: u64, value: Arc<ValueOffsetBlock>) { | ||
if self.capacity > 0 { | ||
self.data.insert((sstable_id, offset).into(), Left(value)); | ||
} | ||
} | ||
|
||
#[doc(hidden)] | ||
pub fn insert_index_block(&self, sstable_id: GlobalSegmentId, offset: u64, value: Arc<IndexBlock>) { | ||
if self.capacity > 0 { | ||
self.data.insert((sstable_id, offset).into(), Right(value)); | ||
} | ||
} | ||
|
||
#[doc(hidden)] | ||
#[must_use] | ||
pub fn get_disk_block(&self, sstable_id: GlobalSegmentId, offset: u64) -> Option<Arc<ValueOffsetBlock>> { | ||
let key = (sstable_id, offset); | ||
let item = self.data.get(&key)?; | ||
Some(item.left()) | ||
} | ||
|
||
#[doc(hidden)] | ||
#[must_use] | ||
pub fn get_index_block(&self, sstable_id: GlobalSegmentId, offset: u64) -> Option<Arc<IndexBlock>> { | ||
let key = (sstable_id, offset); | ||
let item = self.data.get(&key)?; | ||
Some(item.right()) | ||
} | ||
} |
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,31 @@ | ||
use std::collections::VecDeque; | ||
|
||
#[derive(Default)] | ||
#[allow(clippy::module_name_repetitions)] | ||
pub struct LruList<T: Clone + Eq + PartialEq>(VecDeque<T>); | ||
|
||
impl<T: Clone + Eq + PartialEq> LruList<T> { | ||
#[must_use] | ||
pub fn with_capacity(n: usize) -> Self { | ||
Self(VecDeque::with_capacity(n)) | ||
} | ||
|
||
pub fn remove_by(&mut self, f: impl FnMut(&T) -> bool) { | ||
self.0.retain(f); | ||
} | ||
|
||
pub fn remove(&mut self, item: &T) { | ||
self.remove_by(|x| x != item); | ||
} | ||
|
||
pub fn refresh(&mut self, item: T) { | ||
self.remove(&item); | ||
self.0.push_back(item); | ||
} | ||
|
||
pub fn get_least_recently_used(&mut self) -> Option<T> { | ||
let front = self.0.pop_front()?; | ||
self.0.push_back(front.clone()); | ||
Some(front) | ||
} | ||
} |
Oops, something went wrong.