Merge pull request #391 from paritytech/auto_flushing

AutoFlushingOverlayDatabase
This commit is contained in:
Svyatoslav Nikolsky 2017-04-07 09:19:00 +03:00 committed by GitHub
commit a65be02b25
3 changed files with 65 additions and 4 deletions

View File

@ -14,7 +14,7 @@ use ser::{
};
use kv::{
KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Location, Value, DiskDatabase,
DatabaseConfig, MemoryDatabase
DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase
};
use best_block::BestBlock;
use {
@ -58,7 +58,7 @@ impl<'a, T> ForkChain for ForkChainDatabase<'a, T> where T: KeyValueDatabase {
}
}
impl BlockChainDatabase<DiskDatabase> {
impl BlockChainDatabase<AutoFlushingOverlayDatabase<DiskDatabase>> {
pub fn open_at_path<P>(path: P, total_cache: usize) -> Result<Self, Error> where P: AsRef<Path> {
fs::create_dir_all(path.as_ref()).map_err(|err| Error::DatabaseError(err.to_string()))?;
let mut cfg = DatabaseConfig::with_columns(Some(COL_COUNT));
@ -74,7 +74,7 @@ impl BlockChainDatabase<DiskDatabase> {
cfg.bloom_filters.insert(Some(COL_TRANSACTIONS_META), 32);
match DiskDatabase::open(cfg, path) {
Ok(db) => Ok(Self::open(db)),
Ok(db) => Ok(Self::open_with_cache(db)),
Err(err) => Err(Error::DatabaseError(err))
}
}
@ -92,6 +92,17 @@ impl BlockChainDatabase<MemoryDatabase> {
}
}
impl<T> BlockChainDatabase<AutoFlushingOverlayDatabase<T>> where T: KeyValueDatabase {
pub fn open_with_cache(db: T) -> Self {
let db = AutoFlushingOverlayDatabase::new(db, 50);
let best_block = Self::read_best_block(&db).unwrap_or_default();
BlockChainDatabase {
best_block: RwLock::new(best_block),
db: db,
}
}
}
impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
fn read_best_block(db: &T) -> Option<BestBlock> {
let best_number = db.get(COL_META.into(), KEY_BEST_BLOCK_NUMBER);

View File

@ -7,5 +7,5 @@ mod transaction;
pub use self::db::KeyValueDatabase;
pub use self::diskdb::{Database as DiskDatabase, DatabaseConfig, CompactionProfile};
pub use self::memorydb::{MemoryDatabase, SharedMemoryDatabase};
pub use self::overlaydb::OverlayDatabase;
pub use self::overlaydb::{OverlayDatabase, AutoFlushingOverlayDatabase};
pub use self::transaction::{Transaction, Operation, Location, Key, Value, KeyState};

View File

@ -1,3 +1,4 @@
use parking_lot::Mutex;
use kv::{Transaction, Location, Value, KeyValueDatabase, MemoryDatabase};
pub struct OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase {
@ -31,3 +32,52 @@ impl<'a, T> KeyValueDatabase for OverlayDatabase<'a, T> where T: 'a + KeyValueDa
}
}
}
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, location: Location, key: &[u8]) -> Result<Option<Value>, String> {
if self.overlay.is_known(location, key) {
self.overlay.get(location, key)
} else {
self.db.get(location, key)
}
}
}
impl<T> Drop for AutoFlushingOverlayDatabase<T> where T: KeyValueDatabase {
fn drop(&mut self) {
self.flush().expect("Failed to save database");
}
}