commit
e69a03fadc
@ -0,0 +1,80 @@ |
||||
// Copyright 2018 Eugene P.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///! Implementation of bindings to RocksDB Checkpoint[1] API
|
||||
///
|
||||
/// [1]: https://github.com/facebook/rocksdb/wiki/Checkpoints
|
||||
|
||||
use {DB, Error}; |
||||
use ffi; |
||||
use std::ffi::CString; |
||||
use std::path::Path; |
||||
|
||||
/// Undocumented parameter for `ffi::rocksdb_checkpoint_create` function. Zero by default.
|
||||
const LOG_SIZE_FOR_FLUSH: u64 = 0_u64; |
||||
|
||||
/// Database's checkpoint object.
|
||||
/// Used to create checkpoints of the specified DB from time to time.
|
||||
pub struct Checkpoint { |
||||
inner: *mut ffi::rocksdb_checkpoint_t, |
||||
} |
||||
|
||||
impl Checkpoint { |
||||
/// Creates new checkpoint object for specific DB.
|
||||
///
|
||||
/// Does not actually produce checkpoints, call `.create_checkpoint()` method to produce
|
||||
/// a DB checkpoint.
|
||||
pub fn new(db: &DB) -> Result<Checkpoint, Error> { |
||||
let checkpoint: *mut ffi::rocksdb_checkpoint_t; |
||||
|
||||
unsafe { checkpoint = ffi_try!(ffi::rocksdb_checkpoint_object_create(db.inner,)) }; |
||||
|
||||
if checkpoint.is_null() { |
||||
return Err(Error::new("Could not create checkpoint object.".to_owned())); |
||||
} |
||||
|
||||
Ok(Checkpoint { |
||||
inner: checkpoint, |
||||
}) |
||||
} |
||||
|
||||
/// Creates new physical DB checkpoint in directory specified by `path`.
|
||||
pub fn create_checkpoint<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> { |
||||
let path = path.as_ref(); |
||||
let cpath = match CString::new(path.to_string_lossy().as_bytes()) { |
||||
Ok(c) => c, |
||||
Err(_) => { |
||||
return Err(Error::new( |
||||
"Failed to convert path to CString when creating DB checkpoint" |
||||
.to_owned(), |
||||
)); |
||||
} |
||||
}; |
||||
|
||||
unsafe { |
||||
ffi_try!(ffi::rocksdb_checkpoint_create(self.inner, cpath.as_ptr(), LOG_SIZE_FOR_FLUSH,)); |
||||
|
||||
Ok(()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Drop for Checkpoint { |
||||
fn drop(&mut self) { |
||||
unsafe { |
||||
ffi::rocksdb_checkpoint_object_destroy(self.inner); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,113 @@ |
||||
// Copyright 2018 Eugene P.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
extern crate rocksdb; |
||||
|
||||
use rocksdb::{checkpoint::Checkpoint, DB, Options}; |
||||
use std::fs::remove_dir_all; |
||||
|
||||
#[test] |
||||
pub fn test_single_checkpoint() { |
||||
const PATH_PREFIX: &str = "_rust_rocksdb_cp_single_"; |
||||
|
||||
// Create DB with some data
|
||||
let db_path = format!("{}db1", PATH_PREFIX); |
||||
|
||||
let _ = remove_dir_all(&db_path); |
||||
|
||||
let mut opts = Options::default(); |
||||
opts.create_if_missing(true); |
||||
let db = DB::open(&opts, &db_path).unwrap(); |
||||
|
||||
db.put(b"k1", b"v1").unwrap(); |
||||
db.put(b"k2", b"v2").unwrap(); |
||||
db.put(b"k3", b"v3").unwrap(); |
||||
db.put(b"k4", b"v4").unwrap(); |
||||
|
||||
// Create checkpoint
|
||||
let cp1 = Checkpoint::new(&db).unwrap(); |
||||
let cp1_path = format!("{}cp1", PATH_PREFIX); |
||||
let _ = remove_dir_all(&cp1_path); |
||||
cp1.create_checkpoint(&cp1_path).unwrap(); |
||||
|
||||
// Verify checkpoint
|
||||
let cp = DB::open_default(&cp1_path).unwrap(); |
||||
|
||||
assert_eq!(*cp.get(b"k1").unwrap().unwrap(), *b"v1"); |
||||
assert_eq!(*cp.get(b"k2").unwrap().unwrap(), *b"v2"); |
||||
assert_eq!(*cp.get(b"k3").unwrap().unwrap(), *b"v3"); |
||||
assert_eq!(*cp.get(b"k4").unwrap().unwrap(), *b"v4"); |
||||
|
||||
let _ = remove_dir_all(&db_path); |
||||
let _ = remove_dir_all(&cp1_path); |
||||
} |
||||
|
||||
#[test] |
||||
pub fn test_multi_checkpoints() { |
||||
const PATH_PREFIX: &str = "_rust_rocksdb_cp_multi_"; |
||||
|
||||
// Create DB with some data
|
||||
let db_path = format!("{}db1", PATH_PREFIX); |
||||
let _ = remove_dir_all(&db_path); |
||||
|
||||
let mut opts = Options::default(); |
||||
opts.create_if_missing(true); |
||||
let db = DB::open(&opts, &db_path).unwrap(); |
||||
|
||||
db.put(b"k1", b"v1").unwrap(); |
||||
db.put(b"k2", b"v2").unwrap(); |
||||
db.put(b"k3", b"v3").unwrap(); |
||||
db.put(b"k4", b"v4").unwrap(); |
||||
|
||||
// Create first checkpoint
|
||||
let cp1 = Checkpoint::new(&db).unwrap(); |
||||
let cp1_path = format!("{}cp1", PATH_PREFIX); |
||||
let _ = remove_dir_all(&cp1_path); |
||||
cp1.create_checkpoint(&cp1_path).unwrap(); |
||||
|
||||
// Verify checkpoint
|
||||
let cp = DB::open_default(&cp1_path).unwrap(); |
||||
|
||||
assert_eq!(*cp.get(b"k1").unwrap().unwrap(), *b"v1"); |
||||
assert_eq!(*cp.get(b"k2").unwrap().unwrap(), *b"v2"); |
||||
assert_eq!(*cp.get(b"k3").unwrap().unwrap(), *b"v3"); |
||||
assert_eq!(*cp.get(b"k4").unwrap().unwrap(), *b"v4"); |
||||
|
||||
let _ = remove_dir_all(&cp1_path); |
||||
|
||||
// Change some existing keys
|
||||
db.put(b"k1", b"modified").unwrap(); |
||||
db.put(b"k2", b"changed").unwrap(); |
||||
|
||||
// Add some new keys
|
||||
db.put(b"k5", b"v5").unwrap(); |
||||
db.put(b"k6", b"v6").unwrap(); |
||||
|
||||
// Create another checkpoint
|
||||
let cp2 = Checkpoint::new(&db).unwrap(); |
||||
let cp2_path = format!("{}cp2", PATH_PREFIX); |
||||
let _ = remove_dir_all(&cp2_path); |
||||
cp2.create_checkpoint(&cp2_path).unwrap(); |
||||
|
||||
// Verify second checkpoint
|
||||
let cp = DB::open_default(&cp2_path).unwrap(); |
||||
|
||||
assert_eq!(*cp.get(b"k1").unwrap().unwrap(), *b"modified"); |
||||
assert_eq!(*cp.get(b"k2").unwrap().unwrap(), *b"changed"); |
||||
assert_eq!(*cp.get(b"k5").unwrap().unwrap(), *b"v5"); |
||||
assert_eq!(*cp.get(b"k6").unwrap().unwrap(), *b"v6"); |
||||
|
||||
let _ = remove_dir_all(&db_path); |
||||
let _ = remove_dir_all(&cp2_path); |
||||
} |
Loading…
Reference in new issue