From 91b8246735896765ca2494788f1e40ffd57c8f5b Mon Sep 17 00:00:00 2001 From: David Greenberg Date: Tue, 14 Jul 2015 22:37:15 -0400 Subject: [PATCH] Add snapshots --- src/main.rs | 29 +++++++++++++++++++++++++++++ src/rocksdb.rs | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9cb96b9..0876616 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,33 @@ extern crate test; use rocksdb::{Options, RocksDB, MergeOperands, new_bloom_filter, Writable, DBIterator, SubDBIterator }; use rocksdb::RocksDBCompactionStyle::RocksDBUniversalCompaction; +fn snapshot_test() { + let path = "_rust_rocksdb_iteratortest"; + { + let mut db = RocksDB::open_default(path).unwrap(); + let p = db.put(b"k1", b"v1111"); + assert!(p.is_ok()); + let p = db.put(b"k2", b"v2222"); + assert!(p.is_ok()); + let p = db.put(b"k3", b"v3333"); + assert!(p.is_ok()); + let mut snap = db.snapshot(); + let mut view1 = snap.iterator(); + println!("See the output of the first iter"); + for (k,v) in view1.from_start() { + println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); + }; + for (k,v) in view1.from_start() { + println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); + }; + for (k,v) in view1.from_end() { + println!("Hello {}: {}", std::str::from_utf8(k).unwrap(), std::str::from_utf8(v).unwrap()); + }; + } + let opts = Options::new(); + assert!(RocksDB::destroy(&opts, path).is_ok()); +} + fn iterator_test() { let path = "_rust_rocksdb_iteratortest"; { @@ -67,8 +94,10 @@ fn iterator_test() { let opts = Options::new(); assert!(RocksDB::destroy(&opts, path).is_ok()); } + #[cfg(not(feature = "valgrind"))] fn main() { + snapshot_test(); iterator_test(); let path = "/tmp/rust-rocksdb"; let mut db = RocksDB::open_default(path).unwrap(); diff --git a/src/rocksdb.rs b/src/rocksdb.rs index c0a3945..59c2413 100644 --- a/src/rocksdb.rs +++ b/src/rocksdb.rs @@ -40,6 +40,11 @@ pub struct ReadOptions { inner: rocksdb_ffi::RocksDBReadOptions, } +pub struct Snapshot<'a> { + db: &'a RocksDB, + inner: rocksdb_ffi::RocksDBSnapshot, +} + pub struct DBIterator { //TODO: should have a reference to DB to enforce scope, but it's trickier than I thought to add inner: rocksdb_ffi::RocksDBIterator, @@ -87,7 +92,7 @@ impl <'a> Iterator for SubDBIterator<'a> { impl DBIterator { //TODO alias db & opts to different lifetimes, and DBIterator to the db's lifetime - pub fn new(db: &RocksDB, readopts: &ReadOptions) -> DBIterator { + fn new(db: &RocksDB, readopts: &ReadOptions) -> DBIterator { unsafe { let iterator = rocksdb_ffi::rocksdb_create_iterator(db.inner, readopts.inner); rocksdb_ffi::rocksdb_iter_seek_to_first(iterator); @@ -122,13 +127,33 @@ impl DBIterator { impl Drop for DBIterator { fn drop(&mut self) { - println!("Dropped iter"); unsafe { rocksdb_ffi::rocksdb_iter_destroy(self.inner); } } } +impl <'a> Snapshot<'a> { + pub fn new(db: &RocksDB) -> Snapshot { + let snapshot = unsafe { rocksdb_ffi::rocksdb_create_snapshot(db.inner) }; + Snapshot{db: db, inner: snapshot} + } + + pub fn iterator(&self) -> DBIterator { + let mut readopts = ReadOptions::new(); + readopts.set_snapshot(self); + DBIterator::new(self.db, &readopts) + } +} + +impl <'a> Drop for Snapshot<'a> { + fn drop(&mut self) { + unsafe { + rocksdb_ffi::rocksdb_release_snapshot(self.db.inner, self.inner); + } + } +} + // This is for the RocksDB and write batches to share the same API pub trait Writable { fn put(&mut self, key: &[u8], value: &[u8]) -> Result<(), String>; @@ -269,6 +294,10 @@ impl RocksDB { let opts = ReadOptions::new(); DBIterator::new(&self, &opts) } + + pub fn snapshot(&self) -> Snapshot { + Snapshot::new(self) + } } impl Writable for RocksDB { @@ -394,6 +423,11 @@ impl ReadOptions { } } + fn set_snapshot(&mut self, snapshot: &Snapshot) { + unsafe { + rocksdb_ffi::rocksdb_readoptions_set_snapshot(self.inner, snapshot.inner); + } + } } pub struct RocksDBVector {