use crate::{version::Version, version_clock::VersionClock, StmError, TVar};
use read_set::ReadSet;
mod any_var;
mod read_set;
mod write_set;
use write_set::WriteSet;
pub struct Context<'var> {
read_version: Version,
write_set: WriteSet<'var>,
read_set: ReadSet<'var>,
}
impl<'var> Context<'var> {
pub fn new(read_version: Version) -> Self {
Context {
read_version,
write_set: WriteSet::new(),
read_set: ReadSet::new(),
}
}
pub fn read<T: Copy>(&mut self, var: &'var TVar<T>) -> Result<T, StmError> {
self.read_set.log(var);
if let Some(wrote_value) = self.write_set.try_read(var) {
Ok(wrote_value)
} else {
var.read_with_check(self.read_version)
.ok_or_else(|| match () {
#[cfg(not(feature = "retry_info"))]
() => StmError::Retry,
#[cfg(feature = "retry_info")]
() => StmError::Retry("Post-validation failed"),
})
}
}
pub fn write<T: Copy>(&mut self, var: &'var TVar<T>, value: T) -> Result<(), StmError> {
self.write_set.log(var, value);
Ok(())
}
pub fn reset(&mut self, read_version: Version) {
self.read_version = read_version;
self.write_set.clear();
self.read_set.clear();
}
pub fn try_commit(&mut self, clock: &VersionClock) -> Result<(), StmError> {
let mut guard = self.write_set
.try_lock(10)
.ok_or_else(|| match () {
#[cfg(not(feature = "retry_info"))]
() => StmError::Retry,
#[cfg(feature = "retry_info")]
() => StmError::Retry("Lock write-set failed"),
})?;
let write_version = clock.tick();
if write_version > self.read_version + 1 {
for read_entry in self.read_set.iter_vars() {
let mut version = read_entry.lock.version();
if version.is_locked() {
let locked_by_self = guard
.iter_vars()
.any(|write_entry| read_entry == write_entry);
if !locked_by_self {
return Err(match () {
#[cfg(not(feature = "retry_info"))]
() => StmError::Retry,
#[cfg(feature = "retry_info")]
() => StmError::Retry(
"Validate Read-Set Failed: TVar was locked by other transaction",
),
});
}
version = -version
}
if version > self.read_version {
return Err(match () {
#[cfg(not(feature = "retry_info"))]
() => StmError::Retry,
#[cfg(feature = "retry_info")]
() => StmError::Retry(
"Validate Read-Set Failed: TVar was changed by other transaction",
),
});
}
}
}
guard.set_version(write_version);
guard.write_data_from_buffer();
Ok(())
}
}