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
use parking_lot::Mutex;
use kv::{Transaction, Value, KeyValueDatabase, MemoryDatabase, KeyState, Key};

pub struct OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase {
	db: &'a T,
	overlay: MemoryDatabase,
}

impl<'a, T> OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase {
	pub fn new(db: &'a T) -> Self {
		OverlayDatabase {
			db: db,
			overlay: MemoryDatabase::default(),
		}
	}

	pub fn flush(&self) -> Result<(), String> {
		self.db.write(self.overlay.drain_transaction())
	}
}

impl<'a, T> KeyValueDatabase for OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase {
	fn write(&self, tx: Transaction) -> Result<(), String> {
		self.overlay.write(tx)
	}

	fn get(&self, key: &Key) -> Result<KeyState<Value>, String> {
		match self.overlay.get(key)? {
			KeyState::Unknown => self.db.get(key),
			exists => Ok(exists)
		}
	}
}

pub struct AutoFlushingOverlayDatabase<T> where T: KeyValueDatabase {
	db: T,
	overlay: MemoryDatabase,
	operations: Mutex<usize>,
	max_operations: usize,
}

impl<T> AutoFlushingOverlayDatabase<T> where T: KeyValueDatabase {
	pub fn new(db: T, max_operations: usize) -> Self {
		AutoFlushingOverlayDatabase {
			db: db,
			overlay: MemoryDatabase::default(),
			operations: Mutex::default(),
			max_operations: max_operations,
		}
	}

	fn flush(&self) -> Result<(), String> {
		self.db.write(self.overlay.drain_transaction())
	}
}

impl<T> KeyValueDatabase for AutoFlushingOverlayDatabase<T> where T: KeyValueDatabase {
	fn write(&self, tx: Transaction) -> Result<(), String> {
		let mut operations = self.operations.lock();
		*operations += 1;
		self.overlay.write(tx)?;
		if *operations == self.max_operations {
			self.flush()?;
			*operations = 0;
		}
		Ok(())
	}

	fn get(&self, key: &Key) -> Result<KeyState<Value>, String> {
		match self.overlay.get(key)? {
			KeyState::Unknown => self.db.get(key),
			exists => Ok(exists)
		}
	}
}

impl<T> Drop for AutoFlushingOverlayDatabase<T> where T: KeyValueDatabase {
	fn drop(&mut self) {
		self.flush().expect("Failed to save database");
	}
}