use parking_lot::RwLockWriteGuard;
use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};
use crate::{Batch, Error, IVec, Result, Tree};
#[derive(Clone)]
pub struct TransactionalTree {
pub(super) tree: Tree,
pub(super) writes: Rc<RefCell<HashMap<IVec, Option<IVec>>>>,
pub(super) read_cache: Rc<RefCell<HashMap<IVec, Option<IVec>>>>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum UnabortableTransactionError {
Conflict,
Storage(Error),
}
impl fmt::Display for UnabortableTransactionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UnabortableTransactionError::*;
match self {
Conflict => write!(f, "Conflict during transaction"),
Storage(e) => e.fmt(f),
}
}
}
impl std::error::Error for UnabortableTransactionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
UnabortableTransactionError::Storage(ref e) => Some(e),
_ => None,
}
}
}
pub type UnabortableTransactionResult<T> =
std::result::Result<T, UnabortableTransactionError>;
impl From<Error> for UnabortableTransactionError {
fn from(error: Error) -> Self {
UnabortableTransactionError::Storage(error)
}
}
impl<E> From<UnabortableTransactionError> for ConflictableTransactionError<E> {
fn from(error: UnabortableTransactionError) -> Self {
match error {
UnabortableTransactionError::Conflict => {
ConflictableTransactionError::Conflict
}
UnabortableTransactionError::Storage(error) => {
ConflictableTransactionError::Storage(error)
}
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ConflictableTransactionError<T = Error> {
Abort(T),
#[doc(hidden)]
Conflict,
Storage(Error),
}
impl<E: fmt::Display> fmt::Display for ConflictableTransactionError<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ConflictableTransactionError::*;
match self {
Abort(e) => e.fmt(f),
Conflict => write!(f, "Conflict during transaction"),
Storage(e) => e.fmt(f),
}
}
}
impl<E: std::error::Error> std::error::Error
for ConflictableTransactionError<E>
{
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ConflictableTransactionError::Storage(ref e) => Some(e),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TransactionError<T = Error> {
Abort(T),
Storage(Error),
}
impl<E: fmt::Display> fmt::Display for TransactionError<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use TransactionError::*;
match self {
Abort(e) => e.fmt(f),
Storage(e) => e.fmt(f),
}
}
}
impl<E: std::error::Error> std::error::Error for TransactionError<E> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
TransactionError::Storage(ref e) => Some(e),
_ => None,
}
}
}
pub type ConflictableTransactionResult<T, E = ()> =
std::result::Result<T, ConflictableTransactionError<E>>;
impl<T> From<Error> for ConflictableTransactionError<T> {
fn from(error: Error) -> Self {
ConflictableTransactionError::Storage(error)
}
}
pub type TransactionResult<T, E = ()> =
std::result::Result<T, TransactionError<E>>;
impl<T> From<Error> for TransactionError<T> {
fn from(error: Error) -> Self {
TransactionError::Storage(error)
}
}
impl TransactionalTree {
pub fn insert<K, V>(
&self,
key: K,
value: V,
) -> UnabortableTransactionResult<Option<IVec>>
where
IVec: From<K> + From<V>,
K: AsRef<[u8]>,
{
let old = self.get(key.as_ref())?;
let mut writes = self.writes.borrow_mut();
let _last_write =
writes.insert(IVec::from(key), Some(IVec::from(value)));
Ok(old)
}
pub fn remove<K>(
&self,
key: K,
) -> UnabortableTransactionResult<Option<IVec>>
where
IVec: From<K>,
K: AsRef<[u8]>,
{
let old = self.get(key.as_ref());
let mut writes = self.writes.borrow_mut();
let _last_write = writes.insert(IVec::from(key), None);
old
}
pub fn get<K: AsRef<[u8]>>(
&self,
key: K,
) -> UnabortableTransactionResult<Option<IVec>> {
let writes = self.writes.borrow();
if let Some(first_try) = writes.get(key.as_ref()) {
return Ok(first_try.clone());
}
let mut reads = self.read_cache.borrow_mut();
if let Some(second_try) = reads.get(key.as_ref()) {
return Ok(second_try.clone());
}
let get = self.tree.get_inner(key.as_ref())?;
let last = reads.insert(key.as_ref().into(), get.clone());
assert!(last.is_none());
Ok(get)
}
pub fn apply_batch(
&self,
batch: Batch,
) -> UnabortableTransactionResult<()> {
for (k, v_opt) in batch.writes {
if let Some(v) = v_opt {
let _old = self.insert(k, v)?;
} else {
let _old = self.remove(k)?;
}
}
Ok(())
}
fn stage(
&self,
) -> UnabortableTransactionResult<Vec<RwLockWriteGuard<'_, ()>>> {
let guard = self.tree.concurrency_control.write();
Ok(vec![guard])
}
fn unstage(&self) {
unimplemented!()
}
const fn validate(&self) -> bool {
true
}
fn commit(&self) -> Result<()> {
let writes = self.writes.borrow();
for (k, v_opt) in &*writes {
if let Some(v) = v_opt {
let _old = self.tree.insert_inner(k, v)?;
} else {
let _old = self.tree.remove_inner(k)?;
}
}
Ok(())
}
}
pub struct TransactionalTrees {
inner: Vec<TransactionalTree>,
}
impl TransactionalTrees {
fn stage(
&self,
) -> UnabortableTransactionResult<Vec<RwLockWriteGuard<'_, ()>>> {
let mut tree_idxs: Vec<(&[u8], usize)> = self
.inner
.iter()
.enumerate()
.map(|(idx, t)| (&*t.tree.tree_id, idx))
.collect();
tree_idxs.sort_unstable();
let mut last_idx = usize::max_value();
let mut all_guards = vec![];
for (_, idx) in tree_idxs {
if idx == last_idx {
continue;
}
last_idx = idx;
let mut guards = self.inner[idx].stage()?;
all_guards.append(&mut guards);
}
Ok(all_guards)
}
fn unstage(&self) {
for tree in &self.inner {
tree.unstage();
}
}
fn validate(&self) -> bool {
for tree in &self.inner {
if !tree.validate() {
return false;
}
}
true
}
fn commit(&self) -> Result<()> {
let peg = self.inner[0].tree.context.pin_log()?;
for tree in &self.inner {
tree.commit()?;
}
peg.seal_batch()
}
}
pub fn abort<A, T>(t: T) -> ConflictableTransactionResult<A, T> {
Err(ConflictableTransactionError::Abort(t))
}
pub trait Transactional<E = ()> {
type View;
fn make_overlay(&self) -> TransactionalTrees;
fn view_overlay(overlay: &TransactionalTrees) -> Self::View;
fn transaction<F, A>(&self, f: F) -> TransactionResult<A, E>
where
F: Fn(&Self::View) -> ConflictableTransactionResult<A, E>,
{
loop {
let tt = self.make_overlay();
let view = Self::view_overlay(&tt);
let _locks = if let Ok(l) = tt.stage() {
l
} else {
tt.unstage();
continue;
};
let ret = f(&view);
if !tt.validate() {
tt.unstage();
continue;
}
match ret {
Ok(r) => {
tt.commit()?;
return Ok(r);
}
Err(ConflictableTransactionError::Abort(e)) => {
return Err(TransactionError::Abort(e));
}
Err(ConflictableTransactionError::Conflict) => continue,
Err(ConflictableTransactionError::Storage(other)) => {
return Err(TransactionError::Storage(other));
}
}
}
}
}
impl<E> Transactional<E> for &Tree {
type View = TransactionalTree;
fn make_overlay(&self) -> TransactionalTrees {
TransactionalTrees {
inner: vec![TransactionalTree {
tree: (*self).clone(),
writes: Default::default(),
read_cache: Default::default(),
}],
}
}
fn view_overlay(overlay: &TransactionalTrees) -> Self::View {
overlay.inner[0].clone()
}
}
impl<E> Transactional<E> for &&Tree {
type View = TransactionalTree;
fn make_overlay(&self) -> TransactionalTrees {
TransactionalTrees {
inner: vec![TransactionalTree {
tree: (**self).clone(),
writes: Default::default(),
read_cache: Default::default(),
}],
}
}
fn view_overlay(overlay: &TransactionalTrees) -> Self::View {
overlay.inner[0].clone()
}
}
impl<E> Transactional<E> for Tree {
type View = TransactionalTree;
fn make_overlay(&self) -> TransactionalTrees {
TransactionalTrees {
inner: vec![TransactionalTree {
tree: self.clone(),
writes: Default::default(),
read_cache: Default::default(),
}],
}
}
fn view_overlay(overlay: &TransactionalTrees) -> Self::View {
overlay.inner[0].clone()
}
}
macro_rules! repeat_type {
($t:ty, ($($literals:literal),*)) => {
repeat_type!(IMPL $t, (), ($($literals),*))
};
(IMPL $t:ty, (), ($first:literal, $($rest:literal),*)) => {
repeat_type!(IMPL $t, ($t), ($($rest),*))
};
(IMPL $t:ty, ($($partial:tt),*), ($first:literal, $($rest:literal),*)) => {
repeat_type!(IMPL $t, ($t, $($partial),*), ($($rest),*))
};
(IMPL $t:ty, ($($partial:tt),*), ($last:literal)) => {
($($partial),*, $t)
};
}
macro_rules! impl_transactional_tuple_trees {
($($indices:tt),+) => {
impl Transactional for repeat_type!(&Tree, ($($indices),+)) {
type View = repeat_type!(TransactionalTree, ($($indices),+));
fn make_overlay(&self) -> TransactionalTrees {
TransactionalTrees {
inner: vec![
$(
TransactionalTree {
tree: self.$indices.clone(),
writes: Default::default(),
read_cache: Default::default(),
}
),+
],
}
}
fn view_overlay(overlay: &TransactionalTrees) -> Self::View {
(
$(
overlay.inner[$indices].clone()
),+
)
}
}
};
}
impl_transactional_tuple_trees!(0, 1);
impl_transactional_tuple_trees!(0, 1, 2);
impl_transactional_tuple_trees!(0, 1, 2, 3);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
impl_transactional_tuple_trees!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67
);
impl_transactional_tuple_trees!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
59, 60, 61, 62, 63, 64, 65, 66, 67, 68
);