All Downloads are FREE. Search and download functionalities are using the official Maven repository.

endless.transaction.Branch.scala Maven / Gradle / Ivy

The newest version!
package endless.transaction

import endless.transaction.Branch.Vote
import endless.transaction.Transaction.AbortReason

/** A branch defines behavior for the various phases of the 2PC protocol for a certain transaction
  * type. The branch is responsible for preparing, committing and aborting the transaction. The
  * coordinator instantiates a branch for each transaction and branch ID.
  * @tparam F
  *   the effect type
  * @tparam TID
  *   the transaction identifier type
  * @tparam Q
  *   the query type
  * @tparam R
  *   the abort reason type
  */
trait Branch[F[_], TID, Q, R] {

  /** Prepare the branch for a transaction. This is the first step in the 2PC protocol.
    *
    * @note
    *   this operation supports an optional timeout (this is tracked by the coordinator), in which
    *   case the transaction will be aborted. However, there is no intrinsic limitation in the
    *   duration this operation may take. It could span days, as long as it returns a vote at some
    *   point and the coordinator is still alive.
    * @note
    *   this operation is expected to be idempotent, as it may be retried by the coordinator.
    * @note
    *   an exception raised here transitions the transaction to failed state (once all branches *
    *   return).
    * @param id
    *   transaction id
    * @param query
    *   payload relevant for transaction execution
    * @return
    *   vote on whether the transaction should be committed or aborted
    */
  def prepare(id: TID, query: Q): F[Vote[R]]

  /** Commit the transaction branch. This is the second step in the 2PC protocol.
    *
    * @note
    *   this operation should in principle not fail, all branches are expected to commit at this
    *   point to ensure consistency. It's up to the branch to organize retries if necessary.
    * @note
    *   this operation is expected to be idempotent, as it may be retried by the coordinator.
    * @note
    *   an exception raised here transitions the transaction to a failed state (once all branches
    *   return).
    * @note
    *   as for prepare, there is no intrinsic limitation in the duration this operation may take. A
    *   confirmation is expected by the coordinator at some point to transition the transaction to
    *   committed, however.
    * @param id
    *   transaction id
    */
  def commit(id: TID): F[Unit]

  /** Abort the transaction branch. This is the second step in the 2PC protocol, in case of
    * preparation timeout or any branch voting to abort.
    *
    * @note
    *   all branches are expected to abort at this point, failure could lead to local inconsistency.
    *   It's up to the branch to organize retries if necessary.
    * @note
    *   this operation is expected to be idempotent, as it may be retried by the coordinator.
    * @note
    *   an exception raised here transitions the transaction to failed state (once all branches
    *   return).
    * @note
    *   as for prepare, there is no intrinsic limitation in the duration this operation may take. A
    *   confirmation is expected by the coordinator at some point to transition the transaction to
    *   aborted, however.
    * @param id
    *   transaction id
    * @param reason
    *   the reason for the abort
    */
  def abort(id: TID, reason: AbortReason[R]): F[Unit]
}

object Branch {
  def apply[F[_], TID, BID, Q, R](
      prepareF: (TID, Q) => F[Vote[R]],
      commitF: TID => F[Unit],
      abortF: (TID, AbortReason[R]) => F[Unit]
  ): Branch[F, TID, Q, R] =
    new Branch[F, TID, Q, R] {
      def prepare(id: TID, query: Q): F[Vote[R]] = prepareF(id, query)
      def commit(id: TID): F[Unit] = commitF(id)
      def abort(id: TID, reason: AbortReason[R]): F[Unit] = abortF(id, reason)
    }

  /** The vote of a branch in the 2PC protocol.
    * @tparam R
    *   the abort reason type
    */
  sealed trait Vote[+R]
  object Vote {

    /** The branch votes to commit the transaction.
      */
    case object Commit extends Vote[Nothing]

    /** The branch votes to abort the transaction with the specified reason. */
    final case class Abort[R](reason: R) extends Vote[R]
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy