// This file is part of Substrate. // Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // 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. //! The main database trait, allowing Substrate to store data persistently. pub mod error; mod mem; mod kvdb; pub use mem::MemDb; pub use crate::kvdb::as_database; /// An identifier for a column. pub type ColumnId = u32; /// An alteration to the database. #[derive(Clone)] pub enum Change { Set(ColumnId, Vec, Vec), Remove(ColumnId, Vec), Store(ColumnId, H, Vec), Reference(ColumnId, H), Release(ColumnId, H), } /// A series of changes to the database that can be committed atomically. They do not take effect /// until passed into `Database::commit`. #[derive(Default, Clone)] pub struct Transaction(pub Vec>); impl Transaction { /// Create a new transaction to be prepared and committed atomically. pub fn new() -> Self { Transaction(Vec::new()) } /// Set the value of `key` in `col` to `value`, replacing anything that is there currently. pub fn set(&mut self, col: ColumnId, key: &[u8], value: &[u8]) { self.0.push(Change::Set(col, key.to_vec(), value.to_vec())) } /// Set the value of `key` in `col` to `value`, replacing anything that is there currently. pub fn set_from_vec(&mut self, col: ColumnId, key: &[u8], value: Vec) { self.0.push(Change::Set(col, key.to_vec(), value)) } /// Remove the value of `key` in `col`. pub fn remove(&mut self, col: ColumnId, key: &[u8]) { self.0.push(Change::Remove(col, key.to_vec())) } /// Store the `preimage` of `hash` into the database, so that it may be looked up later with /// `Database::get`. This may be called multiple times, but subsequent /// calls will ignore `preimage` and simply increase the number of references on `hash`. pub fn store(&mut self, col: ColumnId, hash: H, preimage: Vec) { self.0.push(Change::Store(col, hash, preimage)) } /// Increase the number of references for `hash` in the database. pub fn reference(&mut self, col: ColumnId, hash: H) { self.0.push(Change::Reference(col, hash)) } /// Release the preimage of `hash` from the database. An equal number of these to the number of /// corresponding `store`s must have been given before it is legal for `Database::get` to /// be unable to provide the preimage. pub fn release(&mut self, col: ColumnId, hash: H) { self.0.push(Change::Release(col, hash)) } } pub trait Database>: Send + Sync { /// Commit the `transaction` to the database atomically. Any further calls to `get` or `lookup` /// will reflect the new state. fn commit(&self, transaction: Transaction) -> error::Result<()>; /// Retrieve the value previously stored against `key` or `None` if /// `key` is not currently in the database. fn get(&self, col: ColumnId, key: &[u8]) -> Option>; /// Check if the value exists in the database without retrieving it. fn contains(&self, col: ColumnId, key: &[u8]) -> bool { self.get(col, key).is_some() } /// Check value size in the database possibly without retrieving it. fn value_size(&self, col: ColumnId, key: &[u8]) -> Option { self.get(col, key).map(|v| v.len()) } /// Call `f` with the value previously stored against `key`. /// /// This may be faster than `get` since it doesn't allocate. /// Use `with_get` helper function if you need `f` to return a value from `f` fn with_get(&self, col: ColumnId, key: &[u8], f: &mut dyn FnMut(&[u8])) { self.get(col, key).map(|v| f(&v)); } } impl std::fmt::Debug for dyn Database { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "Database") } } /// Call `f` with the value previously stored against `key` and return the result, or `None` if /// `key` is not currently in the database. /// /// This may be faster than `get` since it doesn't allocate. pub fn with_get>( db: &dyn Database, col: ColumnId, key: &[u8], mut f: impl FnMut(&[u8]) -> R ) -> Option { let mut result: Option = None; let mut adapter = |k: &_| { result = Some(f(k)); }; db.with_get(col, key, &mut adapter); result }