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