2013-11-25 12:02:29 +01:00
|
|
|
/**
|
2014-02-02 19:05:45 -06:00
|
|
|
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
2013-11-25 12:02:29 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package akka.persistence.journal
|
|
|
|
|
|
|
|
|
|
import scala.collection.immutable
|
|
|
|
|
import scala.concurrent._
|
|
|
|
|
import scala.concurrent.duration.Duration
|
|
|
|
|
import scala.language.postfixOps
|
|
|
|
|
|
|
|
|
|
import akka.AkkaException
|
|
|
|
|
import akka.actor._
|
|
|
|
|
import akka.pattern.ask
|
|
|
|
|
import akka.persistence._
|
|
|
|
|
import akka.util._
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*
|
|
|
|
|
* A journal that delegates actual storage to a target actor. For testing only.
|
|
|
|
|
*/
|
|
|
|
|
private[persistence] trait AsyncWriteProxy extends AsyncWriteJournal with Stash {
|
|
|
|
|
import AsyncWriteProxy._
|
|
|
|
|
import AsyncWriteTarget._
|
|
|
|
|
|
|
|
|
|
private val initialized = super.receive
|
|
|
|
|
private var store: ActorRef = _
|
|
|
|
|
|
|
|
|
|
override def receive = {
|
|
|
|
|
case SetStore(ref) ⇒
|
|
|
|
|
store = ref
|
|
|
|
|
unstashAll()
|
|
|
|
|
context.become(initialized)
|
|
|
|
|
case _ ⇒ stash()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
implicit def timeout: Timeout
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
def asyncWriteMessages(messages: immutable.Seq[PersistentRepr]): Future[Unit] =
|
|
|
|
|
(store ? WriteMessages(messages)).mapTo[Unit]
|
2013-11-25 12:02:29 +01:00
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
def asyncWriteConfirmations(confirmations: immutable.Seq[PersistentConfirmation]): Future[Unit] =
|
|
|
|
|
(store ? WriteConfirmations(confirmations)).mapTo[Unit]
|
2013-11-25 12:02:29 +01:00
|
|
|
|
2014-06-27 11:51:58 +02:00
|
|
|
def asyncDeleteMessages(messageIds: immutable.Seq[PersistentId], permanent: Boolean): Future[Unit] =
|
2014-01-17 06:58:25 +01:00
|
|
|
(store ? DeleteMessages(messageIds, permanent)).mapTo[Unit]
|
2013-11-25 12:02:29 +01:00
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
def asyncDeleteMessagesTo(persistenceId: String, toSequenceNr: Long, permanent: Boolean): Future[Unit] =
|
|
|
|
|
(store ? DeleteMessagesTo(persistenceId, toSequenceNr, permanent)).mapTo[Unit]
|
2014-01-17 06:58:25 +01:00
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
def asyncReplayMessages(persistenceId: String, fromSequenceNr: Long, toSequenceNr: Long, max: Long)(replayCallback: (PersistentRepr) ⇒ Unit): Future[Unit] = {
|
2014-01-17 06:58:25 +01:00
|
|
|
val replayCompletionPromise = Promise[Unit]
|
2013-11-25 12:02:29 +01:00
|
|
|
val mediator = context.actorOf(Props(classOf[ReplayMediator], replayCallback, replayCompletionPromise, timeout.duration).withDeploy(Deploy.local))
|
2014-06-23 14:33:35 +02:00
|
|
|
store.tell(ReplayMessages(persistenceId, fromSequenceNr, toSequenceNr, max), mediator)
|
2013-11-25 12:02:29 +01:00
|
|
|
replayCompletionPromise.future
|
|
|
|
|
}
|
2014-01-17 06:58:25 +01:00
|
|
|
|
2014-06-23 14:33:35 +02:00
|
|
|
def asyncReadHighestSequenceNr(persistenceId: String, fromSequenceNr: Long): Future[Long] =
|
|
|
|
|
(store ? ReadHighestSequenceNr(persistenceId, fromSequenceNr)).mapTo[Long]
|
2013-11-25 12:02:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*/
|
|
|
|
|
private[persistence] object AsyncWriteProxy {
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class SetStore(ref: ActorRef)
|
2013-11-25 12:02:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* INTERNAL API.
|
|
|
|
|
*/
|
|
|
|
|
private[persistence] object AsyncWriteTarget {
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class WriteMessages(messages: immutable.Seq[PersistentRepr])
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class WriteConfirmations(confirmations: immutable.Seq[PersistentConfirmation])
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-06-27 11:51:58 +02:00
|
|
|
final case class DeleteMessages(messageIds: immutable.Seq[PersistentId], permanent: Boolean)
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-06-23 14:33:35 +02:00
|
|
|
final case class DeleteMessagesTo(persistenceId: String, toSequenceNr: Long, permanent: Boolean)
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-06-23 14:33:35 +02:00
|
|
|
final case class ReplayMessages(persistenceId: String, fromSequenceNr: Long, toSequenceNr: Long, max: Long)
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-01-17 06:58:25 +01:00
|
|
|
case object ReplaySuccess
|
2013-11-25 12:02:29 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class ReplayFailure(cause: Throwable)
|
2014-01-17 06:58:25 +01:00
|
|
|
|
|
|
|
|
@SerialVersionUID(1L)
|
2014-06-23 14:33:35 +02:00
|
|
|
final case class ReadHighestSequenceNr(persistenceId: String, fromSequenceNr: Long)
|
2013-11-25 12:02:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Thrown if replay inactivity exceeds a specified timeout.
|
|
|
|
|
*/
|
|
|
|
|
@SerialVersionUID(1L)
|
|
|
|
|
class AsyncReplayTimeoutException(msg: String) extends AkkaException(msg)
|
|
|
|
|
|
2014-01-17 06:58:25 +01:00
|
|
|
private class ReplayMediator(replayCallback: PersistentRepr ⇒ Unit, replayCompletionPromise: Promise[Unit], replayTimeout: Duration) extends Actor {
|
2013-11-25 12:02:29 +01:00
|
|
|
import AsyncWriteTarget._
|
|
|
|
|
|
|
|
|
|
context.setReceiveTimeout(replayTimeout)
|
|
|
|
|
|
|
|
|
|
def receive = {
|
|
|
|
|
case p: PersistentRepr ⇒ replayCallback(p)
|
2014-01-17 06:58:25 +01:00
|
|
|
case ReplaySuccess ⇒
|
|
|
|
|
replayCompletionPromise.success(())
|
2013-11-25 12:02:29 +01:00
|
|
|
context.stop(self)
|
|
|
|
|
case ReplayFailure(cause) ⇒
|
|
|
|
|
replayCompletionPromise.failure(cause)
|
|
|
|
|
context.stop(self)
|
|
|
|
|
case ReceiveTimeout ⇒
|
|
|
|
|
replayCompletionPromise.failure(new AsyncReplayTimeoutException(s"replay timed out after ${replayTimeout.toSeconds} seconds inactivity"))
|
|
|
|
|
context.stop(self)
|
|
|
|
|
}
|
|
|
|
|
}
|