use std::cmp::Ordering;
use std::collections::btree_map::Entry as BTreeEntry;
use std::collections::BTreeMap;
use std::sync::Arc;
use crate::batch::Batch;
use crate::error::{Error, Result};
use crate::lsm::Core;
use crate::snapshot::{HistoryIterator, MergeDirection, Snapshot, SnapshotIterator};
use crate::{InternalKeyKind, InternalKeyRef, IntoBytes, Key, LSMIterator, Value};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Mode {
ReadWrite,
ReadOnly,
WriteOnly,
}
impl Mode {
pub(crate) fn mutable(self) -> bool {
match self {
Self::ReadWrite => true,
Self::ReadOnly => false,
Self::WriteOnly => true,
}
}
pub(crate) fn is_write_only(self) -> bool {
matches!(self, Self::WriteOnly)
}
pub(crate) fn is_read_only(self) -> bool {
matches!(self, Self::ReadOnly)
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub enum Durability {
#[default]
Eventual,
Immediate,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TransactionOptions {
pub mode: Mode,
pub durability: Durability,
}
impl TransactionOptions {
pub fn read_only() -> Self {
Self::new_with_mode(Mode::ReadOnly)
}
pub fn write_only() -> Self {
Self::new_with_mode(Mode::WriteOnly)
}
pub fn new() -> Self {
Self::new_with_mode(Mode::ReadWrite)
}
pub fn new_with_mode(mode: Mode) -> Self {
Self {
mode,
durability: Default::default(),
}
}
pub fn with_durability(mut self, durability: Durability) -> Self {
self.durability = durability;
self
}
}
impl Default for TransactionOptions {
fn default() -> Self {
Self::new()
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct WriteOptions {
pub timestamp: Option<u64>,
}
impl WriteOptions {
pub fn new() -> Self {
Self::default()
}
pub fn with_timestamp(mut self, timestamp: Option<u64>) -> Self {
self.timestamp = timestamp;
self
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct ReadOptions {
pub(crate) lower_bound: Option<Vec<u8>>,
pub(crate) upper_bound: Option<Vec<u8>>,
}
impl ReadOptions {
pub fn new() -> Self {
Self::default()
}
pub fn set_iterate_lower_bound(&mut self, bound: Option<Vec<u8>>) {
self.lower_bound = bound;
}
pub fn set_iterate_upper_bound(&mut self, bound: Option<Vec<u8>>) {
self.upper_bound = bound;
}
pub(crate) fn set_iterate_bounds(&mut self, lower: Option<Vec<u8>>, upper: Option<Vec<u8>>) {
self.lower_bound = lower;
self.upper_bound = upper;
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct HistoryOptions {
pub include_tombstones: bool,
pub ts_range: Option<(u64, u64)>,
pub limit: Option<usize>,
}
impl HistoryOptions {
pub fn new() -> Self {
Self::default()
}
pub fn with_tombstones(mut self, include: bool) -> Self {
self.include_tombstones = include;
self
}
pub fn with_ts_range(mut self, start_ts: u64, end_ts: u64) -> Self {
self.ts_range = Some((start_ts, end_ts));
self
}
pub fn with_limit(mut self, limit: usize) -> Self {
self.limit = Some(limit);
self
}
}
pub struct Transaction {
mode: Mode,
durability: Durability,
pub(crate) snapshot: Option<Snapshot>,
pub(crate) core: Arc<Core>,
pub(crate) write_set: BTreeMap<Key, Vec<Entry>>,
closed: bool,
pub(crate) start_seq_num: u64,
savepoints: u32,
write_seqno: u32,
}
impl Transaction {
fn next_write_seqno(&mut self) -> u32 {
self.write_seqno += 1;
self.write_seqno
}
pub fn set_durability(&mut self, durability: Durability) {
self.durability = durability;
}
pub fn with_durability(mut self, durability: Durability) -> Self {
self.durability = durability;
self
}
pub(crate) fn new(core: Arc<Core>, opts: TransactionOptions) -> Result<Self> {
let TransactionOptions {
mode,
durability,
} = opts;
let start_seq_num = core.seq_num();
let mut snapshot = None;
if !mode.is_write_only() {
snapshot = Some(Snapshot::new(Arc::clone(&core), start_seq_num));
}
Ok(Self {
mode,
snapshot,
core,
write_set: BTreeMap::new(),
durability,
closed: false,
start_seq_num,
savepoints: 0,
write_seqno: 0,
})
}
pub fn set<K, V>(&mut self, key: K, value: V) -> Result<()>
where
K: IntoBytes,
V: IntoBytes,
{
self.set_with_options(key, value, &WriteOptions::default())
}
pub fn set_at<K, V>(&mut self, key: K, value: V, timestamp: u64) -> Result<()>
where
K: IntoBytes,
V: IntoBytes,
{
self.set_with_options(key, value, &WriteOptions::default().with_timestamp(Some(timestamp)))
}
pub fn set_with_options<K, V>(&mut self, key: K, value: V, options: &WriteOptions) -> Result<()>
where
K: IntoBytes,
V: IntoBytes,
{
let write_seqno = self.next_write_seqno();
let ts = options.timestamp.unwrap_or(Entry::COMMIT_TIME);
let entry =
Entry::new(key, Some(value), InternalKeyKind::Set, self.savepoints, write_seqno, ts);
self.write(entry)?;
Ok(())
}
pub fn delete<K>(&mut self, key: K) -> Result<()>
where
K: IntoBytes,
{
self.delete_with_options(key, &WriteOptions::default())
}
pub fn delete_with_options<K>(&mut self, key: K, options: &WriteOptions) -> Result<()>
where
K: IntoBytes,
{
let write_seqno = self.next_write_seqno();
let ts = options.timestamp.unwrap_or(Entry::COMMIT_TIME);
let entry = Entry::new(
key,
None::<&[u8]>,
InternalKeyKind::Delete,
self.savepoints,
write_seqno,
ts,
);
self.write(entry)?;
Ok(())
}
pub fn soft_delete<K>(&mut self, key: K) -> Result<()>
where
K: IntoBytes,
{
self.soft_delete_with_options(key, &WriteOptions::default())
}
pub fn soft_delete_with_options<K>(&mut self, key: K, options: &WriteOptions) -> Result<()>
where
K: IntoBytes,
{
let write_seqno = self.next_write_seqno();
let ts = options.timestamp.unwrap_or(Entry::COMMIT_TIME);
let entry = Entry::new(
key,
None::<&[u8]>,
InternalKeyKind::SoftDelete,
self.savepoints,
write_seqno,
ts,
);
self.write(entry)?;
Ok(())
}
pub fn replace<K, V>(&mut self, key: K, value: V) -> Result<()>
where
K: IntoBytes,
V: IntoBytes,
{
let write_seqno = self.next_write_seqno();
let entry = Entry::new(
key,
Some(value),
InternalKeyKind::Replace,
self.savepoints,
write_seqno,
Entry::COMMIT_TIME,
);
self.write(entry)?;
Ok(())
}
pub fn get<K>(&self, key: K) -> Result<Option<Value>>
where
K: IntoBytes,
{
self.get_with_options(key, &ReadOptions::default())
}
pub fn get_at<K>(&self, key: K, timestamp: u64) -> Result<Option<Value>>
where
K: IntoBytes,
{
if self.closed {
return Err(Error::TransactionClosed);
}
if key.as_slice().is_empty() {
return Err(Error::EmptyKey);
}
if self.mode.is_write_only() {
return Err(Error::TransactionWriteOnly);
}
if !self.core.opts.enable_versioning {
return Err(Error::InvalidArgument("Versioned queries not enabled".to_string()));
}
if let Some(entries) = self.write_set.get(key.as_slice()) {
if let Some(entry) = entries.last() {
if entry.is_hard_delete() {
return Ok(None);
}
if entry.timestamp <= timestamp {
if entry.is_tombstone() {
return Ok(None);
}
return Ok(entry.value.clone());
}
}
}
match &self.snapshot {
Some(snapshot) => snapshot.get_at(key.as_slice(), timestamp),
None => Err(Error::NoSnapshot),
}
}
pub fn get_with_options<K>(&self, key: K, _options: &ReadOptions) -> Result<Option<Value>>
where
K: IntoBytes,
{
if self.closed {
return Err(Error::TransactionClosed);
}
if key.as_slice().is_empty() {
return Err(Error::EmptyKey);
}
if self.mode.is_write_only() {
return Err(Error::TransactionWriteOnly);
}
if let Some(last_entry) =
self.write_set.get(key.as_slice()).and_then(|entries| entries.last())
{
if last_entry.is_tombstone() {
return Ok(None);
}
if let Some(v) = &last_entry.value {
return Ok(Some(v.clone()));
}
return Ok(None);
}
match self.snapshot.as_ref().unwrap().get(key.as_slice())? {
Some(val) => {
let resolved_value = self.core.resolve_value(&val.0)?;
Ok(Some(resolved_value))
}
None => Ok(None),
}
}
pub fn range<K>(&self, start: K, end: K) -> Result<impl LSMIterator + '_>
where
K: IntoBytes,
{
let mut options = ReadOptions::default();
options.set_iterate_bounds(Some(start.into_bytes()), Some(end.into_bytes()));
self.range_with_options(&options)
}
pub fn range_with_options(&self, options: &ReadOptions) -> Result<impl LSMIterator + '_> {
let start_key = options.lower_bound.clone().unwrap_or_default();
let end_key = options.upper_bound.clone().unwrap_or_default();
TransactionRangeIterator::new_with_options(self, Arc::clone(&self.core), start_key, end_key)
}
pub fn history<K>(&self, start: K, end: K) -> Result<impl LSMIterator + '_>
where
K: IntoBytes,
{
self.history_with_options(start, end, &HistoryOptions::default())
}
pub fn history_with_options<K>(
&self,
start: K,
end: K,
opts: &HistoryOptions,
) -> Result<impl LSMIterator + '_>
where
K: IntoBytes,
{
if self.closed {
return Err(Error::TransactionClosed);
}
if self.mode.is_write_only() {
return Err(Error::TransactionWriteOnly);
}
if !self.core.opts.enable_versioning {
return Err(Error::InvalidArgument("Versioning not enabled".to_string()));
}
let snapshot = self.snapshot.as_ref().ok_or(Error::NoSnapshot)?;
let inner = snapshot.history_iter(
Some(start.as_slice()),
Some(end.as_slice()),
opts.include_tombstones,
opts.ts_range,
opts.limit,
)?;
let mut write_set_entries: Vec<(&Key, &Entry)> = Vec::new();
let mut hard_delete_keys: std::collections::HashSet<&[u8]> =
std::collections::HashSet::new();
for (key, entry_list) in
self.write_set.range(start.as_slice().to_vec()..end.as_slice().to_vec())
{
if let Some(entry) = entry_list.last() {
if entry.is_hard_delete() {
hard_delete_keys.insert(key.as_slice());
continue;
}
if let Some((ts_start, ts_end)) = opts.ts_range {
if entry.timestamp >= ts_start && entry.timestamp <= ts_end {
write_set_entries.push((key, entry));
}
} else {
write_set_entries.push((key, entry));
}
}
}
Ok(TransactionHistoryIterator::new(
inner,
Arc::clone(&self.core),
write_set_entries,
hard_delete_keys,
opts.include_tombstones,
))
}
fn write(&mut self, e: Entry) -> Result<()> {
if !self.mode.mutable() {
return Err(Error::TransactionReadOnly);
}
if self.closed {
return Err(Error::TransactionClosed);
}
if e.key.is_empty() {
return Err(Error::EmptyKey);
}
let key = e.key.clone();
match self.write_set.entry(key) {
BTreeEntry::Occupied(mut oe) => {
let entries = oe.get_mut();
if let Some(last_entry) = entries.last() {
if last_entry.savepoint_no == e.savepoint_no {
let last_has_explicit_ts = last_entry.timestamp != Entry::COMMIT_TIME;
let new_has_explicit_ts = e.timestamp != Entry::COMMIT_TIME;
if last_has_explicit_ts
&& new_has_explicit_ts
&& last_entry.timestamp != e.timestamp
{
entries.push(e);
} else {
*entries.last_mut().unwrap() = e;
}
} else {
entries.push(e);
}
} else {
entries.push(e);
}
}
BTreeEntry::Vacant(ve) => {
ve.insert(vec![e]);
}
}
Ok(())
}
pub async fn commit(&mut self) -> Result<()> {
if self.closed {
return Err(Error::TransactionClosed);
}
if self.mode.is_read_only() {
return Err(Error::TransactionReadOnly);
}
if self.write_set.is_empty() {
self.closed = true;
return Ok(());
}
self.validate_write_conflicts()?;
let mut batch = Batch::new(0);
let mut latest_writes: Vec<Entry> =
std::mem::take(&mut self.write_set).into_values().flatten().collect();
latest_writes.sort_by_key(|a| a.seqno);
let commit_timestamp = self.core.opts.clock.now();
for entry in latest_writes {
let timestamp = if entry.timestamp != Entry::COMMIT_TIME {
entry.timestamp
} else {
commit_timestamp
};
batch.add_record(entry.kind, entry.key, entry.value, timestamp)?;
}
let should_sync = self.durability == Durability::Immediate;
self.core.commit(batch, should_sync).await?;
self.closed = true;
Ok(())
}
fn validate_write_conflicts(&self) -> Result<()> {
self.core
.inner
.check_keys_conflict(self.write_set.keys().map(|k| k.as_slice()), self.start_seq_num)
}
pub fn rollback(&mut self) {
self.closed = true;
self.write_set.clear();
self.snapshot.take();
self.savepoints = 0;
self.write_seqno = 0;
}
pub fn set_savepoint(&mut self) -> Result<()> {
if !self.mode.mutable() {
return Err(Error::TransactionReadOnly);
}
if self.closed {
return Err(Error::TransactionClosed);
}
self.savepoints += 1;
Ok(())
}
pub fn rollback_to_savepoint(&mut self) -> Result<()> {
if !self.mode.mutable() {
return Err(Error::TransactionReadOnly);
}
if self.closed {
return Err(Error::TransactionClosed);
}
if self.savepoints == 0 {
return Err(Error::TransactionWithoutSavepoint);
}
for entries in self.write_set.values_mut() {
entries.retain(|entry| entry.savepoint_no != self.savepoints);
}
self.write_set.retain(|_, entries| !entries.is_empty());
self.savepoints -= 1;
Ok(())
}
}
impl Drop for Transaction {
fn drop(&mut self) {
self.rollback();
}
}
#[derive(Clone)]
pub(crate) struct Entry {
pub(crate) key: Key,
pub(crate) value: Option<Value>,
pub(crate) kind: InternalKeyKind,
pub(crate) savepoint_no: u32,
pub(crate) seqno: u32,
pub(crate) timestamp: u64,
}
impl Entry {
const COMMIT_TIME: u64 = 0;
fn new<K: IntoBytes, V: IntoBytes>(
key: K,
value: Option<V>,
kind: InternalKeyKind,
savepoint_no: u32,
seqno: u32,
timestamp: u64,
) -> Entry {
Entry {
key: key.into_bytes(),
value: value.map(|v| v.into_bytes()),
kind,
savepoint_no,
seqno,
timestamp,
}
}
fn is_tombstone(&self) -> bool {
let kind = self.kind;
if kind == InternalKeyKind::Delete
|| kind == InternalKeyKind::SoftDelete
|| kind == InternalKeyKind::RangeDelete
{
return true;
}
false
}
fn is_hard_delete(&self) -> bool {
self.kind == InternalKeyKind::Delete || self.kind == InternalKeyKind::RangeDelete
}
}
#[derive(Clone, Copy, PartialEq)]
enum CurrentSource {
Snapshot,
WriteSet,
None,
}
pub(crate) struct TransactionRangeIterator<'a> {
snapshot_iter: SnapshotIterator<'a>,
core: Arc<Core>,
write_set_entries: Vec<(&'a Key, &'a Entry)>,
ws_pos: Option<usize>,
is_key_equal: bool,
current_source: CurrentSource,
ws_encoded_key_buf: Vec<u8>,
direction: MergeDirection,
initialized: bool,
}
impl<'a> TransactionRangeIterator<'a> {
pub(crate) fn new_with_options(
tx: &'a Transaction,
core: Arc<Core>,
start_key: Vec<u8>,
end_key: Vec<u8>,
) -> Result<Self> {
if tx.closed {
return Err(Error::TransactionClosed);
}
if tx.mode.is_write_only() {
return Err(Error::TransactionWriteOnly);
}
let snapshot = match &tx.snapshot {
Some(snap) => snap,
None => return Err(Error::NoSnapshot),
};
let snapshot_iter = snapshot.range(Some(start_key.as_slice()), Some(end_key.as_slice()))?;
let mut write_set_entries: Vec<(&'a Key, &'a Entry)> = Vec::new();
for (key, entry_list) in tx.write_set.range(start_key..end_key) {
if let Some(entry) = entry_list.last() {
write_set_entries.push((key, entry));
}
}
Ok(Self {
snapshot_iter,
core,
write_set_entries,
ws_pos: None,
is_key_equal: false,
current_source: CurrentSource::None,
ws_encoded_key_buf: Vec::new(),
direction: MergeDirection::Forward,
initialized: false,
})
}
fn ws_valid(&self) -> bool {
self.ws_pos.is_some()
}
fn ws_key(&self) -> &[u8] {
debug_assert!(self.ws_valid());
self.write_set_entries[self.ws_pos.unwrap()].0.as_slice()
}
fn ws_is_tombstone(&self) -> bool {
debug_assert!(self.ws_valid());
self.write_set_entries[self.ws_pos.unwrap()].1.is_tombstone()
}
fn advance_ws(&mut self) {
if let Some(pos) = self.ws_pos {
self.ws_pos = match self.direction {
MergeDirection::Forward => {
if pos + 1 < self.write_set_entries.len() {
Some(pos + 1)
} else {
None
}
}
MergeDirection::Backward => {
if pos > 0 {
Some(pos - 1)
} else {
None
}
}
};
}
}
fn seek_ws(&mut self, target: &[u8]) {
let pos = self.write_set_entries.partition_point(|(k, _)| k.as_slice() < target);
self.ws_pos = if pos < self.write_set_entries.len() {
Some(pos)
} else {
None
};
}
fn seek_ws_first(&mut self) {
self.ws_pos = if self.write_set_entries.is_empty() {
None
} else {
Some(0)
};
}
fn seek_ws_last(&mut self) {
self.ws_pos = if self.write_set_entries.is_empty() {
None
} else {
Some(self.write_set_entries.len() - 1)
};
}
fn populate_ws_encoded_key(&mut self) {
let Some(pos) = self.ws_pos else {
return;
};
let (key, entry) = self.write_set_entries[pos];
self.ws_encoded_key_buf.clear();
self.ws_encoded_key_buf.extend_from_slice(key);
let trailer = ((entry.seqno as u64) << 8) | (entry.kind as u64);
self.ws_encoded_key_buf.extend_from_slice(&trailer.to_be_bytes());
self.ws_encoded_key_buf.extend_from_slice(&entry.timestamp.to_be_bytes());
}
fn position_to_min(&mut self) -> Result<bool> {
loop {
self.is_key_equal = false;
let snap_valid = self.snapshot_iter.valid();
let ws_valid = self.ws_valid();
self.current_source = match (snap_valid, ws_valid) {
(false, false) => CurrentSource::None,
(true, false) => CurrentSource::Snapshot,
(false, true) => {
if self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
(true, true) => {
let snap_key = self.snapshot_iter.key().user_key();
let ws_key = self.ws_key();
match snap_key.cmp(ws_key) {
Ordering::Less => CurrentSource::Snapshot,
Ordering::Greater => {
if self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
self.is_key_equal = true;
if self.ws_is_tombstone() {
self.snapshot_iter.next()?;
self.advance_ws();
self.is_key_equal = false;
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
}
}
};
return Ok(self.current_source != CurrentSource::None);
}
}
fn position_to_max(&mut self) -> Result<bool> {
loop {
self.is_key_equal = false;
let snap_valid = self.snapshot_iter.valid();
let ws_valid = self.ws_valid();
self.current_source = match (snap_valid, ws_valid) {
(false, false) => CurrentSource::None,
(true, false) => CurrentSource::Snapshot,
(false, true) => {
if self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
(true, true) => {
let snap_key = self.snapshot_iter.key().user_key();
let ws_key = self.ws_key();
match snap_key.cmp(ws_key) {
Ordering::Greater => CurrentSource::Snapshot,
Ordering::Less => {
if self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
self.is_key_equal = true;
if self.ws_is_tombstone() {
self.snapshot_iter.prev()?;
self.advance_ws();
self.is_key_equal = false;
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
}
}
};
return Ok(self.current_source != CurrentSource::None);
}
}
}
impl LSMIterator for TransactionRangeIterator<'_> {
fn seek(&mut self, target: &[u8]) -> Result<bool> {
self.direction = MergeDirection::Forward;
self.initialized = true;
self.is_key_equal = false;
let mut encoded = target.to_vec();
encoded.extend_from_slice(&u64::MAX.to_be_bytes()); encoded.extend_from_slice(&u64::MAX.to_be_bytes()); self.snapshot_iter.seek(&encoded)?;
self.seek_ws(target);
self.position_to_min()
}
fn seek_first(&mut self) -> Result<bool> {
self.direction = MergeDirection::Forward;
self.initialized = true;
self.is_key_equal = false;
self.snapshot_iter.seek_first()?;
self.seek_ws_first();
self.position_to_min()
}
fn seek_last(&mut self) -> Result<bool> {
self.direction = MergeDirection::Backward;
self.initialized = true;
self.is_key_equal = false;
self.snapshot_iter.seek_last()?;
self.seek_ws_last();
self.position_to_max()
}
fn next(&mut self) -> Result<bool> {
if !self.initialized {
return self.seek_first();
}
if self.direction != MergeDirection::Forward {
self.direction = MergeDirection::Forward;
self.is_key_equal = false;
if !self.snapshot_iter.valid() || !self.ws_valid() {
self.seek_ws_first();
} else if self.current_source == CurrentSource::Snapshot {
self.advance_ws();
} else {
self.snapshot_iter.next()?;
}
if self.snapshot_iter.valid()
&& self.ws_valid()
&& self.snapshot_iter.key().user_key() == self.ws_key()
{
self.is_key_equal = true;
}
}
if self.is_key_equal {
self.snapshot_iter.next()?;
self.advance_ws();
self.is_key_equal = false;
} else {
match self.current_source {
CurrentSource::Snapshot => {
self.snapshot_iter.next()?;
}
CurrentSource::WriteSet => {
self.advance_ws();
}
CurrentSource::None => return Ok(false),
}
}
self.position_to_min()
}
fn prev(&mut self) -> Result<bool> {
if !self.initialized {
return self.seek_last();
}
if self.direction != MergeDirection::Backward {
self.direction = MergeDirection::Backward;
self.is_key_equal = false;
if !self.snapshot_iter.valid() || !self.ws_valid() {
self.seek_ws_last();
} else if self.current_source == CurrentSource::Snapshot {
self.advance_ws();
} else {
self.snapshot_iter.prev()?;
}
if self.snapshot_iter.valid()
&& self.ws_valid()
&& self.snapshot_iter.key().user_key() == self.ws_key()
{
self.is_key_equal = true;
}
}
if self.is_key_equal {
self.snapshot_iter.prev()?;
self.advance_ws();
self.is_key_equal = false;
} else {
match self.current_source {
CurrentSource::Snapshot => {
self.snapshot_iter.prev()?;
}
CurrentSource::WriteSet => {
self.advance_ws();
}
CurrentSource::None => return Ok(false),
}
}
self.position_to_max()
}
fn valid(&self) -> bool {
self.current_source != CurrentSource::None
}
fn key(&self) -> InternalKeyRef<'_> {
debug_assert!(self.valid());
match self.current_source {
CurrentSource::Snapshot => self.snapshot_iter.key(),
CurrentSource::WriteSet => InternalKeyRef::from_encoded(&self.ws_encoded_key_buf),
CurrentSource::None => panic!("key() called on invalid iterator"),
}
}
fn value_encoded(&self) -> Result<&[u8]> {
debug_assert!(self.valid());
match self.current_source {
CurrentSource::Snapshot => self.snapshot_iter.value_encoded(),
CurrentSource::WriteSet => {
let entry = self.write_set_entries[self.ws_pos.unwrap()].1;
Ok(entry.value.as_ref().map_or(&[], |v| v.as_slice()))
}
CurrentSource::None => panic!("value() called on invalid iterator"),
}
}
fn value(&self) -> Result<Value> {
debug_assert!(self.valid());
let raw = self.value_encoded()?;
if self.current_source == CurrentSource::WriteSet {
Ok(raw.to_vec())
} else {
self.core.resolve_value(raw)
}
}
}
pub(crate) struct TransactionHistoryIterator<'a> {
inner: HistoryIterator<'a>,
core: Arc<Core>,
write_set_entries: Vec<(&'a Key, &'a Entry)>,
hard_delete_keys: std::collections::HashSet<&'a [u8]>,
ws_pos: Option<usize>,
is_key_equal: bool,
current_source: CurrentSource,
ws_encoded_key_buf: Vec<u8>,
direction: MergeDirection,
initialized: bool,
include_tombstones: bool,
}
impl<'a> TransactionHistoryIterator<'a> {
pub(crate) fn new(
inner: HistoryIterator<'a>,
core: Arc<Core>,
write_set_entries: Vec<(&'a Key, &'a Entry)>,
hard_delete_keys: std::collections::HashSet<&'a [u8]>,
include_tombstones: bool,
) -> Self {
Self {
inner,
core,
write_set_entries,
hard_delete_keys,
ws_pos: None,
is_key_equal: false,
current_source: CurrentSource::None,
ws_encoded_key_buf: Vec::new(),
direction: MergeDirection::Forward,
initialized: false,
include_tombstones,
}
}
fn ws_valid(&self) -> bool {
self.ws_pos.is_some()
}
fn ws_key(&self) -> &[u8] {
debug_assert!(self.ws_valid());
self.write_set_entries[self.ws_pos.unwrap()].0.as_slice()
}
fn ws_timestamp(&self) -> u64 {
debug_assert!(self.ws_valid());
self.write_set_entries[self.ws_pos.unwrap()].1.timestamp
}
fn ws_is_tombstone(&self) -> bool {
debug_assert!(self.ws_valid());
self.write_set_entries[self.ws_pos.unwrap()].1.is_tombstone()
}
fn advance_ws(&mut self) {
if let Some(pos) = self.ws_pos {
self.ws_pos = match self.direction {
MergeDirection::Forward => {
if pos + 1 < self.write_set_entries.len() {
Some(pos + 1)
} else {
None
}
}
MergeDirection::Backward => {
if pos > 0 {
Some(pos - 1)
} else {
None
}
}
};
}
}
fn seek_ws(&mut self, target: &[u8]) {
let pos = self.write_set_entries.partition_point(|(k, _)| k.as_slice() < target);
self.ws_pos = if pos < self.write_set_entries.len() {
Some(pos)
} else {
None
};
}
fn seek_ws_first(&mut self) {
self.ws_pos = if self.write_set_entries.is_empty() {
None
} else {
Some(0)
};
}
fn seek_ws_last(&mut self) {
self.ws_pos = if self.write_set_entries.is_empty() {
None
} else {
Some(self.write_set_entries.len() - 1)
};
}
fn populate_ws_encoded_key(&mut self) {
let Some(pos) = self.ws_pos else {
return;
};
let (key, entry) = self.write_set_entries[pos];
self.ws_encoded_key_buf.clear();
self.ws_encoded_key_buf.extend_from_slice(key);
let trailer = ((entry.seqno as u64) << 8) | (entry.kind as u64);
self.ws_encoded_key_buf.extend_from_slice(&trailer.to_be_bytes());
self.ws_encoded_key_buf.extend_from_slice(&entry.timestamp.to_be_bytes());
}
fn position_to_min(&mut self) -> Result<bool> {
loop {
self.is_key_equal = false;
let hist_valid = self.inner.valid();
let ws_valid = self.ws_valid();
if hist_valid {
let hist_key = self.inner.key().user_key();
if self.hard_delete_keys.contains(hist_key) {
self.inner.next()?;
continue;
}
}
self.current_source = match (hist_valid, ws_valid) {
(false, false) => CurrentSource::None,
(true, false) => CurrentSource::Snapshot,
(false, true) => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
(true, true) => {
let hist_key = self.inner.key().user_key();
let hist_ts = self.inner.key().timestamp();
let ws_key = self.ws_key();
let ws_ts = self.ws_timestamp();
match hist_key.cmp(ws_key) {
Ordering::Less => CurrentSource::Snapshot,
Ordering::Greater => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
match hist_ts.cmp(&ws_ts) {
Ordering::Greater => CurrentSource::Snapshot,
Ordering::Less => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
self.is_key_equal = true;
if !self.include_tombstones && self.ws_is_tombstone() {
self.inner.next()?;
self.advance_ws();
self.is_key_equal = false;
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
}
}
}
}
};
return Ok(self.current_source != CurrentSource::None);
}
}
fn position_to_max(&mut self) -> Result<bool> {
loop {
self.is_key_equal = false;
let hist_valid = self.inner.valid();
let ws_valid = self.ws_valid();
if hist_valid {
let hist_key = self.inner.key().user_key();
if self.hard_delete_keys.contains(hist_key) {
self.inner.prev()?;
continue;
}
}
self.current_source = match (hist_valid, ws_valid) {
(false, false) => CurrentSource::None,
(true, false) => CurrentSource::Snapshot,
(false, true) => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
(true, true) => {
let hist_key = self.inner.key().user_key();
let hist_ts = self.inner.key().timestamp();
let ws_key = self.ws_key();
let ws_ts = self.ws_timestamp();
match hist_key.cmp(ws_key) {
Ordering::Greater => CurrentSource::Snapshot,
Ordering::Less => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
match hist_ts.cmp(&ws_ts) {
Ordering::Less => CurrentSource::Snapshot,
Ordering::Greater => {
if !self.include_tombstones && self.ws_is_tombstone() {
self.advance_ws();
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
Ordering::Equal => {
self.is_key_equal = true;
if !self.include_tombstones && self.ws_is_tombstone() {
self.inner.prev()?;
self.advance_ws();
self.is_key_equal = false;
continue;
}
self.populate_ws_encoded_key();
CurrentSource::WriteSet
}
}
}
}
}
};
return Ok(self.current_source != CurrentSource::None);
}
}
pub fn seek_first(&mut self) -> Result<bool> {
self.direction = MergeDirection::Forward;
self.initialized = true;
self.is_key_equal = false;
self.inner.seek_first()?;
self.seek_ws_first();
self.position_to_min()
}
pub fn seek_last(&mut self) -> Result<bool> {
self.direction = MergeDirection::Backward;
self.initialized = true;
self.is_key_equal = false;
self.inner.seek_last()?;
self.seek_ws_last();
self.position_to_max()
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<bool> {
if !self.initialized {
return self.seek_first();
}
if self.direction != MergeDirection::Forward {
self.direction = MergeDirection::Forward;
self.is_key_equal = false;
if !self.inner.valid() || !self.ws_valid() {
self.seek_ws_first();
} else if self.current_source == CurrentSource::Snapshot {
self.advance_ws();
} else {
self.inner.next()?;
}
if self.inner.valid()
&& self.ws_valid()
&& self.inner.key().user_key() == self.ws_key()
&& self.inner.key().timestamp() == self.ws_timestamp()
{
self.is_key_equal = true;
}
}
if self.is_key_equal {
self.inner.next()?;
self.advance_ws();
self.is_key_equal = false;
} else {
match self.current_source {
CurrentSource::Snapshot => {
self.inner.next()?;
}
CurrentSource::WriteSet => {
self.advance_ws();
}
CurrentSource::None => return Ok(false),
}
}
self.position_to_min()
}
pub fn prev(&mut self) -> Result<bool> {
if !self.initialized {
return self.seek_last();
}
if self.direction != MergeDirection::Backward {
self.direction = MergeDirection::Backward;
self.is_key_equal = false;
if !self.inner.valid() || !self.ws_valid() {
self.seek_ws_last();
} else if self.current_source == CurrentSource::Snapshot {
self.advance_ws();
} else {
self.inner.prev()?;
}
if self.inner.valid()
&& self.ws_valid()
&& self.inner.key().user_key() == self.ws_key()
&& self.inner.key().timestamp() == self.ws_timestamp()
{
self.is_key_equal = true;
}
}
if self.is_key_equal {
self.inner.prev()?;
self.advance_ws();
self.is_key_equal = false;
} else {
match self.current_source {
CurrentSource::Snapshot => {
self.inner.prev()?;
}
CurrentSource::WriteSet => {
self.advance_ws();
}
CurrentSource::None => return Ok(false),
}
}
self.position_to_max()
}
pub fn valid(&self) -> bool {
self.current_source != CurrentSource::None
}
}
impl LSMIterator for TransactionHistoryIterator<'_> {
fn seek(&mut self, target: &[u8]) -> Result<bool> {
self.direction = MergeDirection::Forward;
self.initialized = true;
self.is_key_equal = false;
let mut encoded = target.to_vec();
encoded.extend_from_slice(&u64::MAX.to_be_bytes()); encoded.extend_from_slice(&u64::MAX.to_be_bytes()); self.inner.seek(&encoded)?;
self.seek_ws(target);
self.position_to_min()
}
fn seek_first(&mut self) -> Result<bool> {
TransactionHistoryIterator::seek_first(self)
}
fn seek_last(&mut self) -> Result<bool> {
TransactionHistoryIterator::seek_last(self)
}
fn next(&mut self) -> Result<bool> {
TransactionHistoryIterator::next(self)
}
fn prev(&mut self) -> Result<bool> {
TransactionHistoryIterator::prev(self)
}
fn valid(&self) -> bool {
TransactionHistoryIterator::valid(self)
}
fn key(&self) -> InternalKeyRef<'_> {
debug_assert!(self.valid());
match self.current_source {
CurrentSource::Snapshot => self.inner.key(),
CurrentSource::WriteSet => InternalKeyRef::from_encoded(&self.ws_encoded_key_buf),
CurrentSource::None => panic!("key() called on invalid iterator"),
}
}
fn value_encoded(&self) -> Result<&[u8]> {
debug_assert!(self.valid());
match self.current_source {
CurrentSource::Snapshot => self.inner.value_encoded(),
CurrentSource::WriteSet => {
let entry = self.write_set_entries[self.ws_pos.unwrap()].1;
Ok(entry.value.as_ref().map_or(&[], |v| v.as_slice()))
}
CurrentSource::None => panic!("value() called on invalid iterator"),
}
}
fn value(&self) -> Result<Value> {
debug_assert!(self.valid());
let raw = self.value_encoded()?;
if self.current_source == CurrentSource::WriteSet {
Ok(raw.to_vec())
} else {
self.core.resolve_value(raw)
}
}
}