make pruning of CRDT garbage work, #21647
* fix merge issues of DataEnvelope and its pruning * simplify by removing the tombstones, which didn't work in all cases anyway * keep the PruningPerformed markers in the DataEnvelope until configured TTL has elapsed (wall clock) * simplify PruningState structure * also store the pruning markers in durable data * collect removed nodes from the data, listing on MemberRemoved is not enough * possibility to disable pruning altogether * documented caveat for durable data
This commit is contained in:
parent
c5d18c30d6
commit
952be31a7d
28 changed files with 951 additions and 229 deletions
|
|
@ -11,36 +11,37 @@ import akka.cluster.UniqueAddress
|
|||
* INTERNAL API
|
||||
*/
|
||||
private[akka] object PruningState {
|
||||
sealed trait PruningPhase
|
||||
final case class PruningInitialized(seen: Set[Address]) extends PruningPhase
|
||||
case object PruningPerformed extends PruningPhase
|
||||
final case class PruningInitialized(owner: UniqueAddress, seen: Set[Address]) extends PruningState {
|
||||
override def addSeen(node: Address): PruningState = {
|
||||
if (seen(node) || owner.address == node) this
|
||||
else copy(seen = seen + node)
|
||||
}
|
||||
}
|
||||
final case class PruningPerformed(obsoleteTime: Long) extends PruningState {
|
||||
def isObsolete(currentTime: Long): Boolean = obsoleteTime <= currentTime
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
private[akka] final case class PruningState(owner: UniqueAddress, phase: PruningState.PruningPhase) {
|
||||
private[akka] sealed trait PruningState {
|
||||
import PruningState._
|
||||
|
||||
def merge(that: PruningState): PruningState =
|
||||
(this.phase, that.phase) match {
|
||||
// FIXME this will add the PruningPerformed back again when one is None
|
||||
case (PruningPerformed, _) ⇒ this
|
||||
case (_, PruningPerformed) ⇒ that
|
||||
case (PruningInitialized(thisSeen), PruningInitialized(thatSeen)) ⇒
|
||||
if (this.owner == that.owner)
|
||||
copy(phase = PruningInitialized(thisSeen union thatSeen))
|
||||
else if (Member.addressOrdering.compare(this.owner.address, that.owner.address) > 0)
|
||||
(this, that) match {
|
||||
case (p1: PruningPerformed, p2: PruningPerformed) ⇒ if (p1.obsoleteTime >= p2.obsoleteTime) this else that
|
||||
case (_: PruningPerformed, _) ⇒ this
|
||||
case (_, _: PruningPerformed) ⇒ that
|
||||
case (PruningInitialized(thisOwner, thisSeen), PruningInitialized(thatOwner, thatSeen)) ⇒
|
||||
if (thisOwner == thatOwner)
|
||||
PruningInitialized(thisOwner, thisSeen union thatSeen)
|
||||
else if (Member.addressOrdering.compare(thisOwner.address, thatOwner.address) > 0)
|
||||
that
|
||||
else
|
||||
this
|
||||
}
|
||||
|
||||
def addSeen(node: Address): PruningState = phase match {
|
||||
case PruningInitialized(seen) ⇒
|
||||
if (seen(node) || owner.address == node) this
|
||||
else copy(phase = PruningInitialized(seen + node))
|
||||
case _ ⇒ this
|
||||
}
|
||||
def addSeen(node: Address): PruningState = this
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue