diff --git a/Cargo.lock b/Cargo.lock index 67a9372b367ea..926754ace6d5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6832,9 +6832,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e73cd0b0a78045276b19eaae8eaaa20e44a1da9a0217ff934a810d9492ae701" +checksum = "55a7901b85874402471e131de3332dde0e51f38432c69a3853627c8e25433048" dependencies = [ "blake2-rfc", "crc32fast", diff --git a/client/db/Cargo.toml b/client/db/Cargo.toml index 3c20cec72c695..e548887e56fe2 100644 --- a/client/db/Cargo.toml +++ b/client/db/Cargo.toml @@ -22,7 +22,7 @@ kvdb-memorydb = "0.11.0" kvdb-rocksdb = { version = "0.15.2", optional = true } linked-hash-map = "0.5.4" log = "0.4.16" -parity-db = { version = "0.3.12", optional = true } +parity-db = { version = "0.3.13", optional = true } parking_lot = "0.12.0" sc-client-api = { version = "4.0.0-dev", path = "../api" } sc-state-db = { version = "0.10.0-dev", path = "../state-db" } diff --git a/client/db/src/parity_db.rs b/client/db/src/parity_db.rs index f88e6f2e91678..7ce1d6a683401 100644 --- a/client/db/src/parity_db.rs +++ b/client/db/src/parity_db.rs @@ -86,15 +86,57 @@ pub fn open>( Ok(std::sync::Arc::new(DbAdapter(db))) } +fn ref_counted_column(col: u32) -> bool { + col == columns::TRANSACTION || col == columns::STATE +} + impl> Database for DbAdapter { fn commit(&self, transaction: Transaction) -> Result<(), DatabaseError> { - handle_err(self.0.commit(transaction.0.into_iter().map(|change| match change { - Change::Set(col, key, value) => (col as u8, key, Some(value)), - Change::Remove(col, key) => (col as u8, key, None), - _ => unimplemented!(), - }))); + let mut not_ref_counted_column = Vec::new(); + let result = self.0.commit(transaction.0.into_iter().filter_map(|change| { + Some(match change { + Change::Set(col, key, value) => (col as u8, key, Some(value)), + Change::Remove(col, key) => (col as u8, key, None), + Change::Store(col, key, value) => + if ref_counted_column(col) { + (col as u8, key.as_ref().to_vec(), Some(value)) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + Change::Reference(col, key) => + if ref_counted_column(col) { + // FIXME accessing value is not strictly needed, optimize this in parity-db. + let value = >::get(self, col, key.as_ref()); + (col as u8, key.as_ref().to_vec(), value) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + Change::Release(col, key) => + if ref_counted_column(col) { + (col as u8, key.as_ref().to_vec(), None) + } else { + if !not_ref_counted_column.contains(&col) { + not_ref_counted_column.push(col); + } + return None + }, + }) + })); + + if not_ref_counted_column.len() > 0 { + return Err(DatabaseError(Box::new(parity_db::Error::InvalidInput(format!( + "Ref counted operation on non ref counted columns {:?}", + not_ref_counted_column + ))))) + } - Ok(()) + result.map_err(|e| DatabaseError(Box::new(e))) } fn get(&self, col: ColumnId, key: &[u8]) -> Option> {