Add minimum cap for ReadMajority/WriteMajority #21618

This commit is contained in:
inakov 2017-01-18 14:13:40 +02:00
parent 91d6a3f125
commit e043a9fffe
4 changed files with 56 additions and 7 deletions

View file

@ -193,6 +193,8 @@ object Replicator {
Props(new Replicator(settings)).withDeploy(Deploy.local).withDispatcher(settings.dispatcher)
}
val DefaultMajorityMinCap: Int = 0
sealed trait ReadConsistency {
def timeout: FiniteDuration
}
@ -202,7 +204,9 @@ object Replicator {
final case class ReadFrom(n: Int, timeout: FiniteDuration) extends ReadConsistency {
require(n >= 2, "ReadFrom n must be >= 2, use ReadLocal for n=1")
}
final case class ReadMajority(timeout: FiniteDuration) extends ReadConsistency
final case class ReadMajority(timeout: FiniteDuration, minCap: Int = DefaultMajorityMinCap) extends ReadConsistency {
def this(timeout: FiniteDuration) = this(timeout, DefaultMajorityMinCap)
}
final case class ReadAll(timeout: FiniteDuration) extends ReadConsistency
sealed trait WriteConsistency {
@ -214,7 +218,9 @@ object Replicator {
final case class WriteTo(n: Int, timeout: FiniteDuration) extends WriteConsistency {
require(n >= 2, "WriteTo n must be >= 2, use WriteLocal for n=1")
}
final case class WriteMajority(timeout: FiniteDuration) extends WriteConsistency
final case class WriteMajority(timeout: FiniteDuration, minCap: Int = DefaultMajorityMinCap) extends WriteConsistency {
def this(timeout: FiniteDuration) = this(timeout, DefaultMajorityMinCap)
}
final case class WriteAll(timeout: FiniteDuration) extends WriteConsistency
/**
@ -1489,6 +1495,16 @@ final class Replicator(settings: ReplicatorSettings) extends Actor with ActorLog
private[akka] object ReadWriteAggregator {
case object SendToSecondary
val MaxSecondaryNodes = 10
def calculateMajorityWithMinCap(minCap: Int, numberOfNodes: Int): Int = {
if (numberOfNodes <= minCap) {
numberOfNodes
} else {
val majority = numberOfNodes / 2 + 1
if (majority <= minCap) minCap
else majority
}
}
}
/**
@ -1571,9 +1587,9 @@ private[akka] class WriteAggregator(
override val doneWhenRemainingSize = consistency match {
case WriteTo(n, _) nodes.size - (n - 1)
case _: WriteAll 0
case _: WriteMajority
case WriteMajority(_, minCap)
val N = nodes.size + 1
val w = N / 2 + 1 // write to at least (N/2+1) nodes
val w = calculateMajorityWithMinCap(minCap, N)
N - w
case WriteLocal
throw new IllegalArgumentException("WriteLocal not supported by WriteAggregator")
@ -1678,9 +1694,9 @@ private[akka] class ReadAggregator(
override val doneWhenRemainingSize = consistency match {
case ReadFrom(n, _) nodes.size - (n - 1)
case _: ReadAll 0
case _: ReadMajority
case ReadMajority(_, minCap)
val N = nodes.size + 1
val r = N / 2 + 1 // read from at least (N/2+1) nodes
val r = calculateMajorityWithMinCap(minCap, N)
N - r
case ReadLocal
throw new IllegalArgumentException("ReadLocal not supported by ReadAggregator")

View file

@ -162,6 +162,23 @@ class WriteAggregatorSpec extends AkkaSpec(s"""
watch(aggr)
expectTerminated(aggr)
}
"calculate majority with minCap" in {
val minCap = 5
import ReadWriteAggregator._
calculateMajorityWithMinCap(minCap, 3) should be (3)
calculateMajorityWithMinCap(minCap, 4) should be (4)
calculateMajorityWithMinCap(minCap, 5) should be (5)
calculateMajorityWithMinCap(minCap, 6) should be (5)
calculateMajorityWithMinCap(minCap, 7) should be (5)
calculateMajorityWithMinCap(minCap, 8) should be (5)
calculateMajorityWithMinCap(minCap, 9) should be (5)
calculateMajorityWithMinCap(minCap, 10) should be (6)
calculateMajorityWithMinCap(minCap, 11) should be (6)
calculateMajorityWithMinCap(minCap, 12) should be (7)
}
}
"Durable WriteAggregator" must {