referrerpolicy=no-referrer-when-downgrade

sc_client_db/
record_stats_state.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Provides [`RecordStatsState`] for recording stats about state access.
20
21use crate::stats::StateUsageStats;
22use sp_core::storage::ChildInfo;
23use sp_runtime::{
24	traits::{Block as BlockT, HashingFor},
25	StateVersion,
26};
27use sp_state_machine::{
28	backend::{AsTrieBackend, Backend as StateBackend},
29	BackendTransaction, IterArgs, StorageIterator, StorageKey, StorageValue, TrieBackend,
30};
31use sp_trie::MerkleValue;
32use std::sync::Arc;
33
34/// State abstraction for recording stats about state access.
35pub struct RecordStatsState<S, B: BlockT> {
36	/// Usage statistics
37	usage: StateUsageStats,
38	/// State machine registered stats
39	overlay_stats: sp_state_machine::StateMachineStats,
40	/// Backing state.
41	state: S,
42	/// The hash of the block is state belongs to.
43	block_hash: Option<B::Hash>,
44	/// The usage statistics of the backend. These will be updated on drop.
45	state_usage: Arc<StateUsageStats>,
46}
47
48impl<S, B: BlockT> std::fmt::Debug for RecordStatsState<S, B> {
49	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50		write!(f, "Block {:?}", self.block_hash)
51	}
52}
53
54impl<S, B: BlockT> Drop for RecordStatsState<S, B> {
55	fn drop(&mut self) {
56		self.state_usage.merge_sm(self.usage.take());
57	}
58}
59
60impl<S: StateBackend<HashingFor<B>>, B: BlockT> RecordStatsState<S, B> {
61	/// Create a new instance wrapping generic State and shared cache.
62	pub(crate) fn new(
63		state: S,
64		block_hash: Option<B::Hash>,
65		state_usage: Arc<StateUsageStats>,
66	) -> Self {
67		RecordStatsState {
68			usage: StateUsageStats::new(),
69			overlay_stats: sp_state_machine::StateMachineStats::default(),
70			state,
71			block_hash,
72			state_usage,
73		}
74	}
75}
76
77pub struct RawIter<S, B>
78where
79	S: StateBackend<HashingFor<B>>,
80	B: BlockT,
81{
82	inner: <S as StateBackend<HashingFor<B>>>::RawIter,
83}
84
85impl<S, B> StorageIterator<HashingFor<B>> for RawIter<S, B>
86where
87	S: StateBackend<HashingFor<B>>,
88	B: BlockT,
89{
90	type Backend = RecordStatsState<S, B>;
91	type Error = S::Error;
92
93	fn next_key(&mut self, backend: &Self::Backend) -> Option<Result<StorageKey, Self::Error>> {
94		self.inner.next_key(&backend.state)
95	}
96
97	fn next_pair(
98		&mut self,
99		backend: &Self::Backend,
100	) -> Option<Result<(StorageKey, StorageValue), Self::Error>> {
101		self.inner.next_pair(&backend.state)
102	}
103
104	fn was_complete(&self) -> bool {
105		self.inner.was_complete()
106	}
107}
108
109impl<S: StateBackend<HashingFor<B>>, B: BlockT> StateBackend<HashingFor<B>>
110	for RecordStatsState<S, B>
111{
112	type Error = S::Error;
113	type TrieBackendStorage = S::TrieBackendStorage;
114	type RawIter = RawIter<S, B>;
115
116	fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
117		let value = self.state.storage(key)?;
118		self.usage.tally_key_read(key, value.as_ref(), false);
119		Ok(value)
120	}
121
122	fn storage_hash(&self, key: &[u8]) -> Result<Option<B::Hash>, Self::Error> {
123		self.state.storage_hash(key)
124	}
125
126	fn child_storage(
127		&self,
128		child_info: &ChildInfo,
129		key: &[u8],
130	) -> Result<Option<Vec<u8>>, Self::Error> {
131		let key = (child_info.storage_key().to_vec(), key.to_vec());
132		let value = self.state.child_storage(child_info, &key.1)?;
133
134		// just pass it through the usage counter
135		let value = self.usage.tally_child_key_read(&key, value, false);
136
137		Ok(value)
138	}
139
140	fn child_storage_hash(
141		&self,
142		child_info: &ChildInfo,
143		key: &[u8],
144	) -> Result<Option<B::Hash>, Self::Error> {
145		self.state.child_storage_hash(child_info, key)
146	}
147
148	fn closest_merkle_value(
149		&self,
150		key: &[u8],
151	) -> Result<Option<MerkleValue<B::Hash>>, Self::Error> {
152		self.state.closest_merkle_value(key)
153	}
154
155	fn child_closest_merkle_value(
156		&self,
157		child_info: &ChildInfo,
158		key: &[u8],
159	) -> Result<Option<MerkleValue<B::Hash>>, Self::Error> {
160		self.state.child_closest_merkle_value(child_info, key)
161	}
162
163	fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
164		self.state.exists_storage(key)
165	}
166
167	fn exists_child_storage(
168		&self,
169		child_info: &ChildInfo,
170		key: &[u8],
171	) -> Result<bool, Self::Error> {
172		self.state.exists_child_storage(child_info, key)
173	}
174
175	fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
176		self.state.next_storage_key(key)
177	}
178
179	fn next_child_storage_key(
180		&self,
181		child_info: &ChildInfo,
182		key: &[u8],
183	) -> Result<Option<Vec<u8>>, Self::Error> {
184		self.state.next_child_storage_key(child_info, key)
185	}
186
187	fn storage_root<'a>(
188		&self,
189		delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
190		state_version: StateVersion,
191	) -> (B::Hash, BackendTransaction<HashingFor<B>>) {
192		self.state.storage_root(delta, state_version)
193	}
194
195	fn child_storage_root<'a>(
196		&self,
197		child_info: &ChildInfo,
198		delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
199		state_version: StateVersion,
200	) -> (B::Hash, bool, BackendTransaction<HashingFor<B>>) {
201		self.state.child_storage_root(child_info, delta, state_version)
202	}
203
204	fn raw_iter(&self, args: IterArgs) -> Result<Self::RawIter, Self::Error> {
205		self.state.raw_iter(args).map(|inner| RawIter { inner })
206	}
207
208	fn register_overlay_stats(&self, stats: &sp_state_machine::StateMachineStats) {
209		self.overlay_stats.add(stats);
210	}
211
212	fn usage_info(&self) -> sp_state_machine::UsageInfo {
213		let mut info = self.usage.take();
214		info.include_state_machine_states(&self.overlay_stats);
215		info
216	}
217}
218
219impl<S: StateBackend<HashingFor<B>> + AsTrieBackend<HashingFor<B>>, B: BlockT>
220	AsTrieBackend<HashingFor<B>> for RecordStatsState<S, B>
221{
222	type TrieBackendStorage = <S as AsTrieBackend<HashingFor<B>>>::TrieBackendStorage;
223
224	fn as_trie_backend(&self) -> &TrieBackend<Self::TrieBackendStorage, HashingFor<B>> {
225		self.state.as_trie_backend()
226	}
227}