When attempting to use the two-phase commit solution I posted last week, I discovered that it couldn't handle dependency chains so I had to come up with a completely new design:
I unfortunately couldn't come up with a non-unsafe
design that did everything I wanted it to:
- Revertable actions should statically lock the object they operate on via
&mut
until they are either committed or reverted. - Revertable actions should be able to return a reference into the object they modify (the exclusive lock will continue as long as this result exists)
- The result of a revertable action should be usable before commit/revert by a second action, and the combination should commit/revert as a unit. (The ability to revert the secondary action and then do something else with the primary would be nice but isn't required.)
- Dropping/forgetting a revertable action should be safe and equivalent to a commit.
- Reverting a chain of operations should be linear-time wrt. the length of the chain. I think this requires caching the intermediate references.
This is undoubtedly the most complicated piece of unsafe code I've attempted, so I'd appreciate any thoughts you may have on it. I'm only really concerned with asymptotic efficiency here-- If there's a safe abstraction with only a constant-time penalty, I'll happily use it. In addition to any general soundness issues, there are a couple of things that could stand some extra scrutiny:
- The implementor's contract for
RevertableOperation
: Is it unsound or unclear? - Does
chain()
accidentally release one of its static locks due to incorrect lifetime annotations?