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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use crate::TransactionId;
use std::time::Duration;

/// Concurrent Modification Strategy for resolution of conflict on commit.
///
#[derive(PartialEq, Clone, Debug)]
pub enum TxStrategy {
    ///
    /// Last modification received override all the previous modifications
    ///
    LastWin,

    ///
    /// prepare_commit will fail if the persistent version is more recent of the version when
    /// the update_record/delete_record is executed
    ///
    VersionOnWrite,

    ///
    /// prepare_commit will fail if the persistent version is more recent of the version of the
    /// last read_record_tx, if no read_record_tx was called will follow the same behavior of
    /// VersionOnWrite
    ///
    VersionOnRead,
}
impl Default for TxStrategy {
    fn default() -> Self {
        TxStrategy::LastWin
    }
}

impl TxStrategy {
    pub fn value(&self) -> u8 {
        match *self {
            TxStrategy::LastWin => 1,
            TxStrategy::VersionOnWrite => 2,
            TxStrategy::VersionOnRead => 3,
        }
    }
    pub fn from_value(val: u8) -> TxStrategy {
        match val {
            1 => TxStrategy::LastWin,
            2 => TxStrategy::VersionOnWrite,
            3 => TxStrategy::VersionOnRead,
            _ => panic!("something went wrong in tx strategy serialization: {}", val),
        }
    }
}

/// Persy configuration structure.
///
/// Lock are taken in order, should never go in deadlock so the default timeout is huge.
/// Current default values:
///
/// cache_size = 32M
/// cache_age_limit = 1 Day
/// transaction_lock_timeout = 1 Day
/// concurrent_modification_strategy = LastWin
///
#[derive(Debug, Clone)]
pub struct Config {
    cache_size: u64,
    cache_age_limit: Duration,
    transaction_lock_timeout: Duration,
    tx_strategy: TxStrategy,
}

impl Config {
    pub fn new() -> Config {
        Config {
            cache_size: 32 * 1024 * 1024,
            transaction_lock_timeout: Duration::new(24 * 60 * 60, 0),
            cache_age_limit: Duration::from_secs(60 * 60 * 24),
            tx_strategy: TxStrategy::LastWin,
        }
    }

    pub fn cache_size(&self) -> u64 {
        self.cache_size
    }

    pub fn cache_age_limit(&self) -> Duration {
        self.cache_age_limit
    }

    pub fn transaction_lock_timeout(&self) -> &Duration {
        &self.transaction_lock_timeout
    }

    pub fn change_cache_size(&mut self, cache_size: u64) {
        self.cache_size = cache_size;
    }

    pub fn change_cache_age_limit(&mut self, cache_age_limit: Duration) {
        self.cache_age_limit = cache_age_limit;
    }

    pub fn change_transaction_lock_timeout(&mut self, transaction_lock_timeout: Duration) {
        self.transaction_lock_timeout = transaction_lock_timeout;
    }

    pub fn tx_strategy(&self) -> &TxStrategy {
        &self.tx_strategy
    }

    pub fn change_tx_strategy(&mut self, strategy: TxStrategy) {
        self.tx_strategy = strategy;
    }
}

impl Default for Config {
    fn default() -> Self {
        Self::new()
    }
}

/// Configure the parameters for the transaction on the begin of a new transaction.
#[derive(Clone, Default)]
pub struct TransactionConfig {
    pub(crate) tx_strategy: Option<TxStrategy>,
    pub(crate) background_sync: Option<bool>,
    pub(crate) transaction_id: Option<TransactionId>,
}

impl TransactionConfig {
    pub fn new() -> Self {
        Self {
            tx_strategy: None,
            background_sync: None,
            transaction_id: None,
        }
    }
    /// Set the transaction concurrency checks, **experimental** use carefully
    pub fn set_strategy(mut self, strategy: TxStrategy) -> Self {
        self.tx_strategy = Some(strategy);
        self
    }

    /// Set if the transaction will be fsync-ed in background or on the current thread
    /// this option is available only if the "background_ops" feature is enabled
    #[cfg(feature = "background_ops")]
    pub fn set_background_sync(mut self, background: bool) -> Self {
        self.background_sync = Some(background);
        self
    }

    /// Set the transaction id to be used in case of crash recovery.
    pub fn set_transaction_id(mut self, transaction_id: TransactionId) -> Self {
        self.transaction_id = Some(transaction_id);
        self
    }
}