radix_substate_store_impls/
substate_database_overlay.rs

1use radix_common::prelude::*;
2use radix_rust::prelude::borrow::*;
3use radix_substate_store_interface::interface::*;
4
5pub type UnmergeableSubstateDatabaseOverlay<'a, S> = SubstateDatabaseOverlay<&'a S, S>;
6pub type MergeableSubstateDatabaseOverlay<'a, S> = SubstateDatabaseOverlay<&'a mut S, S>;
7pub type OwnedSubstateDatabaseOverlay<S> = SubstateDatabaseOverlay<S, S>;
8
9pub struct SubstateDatabaseOverlay<S, D> {
10    /// The database overlay. All commits made to the database are written to the overlay. This
11    /// covers new values and deletions too.
12    overlay: StagingDatabaseUpdates,
13
14    /// A mutable or immutable reference to the root database that this type overlays.
15    /// It only needs to be mutable if you wish to commit to the root store.
16    /// To be useful, `S` should implement at least `Borrow<D>`.
17    root: S,
18
19    /// The concrete type of the underlying substate database.
20    substate_database_type: PhantomData<D>,
21}
22
23impl<'a, D> UnmergeableSubstateDatabaseOverlay<'a, D> {
24    pub fn new_unmergeable(root_database: &'a D) -> Self {
25        Self::new(root_database)
26    }
27}
28
29impl<'a, D> MergeableSubstateDatabaseOverlay<'a, D> {
30    pub fn new_mergeable(root_database: &'a mut D) -> Self {
31        Self::new(root_database)
32    }
33}
34
35impl<D> OwnedSubstateDatabaseOverlay<D> {
36    pub fn new_owned(root_database: D) -> Self {
37        Self::new(root_database)
38    }
39}
40
41impl<S, D> SubstateDatabaseOverlay<S, D> {
42    pub fn new(root_database: S) -> Self {
43        Self {
44            overlay: Default::default(),
45            root: root_database,
46            substate_database_type: PhantomData,
47        }
48    }
49
50    pub fn deconstruct(self) -> (S, DatabaseUpdates) {
51        (self.root, self.overlay.into())
52    }
53
54    pub fn database_updates(&self) -> DatabaseUpdates {
55        self.overlay.clone().into()
56    }
57
58    pub fn into_database_updates(self) -> DatabaseUpdates {
59        self.overlay.into()
60    }
61}
62
63impl<S: Borrow<D>, D> SubstateDatabaseOverlay<S, D> {
64    fn get_readable_root(&self) -> &D {
65        self.root.borrow()
66    }
67}
68
69impl<S: BorrowMut<D>, D> SubstateDatabaseOverlay<S, D> {
70    fn get_writable_root(&mut self) -> &mut D {
71        self.root.borrow_mut()
72    }
73}
74
75impl<S: BorrowMut<D>, D: CommittableSubstateDatabase> SubstateDatabaseOverlay<S, D> {
76    pub fn commit_overlay_into_root_store(&mut self) {
77        let overlay = mem::replace(&mut self.overlay, StagingDatabaseUpdates::default());
78        self.get_writable_root().commit(&overlay.into());
79    }
80}
81
82impl<S: Borrow<D>, D: SubstateDatabase> SubstateDatabase for SubstateDatabaseOverlay<S, D> {
83    fn get_raw_substate_by_db_key(
84        &self,
85        partition_key @ DbPartitionKey {
86            node_key,
87            partition_num,
88        }: &DbPartitionKey,
89        sort_key: &DbSortKey,
90    ) -> Option<DbSubstateValue> {
91        let overlay_lookup_result = match self.overlay.node_updates.get(node_key) {
92            // This particular node key exists in the overlay and probably has some partitions
93            // written to the overlay.
94            Some(StagingNodeDatabaseUpdates { partition_updates }) => {
95                match partition_updates.get(partition_num) {
96                    // This partition has some data written to the overlay
97                    Some(StagingPartitionDatabaseUpdates::Delta { substate_updates }) => {
98                        match substate_updates.get(sort_key) {
99                            // The substate value is written to the overlay. It is a database set
100                            // so we return the new value.
101                            Some(DatabaseUpdate::Set(substate_value)) => {
102                                OverlayLookupResult::Found(Some(substate_value))
103                            }
104                            // The substate value is written to the overlay. It is a database delete
105                            // so we return a `Found(None)`.
106                            Some(DatabaseUpdate::Delete) => OverlayLookupResult::Found(None),
107                            // This particular substate was not written to the overlay and should be
108                            // read from the underlying database.
109                            None => OverlayLookupResult::NotFound,
110                        }
111                    }
112                    Some(StagingPartitionDatabaseUpdates::Reset {
113                        new_substate_values,
114                    }) => match new_substate_values.get(sort_key) {
115                        // The substate value is written to the overlay.
116                        Some(substate_value) => OverlayLookupResult::Found(Some(substate_value)),
117                        // In a partition reset we delete all substates in a partition and can also
118                        // write new substates there. If the substate that we're looking for can't
119                        // be found in the new substate values of a partition delete then it is
120                        // one of the deleted substates. Therefore, the following will report that
121                        // it has found the substate value in the overlay and that the substate
122                        // does not exist.
123                        None => OverlayLookupResult::Found(None),
124                    },
125                    // This particular partition for the specified node key does not exist in the
126                    // overlay and should be read from the underlying database.
127                    None => OverlayLookupResult::NotFound,
128                }
129            }
130            // This particular node key does not exist in the overlay. The substate must be read
131            // from the underlying database.
132            None => OverlayLookupResult::NotFound,
133        };
134
135        match overlay_lookup_result {
136            OverlayLookupResult::Found(substate_value) => substate_value.cloned(),
137            OverlayLookupResult::NotFound => self
138                .get_readable_root()
139                .get_raw_substate_by_db_key(partition_key, sort_key),
140        }
141    }
142
143    fn list_raw_values_from_db_key(
144        &self,
145        partition_key @ DbPartitionKey {
146            node_key,
147            partition_num,
148        }: &DbPartitionKey,
149        from_sort_key: Option<&DbSortKey>,
150    ) -> Box<dyn Iterator<Item = PartitionEntry> + '_> {
151        // This function iterates over entries of the specified partition. Therefore, we don't need
152        // to think about other partitions here. We first check if there are any partition updates
153        // for the specified partition. If there is not, no overlaying is needed and we can just
154        // return the iterator of the root store.
155        let from_sort_key = from_sort_key.cloned();
156        match self.overlay.node_updates.get(node_key) {
157            // There is a partition update in the overlay.
158            Some(StagingNodeDatabaseUpdates { partition_updates }) => {
159                match partition_updates.get(partition_num) {
160                    // The partition was reset. None of the substates of this partition that exist
161                    // in the root store "exist" anymore. We just need an iterator over the new
162                    // substates in the reset action.
163                    Some(StagingPartitionDatabaseUpdates::Reset {
164                        new_substate_values,
165                    }) => {
166                        match from_sort_key {
167                            // A `from_sort_key` is specified. Only return sort keys that are larger
168                            // than or equal to the from sort key. We do this through BTreeMap's
169                            // range function instead of doing filtering. We're able to do this
170                            // since a `BTreeMap`'s keys are always sorted.
171                            Some(from_sort_key) => {
172                                Box::new(new_substate_values.range(from_sort_key..).map(
173                                    |(sort_key, substate_value)| {
174                                        (sort_key.clone(), substate_value.clone())
175                                    },
176                                ))
177                            }
178                            // No `from_sort_key` is specified. Start iterating from the beginning.
179                            None => Box::new(new_substate_values.iter().map(
180                                |(sort_key, substate_value)| {
181                                    (sort_key.clone(), substate_value.clone())
182                                },
183                            )),
184                        }
185                    }
186                    // There are some changes that need to be overlayed.
187                    Some(StagingPartitionDatabaseUpdates::Delta { substate_updates }) => {
188                        let underlying = self
189                            .get_readable_root()
190                            .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref());
191
192                        match from_sort_key {
193                            // A `from_sort_key` is specified. Only return sort keys that are larger
194                            // than or equal to the from sort key. We do this through BTreeMap's
195                            // range function instead of doing filtering. We're able to do this
196                            // since a `BTreeMap`'s keys are always sorted.
197                            Some(from_sort_key) => {
198                                let overlaying = substate_updates.range(from_sort_key..).map(
199                                    |(sort_key, database_update)| match database_update {
200                                        DatabaseUpdate::Set(substate_value) => {
201                                            (sort_key.clone(), Some(substate_value.clone()))
202                                        }
203                                        DatabaseUpdate::Delete => (sort_key.clone(), None),
204                                    },
205                                );
206                                Box::new(OverlayingIterator::new(underlying, overlaying))
207                            }
208                            // No `from_sort_key` is specified. Start iterating from the beginning.
209                            None => {
210                                let overlaying =
211                                    substate_updates.iter().map(|(sort_key, database_update)| {
212                                        match database_update {
213                                            DatabaseUpdate::Set(substate_value) => {
214                                                (sort_key.clone(), Some(substate_value.clone()))
215                                            }
216                                            DatabaseUpdate::Delete => (sort_key.clone(), None),
217                                        }
218                                    });
219                                Box::new(OverlayingIterator::new(underlying, overlaying))
220                            }
221                        }
222                    }
223                    // Overlay doesn't contain anything for the provided partition number. Return an
224                    // iterator over the data in the root store.
225                    None => self
226                        .get_readable_root()
227                        .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref()),
228                }
229            }
230            // Overlay doesn't contain anything for the provided node key. Return an iterator over
231            // the data in the root store.
232            None => self
233                .get_readable_root()
234                .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref()),
235        }
236    }
237}
238
239impl<S, D> CommittableSubstateDatabase for SubstateDatabaseOverlay<S, D> {
240    fn commit(&mut self, database_updates: &DatabaseUpdates) {
241        merge_database_updates(&mut self.overlay, database_updates.clone())
242    }
243}
244
245impl<S: Borrow<D>, D: ListableSubstateDatabase> ListableSubstateDatabase
246    for SubstateDatabaseOverlay<S, D>
247{
248    fn list_partition_keys(&self) -> Box<dyn Iterator<Item = DbPartitionKey> + '_> {
249        let overlying = self
250            .overlay
251            .node_updates
252            .iter()
253            .flat_map(
254                |(node_key, StagingNodeDatabaseUpdates { partition_updates })| {
255                    partition_updates
256                        .keys()
257                        .map(|partition_num| DbPartitionKey {
258                            node_key: node_key.clone(),
259                            partition_num: *partition_num,
260                        })
261                },
262            )
263            .map(|partition_key| (partition_key, Some(())));
264        let underlying = self
265            .get_readable_root()
266            .list_partition_keys()
267            .map(|partition_key| (partition_key, ()));
268
269        Box::new(OverlayingIterator::new(underlying, overlying).map(|(value, _)| value))
270    }
271}
272
273pub enum OverlayLookupResult<T> {
274    Found(T),
275    NotFound,
276}
277
278fn merge_database_updates(this: &mut StagingDatabaseUpdates, other: DatabaseUpdates) {
279    for (
280        other_node_key,
281        NodeDatabaseUpdates {
282            partition_updates: other_partition_updates,
283        },
284    ) in other.node_updates.into_iter()
285    {
286        // Check if the other node key exists in `this` database updates.
287        match this.node_updates.get_mut(&other_node_key) {
288            // The node key exists in `this` database updates.
289            Some(StagingNodeDatabaseUpdates {
290                partition_updates: this_partition_updates,
291            }) => {
292                for (other_partition_num, other_partition_database_updates) in
293                    other_partition_updates.into_iter()
294                {
295                    // Check if the partition num exists in `this` database updates
296                    match this_partition_updates.get_mut(&other_partition_num) {
297                        // The partition exists in both `this` and `other` and now we must combine
298                        // both the partition database updates together
299                        Some(this_partition_database_updates) => {
300                            match (
301                                this_partition_database_updates,
302                                other_partition_database_updates,
303                            ) {
304                                // This and other are both `Delta`. We insert all entries in the
305                                // other state updates into this substate updates. This will also
306                                // override anything in `this` with anything in `other`.
307                                (
308                                    StagingPartitionDatabaseUpdates::Delta {
309                                        substate_updates: this_substate_updates,
310                                    },
311                                    PartitionDatabaseUpdates::Delta {
312                                        substate_updates: other_substate_updates,
313                                    },
314                                ) => this_substate_updates.extend(other_substate_updates),
315                                // We need to apply the delta on the reset. 
316                                (
317                                    StagingPartitionDatabaseUpdates::Reset {
318                                        new_substate_values: this_new_substate_values,
319                                    },
320                                    PartitionDatabaseUpdates::Delta {
321                                        substate_updates: other_substate_updates,
322                                    },
323                                ) => {
324                                    for (other_sort_key, other_database_update) in
325                                        other_substate_updates.into_iter()
326                                    {
327                                        match other_database_update {
328                                            DatabaseUpdate::Set(other_substate_value) => {
329                                                this_new_substate_values
330                                                    .insert(other_sort_key, other_substate_value);
331                                            }
332                                            DatabaseUpdate::Delete => {
333                                                this_new_substate_values.remove(&other_sort_key);
334                                            }
335                                        }
336                                    }
337                                }
338                                // Whatever the current state is, if the other database update is
339                                // a partition reset then it takes precedence.
340                                (
341                                    this_partition_database_updates,
342                                    other_partition_database_updates @ PartitionDatabaseUpdates::Reset { .. },
343                                ) => {
344                                    *this_partition_database_updates = other_partition_database_updates.into();
345                                }
346                            }
347                        }
348                        // The partition num does not exist in `this` database updates. This merge
349                        // is simple, just insert it.
350                        None => {
351                            this_partition_updates.insert(
352                                other_partition_num,
353                                other_partition_database_updates.into(),
354                            );
355                        }
356                    }
357                }
358            }
359            // The node key does not exist in `this` database updates. This merge is simple, just
360            // insert it.
361            None => {
362                this.node_updates.insert(
363                    other_node_key,
364                    NodeDatabaseUpdates {
365                        partition_updates: other_partition_updates,
366                    }
367                    .into(),
368                );
369            }
370        }
371    }
372}
373
374#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)]
375struct StagingDatabaseUpdates {
376    node_updates: BTreeMap<DbNodeKey, StagingNodeDatabaseUpdates>,
377}
378
379impl From<StagingDatabaseUpdates> for DatabaseUpdates {
380    fn from(value: StagingDatabaseUpdates) -> Self {
381        Self {
382            node_updates: value
383                .node_updates
384                .into_iter()
385                .map(|(key, value)| (key, NodeDatabaseUpdates::from(value)))
386                .collect(),
387        }
388    }
389}
390
391impl From<DatabaseUpdates> for StagingDatabaseUpdates {
392    fn from(value: DatabaseUpdates) -> Self {
393        Self {
394            node_updates: value
395                .node_updates
396                .into_iter()
397                .map(|(key, value)| (key, StagingNodeDatabaseUpdates::from(value)))
398                .collect(),
399        }
400    }
401}
402
403#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)]
404struct StagingNodeDatabaseUpdates {
405    partition_updates: BTreeMap<DbPartitionNum, StagingPartitionDatabaseUpdates>,
406}
407
408impl From<StagingNodeDatabaseUpdates> for NodeDatabaseUpdates {
409    fn from(value: StagingNodeDatabaseUpdates) -> Self {
410        Self {
411            partition_updates: value
412                .partition_updates
413                .into_iter()
414                .map(|(key, value)| (key, PartitionDatabaseUpdates::from(value)))
415                .collect(),
416        }
417    }
418}
419
420impl From<NodeDatabaseUpdates> for StagingNodeDatabaseUpdates {
421    fn from(value: NodeDatabaseUpdates) -> Self {
422        Self {
423            partition_updates: value
424                .partition_updates
425                .into_iter()
426                .map(|(key, value)| (key, StagingPartitionDatabaseUpdates::from(value)))
427                .collect(),
428        }
429    }
430}
431
432#[derive(Debug, Clone, PartialEq, Eq, Sbor)]
433enum StagingPartitionDatabaseUpdates {
434    Delta {
435        substate_updates: BTreeMap<DbSortKey, DatabaseUpdate>,
436    },
437
438    Reset {
439        new_substate_values: BTreeMap<DbSortKey, DbSubstateValue>,
440    },
441}
442
443impl From<StagingPartitionDatabaseUpdates> for PartitionDatabaseUpdates {
444    fn from(value: StagingPartitionDatabaseUpdates) -> Self {
445        match value {
446            StagingPartitionDatabaseUpdates::Delta { substate_updates } => Self::Delta {
447                substate_updates: substate_updates.into_iter().collect(),
448            },
449            StagingPartitionDatabaseUpdates::Reset {
450                new_substate_values,
451            } => Self::Reset {
452                new_substate_values: new_substate_values.into_iter().collect(),
453            },
454        }
455    }
456}
457
458impl From<PartitionDatabaseUpdates> for StagingPartitionDatabaseUpdates {
459    fn from(value: PartitionDatabaseUpdates) -> Self {
460        match value {
461            PartitionDatabaseUpdates::Delta { substate_updates } => Self::Delta {
462                substate_updates: substate_updates.into_iter().collect(),
463            },
464            PartitionDatabaseUpdates::Reset {
465                new_substate_values,
466            } => Self::Reset {
467                new_substate_values: new_substate_values.into_iter().collect(),
468            },
469        }
470    }
471}