Atomic block is retried after exception

已查看 53 次
跳至第一个未读帖子

daniel kroeni

未读,
2014年1月21日 06:37:152014/1/21
收件人 scala-stm-e...@googlegroups.com、Dominik Gruntz
Hi all

I'm puzzled by the behavior of the following program:

object STMExampleA extends App { 
  import scala.concurrent.stm._ 
  val r = Ref(0)
  
 def trouble() = atomic { implicit tx =>
    println("a: " + r())
    r() = 2
    println("b: " + r())
    throw new Exception()
  }

  def a() = atomic { implicit tx =>
    r() = 1
    try { trouble() } catch { case e: Exception => r() }
  }

  println("c:" + a())
}

I would expect the following output:
a: 1
b: 2
c: 1

But it yields this:
a: 1
b: 2
a: 1
b: 2
c: 1

This is with version scala-stm_2.10-0.7.jar and Scala 2.10.3.

ScalaSTM seems to retry the block which throws the exception although on 
http://nbronson.github.io/scala-stm/exceptions.html one can read:
"If an atomic block throws an exception, ScalaSTM rolls it back and then rethrows the exception. The atomic block won’t be retried."

It would be much appreciated if someone could shed some light on this.

Thanks Daniel

Hanns Holger Rutz

未读,
2014年1月21日 12:59:512014/1/21
收件人 scala-stm-e...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

hi,

indeed strange? I can reproduce this, I added a few more prints:

https://gist.github.com/Sciss/8544824

you get

RolledBack(OptimisticFailureCause('restart_to_enable_partial_rollback,Some(java.lang.Exception)))

So the answer must lie in the reasoning behind "restart to enable
partial rollback"...
> --
>
> --- You received this message because you are subscribed to the
> Google Groups "Scala STM Discussion" group. To unsubscribe from
> this group and stop receiving emails from it, send an email to
> scala-stm-expert-...@googlegroups.com. For more
> options, visit https://groups.google.com/groups/opt_out.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.20 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJS3rWWAAoJEKZFmaPaYk6QhnEP+wT8uDeI+hfPCc8zvvrbpZ8M
vYmqPl7Ql2hN0Di0JnTwGpS2ajmUZOVoffmv9yczC0UD04k56Ow4XS6mheS1lO8l
WUR5+OcbJfeqBU3Bl4hvrUeUKkpoOZJxQlrzIk1OqHptW3a95UF6WszUIDFIVxcR
/L48acGVFNOFVbYuiQFHATOq7wV9b33kjuj09UTNwePdXhSyS/iL6WkYX4DVeaeD
pm22GKLkQJUCs5fpy4X0C9quP3UE0BkauXndKWp7WMlJ8IFHYVm+5qWddrKol9CT
PQ8mfIMswzsGJG+b1pe3yh3+HFKMpOnnqZHmA4D+1YAQtZYVWNjU5K5jEXjXd9/8
qXHg6kCsRLISOBXJGkN7JME8xuXmFIF4noh2qSLYh/hsJVVCx2jMEjiRiOnwNEjx
iR9flJHZlTS1BU4/Tu5mw0vtG1TkGKSjrLoQFUmtjE5Olvvi3a35ZERxN72dsaoE
xgnHF7d2hyaTG80Q19c0dLFucOO3LXBHY85veP1XrOPpvjzQKGjPjqhKjJSLJWp+
aRPpgwtD4DoiqDEiB5cAJGh6Z6QDQ46NA64nB38EFJNNg9Mf4NRg7nm5J90NDGz8
BC1lFyCkJByV/w32LCofVhNcdxE6r/SMM+H/ucWAle6k2u7tpVd70XxD1l1U5aCD
sT3iJd2JDZrMl/Fq1iEF
=OfOh
-----END PGP SIGNATURE-----

Nathan Bronson

未读,
2014年1月21日 13:25:212014/1/21
收件人 scala-stm-e...@googlegroups.com
Daniel,

That's an interesting question, and a good minimal example.

Nested transactions add some overhead. I didn't want people to have to choose between their elegance and the performance of a single top-level transaction, so as a performance optimization ScalaSTM first tries to flatten (subsume) all of the nested transactions. During subsumption, nested transactions are just a function call. This is faster for the common case, but it means that when it comes time to roll back just the inner transaction there isn't enough information available to do it properly. Something similar can also happen if you use orAtomic + retry in nested transactions, or if you call NestingLevel.current (NestingLevel.root is okay in subsumed mode).

When ScalaSTM detects that the precise nesting behavior is required, it rolls back and retries the outer transaction, but in a mode that keeps precise nesting information. Then, if the inner transaction throws again we can do the partial rollback properly. If you want to dig into the details, https://github.com/nbronson/scala-stm/blob/master/src/main/scala/scala/concurrent/stm/ccstm/InTxnImpl.scala#L48 is a good starting point. If you enable stats with -Dccstm.stats=1, you should see this rollback listed under restart_to_enable_partial_rollback.

What I was trying to convey with that comment was that final state of the transaction would be that it was rolled back, not that no retry was possible before then. I will fix the comment.

Thanks,
  Nathan


--
 
---
You received this message because you are subscribed to the Google Groups "Scala STM Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-stm-expert-...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--
Nathan Grasso Bronson
ngbr...@gmail.com

daniel kroeni

未读,
2014年1月21日 18:21:022014/1/21
收件人 scala-stm-e...@googlegroups.com
Nathan,

Many thanks for the clarifications. The original comment is now also clear as it stands. I understand it as: The atomic block is not retried until it eventually succeeds but its changes are rolled back (in the end). 
And how ScalaSTM operationally achieves this should not bother me. If I play by the rules (side effects in commit handlers) ScalaSTM can do what it needs to do to be efficient.

Many thanks for your fantastic library. I love it.
Daniel
回复全部
回复作者
转发
0 个新帖子