Skip to content

Commit 1a227d7

Browse files
author
Victor Porof
authored
Merge pull request #161 from mozilla/cow-snapshots
Cow snapshots instead of always cloning
2 parents 2a3dd18 + 2bd0ab7 commit 1a227d7

File tree

3 files changed

+137
-8
lines changed

3 files changed

+137
-8
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = ["/tests/envs/*"]
1616
[features]
1717
default = ["with-safe-mode"]
1818
backtrace = ["failure/backtrace", "failure/std"]
19-
with-safe-mode = ["id-arena", "log", "serde/derive"]
19+
with-safe-mode = ["id-arena", "log", "serde/derive", "serde/rc"]
2020
with-asan = ["lmdb-rkv/with-asan"]
2121
with-fuzzer = ["lmdb-rkv/with-fuzzer"]
2222
with-fuzzer-no-link = ["lmdb-rkv/with-fuzzer-no-link"]

src/backend/impl_safe/database.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::collections::{
1212
BTreeSet,
1313
HashMap,
1414
};
15+
use std::sync::Arc;
1516

1617
use id_arena::Id;
1718
use serde_derive::{
@@ -47,17 +48,20 @@ impl DatabaseImpl {
4748
}
4849
}
4950

51+
type Key = Box<[u8]>;
52+
type Value = Box<[u8]>;
53+
5054
#[derive(Debug, Clone, Serialize, Deserialize)]
5155
pub struct Snapshot {
5256
flags: DatabaseFlagsImpl,
53-
map: HashMap<Box<[u8]>, BTreeSet<Box<[u8]>>>,
57+
map: Arc<HashMap<Key, BTreeSet<Value>>>,
5458
}
5559

5660
impl Snapshot {
5761
pub(crate) fn new(flags: Option<DatabaseFlagsImpl>) -> Snapshot {
5862
Snapshot {
5963
flags: flags.unwrap_or_else(DatabaseFlagsImpl::default),
60-
map: HashMap::new(),
64+
map: Default::default(),
6165
}
6266
}
6367

@@ -70,31 +74,36 @@ impl Snapshot {
7074
}
7175

7276
pub(crate) fn put_one(&mut self, key: &[u8], value: &[u8]) {
73-
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
77+
let map = Arc::make_mut(&mut self.map);
78+
let values = map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
7479
values.clear();
7580
values.insert(Box::from(value));
7681
}
7782

7883
pub(crate) fn put_dup(&mut self, key: &[u8], value: &[u8]) {
79-
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
84+
let map = Arc::make_mut(&mut self.map);
85+
let values = map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
8086
values.insert(Box::from(value));
8187
}
8288

8389
pub(crate) fn del_exact(&mut self, key: &[u8], value: &[u8]) -> Option<()> {
84-
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
90+
let map = Arc::make_mut(&mut self.map);
91+
let values = map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
8592
let was_removed = values.remove(value);
8693
Some(()).filter(|_| was_removed)
8794
}
8895

8996
pub(crate) fn del_all(&mut self, key: &[u8]) -> Option<()> {
90-
let values = self.map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
97+
let map = Arc::make_mut(&mut self.map);
98+
let values = map.entry(Box::from(key)).or_insert_with(BTreeSet::new);
9199
let was_empty = values.is_empty();
92100
values.clear();
93101
Some(()).filter(|_| !was_empty)
94102
}
95103

96104
pub(crate) fn clear(&mut self) {
97-
self.map.clear();
105+
let map = Arc::make_mut(&mut self.map);
106+
map.clear();
98107
}
99108

100109
pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {

src/store/integer.rs

+120
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,66 @@ mod tests {
246246
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("hello!")));
247247
}
248248
}
249+
250+
#[test]
251+
fn test_intertwine_read_write() {
252+
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
253+
fs::create_dir_all(root.path()).expect("dir created");
254+
255+
let k = Rkv::new::<backend::Lmdb>(root.path()).expect("new succeeded");
256+
let s = k.open_integer("s", StoreOptions::create()).expect("open");
257+
258+
{
259+
let mut writer = k.write().expect("writer");
260+
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
261+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
262+
assert_eq!(s.get(&writer, 2).expect("read"), None);
263+
assert_eq!(s.get(&writer, 3).expect("read"), None);
264+
writer.commit().expect("committed");
265+
}
266+
267+
let reader = k.read().expect("reader");
268+
let mut writer = k.write().expect("writer");
269+
270+
{
271+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
272+
assert_eq!(s.get(&reader, 2).expect("read"), None);
273+
assert_eq!(s.get(&reader, 3).expect("read"), None);
274+
}
275+
276+
{
277+
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
278+
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
279+
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
280+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
281+
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
282+
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
283+
writer.commit().expect("committed");
284+
}
285+
286+
{
287+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
288+
assert_eq!(s.get(&reader, 2).expect("read"), None);
289+
assert_eq!(s.get(&reader, 3).expect("read"), None);
290+
}
291+
292+
{
293+
let mut writer = k.write().expect("writer");
294+
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
295+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
296+
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
297+
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
298+
writer.commit().expect("committed");
299+
}
300+
301+
{
302+
let reader = k.write().expect("reader");
303+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
304+
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
305+
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
306+
reader.commit().expect("committed");
307+
}
308+
}
249309
}
250310

