Merge pull request #391 from paritytech/auto_flushing
AutoFlushingOverlayDatabase
This commit is contained in:
commit
a65be02b25
|
@ -14,7 +14,7 @@ use ser::{
|
||||||
};
|
};
|
||||||
use kv::{
|
use kv::{
|
||||||
KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Location, Value, DiskDatabase,
|
KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Location, Value, DiskDatabase,
|
||||||
DatabaseConfig, MemoryDatabase
|
DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase
|
||||||
};
|
};
|
||||||
use best_block::BestBlock;
|
use best_block::BestBlock;
|
||||||
use {
|
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> {
|
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()))?;
|
fs::create_dir_all(path.as_ref()).map_err(|err| Error::DatabaseError(err.to_string()))?;
|
||||||
let mut cfg = DatabaseConfig::with_columns(Some(COL_COUNT));
|
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);
|
cfg.bloom_filters.insert(Some(COL_TRANSACTIONS_META), 32);
|
||||||
|
|
||||||
match DiskDatabase::open(cfg, path) {
|
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))
|
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 {
|
impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
|
||||||
fn read_best_block(db: &T) -> Option<BestBlock> {
|
fn read_best_block(db: &T) -> Option<BestBlock> {
|
||||||
let best_number = db.get(COL_META.into(), KEY_BEST_BLOCK_NUMBER);
|
let best_number = db.get(COL_META.into(), KEY_BEST_BLOCK_NUMBER);
|
||||||
|
|
|
@ -7,5 +7,5 @@ mod transaction;
|
||||||
pub use self::db::KeyValueDatabase;
|
pub use self::db::KeyValueDatabase;
|
||||||
pub use self::diskdb::{Database as DiskDatabase, DatabaseConfig, CompactionProfile};
|
pub use self::diskdb::{Database as DiskDatabase, DatabaseConfig, CompactionProfile};
|
||||||
pub use self::memorydb::{MemoryDatabase, SharedMemoryDatabase};
|
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};
|
pub use self::transaction::{Transaction, Operation, Location, Key, Value, KeyState};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use parking_lot::Mutex;
|
||||||
use kv::{Transaction, Location, Value, KeyValueDatabase, MemoryDatabase};
|
use kv::{Transaction, Location, Value, KeyValueDatabase, MemoryDatabase};
|
||||||
|
|
||||||
pub struct OverlayDatabase<'a, T> where T: 'a + KeyValueDatabase {
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue