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

com.evolutiongaming.kafka.journal.HeadInfo.scala Maven / Gradle / Ivy

The newest version!
package com.evolutiongaming.kafka.journal

import cats.syntax.all._
import cats.{Foldable, Semigroup}
import com.evolutiongaming.skafka.Offset


sealed abstract class HeadInfo extends Product

object HeadInfo {

  def empty: HeadInfo = Empty

  def delete(deleteTo: DeleteTo): HeadInfo = Delete(deleteTo)

  def append(seqNr: SeqNr, deleteTo: Option[DeleteTo], offset: Offset): HeadInfo = {
    Append(offset, seqNr, deleteTo)
  }

  def apply[F[_] : Foldable](actions: F[(ActionHeader, Offset)]): HeadInfo = {
    actions.foldLeft(empty) { case (head, (header, offset)) => head(header, offset) }
  }


  final case object Empty extends HeadInfo


  abstract sealed class NonEmpty extends HeadInfo

  object NonEmpty {

    implicit val semigroupNonEmpty: Semigroup[NonEmpty] = {
      (a: NonEmpty, b: NonEmpty) => {

        def onDelete(a: Append, b: Delete) = {
          val deleteTo = a.deleteTo.fold(b.deleteTo) { _ max b.deleteTo }
          Append(a.offset, a.seqNr, deleteTo.some)
        }

        (a, b) match {
          case (a: Append, b: Append) => Append(a.offset min b.offset, a.seqNr max b.seqNr, a.deleteTo max b.deleteTo)
          case (a: Append, b: Delete) => onDelete(a, b)
          case (_: Append, Purge)     => Purge
          case (a: Delete, b: Append) => onDelete(b, a)
          case (a: Delete, b: Delete) => Delete(a.deleteTo max b.deleteTo)
          case (_: Delete, Purge)     => Purge
          case (Purge, b: Append)     => b
          case (Purge, b: Delete)     => b
          case (Purge, Purge)         => Purge
        }
      }
    }
  }


  final case class Append(
    offset: Offset,
    seqNr: SeqNr,
    deleteTo: Option[DeleteTo]
  ) extends NonEmpty


  final case class Delete(
    deleteTo: DeleteTo
  ) extends NonEmpty


  final case object Purge extends NonEmpty


  implicit class HeadInfoOps(val self: HeadInfo) extends AnyVal {

    def delete(to: DeleteTo): HeadInfo = {

      def onAppend(self: Append) = {
        val deleteTo = self
          .deleteTo
          .fold(to) { _ max to }
          .min(self.seqNr.toDeleteTo)
        self.copy(seqNr = self.seqNr, deleteTo = deleteTo.some)
      }

      def delete = Delete(to)

      self match {
        case a: Append => onAppend(a)
        case a: Delete => Delete(a.deleteTo max to)
        case Empty     => delete
        case Purge     => delete
      }
    }


    def append(range: SeqRange, offset: Offset): HeadInfo = {

      def deleteToOf(deleteTo: DeleteTo) = range
        .from
        .prev[Option]
        .map { _.toDeleteTo min deleteTo }

      def append = Append(offset, range.to, none)

      self match {
        case a: Append => a.copy(seqNr = range.to)
        case a: Delete => Append(offset, range.to, deleteToOf(a.deleteTo))
        case Empty     => append
        case Purge     => append
      }
    }


    def mark: HeadInfo = self


    def purge: HeadInfo = Purge


    def apply(header: ActionHeader, offset: Offset): HeadInfo = {
      header match {
        case a: ActionHeader.Append => append(a.range, offset)
        case _: ActionHeader.Mark   => mark
        case a: ActionHeader.Delete => delete(a.to)
        case _: ActionHeader.Purge  => purge
      }
    }
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy