Skip to content

Commit

Permalink
make TreeIter have static lifetime
Browse files Browse the repository at this point in the history
  • Loading branch information
marvin-j97 committed Jul 11, 2024
1 parent 02c7148 commit 330d2c9
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 52 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "lsm-tree"
description = "A K.I.S.S. implementation of log-structured merge trees (LSM-trees/LSMTs)"
license = "MIT OR Apache-2.0"
version = "1.2.0"
version = "1.3.0"
edition = "2021"
rust-version = "1.74.0"
readme = "README.md"
Expand All @@ -26,6 +26,7 @@ byteorder = "1.5.0"
crc32fast = "1.4.2"
crossbeam-skiplist = "0.1.3"
double-ended-peekable = "0.1.0"
guardian = "1.1.0"
log = "0.4.21"
lz4_flex = "0.11.3"
path-absolutize = "3.1.1"
Expand Down
34 changes: 17 additions & 17 deletions src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,36 @@ use crate::{
value::{ParsedInternalKey, SeqNo, UserKey, UserValue, ValueType},
Value,
};
use guardian::ArcRwLockReadGuardian;
use self_cell::self_cell;
use std::{collections::VecDeque, ops::Bound, sync::RwLockReadGuard};
use std::{collections::VecDeque, ops::Bound, sync::Arc};

pub struct MemtableLockGuard<'a> {
pub(crate) active: RwLockReadGuard<'a, MemTable>,
pub(crate) sealed: RwLockReadGuard<'a, SealedMemtables>,
pub struct MemtableLockGuard {
pub(crate) active: ArcRwLockReadGuardian<MemTable>,
pub(crate) sealed: ArcRwLockReadGuardian<SealedMemtables>,
pub(crate) ephemeral: Option<Arc<MemTable>>,
}

type BoxedMerge<'a> = Box<dyn DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'a>;

self_cell!(
pub struct TreeIter<'a> {
owner: MemtableLockGuard<'a>,
pub struct TreeIter {
owner: MemtableLockGuard,

#[covariant]
dependent: BoxedMerge,
}
);

