code in afterCommit cannot create a follow-up transaction

8 views
Skip to first unread message

Sciss

unread,
Aug 13, 2010, 2:02:33 PM8/13/10
to scala...@googlegroups.com
hi nathan,

i'm getting some bad exception here with the ccstm 0.2.1 and my TxnModel class i had described some time ago ( http://github.com/Sciss/SoundProcesses/blob/master/src/main/scala/de/sciss/synth/proc/TxnModel.scala )

the exception is:

discarding exception from txn callback, status is Committed
java.lang.IllegalStateException: Committed
at edu.stanford.ppl.ccstm.impl.StatusHolder.rollbackOrIllegalState(StatusHolder.scala:71)
at edu.stanford.ppl.ccstm.impl.StatusHolder.requireActiveOrValidating(StatusHolder.scala:81)
(8) at edu.stanford.ppl.ccstm.Txn.addWriteResource(Txn.scala:644)
at de.sciss.synth.proc.ProcTxn$$anonfun$atomic$1.apply(ProcTxn.scala:72)
at de.sciss.synth.proc.ProcTxn$$anonfun$atomic$1.apply(ProcTxn.scala:70)
(7) at edu.stanford.ppl.ccstm.STM$.nestedAtomic(STM.scala:45)
(6) at edu.stanford.ppl.ccstm.STM$.atomic(STM.scala:33)
(5) at de.sciss.synth.proc.ProcTxn$.atomic(ProcTxn.scala:70)
(4) at de.sciss.cupola.ProcessManager$$anon$2.updated(ProcessManager.scala:86)
(3) at de.sciss.cupola.ProcessManager$$anon$2.updated(ProcessManager.scala:83)
(2) at de.sciss.synth.proc.TxnModel$$anonfun$touch$1$$anonfun$apply$4$$anonfun$apply$6.apply(TxnModel.scala:88)
at de.sciss.synth.proc.TxnModel$$anonfun$touch$1$$anonfun$apply$4$$anonfun$apply$6.apply(TxnModel.scala:88)
at scala.collection.Iterator$class.foreach(Iterator.scala:631)
at scala.collection.LinearSeqLike$$anon$1.foreach(LinearSeqLike.scala:52)
at scala.collection.IterableLike$class.foreach(IterableLike.scala:79)
at scala.collection.immutable.Queue.foreach(Queue.scala:31)
(1) at de.sciss.synth.proc.TxnModel$$anonfun$touch$1$$anonfun$apply$4.apply(TxnModel.scala:88)
at de.sciss.synth.proc.TxnModel$$anonfun$touch$1$$anonfun$apply$4.apply(TxnModel.scala:86)
at de.sciss.synth.proc.ProcTxn$Impl$$anonfun$afterCommit$1.apply(ProcTxn.scala:236)
at de.sciss.synth.proc.ProcTxn$Impl$$anonfun$afterCommit$1.apply(ProcTxn.scala:236)
at edu.stanford.ppl.ccstm.Txn$$anonfun$callAfter$1.apply(Txn.scala:740)
at edu.stanford.ppl.ccstm.Txn$$anonfun$callAfter$1.apply(Txn.scala:738)
at edu.stanford.ppl.ccstm.impl.CallbackPrioSlot.visitOne(CallbackList.scala:129)
at edu.stanford.ppl.ccstm.impl.CallbackList.attemptSlot(CallbackList.scala:78)
at edu.stanford.ppl.ccstm.impl.CallbackList.attemptForeach(CallbackList.scala:66)
at edu.stanford.ppl.ccstm.impl.CallbackList.foreach(CallbackList.scala:51)
at edu.stanford.ppl.ccstm.impl.CallbackList.foreach(CallbackList.scala:47)
at edu.stanford.ppl.ccstm.Txn.callAfter(Txn.scala:738)
at edu.stanford.ppl.ccstm.impl.TxnImpl.commitImpl(TxnImpl.scala:267)
at edu.stanford.ppl.ccstm.Txn.commit(Txn.scala:558)
at edu.stanford.ppl.ccstm.Txn.commitAndRethrow(Txn.scala:564)
at edu.stanford.ppl.ccstm.STM$.attemptImpl(STM.scala:134)
at edu.stanford.ppl.ccstm.STM$.topLevelAtomic(STM.scala:61)
at edu.stanford.ppl.ccstm.STM$.atomic(STM.scala:35)
at de.sciss.synth.proc.ProcTxn$.atomic(ProcTxn.scala:70)
at de.sciss.cupola.ProcessManager.de$sciss$cupola$ProcessManager$$timerUpdate(ProcessManager.scala:66)
at de.sciss.cupola.ProcessManager$$anon$1.run(ProcessManager.scala:57)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)

without explaining each line, the situation is:
- i am waiting for an update dispatch from my TxnModel which happens in the afterCommit of the txn (1).
- the dispatch iterates over the current observers and calls their updated method (2)
- i have here a particular listener (3) which issues a new transaction to delete some object (4)
- ProcTxn is my wrapper around Txn (5), and that has a method atomic which just wraps STM.atomic (6).
- now here is the bug: it seems that, although my code runs in the afterCommit, CCSTM hasn't cleared yet
ThreadContext state, hence (6) falsely invokes nestedAtomic (7) which a bit later, as soon as the transaction
(which is the old transaction by mistake) is touched (8) throws an error.

the problem as i see it is this snippet from TxnImpl:

} finally {
callAfter()

// cleanup
val ctx = ThreadContext.get
ctx.put(_callbacks, _readSet, _writeBuffer, _strongRefSet, _slot)
_callbacks = null
_readSet = null
_writeBuffer = null
slotManager.release(_slot)
detach(ctx)
}

because here clearly callAfter is invoked before detach, so essentially it's not possible to create a new transaction in an afterCommit { } code block.

i don't know if there are new issues with moving callAfter after detach? if not, i would suggest that this would fix the problem.

i am working around this now deferring the action to another thread, but this is not a very elegant solution.

best, -sciss-

Nathan Bronson

unread,
Aug 13, 2010, 4:45:52 PM8/13/10
to scala...@googlegroups.com
Sciss,

You're right, the current txn should be detached before firing the
after-completion callbacks. I've deployed a snapshot release of CCSTM
that allows this. You can access it by changing the CCSTM dependency
section in your sbt project file to:

val ccstm = "edu.stanford.ppl" % "ccstm" %
"0.2.2-for-scala-2.8.0-SNAPSHOT"
val ccstmRepo = "CCSTM Release Repository at PPL" at
"http://ppl.stanford.edu/ccstm/repo-releases"
val ccstmSnap = "CCSTM Snapshot Repository at PPL" at
"http://ppl.stanford.edu/ccstm/repo-snapshots"

- Nathan

Sciss

unread,
Aug 13, 2010, 7:44:52 PM8/13/10
to scala...@googlegroups.com
great, thanks for the fast help, it works now!
Reply all
Reply to author
Forward
0 new messages