sp_database/
mem.rs

1// This file is part of Substrate.
2
3// Copyright (C) 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//! In-memory implementation of `Database`
19
20use crate::{error, Change, ColumnId, Database, Transaction};
21use parking_lot::RwLock;
22use std::collections::{hash_map::Entry, HashMap};
23
24#[derive(Default)]
25/// This implements `Database` as an in-memory hash map. `commit` is not atomic.
26pub struct MemDb(RwLock<HashMap<ColumnId, HashMap<Vec<u8>, (u32, Vec<u8>)>>>);
27
28impl<H> Database<H> for MemDb
29where
30	H: Clone + AsRef<[u8]>,
31{
32	fn commit(&self, transaction: Transaction<H>) -> error::Result<()> {
33		let mut s = self.0.write();
34		for change in transaction.0.into_iter() {
35			match change {
36				Change::Set(col, key, value) => {
37					s.entry(col).or_default().insert(key, (1, value));
38				},
39				Change::Remove(col, key) => {
40					s.entry(col).or_default().remove(&key);
41				},
42				Change::Store(col, hash, value) => {
43					s.entry(col)
44						.or_default()
45						.entry(hash.as_ref().to_vec())
46						.and_modify(|(c, _)| *c += 1)
47						.or_insert_with(|| (1, value));
48				},
49				Change::Reference(col, hash) => {
50					if let Entry::Occupied(mut entry) =
51						s.entry(col).or_default().entry(hash.as_ref().to_vec())
52					{
53						entry.get_mut().0 += 1;
54					}
55				},
56				Change::Release(col, hash) => {
57					if let Entry::Occupied(mut entry) =
58						s.entry(col).or_default().entry(hash.as_ref().to_vec())
59					{
60						entry.get_mut().0 -= 1;
61						if entry.get().0 == 0 {
62							entry.remove();
63						}
64					}
65				},
66			}
67		}
68
69		Ok(())
70	}
71
72	fn get(&self, col: ColumnId, key: &[u8]) -> Option<Vec<u8>> {
73		let s = self.0.read();
74		s.get(&col).and_then(|c| c.get(key).map(|(_, v)| v.clone()))
75	}
76}
77
78impl MemDb {
79	/// Create a new instance
80	pub fn new() -> Self {
81		MemDb::default()
82	}
83
84	/// Count number of values in a column
85	pub fn count(&self, col: ColumnId) -> usize {
86		let s = self.0.read();
87		s.get(&col).map(|c| c.len()).unwrap_or(0)
88	}
89}