1#![warn(missing_docs)]
10
11mod block_indexes;
12mod endorsement_indexes;
13mod operation_indexes;
14
15#[cfg(test)]
16mod tests;
17
18use block_indexes::BlockIndexes;
19use endorsement_indexes::EndorsementIndexes;
20use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet, PreHashed};
21use massa_models::secure_share::Id;
22use massa_models::{
23 block::SecureShareBlock,
24 block_id::BlockId,
25 endorsement::{EndorsementId, SecureShareEndorsement},
26 operation::{OperationId, SecureShareOperation},
27};
28use operation_indexes::OperationIndexes;
29use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
30use std::fmt::Debug;
31use std::hash::Hash;
32use std::{collections::hash_map, sync::Arc};
33
34pub struct Storage {
36 blocks: Arc<RwLock<BlockIndexes>>,
38 operations: Arc<RwLock<OperationIndexes>>,
40 endorsements: Arc<RwLock<EndorsementIndexes>>,
42
43 block_owners: Arc<RwLock<PreHashMap<BlockId, usize>>>,
45 operation_owners: Arc<RwLock<PreHashMap<OperationId, usize>>>,
47 endorsement_owners: Arc<RwLock<PreHashMap<EndorsementId, usize>>>,
49
50 local_used_blocks: PreHashSet<BlockId>,
52 local_used_ops: PreHashSet<OperationId>,
54 local_used_endorsements: PreHashSet<EndorsementId>,
56}
57
58impl Debug for Storage {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 f.write_str("")
62 }
63}
64
65impl Clone for Storage {
66 fn clone(&self) -> Self {
67 let mut res = Self::clone_without_refs(self);
68
69 Storage::internal_claim_refs(
71 &self.local_used_ops.clone(),
72 &mut res.operation_owners.write(),
73 &mut res.local_used_ops,
74 );
75
76 Storage::internal_claim_refs(
78 &self.local_used_blocks.clone(),
79 &mut res.block_owners.write(),
80 &mut res.local_used_blocks,
81 );
82
83 Storage::internal_claim_refs(
85 &self.local_used_endorsements.clone(),
86 &mut res.endorsement_owners.write(),
87 &mut res.local_used_endorsements,
88 );
89
90 res
91 }
92}
93
94impl Storage {
95 pub fn create_root() -> Storage {
101 Storage {
102 blocks: Default::default(),
103 operations: Default::default(),
104 endorsements: Default::default(),
105 block_owners: Default::default(),
106 operation_owners: Default::default(),
107 endorsement_owners: Default::default(),
108 local_used_blocks: Default::default(),
109 local_used_ops: Default::default(),
110 local_used_endorsements: Default::default(),
111 }
112 }
113
114 pub fn clone_without_refs(&self) -> Self {
116 Self {
117 blocks: self.blocks.clone(),
118 operations: self.operations.clone(),
119 endorsements: self.endorsements.clone(),
120
121 operation_owners: self.operation_owners.clone(),
122 block_owners: self.block_owners.clone(),
123 endorsement_owners: self.endorsement_owners.clone(),
124
125 local_used_ops: Default::default(),
127 local_used_blocks: Default::default(),
128 local_used_endorsements: Default::default(),
129 }
130 }
131
132 pub fn replace_with(&mut self, other: &Storage) {
134 {
136 let added_ops = other.get_op_refs() - self.get_op_refs();
137 let removed_ops = self.get_op_refs() - other.get_op_refs();
138 {
139 let owners = &mut self.operation_owners.write();
140 let orphaned_ids =
142 Self::internal_drop_refs(&removed_ops, owners, &mut self.local_used_ops);
143 if !orphaned_ids.is_empty() {
145 let mut ops = self.operations.write();
146 for op_id in orphaned_ids {
147 ops.remove(&op_id);
148 }
149 }
150 Self::internal_claim_refs(&added_ops, owners, &mut self.local_used_ops);
152 }
153 }
154
155 {
157 let added_blocks = other.get_block_refs() - self.get_block_refs();
158 let removed_blocks = self.get_block_refs() - other.get_block_refs();
159 {
160 let owners = &mut self.block_owners.write();
161 let orphaned_ids =
163 Self::internal_drop_refs(&removed_blocks, owners, &mut self.local_used_blocks);
164 if !orphaned_ids.is_empty() {
166 let mut blocks = self.blocks.write();
167 for block_id in orphaned_ids {
168 blocks.remove(&block_id);
169 }
170 }
171 Self::internal_claim_refs(&added_blocks, owners, &mut self.local_used_blocks);
173 }
174 }
175
176 {
178 let added_endorsements = other.get_endorsement_refs() - self.get_endorsement_refs();
179 let removed_endorsements = self.get_endorsement_refs() - other.get_endorsement_refs();
180 {
181 let owners = &mut self.endorsement_owners.write();
182 let orphaned_ids = Self::internal_drop_refs(
184 &removed_endorsements,
185 owners,
186 &mut self.local_used_endorsements,
187 );
188 if !orphaned_ids.is_empty() {
190 let mut endorsements = self.endorsements.write();
191 for endorsement_id in orphaned_ids {
192 endorsements.remove(&endorsement_id);
193 }
194 }
195 Self::internal_claim_refs(
197 &added_endorsements,
198 owners,
199 &mut self.local_used_endorsements,
200 );
201 }
202 }
203 }
204
205 pub fn extend(&mut self, mut other: Storage) {
207 other
210 .local_used_ops
211 .retain(|id| !self.local_used_ops.insert(*id));
212
213 other
214 .local_used_blocks
215 .retain(|id| !self.local_used_blocks.insert(*id));
216
217 other
218 .local_used_endorsements
219 .retain(|id| !self.local_used_endorsements.insert(*id));
220 }
221
222 pub fn split_off(
225 &mut self,
226 blocks: &PreHashSet<BlockId>,
227 operations: &PreHashSet<OperationId>,
228 endorsements: &PreHashSet<EndorsementId>,
229 ) -> Storage {
230 let mut res = self.clone_without_refs();
232
233 res.local_used_blocks = blocks
237 .iter()
238 .map(|id| {
239 self.local_used_blocks
240 .take(id)
241 .expect("split block ref not owned by source")
242 })
243 .collect();
244
245 res.local_used_ops = operations
246 .iter()
247 .map(|id| {
248 self.local_used_ops
249 .take(id)
250 .expect("split op ref not owned by source")
251 })
252 .collect();
253
254 res.local_used_endorsements = endorsements
255 .iter()
256 .map(|id| {
257 self.local_used_endorsements
258 .take(id)
259 .expect("split endorsement ref not owned by source")
260 })
261 .collect();
262
263 res
264 }
265
266 fn internal_claim_refs<IdT: Id + PartialEq + Eq + Hash + PreHashed + Copy>(
268 ids: &PreHashSet<IdT>,
269 owners: &mut RwLockWriteGuard<PreHashMap<IdT, usize>>,
270 local_used_ids: &mut PreHashSet<IdT>,
271 ) {
272 for &id in ids {
273 if local_used_ids.insert(id) {
274 owners.entry(id).and_modify(|v| *v += 1).or_insert(1);
275 }
276 }
277 }
278
279 pub fn get_block_refs(&self) -> &PreHashSet<BlockId> {
281 &self.local_used_blocks
282 }
283
284 pub fn claim_block_refs(&mut self, ids: &PreHashSet<BlockId>) -> PreHashSet<BlockId> {
287 let mut claimed = PreHashSet::with_capacity(ids.len());
288
289 if ids.is_empty() {
290 return claimed;
291 }
292
293 let owners = &mut self.block_owners.write();
294
295 claimed.extend(ids.iter().filter(|id| owners.contains_key(id)));
297
298 Storage::internal_claim_refs(&claimed, owners, &mut self.local_used_blocks);
300
301 claimed
302 }
303
304 fn internal_drop_refs<IdT: Id + PartialEq + Eq + Hash + PreHashed + Copy>(
305 ids: &PreHashSet<IdT>,
306 owners: &mut RwLockWriteGuard<PreHashMap<IdT, usize>>,
307 local_used_ids: &mut PreHashSet<IdT>,
308 ) -> Vec<IdT> {
309 let mut orphaned_ids = Vec::new();
310 for id in ids {
311 if !local_used_ids.remove(id) {
312 continue;
314 }
315 match owners.entry(*id) {
316 hash_map::Entry::Occupied(mut occ) => {
317 let res_count = {
318 let cnt = occ.get_mut();
319 *cnt = cnt
320 .checked_sub(1)
321 .expect("less than 1 owner on storage object reference drop");
322 *cnt
323 };
324 if res_count == 0 {
325 orphaned_ids.push(*id);
326 occ.remove();
327 }
328 }
329 hash_map::Entry::Vacant(_vac) => {
330 panic!("missing object in storage on storage object reference drop");
331 }
332 }
333 }
334 orphaned_ids
335 }
336
337 pub fn drop_block_refs(&mut self, ids: &PreHashSet<BlockId>) {
339 if ids.is_empty() {
340 return;
341 }
342 let mut owners = self.block_owners.write();
343 let orphaned_ids = Self::internal_drop_refs(ids, &mut owners, &mut self.local_used_blocks);
344 if !orphaned_ids.is_empty() {
346 let mut blocks = self.blocks.write();
347 for b_id in orphaned_ids {
348 blocks.remove(&b_id);
349 }
350 }
351 }
352
353 pub fn store_block(&mut self, block: SecureShareBlock) {
356 let id = block.id;
357 let mut owners = self.block_owners.write();
358 let mut blocks = self.blocks.write();
359 blocks.insert(block);
360 Storage::internal_claim_refs(
362 &vec![id].into_iter().collect(),
363 &mut owners,
364 &mut self.local_used_blocks,
365 );
366 }
367
368 pub fn claim_operation_refs(
371 &mut self,
372 ids: &PreHashSet<OperationId>,
373 ) -> PreHashSet<OperationId> {
374 let mut claimed = PreHashSet::with_capacity(ids.len());
375
376 if ids.is_empty() {
377 return claimed;
378 }
379
380 let owners = &mut self.operation_owners.write();
381
382 claimed.extend(ids.iter().filter(|id| owners.contains_key(id)));
384
385 Storage::internal_claim_refs(&claimed, owners, &mut self.local_used_ops);
387
388 claimed
389 }
390
391 pub fn get_op_refs(&self) -> &PreHashSet<OperationId> {
393 &self.local_used_ops
394 }
395
396 pub fn drop_operation_refs(&mut self, ids: &PreHashSet<OperationId>) {
399 if ids.is_empty() {
400 return;
401 }
402 let mut owners = self.operation_owners.write();
403 let orphaned_ids = Self::internal_drop_refs(ids, &mut owners, &mut self.local_used_ops);
404 if !orphaned_ids.is_empty() {
406 let mut ops = self.operations.write();
407 for op_id in orphaned_ids {
408 ops.remove(&op_id);
409 }
410 }
411 }
412
413 pub fn store_operations(&mut self, operations: Vec<SecureShareOperation>) {
416 if operations.is_empty() {
417 return;
418 }
419 let mut owners = self.operation_owners.write();
420 let mut op_store = self.operations.write();
421 let ids: PreHashSet<OperationId> = operations.iter().map(|op| op.id).collect();
422 for op in operations {
423 op_store.insert(op);
424 }
425 Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_ops);
426 }
427
428 pub fn read_operations(&self) -> RwLockReadGuard<'_, OperationIndexes> {
430 self.operations.read()
431 }
432
433 pub fn read_endorsements(&self) -> RwLockReadGuard<'_, EndorsementIndexes> {
435 self.endorsements.read()
436 }
437
438 pub fn read_blocks(&self) -> RwLockReadGuard<'_, BlockIndexes> {
440 self.blocks.read()
441 }
442
443 pub fn claim_endorsement_refs(
446 &mut self,
447 ids: &PreHashSet<EndorsementId>,
448 ) -> PreHashSet<EndorsementId> {
449 let mut claimed = PreHashSet::with_capacity(ids.len());
450
451 if ids.is_empty() {
452 return claimed;
453 }
454
455 let owners = &mut self.endorsement_owners.write();
456
457 claimed.extend(ids.iter().filter(|id| owners.contains_key(id)));
459
460 Storage::internal_claim_refs(&claimed, owners, &mut self.local_used_endorsements);
462 claimed
463 }
464
465 pub fn get_endorsement_refs(&self) -> &PreHashSet<EndorsementId> {
467 &self.local_used_endorsements
468 }
469
470 pub fn drop_endorsement_refs(&mut self, ids: &PreHashSet<EndorsementId>) {
473 if ids.is_empty() {
474 return;
475 }
476 let mut owners = self.endorsement_owners.write();
477 let orphaned_ids =
478 Self::internal_drop_refs(ids, &mut owners, &mut self.local_used_endorsements);
479 if !orphaned_ids.is_empty() {
481 let mut endorsements = self.endorsements.write();
482 for e_id in orphaned_ids {
483 endorsements.remove(&e_id);
484 }
485 }
486 }
487
488 pub fn store_endorsements(&mut self, endorsements: Vec<SecureShareEndorsement>) {
491 if endorsements.is_empty() {
492 return;
493 }
494 let mut owners = self.endorsement_owners.write();
495 let mut endo_store = self.endorsements.write();
496 let ids: PreHashSet<EndorsementId> = endorsements.iter().map(|op| op.id).collect();
497 for endorsement in endorsements {
498 endo_store.insert(endorsement);
499 }
500 Storage::internal_claim_refs(&ids, &mut owners, &mut self.local_used_endorsements);
501 }
502}
503
504impl Drop for Storage {
505 fn drop(&mut self) {
507 self.drop_block_refs(&self.local_used_blocks.clone());
509
510 self.drop_operation_refs(&self.local_used_ops.clone());
512
513 self.drop_endorsement_refs(&self.local_used_endorsements.clone());
515 }
516}