massa_storage/
operation_indexes.rs

1use std::collections::hash_map::{self, Entry};
2
3use massa_models::{
4    address::Address,
5    operation::{OperationId, OperationPrefixId, SecureShareOperation},
6    prehash::{PreHashMap, PreHashSet},
7};
8
9/// Container for all operations and different indexes.
10/// Note: The structure can evolve and store more indexes.
11#[derive(Default)]
12pub struct OperationIndexes {
13    /// Operations structure container
14    operations: PreHashMap<OperationId, Box<SecureShareOperation>>,
15    /// Structure mapping creators with the created operations
16    index_by_creator: PreHashMap<Address, PreHashSet<OperationId>>,
17    /// Structure indexing operations by ID prefix
18    index_by_prefix: PreHashMap<OperationPrefixId, PreHashSet<OperationId>>,
19}
20
21impl OperationIndexes {
22    /// Insert an operation and populate the indexes.
23    /// Arguments:
24    /// * `operation`: the operation to insert
25    pub(crate) fn insert(&mut self, operation: SecureShareOperation) {
26        if let Entry::Vacant(vac) = self.operations.entry(operation.id) {
27            let operation = vac.insert(Box::new(operation));
28            // update creator index
29            self.index_by_creator
30                .entry(operation.content_creator_address)
31                .or_default()
32                .insert(operation.id);
33            // update prefix index
34            self.index_by_prefix
35                .entry(operation.id.prefix())
36                .or_default()
37                .insert(operation.id);
38
39            massa_metrics::set_operations_counter(self.operations.len());
40        }
41    }
42
43    /// Remove a operation, remove from the indexes and made some clean-up in indexes if necessary.
44    /// Arguments:
45    /// * `operation_id`: the operation id to remove
46    pub(crate) fn remove(
47        &mut self,
48        operation_id: &OperationId,
49    ) -> Option<Box<SecureShareOperation>> {
50        if let Some(o) = self.operations.remove(operation_id) {
51            massa_metrics::set_operations_counter(self.operations.len());
52
53            // update creator index
54            if let hash_map::Entry::Occupied(mut occ) =
55                self.index_by_creator.entry(o.content_creator_address)
56            {
57                occ.get_mut().remove(&o.id);
58                if occ.get().is_empty() {
59                    occ.remove();
60                }
61            }
62            // update prefix index
63            if let hash_map::Entry::Occupied(mut occ) = self.index_by_prefix.entry(o.id.prefix()) {
64                occ.get_mut().remove(&o.id);
65                if occ.get().is_empty() {
66                    occ.remove();
67                }
68            }
69            return Some(o);
70        }
71        None
72    }
73
74    /// Gets a reference to a stored operation, if any.
75    pub fn get(&self, id: &OperationId) -> Option<&SecureShareOperation> {
76        self.operations.get(id).map(|v| v.as_ref())
77    }
78
79    /// Checks whether an operation exists in global storage.
80    pub fn contains(&self, id: &OperationId) -> bool {
81        self.operations.contains_key(id)
82    }
83
84    /// Get operations created by an address
85    /// Arguments:
86    /// * `address`: the address to get the operations created by
87    ///
88    /// Returns:
89    /// - optional reference to a set of operations created by that address
90    pub fn get_operations_created_by(&self, address: &Address) -> Option<&PreHashSet<OperationId>> {
91        self.index_by_creator.get(address)
92    }
93
94    /// Get operations by prefix
95    /// Arguments:
96    /// * `prefix`: the prefix to look up
97    ///
98    /// Returns:
99    /// - optional reference to a set of operations that match that prefix
100    pub fn get_operations_by_prefix(
101        &self,
102        prefix: &OperationPrefixId,
103    ) -> Option<&PreHashSet<OperationId>> {
104        self.index_by_prefix.get(prefix)
105    }
106}