use parking_lot::Mutex;
use std::collections::HashSet;
use std::sync::Arc;
use crate::common::{Key, Value};
use crate::errors::NitriteResult;
use crate::store::{EntryIteratorProvider, KeyIteratorProvider, NitriteMap, ValueIteratorProvider};
pub struct TransactionEntryProvider {
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
current_key: Option<Key>,
current_phase: IterationPhase,
has_started_reverse: bool,
}
#[derive(Debug, Clone, Copy, PartialEq)]
enum IterationPhase {
Backing,
Primary,
Done,
}
impl TransactionEntryProvider {
pub fn new(
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
) -> NitriteResult<Self> {
Ok(TransactionEntryProvider {
backing_map,
primary_map,
tombstones,
cleared,
current_key: None,
current_phase: IterationPhase::Backing,
has_started_reverse: false,
})
}
}
impl EntryIteratorProvider for TransactionEntryProvider {
fn next_entry(&mut self) -> Option<NitriteResult<(Key, Value)>> {
if *self.cleared.lock() {
return None;
}
loop {
match self.current_phase {
IterationPhase::Backing => {
let next_key_result = match &self.current_key {
Some(key) => self.backing_map.higher_key(key),
None => self.backing_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
match self.backing_map.get(&key) {
Ok(Some(value)) => return Some(Ok((key, value))),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Primary => {
let next_key_result = match &self.current_key {
Some(key) => self.primary_map.higher_key(key),
None => self.primary_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
match self.primary_map.get(&key) {
Ok(Some(value)) => return Some(Ok((key, value))),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
fn prev_entry(&mut self) -> Option<NitriteResult<(Key, Value)>> {
if *self.cleared.lock() {
return None;
}
if !self.has_started_reverse {
self.has_started_reverse = true;
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
loop {
match self.current_phase {
IterationPhase::Primary => {
let prev_key_result = match &self.current_key {
Some(key) => self.primary_map.lower_key(key),
None => self.primary_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
match self.primary_map.get(&key) {
Ok(Some(value)) => return Some(Ok((key, value))),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Backing;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Backing => {
let prev_key_result = match &self.current_key {
Some(key) => self.backing_map.lower_key(key),
None => self.backing_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
match self.backing_map.get(&key) {
Ok(Some(value)) => return Some(Ok((key, value))),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
}
pub struct TransactionKeyProvider {
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
current_key: Option<Key>,
current_phase: IterationPhase,
has_started_reverse: bool,
}
impl TransactionKeyProvider {
pub fn new(
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
) -> NitriteResult<Self> {
Ok(TransactionKeyProvider {
backing_map,
primary_map,
tombstones,
cleared,
current_key: None,
current_phase: IterationPhase::Backing,
has_started_reverse: false,
})
}
}
impl KeyIteratorProvider for TransactionKeyProvider {
fn next_key(&mut self) -> Option<NitriteResult<Key>> {
if *self.cleared.lock() {
return None;
}
loop {
match self.current_phase {
IterationPhase::Backing => {
let next_key_result = match &self.current_key {
Some(key) => self.backing_map.higher_key(key),
None => self.backing_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
return Some(Ok(key));
}
Ok(None) => {
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Primary => {
let next_key_result = match &self.current_key {
Some(key) => self.primary_map.higher_key(key),
None => self.primary_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
return Some(Ok(key));
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
fn prev_key(&mut self) -> Option<NitriteResult<Key>> {
if *self.cleared.lock() {
return None;
}
if !self.has_started_reverse {
self.has_started_reverse = true;
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
loop {
match self.current_phase {
IterationPhase::Primary => {
let prev_key_result = match &self.current_key {
Some(key) => self.primary_map.lower_key(key),
None => self.primary_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
return Some(Ok(key));
}
Ok(None) => {
self.current_phase = IterationPhase::Backing;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Backing => {
let prev_key_result = match &self.current_key {
Some(key) => self.backing_map.lower_key(key),
None => self.backing_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
return Some(Ok(key));
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
}
pub struct TransactionValueProvider {
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
current_key: Option<Key>,
current_phase: IterationPhase,
has_started_reverse: bool,
}
impl TransactionValueProvider {
pub fn new(
backing_map: NitriteMap,
primary_map: NitriteMap,
tombstones: Arc<Mutex<HashSet<Key>>>,
cleared: Arc<Mutex<bool>>,
) -> NitriteResult<Self> {
Ok(TransactionValueProvider {
backing_map,
primary_map,
tombstones,
cleared,
current_key: None,
current_phase: IterationPhase::Backing,
has_started_reverse: false,
})
}
}
impl ValueIteratorProvider for TransactionValueProvider {
fn next_value(&mut self) -> Option<NitriteResult<Value>> {
if *self.cleared.lock() {
return None;
}
loop {
match self.current_phase {
IterationPhase::Backing => {
let next_key_result = match &self.current_key {
Some(key) => self.backing_map.higher_key(key),
None => self.backing_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
match self.backing_map.get(&key) {
Ok(Some(value)) => return Some(Ok(value)),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Primary => {
let next_key_result = match &self.current_key {
Some(key) => self.primary_map.higher_key(key),
None => self.primary_map.first_key(),
};
match next_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
match self.primary_map.get(&key) {
Ok(Some(value)) => return Some(Ok(value)),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
fn prev_value(&mut self) -> Option<NitriteResult<Value>> {
if *self.cleared.lock() {
return None;
}
if !self.has_started_reverse {
self.has_started_reverse = true;
self.current_phase = IterationPhase::Primary;
self.current_key = None;
}
loop {
match self.current_phase {
IterationPhase::Primary => {
let prev_key_result = match &self.current_key {
Some(key) => self.primary_map.lower_key(key),
None => self.primary_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
let in_backing = self.backing_map.contains_key(&key).unwrap_or(false);
let is_tombstoned = {
let tombstones = self.tombstones.lock();
tombstones.contains(&key)
};
if in_backing || is_tombstoned {
continue;
}
match self.primary_map.get(&key) {
Ok(Some(value)) => return Some(Ok(value)),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Backing;
self.current_key = None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Backing => {
let prev_key_result = match &self.current_key {
Some(key) => self.backing_map.lower_key(key),
None => self.backing_map.last_key(),
};
match prev_key_result {
Ok(Some(key)) => {
self.current_key = Some(key.clone());
match self.backing_map.get(&key) {
Ok(Some(value)) => return Some(Ok(value)),
Ok(None) => continue,
Err(e) => return Some(Err(e)),
}
}
Ok(None) => {
self.current_phase = IterationPhase::Done;
return None;
}
Err(e) => return Some(Err(e)),
}
}
IterationPhase::Done => {
return None;
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::common::{AttributeAware, Attributes, Key, Value};
use crate::store::{
EntryIterator, KeyIterator, NitriteMapProvider, NitriteStore, ValueIterator,
};
use std::sync::Arc as StdArc;
struct MockNitriteMapData {
entries: std::collections::BTreeMap<String, String>,
}
#[derive(Clone)]
struct MockNitriteMapImpl {
data: StdArc<parking_lot::Mutex<MockNitriteMapData>>,
}
impl MockNitriteMapImpl {
fn new(entries: Vec<(String, String)>) -> Self {
let mut map = std::collections::BTreeMap::new();
for (k, v) in entries {
map.insert(k, v);
}
MockNitriteMapImpl {
data: StdArc::new(parking_lot::Mutex::new(MockNitriteMapData { entries: map })),
}
}
fn empty() -> Self {
MockNitriteMapImpl {
data: StdArc::new(parking_lot::Mutex::new(MockNitriteMapData {
entries: std::collections::BTreeMap::new(),
})),
}
}
}
impl AttributeAware for MockNitriteMapImpl {
fn attributes(&self) -> crate::errors::NitriteResult<Option<Attributes>> {
Ok(None)
}
fn set_attributes(&self, _attributes: Attributes) -> crate::errors::NitriteResult<()> {
Ok(())
}
}
impl NitriteMapProvider for MockNitriteMapImpl {
fn contains_key(&self, key: &Key) -> crate::errors::NitriteResult<bool> {
let data = self.data.lock();
Ok(data.entries.contains_key(key.as_string().unwrap()))
}
fn get(&self, key: &Key) -> crate::errors::NitriteResult<Option<Value>> {
let data = self.data.lock();
Ok(data
.entries
.get(key.as_string().unwrap())
.map(|v| Value::from(v.as_str())))
}
fn clear(&self) -> crate::errors::NitriteResult<()> {
let mut data = self.data.lock();
data.entries.clear();
Ok(())
}
fn is_closed(&self) -> crate::errors::NitriteResult<bool> {
Ok(false)
}
fn close(&self) -> crate::errors::NitriteResult<()> {
Ok(())
}
fn values(&self) -> crate::errors::NitriteResult<ValueIterator> {
Err(crate::errors::NitriteError::new(
"Not implemented",
crate::errors::ErrorKind::InvalidOperation,
))
}
fn keys(&self) -> crate::errors::NitriteResult<KeyIterator> {
Err(crate::errors::NitriteError::new(
"Not implemented",
crate::errors::ErrorKind::InvalidOperation,
))
}
fn remove(&self, key: &Key) -> crate::errors::NitriteResult<Option<Value>> {
let mut data = self.data.lock();
Ok(data
.entries
.remove(key.as_string().unwrap())
.map(|v| Value::from(v.as_str())))
}
fn put(&self, key: Key, value: Value) -> crate::errors::NitriteResult<()> {
let mut data = self.data.lock();
data.entries.insert(
key.as_string().unwrap().to_string(),
value.as_string().unwrap().to_string(),
);
Ok(())
}
fn size(&self) -> crate::errors::NitriteResult<u64> {
let data = self.data.lock();
Ok(data.entries.len() as u64)
}
fn put_if_absent(
&self,
key: Key,
value: Value,
) -> crate::errors::NitriteResult<Option<Value>> {
let mut data = self.data.lock();
let result = data
.entries
.entry(key.as_string().unwrap().to_string())
.or_insert_with(|| value.as_string().unwrap().to_string())
.clone();
Ok(Some(Value::from(result.as_str())))
}
fn first_key(&self) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
Ok(data.entries.keys().next().map(|k| Key::from(k.as_str())))
}
fn last_key(&self) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
Ok(data.entries.keys().last().map(|k| Key::from(k.as_str())))
}
fn higher_key(&self, key: &Key) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
let key_name = key.as_string().unwrap().clone();
Ok(data
.entries
.range((
std::ops::Bound::Excluded(key_name),
std::ops::Bound::Unbounded,
))
.next()
.map(|(k, _)| Key::from(k.as_str())))
}
fn ceiling_key(&self, key: &Key) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
let key_name = key.as_string().unwrap().clone();
Ok(data
.entries
.range((
std::ops::Bound::Included(key_name),
std::ops::Bound::Unbounded,
))
.next()
.map(|(k, _)| Key::from(k.as_str())))
}
fn lower_key(&self, key: &Key) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
let key_name = key.as_string().unwrap().clone();
Ok(data
.entries
.range((
std::ops::Bound::Unbounded,
std::ops::Bound::Excluded(key_name),
))
.last()
.map(|(k, _)| Key::from(k.as_str())))
}
fn floor_key(&self, key: &Key) -> crate::errors::NitriteResult<Option<Key>> {
let data = self.data.lock();
let key_name = key.as_string().unwrap().clone();
Ok(data
.entries
.range((
std::ops::Bound::Unbounded,
std::ops::Bound::Included(key_name),
))
.last()
.map(|(k, _)| Key::from(k.as_str())))
}
fn is_empty(&self) -> crate::errors::NitriteResult<bool> {
let data = self.data.lock();
Ok(data.entries.is_empty())
}
fn get_store(&self) -> crate::errors::NitriteResult<NitriteStore> {
Err(crate::errors::NitriteError::new(
"Not implemented",
crate::errors::ErrorKind::InvalidOperation,
))
}
fn get_name(&self) -> crate::errors::NitriteResult<String> {
Ok("mock".to_string())
}
fn entries(&self) -> crate::errors::NitriteResult<EntryIterator> {
Err(crate::errors::NitriteError::new(
"Not implemented",
crate::errors::ErrorKind::InvalidOperation,
))
}
fn reverse_entries(&self) -> crate::errors::NitriteResult<std::iter::Rev<EntryIterator>> {
Err(crate::errors::NitriteError::new(
"Not implemented",
crate::errors::ErrorKind::InvalidOperation,
))
}
fn dispose(&self) -> crate::errors::NitriteResult<()> {
Ok(())
}
fn is_dropped(&self) -> crate::errors::NitriteResult<bool> {
Ok(false)
}
}
#[test]
fn test_entry_provider_creation() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let provider = TransactionEntryProvider::new(backing, primary, tombstones, cleared);
assert!(provider.is_ok());
}
#[test]
fn test_entry_provider_empty_maps() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_entry();
assert!(result.is_none());
}
#[test]
fn test_entry_provider_from_backing_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.next_entry();
assert!(entry.is_some());
let result = entry.unwrap();
assert!(result.is_ok());
let (key, value) = result.unwrap();
assert_eq!(key.as_string().unwrap(), &"key1".to_string());
assert_eq!(value.as_string().unwrap(), &"val1".to_string());
}
#[test]
fn test_entry_provider_from_primary_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.next_entry();
assert!(entry.is_some());
let result = entry.unwrap();
assert!(result.is_ok());
let (key, value) = result.unwrap();
assert_eq!(key.as_string().unwrap(), &"key1".to_string());
assert_eq!(value.as_string().unwrap(), &"val1".to_string());
}
#[test]
fn test_entry_provider_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key1"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.next_entry();
assert!(entry.is_some());
let (key, _) = entry.unwrap().unwrap();
assert_eq!(key.as_string().unwrap(), "key2");
}
#[test]
fn test_entry_provider_skips_keys_in_backing() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"newval1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let e1 = provider.next_entry().unwrap().unwrap();
assert_eq!(e1.0.as_string().unwrap(), "key1");
assert_eq!(e1.1.as_string().unwrap(), "newval1");
let e2 = provider.next_entry().unwrap().unwrap();
assert_eq!(e2.0.as_string().unwrap(), "key2");
}
#[test]
fn test_entry_provider_returns_none_when_cleared() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(true));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_entry();
assert!(result.is_none());
}
#[test]
fn test_entry_provider_prev_entry_from_backing() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.prev_entry();
assert!(entry.is_some());
let result = entry.unwrap();
assert!(result.is_ok());
let (key, value) = result.unwrap();
assert_eq!(key.as_string().unwrap(), "key1");
assert_eq!(value.as_string().unwrap(), "val1");
}
#[test]
fn test_entry_provider_prev_entry_from_primary() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.prev_entry();
assert!(entry.is_some());
let (key, _) = entry.unwrap().unwrap();
assert_eq!(key.as_string().unwrap(), "key1");
}
#[test]
fn test_entry_provider_prev_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key2"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let entry = provider.prev_entry();
assert!(entry.is_some());
let (key, _) = entry.unwrap().unwrap();
assert_eq!(key.as_string().unwrap(), "key1");
}
#[test]
fn test_entry_provider_prev_returns_none_when_cleared() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(true));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.prev_entry();
assert!(result.is_none());
}
#[test]
fn test_key_provider_creation() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let provider = TransactionKeyProvider::new(backing, primary, tombstones, cleared);
assert!(provider.is_ok());
}
#[test]
fn test_key_provider_empty_maps() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_key();
assert!(result.is_none());
}
#[test]
fn test_key_provider_from_backing_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let key = provider.next_key();
assert!(key.is_some());
let result = key.unwrap();
assert!(result.is_ok());
assert_eq!(result.unwrap().as_string().unwrap(), "key1");
}
#[test]
fn test_key_provider_from_primary_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let key = provider.next_key();
assert!(key.is_some());
assert_eq!(key.unwrap().unwrap().as_string().unwrap(), "key1");
}
#[test]
fn test_key_provider_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key1"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let key = provider.next_key();
assert_eq!(key.unwrap().unwrap().as_string().unwrap(), "key2");
}
#[test]
fn test_key_provider_returns_none_when_cleared() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(true));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_key();
assert!(result.is_none());
}
#[test]
fn test_key_provider_prev_key() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let key = provider.prev_key();
assert!(key.is_some());
assert_eq!(key.unwrap().unwrap().as_string().unwrap(), "key1");
}
#[test]
fn test_key_provider_prev_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key2"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let key = provider.prev_key();
assert_eq!(key.unwrap().unwrap().as_string().unwrap(), "key1");
}
#[test]
fn test_value_provider_creation() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let provider = TransactionValueProvider::new(backing, primary, tombstones, cleared);
assert!(provider.is_ok());
}
#[test]
fn test_value_provider_empty_maps() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_value();
assert!(result.is_none());
}
#[test]
fn test_value_provider_from_backing_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let value = provider.next_value();
assert!(value.is_some());
let result = value.unwrap();
assert!(result.is_ok());
assert_eq!(result.unwrap().as_string().unwrap(), "val1");
}
#[test]
fn test_value_provider_from_primary_map() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let value = provider.next_value();
assert!(value.is_some());
assert_eq!(value.unwrap().unwrap().as_string().unwrap(), "val1");
}
#[test]
fn test_value_provider_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key1"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let value = provider.next_value();
assert_eq!(value.unwrap().unwrap().as_string().unwrap(), "val2");
}
#[test]
fn test_value_provider_returns_none_when_cleared() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(true));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let result = provider.next_value();
assert!(result.is_none());
}
#[test]
fn test_value_provider_prev_value() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"key1".to_string(),
"val1".to_string(),
)]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let value = provider.prev_value();
assert!(value.is_some());
assert_eq!(value.unwrap().unwrap().as_string().unwrap(), "val1");
}
#[test]
fn test_value_provider_prev_skips_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key2"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let value = provider.prev_value();
assert_eq!(value.unwrap().unwrap().as_string().unwrap(), "val1");
}
#[test]
fn test_entry_provider_multiple_entries_sequence() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("a".to_string(), "val_a".to_string()),
("b".to_string(), "val_b".to_string()),
]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("c".to_string(), "val_c".to_string()),
("d".to_string(), "val_d".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let e1 = provider.next_entry().unwrap().unwrap();
assert_eq!(e1.0.as_string().unwrap(), "a");
let e2 = provider.next_entry().unwrap().unwrap();
assert_eq!(e2.0.as_string().unwrap(), "b");
let e3 = provider.next_entry().unwrap().unwrap();
assert_eq!(e3.0.as_string().unwrap(), "c");
let e4 = provider.next_entry().unwrap().unwrap();
assert_eq!(e4.0.as_string().unwrap(), "d");
let e5 = provider.next_entry();
assert!(e5.is_none());
}
#[test]
fn test_key_provider_multiple_keys_sequence() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"a".to_string(),
"val_a".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("b".to_string(), "val_b".to_string()),
("c".to_string(), "val_c".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionKeyProvider::new(backing, primary, tombstones, cleared).unwrap();
let k1 = provider.next_key().unwrap().unwrap();
assert_eq!(k1.as_string().unwrap(), "a");
let k2 = provider.next_key().unwrap().unwrap();
assert_eq!(k2.as_string().unwrap(), "b");
let k3 = provider.next_key().unwrap().unwrap();
assert_eq!(k3.as_string().unwrap(), "c");
let k4 = provider.next_key();
assert!(k4.is_none());
}
#[test]
fn test_value_provider_multiple_values_sequence() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![(
"a".to_string(),
"val_a".to_string(),
)]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("b".to_string(), "val_b".to_string()),
("c".to_string(), "val_c".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionValueProvider::new(backing, primary, tombstones, cleared).unwrap();
let v1 = provider.next_value().unwrap().unwrap();
assert_eq!(v1.as_string().unwrap(), "val_a");
let v2 = provider.next_value().unwrap().unwrap();
assert_eq!(v2.as_string().unwrap(), "val_b");
let v3 = provider.next_value().unwrap().unwrap();
assert_eq!(v3.as_string().unwrap(), "val_c");
let v4 = provider.next_value();
assert!(v4.is_none());
}
#[test]
fn test_iteration_phase_transitions() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("a".to_string(), "val_a".to_string()),
("b".to_string(), "val_b".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
assert_eq!(provider.current_phase, IterationPhase::Backing);
let e1 = provider.next_entry().unwrap().unwrap();
assert_eq!(e1.0.as_string().unwrap(), &"a".to_string());
assert_eq!(provider.current_phase, IterationPhase::Primary);
let e2 = provider.next_entry().unwrap().unwrap();
assert_eq!(e2.0.as_string().unwrap(), &"b".to_string());
assert_eq!(provider.current_phase, IterationPhase::Primary);
let result = provider.next_entry();
assert!(result.is_none());
assert_eq!(provider.current_phase, IterationPhase::Done);
}
#[test]
fn test_multiple_tombstoned_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::empty());
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "val1".to_string()),
("key2".to_string(), "val2".to_string()),
("key3".to_string(), "val3".to_string()),
]));
let mut tombstones = HashSet::new();
tombstones.insert(Key::from("key1"));
tombstones.insert(Key::from("key3"));
let tombstones = Arc::new(parking_lot::Mutex::new(tombstones));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let e1 = provider.next_entry().unwrap().unwrap();
assert_eq!(e1.0.as_string().unwrap(), "key2");
let e2 = provider.next_entry();
assert!(e2.is_none());
}
#[test]
fn test_backing_and_primary_with_overlapping_keys() {
let backing = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "new_val1".to_string()),
("key2".to_string(), "new_val2".to_string()),
]));
let primary = crate::store::NitriteMap::new(MockNitriteMapImpl::new(vec![
("key1".to_string(), "old_val1".to_string()),
("key3".to_string(), "val3".to_string()),
]));
let tombstones = Arc::new(parking_lot::Mutex::new(HashSet::new()));
let cleared = Arc::new(parking_lot::Mutex::new(false));
let mut provider =
TransactionEntryProvider::new(backing, primary, tombstones, cleared).unwrap();
let e1 = provider.next_entry().unwrap().unwrap();
assert_eq!(e1.0.as_string().unwrap(), "key1");
assert_eq!(e1.1.as_string().unwrap(), "new_val1");
let e2 = provider.next_entry().unwrap().unwrap();
assert_eq!(e2.0.as_string().unwrap(), "key2");
assert_eq!(e2.1.as_string().unwrap(), "new_val2");
let e3 = provider.next_entry().unwrap().unwrap();
assert_eq!(e3.0.as_string().unwrap(), "key3");
assert_eq!(e3.1.as_string().unwrap(), "val3");
assert!(provider.next_entry().is_none());
}
}