pekko/akka-bench-jmh/src/main/scala/akka/persistence/PersistentActorThroughputBenchmark.scala
Konrad 'ktoso' Malawski d51b79c95a !per persistAsync
Breaks binary compatibility because adding new methods to Eventsourced
trait. Since akka-persistence is experimental this is ok, yet
source-level compatibility has been perserved thankfuly :-)

Deprecates:
* Rename of EventsourcedProcessor -> PersistentActor
* Processor -> suggest using PersistentActor
* Migration guide for akka-persistence is separate, as wel'll deprecate in minor versions (its experimental)
* Persistent as well as ConfirmablePersistent - since Processor, their
  main user will be removed soon.

Other changes:
* persistAsync works as expected when mixed with persist
* A counter must be kept for pending stashing invocations
* Uses only 1 shared list buffer for persit / persistAsync
* Includes small benchmark
* Docs also include info about not using Persistent() wrapper
* uses java LinkedList, for best performance of append / head on
  persistInvocations; the get(0) is safe, because these msgs only
  come in response to persistInvocations
* Renamed internal *MessagesSuccess/Failure messages because we kept
  small mistakes seeing the class "with s" and "without s" as the same
* Updated everything that refered to EventsourcedProcessor to
  PersistentActor, including samples

Refs #15227

Conflicts:
	akka-docs/rst/project/migration-guides.rst
	akka-persistence/src/main/scala/akka/persistence/JournalProtocol.scala
	akka-persistence/src/main/scala/akka/persistence/Persistent.scala
	akka-persistence/src/test/scala/akka/persistence/PersistentActorSpec.scala
	project/AkkaBuild.scala
2014-06-10 11:09:12 +02:00

144 lines
No EOL
4.2 KiB
Scala

/**
* Copyright (C) 2014 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.persistence
import org.openjdk.jmh.annotations._
import org.openjdk.jmh._
import com.typesafe.config.ConfigFactory
import akka.actor._
import akka.testkit.TestProbe
import java.io.File
import org.apache.commons.io.FileUtils
import org.openjdk.jmh.annotations.Scope
@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class PersistentActorThroughputBenchmark {
val config = PersistenceSpec.config("leveldb", "benchmark")
lazy val storageLocations = List(
"akka.persistence.journal.leveldb.dir",
"akka.persistence.journal.leveldb-shared.store.dir",
"akka.persistence.snapshot-store.local.dir").map(s new File(system.settings.config.getString(s)))
var system: ActorSystem = _
var probe: TestProbe = _
var actor: ActorRef = _
var persist1EventProcessor: ActorRef = _
var persist1CommandProcessor: ActorRef = _
var persistAsync1EventProcessor: ActorRef = _
var persistAsync1QuickReplyEventProcessor: ActorRef = _
val data10k = (1 to 10000).toArray
@Setup
def setup() {
system = ActorSystem("test", config)
probe = TestProbe()(system)
storageLocations.foreach(FileUtils.deleteDirectory)
actor = system.actorOf(Props(classOf[BaselineActor], data10k.last), "a-1")
persist1CommandProcessor = system.actorOf(Props(classOf[Persist1EventPersistentActor], data10k.last), "p-1")
persist1EventProcessor = system.actorOf(Props(classOf[Persist1EventPersistentActor], data10k.last), "ep-1")
persistAsync1EventProcessor = system.actorOf(Props(classOf[PersistAsync1EventPersistentActor], data10k.last), "epa-1")
persistAsync1QuickReplyEventProcessor = system.actorOf(Props(classOf[PersistAsync1EventQuickReplyPersistentActor], data10k.last), "epa-2")
}
@TearDown
def shutdown() {
system.shutdown()
system.awaitTermination()
storageLocations.foreach(FileUtils.deleteDirectory)
}
@GenerateMicroBenchmark
@OperationsPerInvocation(10000)
def tell_normalActor_reply_baseline() {
for (i <- data10k) actor.tell(i, probe.ref)
probe.expectMsg(Evt(data10k.last))
}
@GenerateMicroBenchmark
@OperationsPerInvocation(10000)
def tell_persist_reply() {
for (i <- data10k) persist1EventProcessor.tell(i, probe.ref)
probe.expectMsg(Evt(data10k.last))
}
@GenerateMicroBenchmark
@OperationsPerInvocation(10000)
def tell_commandPersist_reply() {
for (i <- data10k) persist1CommandProcessor.tell(i, probe.ref)
probe.expectMsg(Evt(data10k.last))
}
@GenerateMicroBenchmark
@OperationsPerInvocation(10000)
def tell_persistAsync_reply() {
for (i <- data10k) persistAsync1EventProcessor.tell(i, probe.ref)
probe.expectMsg(Evt(data10k.last))
}
@GenerateMicroBenchmark
@OperationsPerInvocation(10000)
def tell_persistAsync_replyRightOnCommandReceive() {
for (i <- data10k) persistAsync1QuickReplyEventProcessor.tell(i, probe.ref)
probe.expectMsg(Evt(data10k.last))
}
}
final case class Evt(i: Int)
class Persist1EventPersistentActor(respondAfter: Int) extends PersistentActor {
override def receiveCommand = {
case n: Int => persist(Evt(n)) { e => if (e.i == respondAfter) sender() ! e }
}
override def receiveRecover = {
case _ => // do nothing
}
}
class Persist1CommandProcessor(respondAfter: Int) extends Processor {
override def receive = {
case n: Int => if (n == respondAfter) sender() ! Evt(n)
}
}
class PersistAsync1EventPersistentActor(respondAfter: Int) extends PersistentActor {
override def receiveCommand = {
case n: Int =>
persistAsync(Evt(n)) { e => if (e.i == respondAfter) sender() ! e }
}
override def receiveRecover = {
case _ => // do nothing
}
}
class PersistAsync1EventQuickReplyPersistentActor(respondAfter: Int) extends PersistentActor {
override def receiveCommand = {
case n: Int =>
val e = Evt(n)
if (n == respondAfter) sender() ! e
persistAsync(e)(identity)
}
override def receiveRecover = {
case _ => // do nothing
}
}
/** only as a "the best we could possibly get" baseline, does not persist anything */
class BaselineActor(respondAfter: Int) extends Actor {
override def receive = {
case n: Int => if (n == respondAfter) sender() ! Evt(n)
}
}