2010-04-05 11:53:43 +02:00
|
|
|
package se.scalablesolutions.akka.actor
|
|
|
|
|
|
|
|
|
|
import se.scalablesolutions.akka.stm._
|
|
|
|
|
|
2010-05-01 12:59:24 +02:00
|
|
|
import Actor._
|
|
|
|
|
|
2010-04-05 11:53:43 +02:00
|
|
|
import org.scalatest.Spec
|
|
|
|
|
import org.scalatest.Assertions
|
|
|
|
|
import org.scalatest.matchers.ShouldMatchers
|
|
|
|
|
import org.scalatest.BeforeAndAfterAll
|
|
|
|
|
import org.scalatest.junit.JUnitRunner
|
|
|
|
|
import org.junit.runner.RunWith
|
|
|
|
|
|
|
|
|
|
@RunWith(classOf[JUnitRunner])
|
2010-04-07 14:23:58 +02:00
|
|
|
class StmSpec extends
|
|
|
|
|
Spec with
|
|
|
|
|
ShouldMatchers with
|
2010-04-05 11:53:43 +02:00
|
|
|
BeforeAndAfterAll {
|
2010-04-07 14:23:58 +02:00
|
|
|
|
|
|
|
|
describe("Transaction.Local") {
|
2010-04-05 11:53:43 +02:00
|
|
|
it("should be able to do multiple consecutive atomic {..} statements") {
|
2010-04-07 14:23:58 +02:00
|
|
|
import Transaction.Local._
|
2010-04-05 11:53:43 +02:00
|
|
|
|
|
|
|
|
lazy val ref = TransactionalState.newRef[Int]
|
|
|
|
|
|
|
|
|
|
def increment = atomic {
|
|
|
|
|
ref.swap(ref.get.getOrElse(0) + 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def total: Int = atomic {
|
|
|
|
|
ref.get.getOrElse(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
increment
|
|
|
|
|
increment
|
|
|
|
|
increment
|
|
|
|
|
total should equal(3)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it("should be able to do nested atomic {..} statements") {
|
2010-04-07 14:23:58 +02:00
|
|
|
import Transaction.Local._
|
2010-04-05 11:53:43 +02:00
|
|
|
|
|
|
|
|
lazy val ref = TransactionalState.newRef[Int]
|
|
|
|
|
|
|
|
|
|
def increment = atomic {
|
|
|
|
|
ref.swap(ref.get.getOrElse(0) + 1)
|
|
|
|
|
}
|
|
|
|
|
def total: Int = atomic {
|
|
|
|
|
ref.get.getOrElse(0)
|
|
|
|
|
}
|
2010-04-07 14:23:58 +02:00
|
|
|
|
2010-04-05 11:53:43 +02:00
|
|
|
atomic {
|
|
|
|
|
increment
|
2010-04-07 14:23:58 +02:00
|
|
|
increment
|
2010-04-05 11:53:43 +02:00
|
|
|
}
|
|
|
|
|
atomic {
|
|
|
|
|
increment
|
|
|
|
|
total should equal(3)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
it("should roll back failing nested atomic {..} statements") {
|
2010-04-07 14:23:58 +02:00
|
|
|
import Transaction.Local._
|
2010-04-05 11:53:43 +02:00
|
|
|
|
|
|
|
|
lazy val ref = TransactionalState.newRef[Int]
|
|
|
|
|
|
|
|
|
|
def increment = atomic {
|
|
|
|
|
ref.swap(ref.get.getOrElse(0) + 1)
|
|
|
|
|
}
|
|
|
|
|
def total: Int = atomic {
|
|
|
|
|
ref.get.getOrElse(0)
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
atomic {
|
|
|
|
|
increment
|
|
|
|
|
increment
|
|
|
|
|
throw new Exception
|
2010-04-07 14:23:58 +02:00
|
|
|
}
|
2010-04-05 11:53:43 +02:00
|
|
|
} catch {
|
|
|
|
|
case e => {}
|
|
|
|
|
}
|
|
|
|
|
total should equal(0)
|
|
|
|
|
}
|
2010-05-24 13:55:56 +02:00
|
|
|
}
|
2010-05-24 12:31:04 +02:00
|
|
|
|
2010-05-24 13:55:56 +02:00
|
|
|
describe("Transaction.Global") {
|
2010-05-24 13:12:06 +02:00
|
|
|
it("should be able to initialize with atomic {..} block inside actor constructor") {
|
2010-05-24 13:55:56 +02:00
|
|
|
import GlobalTransactionVectorTestActor._
|
2010-05-24 12:31:04 +02:00
|
|
|
try {
|
2010-05-24 13:55:56 +02:00
|
|
|
val actor = actorOf[GlobalTransactionVectorTestActor].start
|
2010-05-24 13:12:06 +02:00
|
|
|
actor !! Add(5)
|
|
|
|
|
val size1: Int = (actor !! Size).getOrElse(fail("Could not get Vector::size"))
|
|
|
|
|
size1 should equal(2)
|
|
|
|
|
actor !! Add(2)
|
|
|
|
|
val size2: Int = (actor !! Size).getOrElse(fail("Could not get Vector::size"))
|
2010-05-24 13:55:56 +02:00
|
|
|
size2 should equal(3)
|
2010-05-24 12:31:04 +02:00
|
|
|
} catch {
|
2010-05-24 13:55:56 +02:00
|
|
|
case e =>
|
|
|
|
|
e.printStackTrace
|
|
|
|
|
fail(e.toString)
|
2010-05-24 12:31:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-05-28 23:50:08 +02:00
|
|
|
/*
|
|
|
|
|
describe("Multiverse API") {
|
|
|
|
|
it("should blablabla") {
|
|
|
|
|
|
|
|
|
|
import org.multiverse.api.programmatic._
|
|
|
|
|
// import org.multiverse.api._
|
|
|
|
|
import org.multiverse.templates._
|
|
|
|
|
import java.util.concurrent.atomic._
|
|
|
|
|
import se.scalablesolutions.akka.stm.Ref
|
|
|
|
|
import org.multiverse.api.{GlobalStmInstance, ThreadLocalTransaction, Transaction => MultiverseTransaction}
|
|
|
|
|
import org.multiverse.api.lifecycle.{TransactionLifecycleListener, TransactionLifecycleEvent}
|
|
|
|
|
import org.multiverse.commitbarriers._
|
|
|
|
|
|
|
|
|
|
def createRef[T]: ProgrammaticReference[T] = GlobalStmInstance
|
|
|
|
|
.getGlobalStmInstance
|
|
|
|
|
.getProgrammaticReferenceFactoryBuilder
|
|
|
|
|
.build
|
|
|
|
|
.atomicCreateReference(null.asInstanceOf[T])
|
|
|
|
|
|
|
|
|
|
val ref1 = Ref(0)//createRef[Int]
|
|
|
|
|
val ref2 = Ref(0)//createRef[Int]
|
|
|
|
|
|
|
|
|
|
val committedCount = new AtomicInteger
|
|
|
|
|
val abortedCount = new AtomicInteger
|
|
|
|
|
val barrierHolder = new AtomicReference[CountDownCommitBarrier]
|
|
|
|
|
|
|
|
|
|
val template = new TransactionTemplate[Int]() {
|
|
|
|
|
override def onStart(tx: MultiverseTransaction) = barrierHolder.set(new CountDownCommitBarrier(1))
|
|
|
|
|
override def execute(tx: MultiverseTransaction): Int = {
|
|
|
|
|
ref1.swap(ref1.get.get + 1)
|
|
|
|
|
ref2.swap(ref2.get.get + 1)
|
|
|
|
|
barrierHolder.get.joinCommit(tx)
|
|
|
|
|
null.asInstanceOf[Int]
|
|
|
|
|
}
|
|
|
|
|
override def onPostCommit = committedCount.incrementAndGet
|
|
|
|
|
override def onPostAbort = abortedCount.incrementAndGet
|
|
|
|
|
}
|
|
|
|
|
template.execute
|
|
|
|
|
|
|
|
|
|
ref1.get.get should equal(1)
|
|
|
|
|
ref2.get.get should equal(1)
|
|
|
|
|
committedCount.get should equal(1)
|
|
|
|
|
abortedCount.get should equal(2)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
2010-05-24 12:31:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-05-24 13:55:56 +02:00
|
|
|
object GlobalTransactionVectorTestActor {
|
2010-05-24 13:12:06 +02:00
|
|
|
case class Add(value: Int)
|
|
|
|
|
case object Size
|
|
|
|
|
case object Success
|
|
|
|
|
}
|
2010-05-24 13:55:56 +02:00
|
|
|
class GlobalTransactionVectorTestActor extends Actor {
|
|
|
|
|
import GlobalTransactionVectorTestActor._
|
2010-05-24 12:31:04 +02:00
|
|
|
import se.scalablesolutions.akka.stm.Transaction.Global
|
|
|
|
|
|
2010-05-24 13:12:06 +02:00
|
|
|
private var vector: TransactionalVector[Int] = Global.atomic { TransactionalVector(1) }
|
2010-05-24 13:55:56 +02:00
|
|
|
|
2010-05-24 13:12:06 +02:00
|
|
|
def receive = {
|
|
|
|
|
case Add(value) =>
|
|
|
|
|
Global.atomic { vector + value}
|
|
|
|
|
self.reply(Success)
|
2010-05-24 12:31:04 +02:00
|
|
|
|
2010-05-24 13:12:06 +02:00
|
|
|
case Size =>
|
|
|
|
|
val size = Global.atomic { vector.size }
|
|
|
|
|
self.reply(size)
|
2010-04-05 11:53:43 +02:00
|
|
|
}
|
|
|
|
|
}
|