impl<'a> Iterator for TreeIter<'a> {
impl Iterator for TreeIter {
type Item = crate::Result<(UserKey, UserValue)>;

fn next(&mut self) -> Option<Self::Item> {
self.with_dependent_mut(|_, iter| iter.next())
}
}

impl<'a> DoubleEndedIterator for TreeIter<'a> {
impl DoubleEndedIterator for TreeIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.with_dependent_mut(|_, iter| iter.next_back())
}
Expand Down Expand Up @@ -78,14 +80,13 @@ fn collect_disjoint_tree_with_range(
MultiReader::new(readers)
}

impl<'a> TreeIter<'a> {
impl TreeIter {
#[must_use]
pub fn create_prefix(
guard: MemtableLockGuard<'a>,
guard: MemtableLockGuard,
prefix: &UserKey,
seqno: Option<SeqNo>,
level_manifest: RwLockReadGuard<'a, LevelManifest>,
add_index: Option<&'a MemTable>,
level_manifest: ArcRwLockReadGuardian<LevelManifest>,
) -> Self {
TreeIter::new(guard, |lock| {
let prefix = prefix.clone();
Expand Down Expand Up @@ -185,7 +186,7 @@ impl<'a> TreeIter<'a> {
}

// Add index
if let Some(index) = add_index {
if let Some(index) = &lock.ephemeral {
iters.push(Box::new(index.prefix(prefix).map(Ok)));
}

Expand All @@ -208,11 +209,10 @@ impl<'a> TreeIter<'a> {
#[must_use]
#[allow(clippy::too_many_lines)]
pub fn create_range(
guard: MemtableLockGuard<'a>,
guard: MemtableLockGuard,
bounds: (Bound<UserKey>, Bound<UserKey>),
seqno: Option<SeqNo>,
level_manifest: RwLockReadGuard<'a, LevelManifest>,
add_index: Option<&'a MemTable>,
level_manifest: ArcRwLockReadGuardian<LevelManifest>,
) -> Self {
TreeIter::new(guard, |lock| {
let lo = match &bounds.0 {
Expand Down Expand Up @@ -359,7 +359,7 @@ impl<'a> TreeIter<'a> {
}
}

if let Some(index) = add_index {
if let Some(index) = &lock.ephemeral {
let iter =
Box::new(index.items.range(range).map(|entry| {
Ok(Value::from((entry.key().clone(), entry.value().clone())))
Expand Down
10 changes: 4 additions & 6 deletions src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,7 @@ impl Snapshot {
///
/// Will return `Err` if an IO error occurs.
#[must_use]
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
pub fn iter(&self) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.tree.create_iter(Some(self.seqno), None)
}

Expand Down Expand Up @@ -152,8 +150,8 @@ impl Snapshot {
pub fn range<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
self.tree.create_range(range, Some(self.seqno), None)
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.tree.create_range(&range, Some(self.seqno), None)
}

/// Returns an iterator over a prefixed set of items in the snapshot.
Expand Down Expand Up @@ -185,7 +183,7 @@ impl Snapshot {
pub fn prefix<K: AsRef<[u8]>>(
&self,
prefix: K,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.tree.create_prefix(prefix, Some(self.seqno), None)
}

Expand Down
70 changes: 42 additions & 28 deletions src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,12 +584,12 @@ impl Tree {

#[doc(hidden)]
#[must_use]
pub fn create_iter<'a>(
&'a self,
pub fn create_iter(
&self,
seqno: Option<SeqNo>,
index: Option<&'a MemTable>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'a {
self.create_range::<UserKey, _>(.., seqno, index)
ephemeral: Option<Arc<MemTable>>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.create_range::<UserKey, _>(&.., seqno, ephemeral)
}

/// Returns an iterator that scans through the entire tree.
Expand Down Expand Up @@ -617,19 +617,17 @@ impl Tree {
/// Will return `Err` if an IO error occurs.
#[allow(clippy::iter_not_returning_iterator)]
#[must_use]
pub fn iter(
&self,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
pub fn iter(&self) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.create_iter(None, None)
}

#[doc(hidden)]
pub fn create_range<'a, K: AsRef<[u8]>, R: RangeBounds<K>>(
pub fn create_range<'a, K: AsRef<[u8]> + 'a, R: RangeBounds<K> + 'a>(
&'a self,
range: R,
range: &'a R,
seqno: Option<SeqNo>,
add_index: Option<&'a MemTable>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'a {
ephemeral: Option<Arc<MemTable>>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'static {
use std::ops::Bound::{self, Excluded, Included, Unbounded};

let lo: Bound<UserKey> = match range.start_bound() {
Expand All @@ -647,16 +645,24 @@ impl Tree {
let bounds: (Bound<UserKey>, Bound<UserKey>) = (lo, hi);

// NOTE: Mind lock order L -> M -> S
let level_manifest_lock = self.levels.read().expect("lock is poisoned");
let active = self.active_memtable.read().expect("lock is poisoned");
let sealed = self.sealed_memtables.read().expect("lock is poisoned");
let level_manifest_lock =
guardian::ArcRwLockReadGuardian::take(self.levels.clone()).expect("lock is poisoned");

let active = guardian::ArcRwLockReadGuardian::take(self.active_memtable.clone())
.expect("lock is poisoned");

let sealed = guardian::ArcRwLockReadGuardian::take(self.sealed_memtables.clone())
.expect("lock is poisoned");

TreeIter::create_range(
MemtableLockGuard { active, sealed },
MemtableLockGuard {
active,
sealed,
ephemeral,
},
bounds,
seqno,
level_manifest_lock,
add_index,
)
}

Expand Down Expand Up @@ -686,30 +692,38 @@ impl Tree {
pub fn range<K: AsRef<[u8]>, R: RangeBounds<K>>(
&self,
range: R,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
self.create_range(range, None, None)
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.create_range(&range, None, None)
}

#[doc(hidden)]
pub fn create_prefix<'a, K: AsRef<[u8]>>(
pub fn create_prefix<'a, K: AsRef<[u8]> + 'a>(
&'a self,
prefix: K,
seqno: Option<SeqNo>,
add_index: Option<&'a MemTable>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'a {
ephemeral: Option<Arc<MemTable>>,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + 'static {
let prefix = prefix.as_ref();

// NOTE: Mind lock order L -> M -> S
let level_manifest_lock = self.levels.read().expect("lock is poisoned");
let active = self.active_memtable.read().expect("lock is poisoned");
let sealed = self.sealed_memtables.read().expect("lock is poisoned");
let level_manifest_lock =
guardian::ArcRwLockReadGuardian::take(self.levels.clone()).expect("lock is poisoned");

let active = guardian::ArcRwLockReadGuardian::take(self.active_memtable.clone())
.expect("lock is poisoned");

let sealed = guardian::ArcRwLockReadGuardian::take(self.sealed_memtables.clone())
.expect("lock is poisoned");

TreeIter::create_prefix(
MemtableLockGuard { active, sealed },
MemtableLockGuard {
active,
sealed,
ephemeral,
},
&prefix.into(),
seqno,
level_manifest_lock,
add_index,
)
}

Expand Down Expand Up @@ -739,7 +753,7 @@ impl Tree {
pub fn prefix<K: AsRef<[u8]>>(
&self,
prefix: K,
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> + '_ {
) -> impl DoubleEndedIterator<Item = crate::Result<(UserKey, UserValue)>> {
self.create_prefix(prefix, None, None)
}

Expand Down

0 comments on commit 330d2c9

Please sign in to comment.