2016-10-22 21:35:48 +03:00
// Copyright 2016 The Grin Developers
//
// 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.
2016-10-21 03:06:12 +03:00
//! Storage of core types using RocksDB.
#![ deny(non_upper_case_globals) ]
#![ deny(non_camel_case_types) ]
#![ deny(non_snake_case) ]
#![ deny(unused_mut) ]
#![ warn(missing_docs) ]
extern crate grin_core as core ;
extern crate rocksdb ;
use std ::sync ::RwLock ;
use core ::ser ;
use rocksdb ::{ DB , Options , Writable , DBCompactionStyle } ;
/// Main error type for this crate.
#[ derive(Debug) ]
pub enum Error {
/// Wraps an error originating from RocksDB (which unfortunately returns
/// string errors).
RocksDbErr ( String ) ,
/// Wraps a serialization error for Writeable or Readable
SerErr ( ser ::Error ) ,
}
impl From < String > for Error {
fn from ( s : String ) -> Error {
Error ::RocksDbErr ( s )
}
}
/// Thread-safe rocksdb wrapper
pub struct Store {
rdb : RwLock < DB > ,
}
impl Store {
/// Opens a new RocksDB at the specified location.
pub fn open ( path : & str ) -> Result < Store , Error > {
let mut opts = Options ::new ( ) ;
opts . create_if_missing ( true ) ;
opts . set_compaction_style ( DBCompactionStyle ::DBUniversalCompaction ) ;
opts . set_max_open_files ( 256 ) ;
opts . set_use_fsync ( false ) ;
let db = try ! ( DB ::open ( & opts , & path ) ) ;
Ok ( Store { rdb : RwLock ::new ( db ) } )
}
/// Writes a single key/value pair to the db
2016-11-16 04:29:42 +03:00
pub fn put ( & self , key : & [ u8 ] , value : Vec < u8 > ) -> Result < ( ) , Error > {
2016-10-21 03:06:12 +03:00
let db = self . rdb . write ( ) . unwrap ( ) ;
2016-11-16 04:29:42 +03:00
db . put ( key , & value [ .. ] ) . map_err ( Error ::RocksDbErr )
2016-10-21 03:06:12 +03:00
}
/// Writes a single key and its `Writeable` value to the db. Encapsulates
/// serialization.
2016-11-16 04:29:42 +03:00
pub fn put_ser ( & self , key : & [ u8 ] , value : & ser ::Writeable ) -> Result < ( ) , Error > {
2016-10-21 03:06:12 +03:00
let ser_value = ser ::ser_vec ( value ) ;
match ser_value {
Ok ( data ) = > self . put ( key , data ) ,
2016-11-16 04:29:42 +03:00
Err ( err ) = > Err ( Error ::SerErr ( err ) ) ,
2016-10-21 03:06:12 +03:00
}
}
/// Gets a value from the db, provided its key
pub fn get ( & self , key : & [ u8 ] ) -> Result < Option < Vec < u8 > > , Error > {
let db = self . rdb . read ( ) . unwrap ( ) ;
db . get ( key ) . map ( | r | r . map ( | o | o . to_vec ( ) ) ) . map_err ( Error ::RocksDbErr )
}
/// Gets a `Readable` value from the db, provided its key. Encapsulates
/// serialization.
pub fn get_ser < T : ser ::Readable < T > > ( & self , key : & [ u8 ] ) -> Result < Option < T > , Error > {
2016-11-17 04:03:23 +03:00
self . get_ser_limited ( key , 0 )
}
/// Gets a `Readable` value from the db, provided its key, allowing to extract only partial data. The underlying Readable size must align accordingly. Encapsulates serialization.
pub fn get_ser_limited < T : ser ::Readable < T > > ( & self , key : & [ u8 ] , len : usize ) -> Result < Option < T > , Error > {
2016-10-21 03:06:12 +03:00
let data = try ! ( self . get ( key ) ) ;
match data {
Some ( val ) = > {
2016-11-17 04:03:23 +03:00
let mut lval = if len > 0 { & val [ .. len ] } else { & val [ .. ] } ;
let r = try ! ( ser ::deserialize ( & mut lval ) . map_err ( Error ::SerErr ) ) ;
2016-10-21 03:06:12 +03:00
Ok ( Some ( r ) )
}
None = > Ok ( None ) ,
}
}
/// Deletes a key/value pair from the db
2016-11-16 04:29:42 +03:00
pub fn delete ( & self , key : & [ u8 ] ) -> Result < ( ) , Error > {
2016-10-21 03:06:12 +03:00
let db = self . rdb . write ( ) . unwrap ( ) ;
2016-11-16 04:29:42 +03:00
db . delete ( key ) . map_err ( Error ::RocksDbErr )
2016-10-21 03:06:12 +03:00
}
}