Code:
object Blub {
import scala.concurrent.stm._
val last = Ref("none")
def bla() = atomic { implicit txn =>
last() = "outer"
try {
atomic { implicit txn =>
last() = "inner"
println(last())
throw new RuntimeException
}
} catch {
case _: RuntimeException =>
}
}
def main(args: Array[String]): Unit = {
bla()
println("Result: "+last.single())
}
}
Output:
inner
inner
Result: outer
Can anyone explain why the inner atomic block is run twice? I know that it does a rollback due to the exception, hence the final result. But i don't understand the why it runs the code for a second time.
The bottom of this page on the ScalaSTM documentation has this to say:
To make nesting very cheap, ScalaSTM tries to flatten all of the nesting levels together into a single top-level transaction. If an inner transaction throws an exception then there isn’t enough information to perform the partial rollback, so ScalaSTM restarts the entire transaction in a mode that does exact nesting. This optimization is called subsumption.
So what happens is:
last
is set to "outer"
last
is set to "inner"
"inner"
is printedlast
is now back to "none"
) and retries it "non-flattened"last
is set to "outer"
last
is set to "inner"
"inner
is printedlast
is set back to "outer"
.