mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 23:57:56 +00:00
Implement nested storage transactions (#6269)
* Add transactional storage functionality to OverlayChanges A collection already has a natural None state. No need to wrap it with an option. * Add storage transactions runtime interface * Add frame support for transactions * Fix committed typo * Rename 'changes' variable to 'overlay' * Fix renaming change * Fixed strange line break * Rename clear to clear_where * Add comment regarding delete value on mutation * Add comment which changes are covered by a transaction * Do force the arg to with_transaction return a Result * Use rust doc comments on every documentable place * Fix wording of insert_diry doc * Improve doc on start_transaction * Rename value to overlayed in close_transaction * Inline negation * Improve wording of close_transaction comments * Get rid of an expect by using get_or_insert_with * Remove trailing whitespace * Rename should to expected in tests * Rolling back a transaction must mark the overlay as dirty * Protect client initiated storage tx from being droped by runtime * Review nits * Return Err when entering or exiting runtime fails * Documentation fixup * Remove close type * Move enter/exit runtime to excute_aux in the state-machine * Rename Discard -> Rollback * Move child changeset creation to constructor * Move child spawning into the closure * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Fixup for code suggestion * Unify re-exports * Rename overlay_changes to mod.rs and move into subdir * Change proof wording * Adapt a new test from master to storage-tx * Suggestions from the latest round of review * Fix warning message Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
6aa8965f33
commit
bb2df2122e
@@ -37,6 +37,10 @@ use std::{error, fmt, any::{Any, TypeId}};
|
||||
use log::{warn, trace};
|
||||
|
||||
const EXT_NOT_ALLOWED_TO_FAIL: &str = "Externalities not allowed to fail within runtime";
|
||||
const BENCHMARKING_FN: &str = "\
|
||||
This is a special fn only for benchmarking where a database commit happens from the runtime.
|
||||
For that reason client started transactions before calling into runtime are not allowed.
|
||||
Without client transactions the loop condition garantuees the success of the tx close.";
|
||||
|
||||
/// Errors that can occur when interacting with the externalities.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -147,7 +151,7 @@ where
|
||||
|
||||
self.backend.pairs().iter()
|
||||
.map(|&(ref k, ref v)| (k.to_vec(), Some(v.to_vec())))
|
||||
.chain(self.overlay.changes(None).map(|(k, v)| (k.clone(), v.value().cloned())))
|
||||
.chain(self.overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned())))
|
||||
.collect::<HashMap<_, _>>()
|
||||
.into_iter()
|
||||
.filter_map(|(k, maybe_val)| maybe_val.map(|val| (k, val)))
|
||||
@@ -477,15 +481,14 @@ where
|
||||
);
|
||||
root.encode()
|
||||
} else {
|
||||
let root = if let Some((changes, info)) = self.overlay.child_changes(storage_key) {
|
||||
let delta = changes.map(|(k, v)| (k.as_ref(), v.value().map(AsRef::as_ref)));
|
||||
Some(self.backend.child_storage_root(info, delta))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(child_info) = self.overlay.default_child_info(storage_key) {
|
||||
let (root, is_empty, _) = {
|
||||
let delta = self.overlay.changes(Some(child_info))
|
||||
.map(|(k, v)| (k.as_ref(), v.value().map(AsRef::as_ref)));
|
||||
|
||||
self.backend.child_storage_root(child_info, delta)
|
||||
};
|
||||
|
||||
if let Some((root, is_empty, _)) = root {
|
||||
let root = root.encode();
|
||||
// We store update in the overlay in order to be able to use 'self.storage_transaction'
|
||||
// cache. This is brittle as it rely on Ext only querying the trie backend for
|
||||
@@ -547,20 +550,37 @@ where
|
||||
root.map(|r| r.map(|o| o.encode()))
|
||||
}
|
||||
|
||||
fn storage_start_transaction(&mut self) {
|
||||
self.overlay.start_transaction()
|
||||
}
|
||||
|
||||
fn storage_rollback_transaction(&mut self) -> Result<(), ()> {
|
||||
self.mark_dirty();
|
||||
self.overlay.rollback_transaction().map_err(|_| ())
|
||||
}
|
||||
|
||||
fn storage_commit_transaction(&mut self) -> Result<(), ()> {
|
||||
self.overlay.commit_transaction().map_err(|_| ())
|
||||
}
|
||||
|
||||
fn wipe(&mut self) {
|
||||
self.overlay.discard_prospective();
|
||||
for _ in 0..self.overlay.transaction_depth() {
|
||||
self.overlay.rollback_transaction().expect(BENCHMARKING_FN);
|
||||
}
|
||||
self.overlay.drain_storage_changes(
|
||||
&self.backend,
|
||||
None,
|
||||
Default::default(),
|
||||
self.storage_transaction_cache,
|
||||
).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||
self.storage_transaction_cache.reset();
|
||||
self.backend.wipe().expect(EXT_NOT_ALLOWED_TO_FAIL)
|
||||
self.backend.wipe().expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||
self.mark_dirty();
|
||||
}
|
||||
|
||||
fn commit(&mut self) {
|
||||
self.overlay.commit_prospective();
|
||||
for _ in 0..self.overlay.transaction_depth() {
|
||||
self.overlay.commit_transaction().expect(BENCHMARKING_FN);
|
||||
}
|
||||
let changes = self.overlay.drain_storage_changes(
|
||||
&self.backend,
|
||||
None,
|
||||
@@ -571,7 +591,7 @@ where
|
||||
changes.transaction_storage_root,
|
||||
changes.transaction,
|
||||
).expect(EXT_NOT_ALLOWED_TO_FAIL);
|
||||
self.storage_transaction_cache.reset();
|
||||
self.mark_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user