fixed bugs regarding oneway transaction managament
This commit is contained in:
parent
6359920fa4
commit
2cfeda0ce0
23 changed files with 1095 additions and 2694 deletions
|
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/scala"/>
|
||||
<classpathentry including="**/*.java" kind="src" path="src/main/scala"/>
|
||||
<classpathentry excluding="**/*.java" kind="src" path="src/main/resources"/>
|
||||
<classpathentry including="**/*.scala" kind="src" output="target/test-classes" path="src/test/scala"/>
|
||||
<classpathentry including="**/*.scala" kind="src" path="src/main/scala"/>
|
||||
<classpathentry excluding="**/*.scala" kind="src" path="src/main/resources"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/activation/activation/1.1/activation-1.1.jar" sourcepath="M2_REPO/javax/activation/activation/1.1/activation-1.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/xml/bind/jaxb-api/2.1/jaxb-api-2.1.jar" sourcepath="M2_REPO/javax/xml/bind/jaxb-api/2.1/jaxb-api-2.1-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar" sourcepath="M2_REPO/javax/annotation/jsr250-api/1.0/jsr250-api-1.0-sources.jar"/>
|
||||
|
|
@ -41,14 +41,13 @@
|
|||
<classpathentry kind="var" path="M2_REPO/com/assembla/scala/mina/mina-integration-scala/2.0.0-M2-SNAPSHOT/mina-integration-scala-2.0.0-M2-SNAPSHOT.jar" sourcepath="M2_REPO/com/assembla/scala/mina/mina-integration-scala/2.0.0-M2-SNAPSHOT/mina-integration-scala-2.0.0-M2-SNAPSHOT-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/jboss/netty/netty/3.1.0.BETA2/netty-3.1.0.BETA2.jar" sourcepath="M2_REPO/org/jboss/netty/netty/3.1.0.BETA2/netty-3.1.0.BETA2-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/rome/rome/0.9/rome-0.9.jar" sourcepath="M2_REPO/rome/rome/0.9/rome-0.9-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/scala-lang/scala-library/2.7.3/scala-library-2.7.3.jar" sourcepath="M2_REPO/org/scala-lang/scala-library/2.7.3/scala-library-2.7.3-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/scala-tools/testing/scalatest/0.9.5/scalatest-0.9.5.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.4.3/slf4j-api-1.4.3.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.4.3/slf4j-api-1.4.3-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-log4j12/1.4.3/slf4j-log4j12-1.4.3.jar" sourcepath="M2_REPO/org/slf4j/slf4j-log4j12/1.4.3/slf4j-log4j12-1.4.3-sources.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/stax/stax-api/1.0.1/stax-api-1.0.1.jar"/>
|
||||
<classpathentry kind="var" path="M2_REPO/com/facebook/thrift/1.0/thrift-1.0.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="ch.epfl.lamp.sdt.launching.SCALA_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/akka-util-java"/>
|
||||
<classpathentry kind="con" path="ch.epfl.lamp.sdt.launching.SCALA_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>akka-kernel</name>
|
||||
<comment/>
|
||||
<projects>
|
||||
<project>akka-util-java</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>ch.epfl.lamp.sdt.core.scalabuilder</name>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>ch.epfl.lamp.sdt.core.scalanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
<name>akka-kernel</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
<project>akka-util-java</project>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>ch.epfl.lamp.sdt.core.scalabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>ch.epfl.lamp.sdt.core.scalanature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
|
|
|||
|
|
@ -1,29 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/web.xml" optional="false" version="2.5" />
|
||||
</descriptors>
|
||||
<webroots>
|
||||
<root url="file://$MODULE_DIR$/src/main/resources" relative="/" />
|
||||
</webroots>
|
||||
<building>
|
||||
<setting name="EXPLODED_URL" value="file://" />
|
||||
<setting name="EXPLODED_ENABLED" value="false" />
|
||||
<setting name="JAR_URL" value="file://" />
|
||||
<setting name="JAR_ENABLED" value="false" />
|
||||
<setting name="EXCLUDE_EXPLODED_DIRECTORY" value="true" />
|
||||
</building>
|
||||
<packaging>
|
||||
<containerElement type="module" name="akka-kernel">
|
||||
<attribute name="method" value="1" />
|
||||
<attribute name="URI" value="/WEB-INF/classes" />
|
||||
</containerElement>
|
||||
</packaging>
|
||||
</configuration>
|
||||
</facet>
|
||||
<facet type="Scala" name="Scala">
|
||||
<configuration />
|
||||
</facet>
|
||||
|
|
@ -35,61 +12,9 @@
|
|||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/scala" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/scala" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="Scala 2.7.3">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../../../bin/scala-2.7.3.final/lib/scala-compiler.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/../../../../bin/scala-2.7.3.final/lib/scala-library.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MODULE_DIR$/../../../../bin/scala-2.7.3.final/src/scala-compiler-src.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/../../../../bin/scala-2.7.3.final/src/scala-library-src.jar!/" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../lib/junit4runner-1.0.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../lib/junit-4.5.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$APPLICATION_HOME_DIR$/lib/javaee.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module-library">
|
||||
<library name="aspectwerkz 2.1">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../lib/aspectwerkz-nodeps-jdk5-2.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="file://$MODULE_DIR$/../../../java/aspectwerkz4/src/main" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module" module-name="akka-util-java" exported="" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.guiceyfruit:guice-core:2.0-beta-4" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.guiceyfruit:guice-jsr250:2.0-beta-4" level="project" />
|
||||
|
|
@ -100,7 +25,7 @@
|
|||
<orderEntry type="library" exported="" name="Maven: org.scala-lang:scala-compiler:2.7.4" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.scala-tools:vscaladoc:1.1-md-3" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: markdownj:markdownj:1.0.2b4-0.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: junit:junit:4.5" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: junit:junit:4.5" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.scala-tools.testing:specs:1.4.4" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.guiceyfruit:guiceyfruit-core:2.0" level="project" />
|
||||
<orderEntry type="library" exported="" name="Maven: org.guiceyfruit:guice-all:2.0" level="project" />
|
||||
|
|
@ -151,6 +76,15 @@
|
|||
<orderEntry type="library" exported="" name="Maven: log4j:log4j:1.2.13" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.scala-tools.testing:scalatest:0.9.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.jteigen.scalatest:junit4runner:1.0" level="project" />
|
||||
<orderEntry type="module-library">
|
||||
<library name="$MODULE_DIR$/../util-java/target">
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../util-java/target/akka-util-java-0.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ object ActiveObject {
|
|||
|
||||
private def localDispatch(joinpoint: JoinPoint): AnyRef = {
|
||||
val rtti = joinpoint.getRtti.asInstanceOf[MethodRtti]
|
||||
if (isOneWay(rtti)) actor !! Invocation(joinpoint) // FIXME investigate why ! causes TX to race
|
||||
if (isOneWay(rtti)) actor ! Invocation(joinpoint)
|
||||
else {
|
||||
val result = actor !! Invocation(joinpoint)
|
||||
if (result.isDefined) result.get
|
||||
|
|
@ -160,10 +160,12 @@ object ActiveObject {
|
|||
new RemoteRequest(false, rtti.getParameterValues, rtti.getMethod.getName, target.getName, None, oneWay, false))
|
||||
if (oneWay) null // for void methods
|
||||
else {
|
||||
future.await
|
||||
val result = getResultOrThrowException(future)
|
||||
if (result.isDefined) result.get
|
||||
else throw new IllegalStateException("No result defined for invocation [" + joinpoint + "]")
|
||||
if (future.isDefined) {
|
||||
future.get.await
|
||||
val result = getResultOrThrowException(future.get)
|
||||
if (result.isDefined) result.get
|
||||
else throw new IllegalStateException("No result returned from call to [" + joinpoint + "]")
|
||||
} else throw new IllegalStateException("No future returned from call to [" + joinpoint + "]")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +175,9 @@ object ActiveObject {
|
|||
throw cause
|
||||
} else future.result.asInstanceOf[Option[T]]
|
||||
|
||||
private def isOneWay(rtti: MethodRtti) = rtti.getMethod.getReturnType == java.lang.Void.TYPE
|
||||
private def isOneWay(rtti: MethodRtti) =
|
||||
rtti.getMethod.isAnnotationPresent(Annotations.oneway) // FIXME investigate why @oneway causes TX to race
|
||||
//rtti.getMethod.getReturnType == java.lang.Void.TYPE
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ trait Actor extends Logging with TransactionManagement {
|
|||
/**
|
||||
* TODO: document
|
||||
*/
|
||||
def !(message: AnyRef) = if (isRunning) {
|
||||
if (isRemote) NettyClient.send(new RemoteRequest(true, message, null, this.getClass.getName, null, true, false))
|
||||
else mailbox.append(new MessageHandle(this, message, new NullFutureResult, activeTx))
|
||||
def !(message: AnyRef): Unit = if (isRunning) {
|
||||
if (TransactionManagement.isTransactionalityEnabled) transactionalDispatch(message, timeout, false, true)
|
||||
else postMessageToMailbox(message)
|
||||
} else throw new IllegalStateException("Actor has not been started, you need to invoke 'actor.start' before using it")
|
||||
|
||||
/**
|
||||
|
|
@ -135,7 +135,7 @@ trait Actor extends Logging with TransactionManagement {
|
|||
*/
|
||||
def !: Option[T] = if (isRunning) {
|
||||
if (TransactionManagement.isTransactionalityEnabled) {
|
||||
transactionalDispatch(message, timeout, false)
|
||||
transactionalDispatch(message, timeout, false, false)
|
||||
} else {
|
||||
val future = postMessageToMailboxAndCreateFutureResultWithTimeout(message, timeout)
|
||||
future.await
|
||||
|
|
@ -153,7 +153,7 @@ trait Actor extends Logging with TransactionManagement {
|
|||
*/
|
||||
def !?[T](message: AnyRef): T = if (isRunning) {
|
||||
if (TransactionManagement.isTransactionalityEnabled) {
|
||||
transactionalDispatch(message, 0, true).get
|
||||
transactionalDispatch(message, 0, true, false).get
|
||||
} else {
|
||||
val future = postMessageToMailboxAndCreateFutureResultWithTimeout(message, 0)
|
||||
future.awaitBlocking
|
||||
|
|
@ -165,7 +165,7 @@ trait Actor extends Logging with TransactionManagement {
|
|||
* TODO: document
|
||||
*/
|
||||
protected[this] def reply(message: AnyRef) = senderFuture match {
|
||||
case None => throw new IllegalStateException("No sender future in scope, can't reply. Have you used '!' (async, fire-and-forget)? If so, switch to '!!' which will return a future to wait on." )
|
||||
case None => throw new IllegalStateException("No sender in scope, can't reply. Have you used '!' (async, fire-and-forget)? If so, switch to '!!' which will return a future to wait on." )
|
||||
case Some(future) => future.completeWithResult(message)
|
||||
}
|
||||
|
||||
|
|
@ -293,34 +293,50 @@ trait Actor extends Logging with TransactionManagement {
|
|||
try {
|
||||
if (messageHandle.tx.isDefined)
|
||||
TransactionManagement.threadBoundTx.set(messageHandle.tx)
|
||||
senderFuture = Some(future)
|
||||
senderFuture = future
|
||||
if (base.isDefinedAt(message)) base(message) // invoke user actor's receive partial function
|
||||
else throw new IllegalArgumentException("No handler matching message [" + message + "] in actor [" + this.getClass.getName + "]")
|
||||
else throw new IllegalArgumentException("No handler matching message [" + message + "] in " + toString)
|
||||
} catch {
|
||||
case e =>
|
||||
if (supervisor.isDefined) supervisor.get ! Exit(this, e)
|
||||
future.completeWithException(this, e)
|
||||
if (future.isDefined) future.get.completeWithException(this, e)
|
||||
else e.printStackTrace
|
||||
} finally {
|
||||
TransactionManagement.threadBoundTx.set(None)
|
||||
}
|
||||
}
|
||||
|
||||
private def postMessageToMailbox(message: AnyRef): Unit =
|
||||
if (isRemote) NettyClient.send(new RemoteRequest(true, message, null, this.getClass.getName, null, true, false))
|
||||
else mailbox.append(new MessageHandle(this, message, None, activeTx))
|
||||
|
||||
private def postMessageToMailboxAndCreateFutureResultWithTimeout(message: AnyRef, timeout: Long): CompletableFutureResult =
|
||||
if (isRemote) NettyClient.send(new RemoteRequest(true, message, null, this.getClass.getName, null, false, false))
|
||||
if (isRemote) {
|
||||
val future = NettyClient.send(new RemoteRequest(true, message, null, this.getClass.getName, null, false, false))
|
||||
if (future.isDefined) future.get
|
||||
else throw new IllegalStateException("Expected a future from remote call to actor " + toString)
|
||||
}
|
||||
else {
|
||||
val future = new DefaultCompletableFutureResult(timeout)
|
||||
mailbox.append(new MessageHandle(this, message, future, TransactionManagement.threadBoundTx.get))
|
||||
mailbox.append(new MessageHandle(this, message, Some(future), TransactionManagement.threadBoundTx.get))
|
||||
future
|
||||
}
|
||||
|
||||
private def transactionalDispatch[T](message: AnyRef, timeout: Long, blocking: Boolean): Option[T] = {
|
||||
private def transactionalDispatch[T](message: AnyRef, timeout: Long, blocking: Boolean, oneWay: Boolean): Option[T] = {
|
||||
tryToCommitTransaction
|
||||
if (isInExistingTransaction) joinExistingTransaction
|
||||
else if (isTransactional) startNewTransaction
|
||||
incrementTransaction
|
||||
try {
|
||||
val future = postMessageToMailboxAndCreateFutureResultWithTimeout(message, timeout)
|
||||
if (blocking) future.awaitBlocking
|
||||
else future.await
|
||||
getResultOrThrowException(future)
|
||||
if (oneWay) {
|
||||
postMessageToMailbox(message)
|
||||
None
|
||||
} else {
|
||||
val future = postMessageToMailboxAndCreateFutureResultWithTimeout(message, timeout)
|
||||
if (blocking) future.awaitBlocking
|
||||
else future.await
|
||||
getResultOrThrowException(future)
|
||||
}
|
||||
} catch {
|
||||
case e: TransactionAwareWrapperException =>
|
||||
e.cause.printStackTrace
|
||||
|
|
@ -408,4 +424,4 @@ trait Actor extends Logging with TransactionManagement {
|
|||
}
|
||||
|
||||
override def toString(): String = "Actor[" + id + "]"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@
|
|||
package se.scalablesolutions.akka.kernel.nio
|
||||
|
||||
import java.net.InetSocketAddress
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.concurrent.{Executors, ConcurrentMap, ConcurrentHashMap}
|
||||
|
||||
import kernel.reactor.{NullFutureResult, DefaultCompletableFutureResult, CompletableFutureResult}
|
||||
import kernel.util.{HashCode, Logging};
|
||||
import kernel.reactor.{DefaultCompletableFutureResult, CompletableFutureResult}
|
||||
import kernel.util.Logging
|
||||
|
||||
import org.jboss.netty.handler.codec.serialization.{ObjectEncoder, ObjectDecoder}
|
||||
import org.jboss.netty.bootstrap.ClientBootstrap
|
||||
|
|
@ -58,17 +57,17 @@ object NettyClient extends Logging {
|
|||
}
|
||||
}
|
||||
|
||||
def send(request: RemoteRequest): CompletableFutureResult = if (isRunning) {
|
||||
def send(request: RemoteRequest): Option[CompletableFutureResult] = if (isRunning) {
|
||||
val escapedRequest = escapeRequest(request)
|
||||
if (escapedRequest.isOneWay) {
|
||||
connection.getChannel.write(escapedRequest)
|
||||
new NullFutureResult
|
||||
None
|
||||
} else {
|
||||
futures.synchronized {
|
||||
val futureResult = new DefaultCompletableFutureResult(100000)
|
||||
futures.put(request.id, futureResult)
|
||||
connection.getChannel.write(escapedRequest)
|
||||
futureResult
|
||||
Some(futureResult)
|
||||
}
|
||||
}
|
||||
} else throw new IllegalStateException("Netty client is not running, make sure you have invoked 'connect' before using the client")
|
||||
|
|
@ -121,6 +120,7 @@ class ObjectClientHandler(val futures: ConcurrentMap[Long, CompletableFutureResu
|
|||
//if (reply.successful) future.completeWithResult((reply.message, tx))
|
||||
if (reply.successful) future.completeWithResult(reply.message)
|
||||
else future.completeWithException(null, reply.exception)
|
||||
futures.remove(reply.id)
|
||||
} else throw new IllegalArgumentException("Unknown message received in NIO client handler: " + result)
|
||||
} catch {
|
||||
case e: Exception => log.error("Unexpected exception in NIO client handler: %s", e); throw e
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ object NettyServer extends Logging {
|
|||
}
|
||||
}
|
||||
|
||||
@ChannelPipelineCoverage {val value = "all"}
|
||||
@ChannelPipelineCoverage { val value = "all" }
|
||||
class ObjectServerHandler extends SimpleChannelUpstreamHandler with Logging {
|
||||
private val activeObjectFactory = new ActiveObjectFactory
|
||||
private val activeObjects = new ConcurrentHashMap[String, AnyRef]
|
||||
|
|
|
|||
|
|
@ -117,15 +117,3 @@ class DefaultCompletableFutureResult(timeout: Long) extends CompletableFutureRes
|
|||
|
||||
private def currentTimeInNanos: Long = TIME_UNIT.toNanos(System.currentTimeMillis)
|
||||
}
|
||||
|
||||
class NullFutureResult extends CompletableFutureResult {
|
||||
def completeWithResult(result: AnyRef) = {}
|
||||
def completeWithException(toBlame: AnyRef, exception: Throwable) = {}
|
||||
def await = throw new UnsupportedOperationException("Not implemented for NullFutureResult")
|
||||
def awaitBlocking = throw new UnsupportedOperationException("Not implemented for NullFutureResult")
|
||||
def isCompleted: Boolean = throw new UnsupportedOperationException("Not implemented for NullFutureResult")
|
||||
def isExpired: Boolean = throw new UnsupportedOperationException("Not implemented for NullFutureResult")
|
||||
def timeoutInNanos: Long = throw new UnsupportedOperationException("Not implemented for NullFutureResult")
|
||||
def result: Option[AnyRef] = None
|
||||
def exception: Option[Tuple2[AnyRef, Throwable]] = None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,18 +33,20 @@ class ProxyMessageDispatcher extends MessageDispatcherBase {
|
|||
guard.synchronized { /* empty */ } // prevents risk for deadlock as described in [http://developers.sun.com/learning/javaoneonline/2006/coreplatform/TS-1315.pdf]
|
||||
try {
|
||||
messageDemultiplexer.select
|
||||
} catch {case e: InterruptedException => active = false}
|
||||
} catch { case e: InterruptedException => active = false }
|
||||
val queue = messageDemultiplexer.acquireSelectedQueue
|
||||
for (index <- 0 until queue.size) {
|
||||
val handle = queue.remove
|
||||
handlerExecutor.execute(new Runnable {
|
||||
val invocation = handle.message.asInstanceOf[Invocation]
|
||||
override def run = {
|
||||
val future = handle.future
|
||||
try {
|
||||
val result = invocation.joinpoint.proceed
|
||||
handle.future.completeWithResult(result)
|
||||
if (future.isDefined) future.get.completeWithResult(result)
|
||||
} catch {
|
||||
case e: Exception => handle.future.completeWithException(invocation.joinpoint.getTarget, e)
|
||||
case e: Exception =>
|
||||
if (future.isDefined) future.get.completeWithException(invocation.joinpoint.getTarget, e)
|
||||
}
|
||||
messageDemultiplexer.wakeUp
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ trait MessageDemultiplexer {
|
|||
|
||||
class MessageHandle(val sender: AnyRef,
|
||||
val message: AnyRef,
|
||||
val future: CompletableFutureResult,
|
||||
val future: Option[CompletableFutureResult],
|
||||
val tx: Option[Transaction]) {
|
||||
|
||||
override def hashCode(): Int = {
|
||||
var result = HashCode.SEED
|
||||
result = HashCode.hash(result, sender)
|
||||
result = HashCode.hash(result, message)
|
||||
result = HashCode.hash(result, future)
|
||||
result = if (future.isDefined) HashCode.hash(result, future.get) else result
|
||||
result = if (tx.isDefined) HashCode.hash(result, tx.get.id) else result
|
||||
result
|
||||
}
|
||||
|
|
@ -53,7 +53,8 @@ class MessageHandle(val sender: AnyRef,
|
|||
that.isInstanceOf[MessageHandle] &&
|
||||
that.asInstanceOf[MessageHandle].sender == sender &&
|
||||
that.asInstanceOf[MessageHandle].message == message &&
|
||||
that.asInstanceOf[MessageHandle].future == future &&
|
||||
that.asInstanceOf[MessageHandle].future.isDefined == future.isDefined &&
|
||||
that.asInstanceOf[MessageHandle].future.get == future.get &&
|
||||
that.asInstanceOf[MessageHandle].tx.isDefined == tx.isDefined &&
|
||||
that.asInstanceOf[MessageHandle].tx.get.id == tx.get.id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ object TransactionIdFactory {
|
|||
|
||||
def begin(participant: String) = synchronized {
|
||||
ensureIsActiveOrNew
|
||||
if (status == TransactionStatus.New) log.debug("TX BEGIN - Server [%s] is starting NEW transaction [%s]", participant, this)
|
||||
if (status == TransactionStatus.New) log.debug("TX BEGIN - Server [%s] is starting NEW transaction [%s]", participant, toString)
|
||||
else log.debug("Server [%s] is participating in transaction", participant)
|
||||
participants ::= participant
|
||||
status = TransactionStatus.Active
|
||||
|
|
@ -67,14 +67,14 @@ object TransactionIdFactory {
|
|||
|
||||
def precommit(participant: String) = synchronized {
|
||||
if (status == TransactionStatus.Active) {
|
||||
log.debug("TX PRECOMMIT - Pre-committing transaction [%s] for server [%s]", this, participant)
|
||||
log.debug("TX PRECOMMIT - Pre-committing transaction [%s] for server [%s]", toString, participant)
|
||||
precommitted ::= participant
|
||||
}
|
||||
}
|
||||
|
||||
def commit(participant: String) = synchronized {
|
||||
if (status == TransactionStatus.Active) {
|
||||
log.debug("TX COMMIT - Committing transaction [%s] for server [%s]", this, participant)
|
||||
log.debug("TX COMMIT - Committing transaction [%s] for server [%s]", toString, participant)
|
||||
val haveAllPreCommitted =
|
||||
if (participants.size == precommitted.size) {{
|
||||
for (part <- participants) yield {
|
||||
|
|
@ -92,7 +92,7 @@ object TransactionIdFactory {
|
|||
|
||||
def rollback(participant: String) = synchronized {
|
||||
ensureIsActiveOrAborted
|
||||
log.debug("TX ROLLBACK - Server [%s] has initiated transaction rollback for [%s]", participant, this)
|
||||
log.debug("TX ROLLBACK - Server [%s] has initiated transaction rollback for [%s]", participant, toString)
|
||||
transactionals.items.foreach(_.rollback)
|
||||
status = TransactionStatus.Aborted
|
||||
reset
|
||||
|
|
@ -100,7 +100,7 @@ object TransactionIdFactory {
|
|||
|
||||
def join(participant: String) = synchronized {
|
||||
ensureIsActive
|
||||
log.debug("TX JOIN - Server [%s] is joining transaction [%s]" , participant, this)
|
||||
log.debug("TX JOIN - Server [%s] is joining transaction [%s]" , participant, toString)
|
||||
participants ::= participant
|
||||
}
|
||||
|
||||
|
|
@ -116,13 +116,13 @@ object TransactionIdFactory {
|
|||
}
|
||||
|
||||
private def ensureIsActive = if (status != TransactionStatus.Active)
|
||||
throw new IllegalStateException("Expected ACTIVE transaction - current status [" + status + "]")
|
||||
throw new IllegalStateException("Expected ACTIVE transaction - current status [" + status + "]: " + toString)
|
||||
|
||||
private def ensureIsActiveOrAborted = if (!(status == TransactionStatus.Active || status == TransactionStatus.Aborted))
|
||||
throw new IllegalStateException("Expected ACTIVE or ABORTED transaction - current status [" + status + "]")
|
||||
throw new IllegalStateException("Expected ACTIVE or ABORTED transaction - current status [" + status + "]: " + toString)
|
||||
|
||||
private def ensureIsActiveOrNew = if (!(status == TransactionStatus.Active || status == TransactionStatus.New))
|
||||
throw new IllegalStateException("Expected ACTIVE or NEW transaction - current status [" + status + "]")
|
||||
throw new IllegalStateException("Expected ACTIVE or NEW transaction - current status [" + status + "]: " + toString)
|
||||
|
||||
// For reinitialize transaction after sending it over the wire
|
||||
private[kernel] def reinit = {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package se.scalablesolutions.akka.kernel.reactor
|
||||
|
||||
import java.util.concurrent.BrokenBarrierException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
|
@ -60,7 +58,7 @@ class EventBasedDispatcherTest {
|
|||
dispatcher.registerHandler(key, new TestMessageHandle(handleLatch))
|
||||
dispatcher.start
|
||||
for (i <- 0 until 100) {
|
||||
dispatcher.messageQueue.append(new MessageHandle(key, new Object, new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key, new Object, None, None))
|
||||
}
|
||||
assertTrue(handleLatch.await(5, TimeUnit.SECONDS))
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
|
|
@ -74,8 +72,8 @@ class EventBasedDispatcherTest {
|
|||
dispatcher.registerHandler(key1, new TestMessageHandle(handleLatch))
|
||||
dispatcher.registerHandler(key2, new TestMessageHandle(handleLatch))
|
||||
dispatcher.start
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Object, new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Object, new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Object, None, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Object, None, None))
|
||||
assertTrue(handleLatch.await(5, TimeUnit.SECONDS))
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
}
|
||||
|
|
@ -109,8 +107,8 @@ class EventBasedDispatcherTest {
|
|||
})
|
||||
dispatcher.start
|
||||
for (i <- 0 until 100) {
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Integer(i), new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Integer(i), new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Integer(i), None, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Integer(i), None, None))
|
||||
}
|
||||
assertTrue(handleLatch.await(5, TimeUnit.SECONDS))
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,29 @@
|
|||
package se.scalablesolutions.akka.kernel.actor
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import junit.framework.TestCase
|
||||
import kernel.state.TransactionalState
|
||||
import kernel.reactor._
|
||||
|
||||
import org.junit.{Test, Before}
|
||||
import org.junit.Assert._
|
||||
|
||||
case class SetMapState(key: String, value: String)
|
||||
case class SetVectorState(key: String)
|
||||
case class SetRefState(key: String)
|
||||
case class GetMapState(key: String)
|
||||
case object GetVectorState
|
||||
case object GetRefState
|
||||
|
||||
case class SetMapState(key: String, value: String)
|
||||
case class SetVectorState(key: String)
|
||||
case class SetRefState(key: String)
|
||||
case class Success(key: String, value: String)
|
||||
case class Failure(key: String, value: String, failer: Actor)
|
||||
|
||||
case class SetMapStateOneWay(key: String, value: String)
|
||||
case class SetVectorStateOneWay(key: String)
|
||||
case class SetRefStateOneWay(key: String)
|
||||
case class SuccessOneWay(key: String, value: String)
|
||||
case class FailureOneWay(key: String, value: String, failer: Actor)
|
||||
|
||||
class InMemStatefulActor extends Actor {
|
||||
timeout = 100000
|
||||
makeTransactional
|
||||
private val mapState = TransactionalState.newInMemoryMap[String, String]
|
||||
private val vectorState = TransactionalState.newInMemoryVector[String]
|
||||
|
|
@ -51,6 +56,22 @@ class InMemStatefulActor extends Actor {
|
|||
refState.swap(msg)
|
||||
failer !! "Failure"
|
||||
reply(msg)
|
||||
|
||||
case SetMapStateOneWay(key, msg) =>
|
||||
mapState.put(key, msg)
|
||||
case SetVectorStateOneWay(msg) =>
|
||||
vectorState.add(msg)
|
||||
case SetRefStateOneWay(msg) =>
|
||||
refState.swap(msg)
|
||||
case SuccessOneWay(key, msg) =>
|
||||
mapState.put(key, msg)
|
||||
vectorState.add(msg)
|
||||
refState.swap(msg)
|
||||
case FailureOneWay(key, msg, failer) =>
|
||||
mapState.put(key, msg)
|
||||
vectorState.add(msg)
|
||||
refState.swap(msg)
|
||||
failer ! "Failure"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,8 +82,19 @@ class InMemFailerActor extends Actor {
|
|||
throw new RuntimeException("expected")
|
||||
}
|
||||
}
|
||||
|
||||
class InMemoryActorSpec extends TestCase {
|
||||
@Test
|
||||
def testOneWayMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful ! SetMapStateOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "init") // set init state
|
||||
Thread.sleep(100)
|
||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactional
|
||||
Thread.sleep(100)
|
||||
assertEquals("new state", (stateful !! GetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess")).get)
|
||||
}
|
||||
|
||||
class InMemoryActorSpec {
|
||||
@Test
|
||||
def testMapShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
|
|
@ -72,6 +104,19 @@ class InMemoryActorSpec {
|
|||
assertEquals("new state", (stateful !! GetMapState("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess")).get)
|
||||
}
|
||||
|
||||
@Test
|
||||
def testOneWayMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
val failer = new InMemFailerActor
|
||||
failer.start
|
||||
stateful ! SetMapStateOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "init") // set init state
|
||||
Thread.sleep(100)
|
||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactional method
|
||||
Thread.sleep(100)
|
||||
assertEquals("init", (stateful !! GetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")).get) // check that state is == init state
|
||||
}
|
||||
|
||||
@Test
|
||||
def testMapShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
|
|
@ -86,16 +131,39 @@ class InMemoryActorSpec {
|
|||
assertEquals("init", (stateful !! GetMapState("testShouldRollbackStateForStatefulServerInCaseOfFailure")).get) // check that state is == init state
|
||||
}
|
||||
|
||||
@Test
|
||||
def testOneWayVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful ! SetVectorStateOneWay("init") // set init state
|
||||
Thread.sleep(100)
|
||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactional
|
||||
Thread.sleep(100)
|
||||
assertEquals("new state", (stateful !! GetVectorState).get)
|
||||
}
|
||||
|
||||
@Test
|
||||
def testVectorShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful !! SetVectorState("init") // set init state
|
||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactional
|
||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // to trigger commit
|
||||
assertEquals("new state", (stateful !! GetVectorState).get)
|
||||
}
|
||||
|
||||
@Test
|
||||
def testOneWayVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful ! SetVectorStateOneWay("init") // set init state
|
||||
Thread.sleep(100)
|
||||
val failer = new InMemFailerActor
|
||||
failer.start
|
||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactional method
|
||||
Thread.sleep(100)
|
||||
assertEquals("init", (stateful !! GetVectorState).get) // check that state is == init state
|
||||
}
|
||||
|
||||
@Test
|
||||
def testVectorShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
|
|
@ -110,16 +178,39 @@ class InMemoryActorSpec {
|
|||
assertEquals("init", (stateful !! GetVectorState).get) // check that state is == init state
|
||||
}
|
||||
|
||||
@Test
|
||||
def testOneWayRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful ! SetRefStateOneWay("init") // set init state
|
||||
Thread.sleep(100)
|
||||
stateful ! SuccessOneWay("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactional
|
||||
Thread.sleep(100)
|
||||
assertEquals("new state", (stateful !! GetRefState).get)
|
||||
}
|
||||
|
||||
@Test
|
||||
def testRefShouldNotRollbackStateForStatefulServerInCaseOfSuccess = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful !! SetRefState("init") // set init state
|
||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // transactional
|
||||
stateful !! Success("testShouldNotRollbackStateForStatefulServerInCaseOfSuccess", "new state") // to trigger commit
|
||||
assertEquals("new state", (stateful !! GetRefState).get)
|
||||
}
|
||||
|
||||
@Test
|
||||
def testOneWayRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
stateful.start
|
||||
stateful ! SetRefStateOneWay("init") // set init state
|
||||
Thread.sleep(100)
|
||||
val failer = new InMemFailerActor
|
||||
failer.start
|
||||
stateful ! FailureOneWay("testShouldRollbackStateForStatefulServerInCaseOfFailure", "new state", failer) // call failing transactional method
|
||||
Thread.sleep(100)
|
||||
assertEquals("init", (stateful !! GetRefState).get) // check that state is == init state
|
||||
}
|
||||
|
||||
@Test
|
||||
def testRefShouldRollbackStateForStatefulServerInCaseOfFailure = {
|
||||
val stateful = new InMemStatefulActor
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ package se.scalablesolutions.akka.kernel.actor
|
|||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import junit.framework.TestCase
|
||||
import kernel.Kernel
|
||||
|
||||
import kernel.reactor._
|
||||
|
||||
import kernel.state.{CassandraStorageConfig, TransactionalState}
|
||||
|
|
@ -61,7 +64,7 @@ object PersistenceManager {
|
|||
isRunning = true
|
||||
}
|
||||
}
|
||||
class PersistentActorSpec {
|
||||
class PersistentActorSpec extends TestCase {
|
||||
PersistenceManager.init
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package se.scalablesolutions.akka.kernel.actor
|
|||
import concurrent.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import java.util.concurrent.TimeUnit
|
||||
import junit.framework.TestCase
|
||||
import kernel.nio.{NettyClient, NettyServer}
|
||||
import reactor._
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ class RemoteActorSpecActorBidirectional extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
class RemoteActorSpec {
|
||||
class RemoteActorSpec extends TestCase {
|
||||
|
||||
new Thread(new Runnable() {
|
||||
def run = {
|
||||
|
|
@ -42,7 +43,7 @@ class RemoteActorSpec {
|
|||
private val unit = TimeUnit.MILLISECONDS
|
||||
|
||||
@Test
|
||||
def sendOneWay = {
|
||||
def testSendOneWay = {
|
||||
implicit val timeout = 5000L
|
||||
val actor = new RemoteActorSpecActorUnidirectional
|
||||
actor.makeRemote
|
||||
|
|
@ -54,7 +55,7 @@ class RemoteActorSpec {
|
|||
}
|
||||
|
||||
@Test
|
||||
def sendReplySync = {
|
||||
def testSendReplySync = {
|
||||
implicit val timeout = 5000L
|
||||
val actor = new RemoteActorSpecActorBidirectional
|
||||
actor.makeRemote
|
||||
|
|
@ -65,7 +66,7 @@ class RemoteActorSpec {
|
|||
}
|
||||
|
||||
@Test
|
||||
def sendReplyAsync = {
|
||||
def testSendReplyAsync = {
|
||||
implicit val timeout = 5000L
|
||||
val actor = new RemoteActorSpecActorBidirectional
|
||||
actor.makeRemote
|
||||
|
|
@ -75,8 +76,8 @@ class RemoteActorSpec {
|
|||
actor.stop
|
||||
}
|
||||
|
||||
@Test
|
||||
def sendReceiveException = {
|
||||
@Test
|
||||
def testSendReceiveException = {
|
||||
implicit val timeout = 5000L
|
||||
val actor = new RemoteActorSpecActorBidirectional
|
||||
actor.makeRemote
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@ package se.scalablesolutions.akka.kernel
|
|||
import kernel.actor.{Supervisor, SupervisorFactory, Actor, StartSupervisor}
|
||||
import kernel.config.ScalaConfig._
|
||||
|
||||
import scala.collection.Map
|
||||
import scala.collection.mutable.HashMap
|
||||
|
||||
import com.jteigen.scalatest.JUnit4Runner
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest._
|
||||
|
|
@ -21,6 +18,8 @@ import org.scalatest._
|
|||
class SupervisorSpec extends Suite {
|
||||
|
||||
var messageLog: String = ""
|
||||
var oneWayLog: String = ""
|
||||
|
||||
var pingpong1: PingPong1Actor = _
|
||||
var pingpong2: PingPong2Actor = _
|
||||
var pingpong3: PingPong3Actor = _
|
||||
|
|
@ -39,11 +38,11 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getSingleActorOneForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -53,49 +52,7 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getSingleActorOneForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
expect("ping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
expect("pingDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
expect("pingDIEping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testKillSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testCallKillCallSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
pingpong1.timeout = 10000000
|
||||
sup.timeout = 10000000
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
|
|
@ -106,7 +63,49 @@ class SupervisorSpec extends Suite {
|
|||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(1100)
|
||||
Thread.sleep(500)
|
||||
expect("pingDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingDIEping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testKillSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testCallKillCallSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("ping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingDIE") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -123,10 +122,11 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getMultipleActorsOneForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong3 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -136,40 +136,41 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getMultipleActorsOneForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEpingpingping") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -179,10 +180,11 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getMultipleActorsAllForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("DIEDIEDIE") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -192,45 +194,240 @@ class SupervisorSpec extends Suite {
|
|||
messageLog = ""
|
||||
val sup = getMultipleActorsAllForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEDIEDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 !! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEDIEDIEpingpingping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testOneWayKillSingleActorOneForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorOneForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
pingpong1 ! Die
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testOneWayCallKillCallSingleActorOneForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorOneForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
pingpong1 ! OneWay
|
||||
Thread.sleep(500)
|
||||
expect("oneway") {
|
||||
oneWayLog
|
||||
}
|
||||
pingpong1 ! Die
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
pingpong1 ! OneWay
|
||||
Thread.sleep(500)
|
||||
expect("onewayoneway") {
|
||||
oneWayLog
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
def testOneWayKillSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testOneWayCallKillCallSingleActorAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getSingleActorAllForOneSupervisor
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("ping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingDIEping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testOneWayKillMultipleActorsOneForOne = {
|
||||
messageLog = ""
|
||||
val sup = getMultipleActorsOneForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong3 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("DIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def tesOneWayCallKillCallMultipleActorsOneForOne = {
|
||||
messageLog = ""
|
||||
val sup = getMultipleActorsOneForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong1 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEpingpingping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def testOneWayKillMultipleActorsAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getMultipleActorsAllForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("DIEDIEDIE") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
|
||||
def tesOneWayCallKillCallMultipleActorsAllForOne = {
|
||||
messageLog = ""
|
||||
val sup = getMultipleActorsAllForOneConf
|
||||
sup ! StartSupervisor
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
pingpong1 ! Ping
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingping") {
|
||||
messageLog
|
||||
}
|
||||
intercept(classOf[RuntimeException]) {
|
||||
pingpong2 ! Die
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEDIEDIE") {
|
||||
messageLog
|
||||
}
|
||||
expect("pong") {
|
||||
(pingpong1 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong2 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pong") {
|
||||
(pingpong3 ! Ping).getOrElse("nil")
|
||||
}
|
||||
Thread.sleep(500)
|
||||
expect("pingpingpingDIEDIEDIEpingpingping") {
|
||||
messageLog
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
def testNestedSupervisorsTerminateFirstLevelActorAllForOne = {
|
||||
messageLog = ""
|
||||
|
|
@ -239,7 +436,7 @@ class SupervisorSpec extends Suite {
|
|||
intercept(classOf[RuntimeException]) {
|
||||
pingpong1 !! Die
|
||||
}
|
||||
Thread.sleep(100)
|
||||
Thread.sleep(500)
|
||||
expect("DIEDIEDIE") {
|
||||
messageLog
|
||||
}
|
||||
|
|
@ -374,6 +571,9 @@ class SupervisorSpec extends Suite {
|
|||
case Ping =>
|
||||
messageLog += "ping"
|
||||
reply("pong")
|
||||
|
||||
case OneWay =>
|
||||
oneWayLog += "oneway"
|
||||
|
||||
case Die =>
|
||||
throw new RuntimeException("DIE")
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
package se.scalablesolutions.akka.kernel.reactor
|
||||
|
||||
import java.util.concurrent.BrokenBarrierException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.CyclicBarrier
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
|
@ -62,7 +60,7 @@ class ThreadBasedDispatcherTest {
|
|||
dispatcher.registerHandler(key, new TestMessageHandle(handleLatch))
|
||||
dispatcher.start
|
||||
for (i <- 0 until 100) {
|
||||
dispatcher.messageQueue.append(new MessageHandle(key, new Object, new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key, new Object, None, None))
|
||||
}
|
||||
assertTrue(handleLatch.await(5, TimeUnit.SECONDS))
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
|
|
@ -86,8 +84,8 @@ class ThreadBasedDispatcherTest {
|
|||
}
|
||||
})
|
||||
dispatcher.start
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, "Sending Message 1", new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, "Sending Message 2", new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, "Sending Message 1", None, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, "Sending Message 2", None, None))
|
||||
handlersBarrier.await(5, TimeUnit.SECONDS)
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
//dispatcher.shutdown
|
||||
|
|
@ -122,8 +120,8 @@ class ThreadBasedDispatcherTest {
|
|||
})
|
||||
dispatcher.start
|
||||
for (i <- 0 until 100) {
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Integer(i), new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Integer(i), new NullFutureResult, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key1, new Integer(i), None, None))
|
||||
dispatcher.messageQueue.append(new MessageHandle(key2, new Integer(i), None, None))
|
||||
}
|
||||
assertTrue(handleLatch.await(5, TimeUnit.SECONDS))
|
||||
assertFalse(threadingIssueDetected.get)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue