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:
Alexander Theißen
2020-06-23 11:17:53 +02:00
committed by GitHub
parent 6aa8965f33
commit bb2df2122e
16 changed files with 1383 additions and 532 deletions
@@ -260,6 +260,7 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
&self,
map_call: F,
) -> std::result::Result<R, E> where Self: Sized {
self.changes.borrow_mut().start_transaction();
*self.commit_on_success.borrow_mut() = false;
let res = map_call(self);
*self.commit_on_success.borrow_mut() = true;
@@ -369,6 +370,9 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
&self,
call_api_at: F,
) -> std::result::Result<#crate_::NativeOrEncoded<R>, E> {
if *self.commit_on_success.borrow() {
self.changes.borrow_mut().start_transaction();
}
let res = call_api_at(
&self.call,
self,
@@ -384,11 +388,16 @@ fn generate_runtime_api_base_structures() -> Result<TokenStream> {
}
fn commit_on_ok<R, E>(&self, res: &std::result::Result<R, E>) {
let proof = "\
We only close a transaction when we opened one ourself.
Other parts of the runtime that make use of transactions (state-machine)
also balance their transactions. The runtime cannot close client initiated
transactions. qed";
if *self.commit_on_success.borrow() {
if res.is_err() {
self.changes.borrow_mut().discard_prospective();
self.changes.borrow_mut().rollback_transaction().expect(proof);
} else {
self.changes.borrow_mut().commit_prospective();
self.changes.borrow_mut().commit_transaction().expect(proof);
}
}
}