sc_client_db/
pinned_blocks_cache.rs1use schnellru::{Limiter, LruMap};
20use sp_runtime::{traits::Block as BlockT, Justifications};
21
22const LOG_TARGET: &str = "db::pin";
23const PINNING_CACHE_SIZE: usize = 2048;
24
25struct PinnedBlockCacheEntry<Block: BlockT> {
27 ref_count: u32,
29
30 pub justifications: Option<Option<Justifications>>,
32
33 pub body: Option<Option<Vec<Block::Extrinsic>>>,
35}
36
37impl<Block: BlockT> Default for PinnedBlockCacheEntry<Block> {
38 fn default() -> Self {
39 Self { ref_count: 0, justifications: None, body: None }
40 }
41}
42
43impl<Block: BlockT> PinnedBlockCacheEntry<Block> {
44 pub fn decrease_ref(&mut self) {
45 self.ref_count = self.ref_count.saturating_sub(1);
46 }
47
48 pub fn increase_ref(&mut self) {
49 self.ref_count = self.ref_count.saturating_add(1);
50 }
51
52 pub fn has_no_references(&self) -> bool {
53 self.ref_count == 0
54 }
55}
56
57#[derive(Copy, Clone, Debug)]
59struct LoggingByLengthLimiter {
60 max_length: usize,
61}
62
63impl LoggingByLengthLimiter {
64 pub const fn new(max_length: usize) -> LoggingByLengthLimiter {
66 LoggingByLengthLimiter { max_length }
67 }
68}
69
70impl<Block: BlockT> Limiter<Block::Hash, PinnedBlockCacheEntry<Block>> for LoggingByLengthLimiter {
71 type KeyToInsert<'a> = Block::Hash;
72 type LinkType = usize;
73
74 fn is_over_the_limit(&self, length: usize) -> bool {
75 length > self.max_length
76 }
77
78 fn on_insert(
79 &mut self,
80 _length: usize,
81 key: Self::KeyToInsert<'_>,
82 value: PinnedBlockCacheEntry<Block>,
83 ) -> Option<(Block::Hash, PinnedBlockCacheEntry<Block>)> {
84 if self.max_length > 0 {
85 Some((key, value))
86 } else {
87 None
88 }
89 }
90
91 fn on_replace(
92 &mut self,
93 _length: usize,
94 _old_key: &mut Block::Hash,
95 _new_key: Block::Hash,
96 _old_value: &mut PinnedBlockCacheEntry<Block>,
97 _new_value: &mut PinnedBlockCacheEntry<Block>,
98 ) -> bool {
99 true
100 }
101
102 fn on_removed(&mut self, key: &mut Block::Hash, value: &mut PinnedBlockCacheEntry<Block>) {
103 if value.ref_count > 0 {
108 log::warn!(
109 target: LOG_TARGET,
110 "Pinned block cache limit reached. Evicting value. hash = {}",
111 key
112 );
113 } else {
114 log::trace!(
115 target: LOG_TARGET,
116 "Evicting value from pinned block cache. hash = {}",
117 key
118 )
119 }
120 }
121
122 fn on_cleared(&mut self) {}
123
124 fn on_grow(&mut self, _new_memory_usage: usize) -> bool {
125 true
126 }
127}
128
129pub struct PinnedBlocksCache<Block: BlockT> {
131 cache: LruMap<Block::Hash, PinnedBlockCacheEntry<Block>, LoggingByLengthLimiter>,
132}
133
134impl<Block: BlockT> PinnedBlocksCache<Block> {
135 pub fn new() -> Self {
136 Self { cache: LruMap::new(LoggingByLengthLimiter::new(PINNING_CACHE_SIZE)) }
137 }
138
139 pub fn pin(&mut self, hash: Block::Hash) {
142 match self.cache.get_or_insert(hash, Default::default) {
143 Some(entry) => {
144 entry.increase_ref();
145 log::trace!(
146 target: LOG_TARGET,
147 "Bumped cache refcount. hash = {}, num_entries = {}",
148 hash,
149 self.cache.len()
150 );
151 },
152 None => {
153 log::warn!(target: LOG_TARGET, "Unable to bump reference count. hash = {}", hash)
154 },
155 };
156 }
157
158 pub fn clear(&mut self) {
160 self.cache.clear();
161 }
162
163 pub fn contains(&self, hash: Block::Hash) -> bool {
165 self.cache.peek(&hash).is_some()
166 }
167
168 pub fn insert_body(&mut self, hash: Block::Hash, extrinsics: Option<Vec<Block::Extrinsic>>) {
170 match self.cache.peek_mut(&hash) {
171 Some(entry) => {
172 entry.body = Some(extrinsics);
173 log::trace!(
174 target: LOG_TARGET,
175 "Cached body. hash = {}, num_entries = {}",
176 hash,
177 self.cache.len()
178 );
179 },
180 None => log::warn!(
181 target: LOG_TARGET,
182 "Unable to insert body for uncached item. hash = {}",
183 hash
184 ),
185 }
186 }
187
188 pub fn insert_justifications(
190 &mut self,
191 hash: Block::Hash,
192 justifications: Option<Justifications>,
193 ) {
194 match self.cache.peek_mut(&hash) {
195 Some(entry) => {
196 entry.justifications = Some(justifications);
197 log::trace!(
198 target: LOG_TARGET,
199 "Cached justification. hash = {}, num_entries = {}",
200 hash,
201 self.cache.len()
202 );
203 },
204 None => log::warn!(
205 target: LOG_TARGET,
206 "Unable to insert justifications for uncached item. hash = {}",
207 hash
208 ),
209 }
210 }
211
212 pub fn unpin(&mut self, hash: Block::Hash) {
215 if let Some(entry) = self.cache.peek_mut(&hash) {
216 entry.decrease_ref();
217 if entry.has_no_references() {
218 self.cache.remove(&hash);
219 }
220 }
221 }
222
223 pub fn justifications(&self, hash: &Block::Hash) -> Option<&Option<Justifications>> {
225 self.cache.peek(hash).and_then(|entry| entry.justifications.as_ref())
226 }
227
228 pub fn body(&self, hash: &Block::Hash) -> Option<&Option<Vec<Block::Extrinsic>>> {
230 self.cache.peek(hash).and_then(|entry| entry.body.as_ref())
231 }
232}