251311
#[cfg(test)]
@@ -419,4 +479,64 @@ mod tests_safe {
419479
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("hello!")));
420480
}
421481
}
482+
483+
#[test]
484+
fn test_intertwine_read_write() {
485+
let root = Builder::new().prefix("test_integer_intertwine_read_write").tempdir().expect("tempdir");
486+
fs::create_dir_all(root.path()).expect("dir created");
487+
488+
let k = Rkv::new::<backend::SafeMode>(root.path()).expect("new succeeded");
489+
let s = k.open_integer("s", StoreOptions::create()).expect("open");
490+
491+
{
492+
let mut writer = k.write().expect("writer");
493+
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
494+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
495+
assert_eq!(s.get(&writer, 2).expect("read"), None);
496+
assert_eq!(s.get(&writer, 3).expect("read"), None);
497+
writer.commit().expect("committed");
498+
}
499+
500+
let reader = k.read().expect("reader");
501+
let mut writer = k.write().expect("writer");
502+
503+
{
504+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
505+
assert_eq!(s.get(&reader, 2).expect("read"), None);
506+
assert_eq!(s.get(&reader, 3).expect("read"), None);
507+
}
508+
509+
{
510+
s.put(&mut writer, 1, &Value::Str("goodbye!")).expect("write");
511+
s.put(&mut writer, 2, &Value::Str("goodbye!")).expect("write");
512+
s.put(&mut writer, 3, &Value::Str("goodbye!")).expect("write");
513+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("goodbye!")));
514+
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
515+
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
516+
writer.commit().expect("committed");
517+
}
518+
519+
{
520+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
521+
assert_eq!(s.get(&reader, 2).expect("read"), None);
522+
assert_eq!(s.get(&reader, 3).expect("read"), None);
523+
}
524+
525+
{
526+
let mut writer = k.write().expect("writer");
527+
s.put(&mut writer, 1, &Value::Str("hello!")).expect("write");
528+
assert_eq!(s.get(&writer, 1).expect("read"), Some(Value::Str("hello!")));
529+
assert_eq!(s.get(&writer, 2).expect("read"), Some(Value::Str("goodbye!")));
530+
assert_eq!(s.get(&writer, 3).expect("read"), Some(Value::Str("goodbye!")));
531+
writer.commit().expect("committed");
532+
}
533+
534+
{
535+
let reader = k.write().expect("reader");
536+
assert_eq!(s.get(&reader, 1).expect("read"), Some(Value::Str("hello!")));
537+
assert_eq!(s.get(&reader, 2).expect("read"), Some(Value::Str("goodbye!")));
538+
assert_eq!(s.get(&reader, 3).expect("read"), Some(Value::Str("goodbye!")));
539+
reader.commit().expect("committed");
540+
}
541+
}
422542
}

0 commit comments

Comments
 (0)