2009-06-29 15:01:20 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009 Scalable Solutions.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package se.scalablesolutions.akka.kernel.stm
|
|
|
|
|
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean
|
|
|
|
|
|
|
|
|
|
import kernel.util.Logging
|
|
|
|
|
|
|
|
|
|
class TransactionAwareWrapperException(val cause: Throwable, val tx: Option[Transaction]) extends RuntimeException(cause) {
|
|
|
|
|
override def toString(): String = "TransactionAwareWrapperException[" + cause + ", " + tx + "]"
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 17:33:38 +02:00
|
|
|
object TransactionManagement {
|
2009-06-29 15:01:20 +02:00
|
|
|
private val txEnabled = new AtomicBoolean(true)
|
2009-06-29 17:33:38 +02:00
|
|
|
|
2009-06-29 23:38:10 +02:00
|
|
|
def isTransactionalityEnabled = txEnabled.get
|
2009-06-29 15:01:20 +02:00
|
|
|
def enableTransactions = txEnabled.set(true)
|
|
|
|
|
|
2009-06-29 17:33:38 +02:00
|
|
|
private[kernel] val threadBoundTx: ThreadLocal[Option[Transaction]] = {
|
2009-06-29 15:01:20 +02:00
|
|
|
val tl = new ThreadLocal[Option[Transaction]]
|
|
|
|
|
tl.set(None)
|
|
|
|
|
tl
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FIXME: STM that allows concurrent updates, detects collision, rolls back and restarts
|
|
|
|
|
trait TransactionManagement extends Logging {
|
2009-06-29 23:38:10 +02:00
|
|
|
val id: String
|
2009-06-29 15:01:20 +02:00
|
|
|
|
|
|
|
|
import TransactionManagement.threadBoundTx
|
|
|
|
|
private[kernel] var activeTx: Option[Transaction] = None
|
|
|
|
|
|
|
|
|
|
protected def startNewTransaction = {
|
|
|
|
|
val newTx = new Transaction
|
2009-06-29 23:38:10 +02:00
|
|
|
newTx.begin(id)
|
2009-06-29 15:01:20 +02:00
|
|
|
val tx = Some(newTx)
|
|
|
|
|
activeTx = tx
|
|
|
|
|
threadBoundTx.set(tx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected def joinExistingTransaction = {
|
|
|
|
|
val cflowTx = threadBoundTx.get
|
2009-06-29 23:38:10 +02:00
|
|
|
if (!activeTx.isDefined && cflowTx.isDefined) {
|
2009-06-29 15:01:20 +02:00
|
|
|
val currentTx = cflowTx.get
|
2009-06-29 23:38:10 +02:00
|
|
|
currentTx.join(id)
|
2009-06-29 15:01:20 +02:00
|
|
|
activeTx = Some(currentTx)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 23:38:10 +02:00
|
|
|
protected def tryToPrecommitTransaction = if (activeTx.isDefined) activeTx.get.precommit(id)
|
2009-06-29 15:01:20 +02:00
|
|
|
|
|
|
|
|
protected def tryToCommitTransaction: Boolean = if (activeTx.isDefined) {
|
|
|
|
|
val tx = activeTx.get
|
2009-06-29 23:38:10 +02:00
|
|
|
tx.commit(id)
|
2009-06-29 15:01:20 +02:00
|
|
|
removeTransactionIfTopLevel
|
|
|
|
|
true
|
|
|
|
|
} else false
|
|
|
|
|
|
|
|
|
|
protected def rollback(tx: Option[Transaction]) = tx match {
|
|
|
|
|
case None => {} // no tx; nothing to do
|
|
|
|
|
case Some(tx) =>
|
2009-06-29 23:38:10 +02:00
|
|
|
tx.rollback(id)
|
2009-06-29 15:01:20 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-29 23:38:10 +02:00
|
|
|
protected def isInExistingTransaction = TransactionManagement.threadBoundTx.get.isDefined
|
2009-06-29 15:01:20 +02:00
|
|
|
|
|
|
|
|
protected def isTransactionAborted = activeTx.isDefined && activeTx.get.isAborted
|
|
|
|
|
|
|
|
|
|
protected def incrementTransaction = if (activeTx.isDefined) activeTx.get.increment
|
|
|
|
|
|
|
|
|
|
protected def decrementTransaction = if (activeTx.isDefined) activeTx.get.decrement
|
|
|
|
|
|
|
|
|
|
protected def removeTransactionIfTopLevel =
|
|
|
|
|
if (activeTx.isDefined && activeTx.get.topLevel_?) {
|
|
|
|
|
activeTx = None
|
|
|
|
|
threadBoundTx.set(None)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected def reenteringExistingTransaction= if (activeTx.isDefined) {
|
|
|
|
|
val cflowTx = threadBoundTx.get
|
|
|
|
|
if (cflowTx.isDefined && cflowTx.get.id == activeTx.get.id) false
|
|
|
|
|
else true
|
|
|
|
|
} else true
|
|
|
|
|
}
|
|
|
|
|
|