tetcore_database/lib.rs
1// This file is part of Tetcore.
2
3// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! The main database trait, allowing Tetcore to store data persistently.
19
20pub mod error;
21mod mem;
22mod tetsy_kvdb;
23
24pub use mem::MemDb;
25pub use crate::tetsy_kvdb::as_database;
26
27/// An identifier for a column.
28pub type ColumnId = u32;
29
30/// An alteration to the database.
31#[derive(Clone)]
32pub enum Change<H> {
33 Set(ColumnId, Vec<u8>, Vec<u8>),
34 Remove(ColumnId, Vec<u8>),
35 Store(H, Vec<u8>),
36 Release(H),
37}
38
39/// An alteration to the database that references the data.
40pub enum ChangeRef<'a, H> {
41 Set(ColumnId, &'a [u8], &'a [u8]),
42 Remove(ColumnId, &'a [u8]),
43 Store(H, &'a [u8]),
44 Release(H),
45}
46
47/// A series of changes to the database that can be committed atomically. They do not take effect
48/// until passed into `Database::commit`.
49#[derive(Default, Clone)]
50pub struct Transaction<H>(pub Vec<Change<H>>);
51
52impl<H> Transaction<H> {
53 /// Create a new transaction to be prepared and committed atomically.
54 pub fn new() -> Self {
55 Transaction(Vec::new())
56 }
57 /// Set the value of `key` in `col` to `value`, replacing anything that is there currently.
58 pub fn set(&mut self, col: ColumnId, key: &[u8], value: &[u8]) {
59 self.0.push(Change::Set(col, key.to_vec(), value.to_vec()))
60 }
61 /// Set the value of `key` in `col` to `value`, replacing anything that is there currently.
62 pub fn set_from_vec(&mut self, col: ColumnId, key: &[u8], value: Vec<u8>) {
63 self.0.push(Change::Set(col, key.to_vec(), value))
64 }
65 /// Remove the value of `key` in `col`.
66 pub fn remove(&mut self, col: ColumnId, key: &[u8]) {
67 self.0.push(Change::Remove(col, key.to_vec()))
68 }
69 /// Store the `preimage` of `hash` into the database, so that it may be looked up later with
70 /// `Database::lookup`. This may be called multiple times, but `Database::lookup` but subsequent
71 /// calls will ignore `preimage` and simply increase the number of references on `hash`.
72 pub fn store(&mut self, hash: H, preimage: &[u8]) {
73 self.0.push(Change::Store(hash, preimage.to_vec()))
74 }
75 /// Release the preimage of `hash` from the database. An equal number of these to the number of
76 /// corresponding `store`s must have been given before it is legal for `Database::lookup` to
77 /// be unable to provide the preimage.
78 pub fn release(&mut self, hash: H) {
79 self.0.push(Change::Release(hash))
80 }
81}
82
83pub trait Database<H: Clone>: Send + Sync {
84 /// Commit the `transaction` to the database atomically. Any further calls to `get` or `lookup`
85 /// will reflect the new state.
86 fn commit(&self, transaction: Transaction<H>) -> error::Result<()> {
87 for change in transaction.0.into_iter() {
88 match change {
89 Change::Set(col, key, value) => self.set(col, &key, &value),
90 Change::Remove(col, key) => self.remove(col, &key),
91 Change::Store(hash, preimage) => self.store(&hash, &preimage),
92 Change::Release(hash) => self.release(&hash),
93 }?;
94 }
95
96 Ok(())
97 }
98
99 /// Commit the `transaction` to the database atomically. Any further calls to `get` or `lookup`
100 /// will reflect the new state.
101 fn commit_ref<'a>(&self, transaction: &mut dyn Iterator<Item=ChangeRef<'a, H>>) -> error::Result<()> {
102 let mut tx = Transaction::new();
103 for change in transaction {
104 match change {
105 ChangeRef::Set(col, key, value) => tx.set(col, key, value),
106 ChangeRef::Remove(col, key) => tx.remove(col, key),
107 ChangeRef::Store(hash, preimage) => tx.store(hash, preimage),
108 ChangeRef::Release(hash) => tx.release(hash),
109 }
110 }
111 self.commit(tx)
112 }
113
114 /// Retrieve the value previously stored against `key` or `None` if
115 /// `key` is not currently in the database.
116 fn get(&self, col: ColumnId, key: &[u8]) -> Option<Vec<u8>>;
117
118 /// Call `f` with the value previously stored against `key`.
119 ///
120 /// This may be faster than `get` since it doesn't allocate.
121 /// Use `with_get` helper function if you need `f` to return a value from `f`
122 fn with_get(&self, col: ColumnId, key: &[u8], f: &mut dyn FnMut(&[u8])) {
123 self.get(col, key).map(|v| f(&v));
124 }
125
126 /// Set the value of `key` in `col` to `value`, replacing anything that is there currently.
127 fn set(&self, col: ColumnId, key: &[u8], value: &[u8]) -> error::Result<()> {
128 let mut t = Transaction::new();
129 t.set(col, key, value);
130 self.commit(t)
131 }
132 /// Remove the value of `key` in `col`.
133 fn remove(&self, col: ColumnId, key: &[u8]) -> error::Result<()> {
134 let mut t = Transaction::new();
135 t.remove(col, key);
136 self.commit(t)
137 }
138
139 /// Retrieve the first preimage previously `store`d for `hash` or `None` if no preimage is
140 /// currently stored.
141 fn lookup(&self, hash: &H) -> Option<Vec<u8>>;
142
143 /// Call `f` with the preimage stored for `hash` and return the result, or `None` if no preimage
144 /// is currently stored.
145 ///
146 /// This may be faster than `lookup` since it doesn't allocate.
147 /// Use `with_lookup` helper function if you need `f` to return a value from `f`
148 fn with_lookup(&self, hash: &H, f: &mut dyn FnMut(&[u8])) {
149 self.lookup(hash).map(|v| f(&v));
150 }
151
152 /// Store the `preimage` of `hash` into the database, so that it may be looked up later with
153 /// `Database::lookup`. This may be called multiple times, but `Database::lookup` but subsequent
154 /// calls will ignore `preimage` and simply increase the number of references on `hash`.
155 fn store(&self, hash: &H, preimage: &[u8]) -> error::Result<()> {
156 let mut t = Transaction::new();
157 t.store(hash.clone(), preimage);
158 self.commit(t)
159 }
160
161 /// Release the preimage of `hash` from the database. An equal number of these to the number of
162 /// corresponding `store`s must have been given before it is legal for `Database::lookup` to
163 /// be unable to provide the preimage.
164 fn release(&self, hash: &H) -> error::Result<()> {
165 let mut t = Transaction::new();
166 t.release(hash.clone());
167 self.commit(t)
168 }
169}
170
171impl<H> std::fmt::Debug for dyn Database<H> {
172 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
173 write!(f, "Database")
174 }
175}
176
177/// Call `f` with the value previously stored against `key` and return the result, or `None` if
178/// `key` is not currently in the database.
179///
180/// This may be faster than `get` since it doesn't allocate.
181pub fn with_get<R, H: Clone>(db: &dyn Database<H>, col: ColumnId, key: &[u8], mut f: impl FnMut(&[u8]) -> R) -> Option<R> {
182 let mut result: Option<R> = None;
183 let mut adapter = |k: &_| { result = Some(f(k)); };
184 db.with_get(col, key, &mut adapter);
185 result
186}
187
188/// Call `f` with the preimage stored for `hash` and return the result, or `None` if no preimage
189/// is currently stored.
190///
191/// This may be faster than `lookup` since it doesn't allocate.
192pub fn with_lookup<R, H: Clone>(db: &dyn Database<H>, hash: &H, mut f: impl FnMut(&[u8]) -> R) -> Option<R> {
193 let mut result: Option<R> = None;
194 let mut adapter = |k: &_| { result = Some(f(k)); };
195 db.with_lookup(hash, &mut adapter);
196 result
197}