cfxcore/
db.rs

1// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2019 Conflux Foundation. All rights reserved.
18// Conflux is free software and distributed under GNU General Public License.
19// See http://www.gnu.org/licenses/
20
21//! Database utilities and definitions.
22
23use kvdb::{DBTransaction, KeyValueDB};
24use parking_lot::RwLock;
25use std::{collections::HashMap, hash::Hash, ops::Deref};
26
27use rlp;
28
29// database columns for rocksdb
30/// Column for miscellaneous items
31pub const COL_MISC: u32 = 0;
32/// Column for Blocks.
33pub const COL_BLOCKS: u32 = 1;
34/// Column for Transaction Index
35pub const COL_TX_INDEX: u32 = 2;
36/// Column for Epoch Sets
37pub const COL_EPOCH_NUMBER: u32 = 3;
38/// Column for verified roots of blamed headers on light nodes
39pub const COL_BLAMED_HEADER_VERIFIED_ROOTS: u32 = 4;
40/// Column for block traces
41pub const COL_BLOCK_TRACES: u32 = 5;
42/// Column for block number index
43pub const COL_HASH_BY_BLOCK_NUMBER: u32 = 6;
44/// Column for PoS interest reward info.
45pub const COL_REWARD_BY_POS_EPOCH: u32 = 7;
46/// Number of columns in DB
47pub const NUM_COLUMNS: u32 = 8;
48
49/// Modes for updating caches.
50#[derive(Clone, Copy)]
51pub enum CacheUpdatePolicy {
52    /// Overwrite entries.
53    Overwrite,
54    /// Invalidate entries.
55    Invalidate,
56}
57
58/// A cache for arbitrary key-value pairs.
59pub trait Cache<K, V> {
60    /// Insert an entry into the cache and get the old value.
61    fn insert(&mut self, k: K, v: V) -> Option<V>;
62
63    /// Invalidate an entry in the cache, getting the old value if it existed.
64    fn invalidate(&mut self, k: &K) -> Option<V>;
65
66    /// Query the cache for a key's associated value.
67    fn get(&self, k: &K) -> Option<&V>;
68}
69
70impl<K, V> Cache<K, V> for HashMap<K, V>
71where K: Hash + Eq
72{
73    fn insert(&mut self, k: K, v: V) -> Option<V> {
74        HashMap::insert(self, k, v)
75    }
76
77    fn invalidate(&mut self, k: &K) -> Option<V> { HashMap::remove(self, k) }
78
79    fn get(&self, k: &K) -> Option<&V> { HashMap::get(self, k) }
80}
81
82/// Should be used to get database key associated with given value.
83pub trait Key<T> {
84    /// The db key associated with this value.
85    type Target: Deref<Target = [u8]>;
86
87    /// Returns db key.
88    fn key(&self) -> Self::Target;
89}
90
91/// Should be used to write value into database.
92pub trait Writable {
93    /// Writes the value into the database.
94    fn write<T, R>(
95        &mut self, col: u32, key: &dyn Key<T, Target = R>, value: &T,
96    ) where
97        T: rlp::Encodable,
98        R: Deref<Target = [u8]>;
99
100    /// Deletes key from the database.
101    fn delete<T, R>(&mut self, col: u32, key: &dyn Key<T, Target = R>)
102    where
103        T: rlp::Encodable,
104        R: Deref<Target = [u8]>;
105
106    /// Writes the value into the database and updates the cache.
107    fn write_with_cache<K, T, R>(
108        &mut self, col: u32, cache: &mut dyn Cache<K, T>, key: K, value: T,
109        policy: CacheUpdatePolicy,
110    ) where
111        K: Key<T, Target = R> + Hash + Eq,
112        T: rlp::Encodable,
113        R: Deref<Target = [u8]>,
114    {
115        self.write(col, &key, &value);
116        match policy {
117            CacheUpdatePolicy::Overwrite => {
118                cache.insert(key, value);
119            }
120            CacheUpdatePolicy::Invalidate => {
121                cache.invalidate(&key);
122            }
123        }
124    }
125
126    /// Writes the values into the database and updates the cache.
127    fn extend_with_cache<K, T, R>(
128        &mut self, col: u32, cache: &mut dyn Cache<K, T>,
129        values: HashMap<K, T>, policy: CacheUpdatePolicy,
130    ) where
131        K: Key<T, Target = R> + Hash + Eq,
132        T: rlp::Encodable,
133        R: Deref<Target = [u8]>,
134    {
135        match policy {
136            CacheUpdatePolicy::Overwrite => {
137                for (key, value) in values {
138                    self.write(col, &key, &value);
139                    cache.insert(key, value);
140                }
141            }
142            CacheUpdatePolicy::Invalidate => {
143                for (key, value) in &values {
144                    self.write(col, key, value);
145                    cache.invalidate(key);
146                }
147            }
148        }
149    }
150
151    /// Writes and removes the values into the database and updates the cache.
152    fn extend_with_option_cache<K, T, R>(
153        &mut self, col: u32, cache: &mut dyn Cache<K, Option<T>>,
154        values: HashMap<K, Option<T>>, policy: CacheUpdatePolicy,
155    ) where
156        K: Key<T, Target = R> + Hash + Eq,
157        T: rlp::Encodable,
158        R: Deref<Target = [u8]>,
159    {
160        match policy {
161            CacheUpdatePolicy::Overwrite => {
162                for (key, value) in values {
163                    match value {
164                        Some(ref v) => self.write(col, &key, v),
165                        None => self.delete(col, &key),
166                    }
167                    cache.insert(key, value);
168                }
169            }
170            CacheUpdatePolicy::Invalidate => {
171                for (key, value) in values {
172                    match value {
173                        Some(v) => self.write(col, &key, &v),
174                        None => self.delete(col, &key),
175                    }
176                    cache.invalidate(&key);
177                }
178            }
179        }
180    }
181}
182
183/// Should be used to read values from database.
184pub trait Readable {
185    /// Returns value for given key.
186    fn read<T, R>(&self, col: u32, key: &dyn Key<T, Target = R>) -> Option<T>
187    where
188        T: rlp::Decodable,
189        R: Deref<Target = [u8]>;
190
191    /// Returns value for given key either in cache or in database.
192    fn read_with_cache<K, T, C>(
193        &self, col: u32, cache: &RwLock<C>, key: &K,
194    ) -> Option<T>
195    where
196        K: Key<T> + Eq + Hash + Clone,
197        T: Clone + rlp::Decodable,
198        C: Cache<K, T>,
199    {
200        {
201            let read = cache.read();
202            if let Some(v) = read.get(key) {
203                return Some(v.clone());
204            }
205        }
206
207        self.read(col, key).map(|value: T| {
208            let mut write = cache.write();
209            write.insert(key.clone(), value.clone());
210            value
211        })
212    }
213
214    /// Returns true if given value exists.
215    fn exists<T, R>(&self, col: u32, key: &dyn Key<T, Target = R>) -> bool
216    where R: Deref<Target = [u8]>;
217
218    /// Returns true if given value exists either in cache or in database.
219    fn exists_with_cache<K, T, R, C>(
220        &self, col: u32, cache: &RwLock<C>, key: &K,
221    ) -> bool
222    where
223        K: Eq + Hash + Key<T, Target = R>,
224        R: Deref<Target = [u8]>,
225        C: Cache<K, T>,
226    {
227        {
228            let read = cache.read();
229            if read.get(key).is_some() {
230                return true;
231            }
232        }
233
234        self.exists::<T, R>(col, key)
235    }
236}
237
238impl Writable for DBTransaction {
239    fn write<T, R>(&mut self, col: u32, key: &dyn Key<T, Target = R>, value: &T)
240    where
241        T: rlp::Encodable,
242        R: Deref<Target = [u8]>,
243    {
244        self.put(col, &key.key(), &rlp::encode(value));
245    }
246
247    fn delete<T, R>(&mut self, col: u32, key: &dyn Key<T, Target = R>)
248    where
249        T: rlp::Encodable,
250        R: Deref<Target = [u8]>,
251    {
252        self.delete(col, &key.key());
253    }
254}
255
256impl<KVDB: KeyValueDB + ?Sized> Readable for KVDB {
257    fn read<T, R>(&self, col: u32, key: &dyn Key<T, Target = R>) -> Option<T>
258    where
259        T: rlp::Decodable,
260        R: Deref<Target = [u8]>,
261    {
262        self.get(col, &key.key())
263            .unwrap_or_else(|_| {
264                panic!("db get failed, key: {:?}", &key.key() as &[u8])
265            })
266            .map(|v| rlp::decode(&v).expect("decode db value failed"))
267    }
268
269    fn exists<T, R>(&self, col: u32, key: &dyn Key<T, Target = R>) -> bool
270    where R: Deref<Target = [u8]> {
271        let result = self.get(col, &key.key());
272
273        match result {
274            Ok(v) => v.is_some(),
275            Err(err) => {
276                panic!(
277                    "db get failed, key: {:?}, err: {:?}",
278                    &key.key() as &[u8],
279                    err
280                );
281            }
282        }
283    }
284}