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)
    }
}