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
use std::sync::*;
use std::default::*;
use transaction::*;
use error::*;
use persist::*;
pub struct Database {
pub flushes: i32,
txn_mut: RwLock<Transaction>,
sync_policy: SyncPolicy,
closed: bool,
}
pub struct Config {
persist_type: PersistType,
sync_policy: SyncPolicy,
}
impl Default for Config {
fn default() -> Self {
Config {
persist_type: PersistType::Memory,
sync_policy: SyncPolicy::Never,
}
}
}
impl Database {
pub fn new(config: Config) -> Result<Database> {
let mut persist_store: Box<Persistable> = match config.persist_type {
PersistType::Memory => Box::new(MemoryStore::default()),
PersistType::File(path) => Box::new(FileStore::new(path)?),
};
Ok(Database {
flushes: 0,
txn_mut: RwLock::new(Transaction::new(persist_store.load()?, persist_store)),
sync_policy: config.sync_policy,
closed: false,
})
}
pub fn read<F, K>(&self, f: F) -> Result<()>
where F: Fn(&ReadTransaction<K>) -> Result<()>,
K: Into<String> + Ord + Clone
{
let store = self.txn_mut.read()?;
if self.closed {
return Err(Error::new(ErrorKind::DataBaseClosed));
}
f(&*store)
}
pub fn update<F, K>(&self, f: F) -> Result<()>
where F: Fn(&mut WriteTransaction<K>) -> Result<()>,
K: Into<String> + Ord + Clone
{
let mut store = self.txn_mut.write()?;
if self.closed {
return Err(Error::new(ErrorKind::DataBaseClosed));
}
if f(&mut *store).is_err() {
store.rollback();
} else if self.sync_policy == SyncPolicy::Always {
store.save()?;
}
store.commit();
Ok(())
}
pub fn save(&mut self) -> Result<()> {
self.txn_mut.write()?.save()?;
self.flushes += 1;
Ok(())
}
pub fn close(&mut self) -> Result<()> {
if self.closed {
return Err(Error::new(ErrorKind::DataBaseClosed));
}
let _ = self.txn_mut.write()?;
self.closed = true;
Ok(())
}
}
impl Drop for Database {
fn drop(&mut self) {
if !self.closed {
self.close().unwrap();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let db = Database::new(Config::default()).unwrap();
assert_eq!(false, db.closed);
assert_eq!(SyncPolicy::Never, db.sync_policy)
}
#[test]
fn test_close() {
let mut db = Database::new(Config::default()).unwrap();
assert!(db.close().is_ok());
assert!(db.close().is_err());
assert!(db.close().is_err());
}
}