pekko/akka-distributed-data/src/test/scala/akka/cluster/ddata/DeltaPropagationSelectorSpec.scala

242 lines
9.6 KiB
Scala
Raw Normal View History

/*
2021-01-08 17:55:38 +01:00
* Copyright (C) 2017-2021 Lightbend Inc. <https://www.lightbend.com>
*/
package akka.cluster.ddata
import org.scalactic.TypeCheckedTripleEquals
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import akka.actor.Address
import akka.cluster.UniqueAddress
import akka.cluster.ddata.Key.KeyId
import akka.cluster.ddata.Replicator.Internal.DataEnvelope
import akka.cluster.ddata.Replicator.Internal.Delta
import akka.cluster.ddata.Replicator.Internal.DeltaPropagation
import akka.cluster.ddata.Replicator.Internal.DeltaPropagation.NoDeltaPlaceholder
object DeltaPropagationSelectorSpec {
class TestSelector(val selfUniqueAddress: UniqueAddress, override val allNodes: Vector[UniqueAddress])
2019-03-11 10:38:24 +01:00
extends DeltaPropagationSelector {
override val gossipIntervalDivisor = 5
override def createDeltaPropagation(deltas: Map[KeyId, (ReplicatedData, Long, Long)]): DeltaPropagation =
Various scala-2.13.0-M5 fixes fix akka-actor-tests compile errors some tests still fail though Fix test failures in akka-actor-test Manually work arround missing implicit Factory[Nothing, Seq[Nothing]] see https://github.com/scala/scala-collection-compat/issues/137 akka-remote scalafix changes Fix shutdownAll compile error test:akka-remote scalafix changes akka-multi-node-testkit scalafix Fix akka-remote-tests multi-jvm compile errors akka-stream-tests/test:scalafix Fix test:akka-stream-tests Crude implementation of ByteString.map scalafix akka-actor-typed, akka-actor-typed-tests akka-actor-typed-tests compile and succeed scalafix akka-camel scalafix akka-cluster akka-cluster compile & test scalafix akka-cluster-metrics Fix akka-cluster-metrics scalafix akka-cluster-tools akka-cluster-tools compile and test scalafix akka-distributed-data akka-distributed-data fixes scalafix akka-persistence scalafix akka-cluster-sharding fix akka-cluster-sharding scalafix akka-contrib Fix akka-cluster-sharding-typed test scalafix akka-docs Use scala-stm 0.9 (released for M5) akka-docs Remove dependency on collections-compat Cherry-pick the relevant constructs to our own private utils Shorten 'scala.collections.immutable' by importing it Duplicate 'immutable' imports Use 'foreach' on futures Replace MapLike with regular Map Internal API markers Simplify ccompat by moving PackageShared into object Since we don't currently need to differentiate between 2.11 and Avoid relying on 'union' (and ++) being left-biased Fix akka-actor/doc by removing -Ywarn-unused Make more things more private Copyright headers Use 'unsorted' to go from SortedSet to Set Duplicate import Use onComplete rather than failed.foreach Clarify why we partly duplicate scala-collection-compat
2018-11-22 16:18:10 +01:00
DeltaPropagation(selfUniqueAddress, false, deltas.map {
case (key, (d, fromSeqNr, toSeqNr)) => (key, Delta(DataEnvelope(d), fromSeqNr, toSeqNr))
})
override def maxDeltaSize: Int = 10
}
val deltaA = GSet.empty[String] + "a"
val deltaB = GSet.empty[String] + "b"
val deltaC = GSet.empty[String] + "c"
}
2020-01-11 15:14:21 +03:00
class DeltaPropagationSelectorSpec extends AnyWordSpec with Matchers with TypeCheckedTripleEquals {
import DeltaPropagationSelectorSpec._
val selfUniqueAddress = UniqueAddress(Address("akka", "Sys", "localhost", 4999), 17L)
val nodes = (2500 until 2600).map(n => UniqueAddress(Address("akka", "Sys", "localhost", n), 17L)).toVector
"DeltaPropagationSelector" must {
"collect none when no nodes" in {
val selector = new TestSelector(selfUniqueAddress, Vector.empty)
selector.update("A", deltaA)
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(false)
}
"collect 1 when one node" in {
val selector = new TestSelector(selfUniqueAddress, nodes.take(1))
selector.update("A", deltaA)
selector.update("B", deltaB)
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(true)
selector.hasDeltaEntries("B") should ===(true)
2019-03-11 10:38:24 +01:00
val expected =
2019-03-13 10:56:20 +01:00
DeltaPropagation(
selfUniqueAddress,
false,
2019-04-15 17:40:26 +02:00
Map("A" -> Delta(DataEnvelope(deltaA), 1L, 1L), "B" -> Delta(DataEnvelope(deltaB), 1L, 1L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected))
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(false)
selector.hasDeltaEntries("B") should ===(false)
}
"collect 2+1 when three nodes" in {
val selector = new TestSelector(selfUniqueAddress, nodes.take(3))
selector.update("A", deltaA)
selector.update("B", deltaB)
2019-03-11 10:38:24 +01:00
val expected =
2019-03-13 10:56:20 +01:00
DeltaPropagation(
selfUniqueAddress,
false,
2019-04-15 17:40:26 +02:00
Map("A" -> Delta(DataEnvelope(deltaA), 1L, 1L), "B" -> Delta(DataEnvelope(deltaB), 1L, 1L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected, nodes(1) -> expected))
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(true)
selector.hasDeltaEntries("B") should ===(true)
selector.collectPropagations() should ===(Map(nodes(2) -> expected))
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(false)
selector.hasDeltaEntries("B") should ===(false)
}
"keep track of deltas per node" in {
val selector = new TestSelector(selfUniqueAddress, nodes.take(3))
selector.update("A", deltaA)
selector.update("B", deltaB)
2019-03-11 10:38:24 +01:00
val expected1 =
2019-03-13 10:56:20 +01:00
DeltaPropagation(
selfUniqueAddress,
false,
2019-04-15 17:40:26 +02:00
Map("A" -> Delta(DataEnvelope(deltaA), 1L, 1L), "B" -> Delta(DataEnvelope(deltaB), 1L, 1L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected1, nodes(1) -> expected1))
// new update before previous was propagated to all nodes
selector.update("C", deltaC)
2019-03-13 10:56:20 +01:00
val expected2 = DeltaPropagation(
selfUniqueAddress,
false,
Map(
"A" -> Delta(DataEnvelope(deltaA), 1L, 1L),
"B" -> Delta(DataEnvelope(deltaB), 1L, 1L),
"C" -> Delta(DataEnvelope(deltaC), 1L, 1L)))
val expected3 =
DeltaPropagation(selfUniqueAddress, false, Map("C" -> Delta(DataEnvelope(deltaC), 1L, 1L)))
2019-04-15 17:40:26 +02:00
selector.collectPropagations() should ===(Map(nodes(2) -> expected2, nodes(0) -> expected3))
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("A") should ===(false)
selector.hasDeltaEntries("B") should ===(false)
selector.hasDeltaEntries("C") should ===(true)
selector.collectPropagations() should ===(Map(nodes(1) -> expected3))
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
selector.cleanupDeltaEntries()
selector.hasDeltaEntries("C") should ===(false)
}
"bump version for each update" in {
val delta1 = GSet.empty[String] + "a1"
val delta2 = GSet.empty[String] + "a2"
val delta3 = GSet.empty[String] + "a3"
val selector = new TestSelector(selfUniqueAddress, nodes.take(1))
selector.update("A", delta1)
selector.currentVersion("A") should ===(1L)
selector.update("A", delta2)
selector.currentVersion("A") should ===(2L)
2019-03-11 10:38:24 +01:00
val expected1 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta1.merge(delta2)), 1L, 2L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected1))
selector.update("A", delta3)
selector.currentVersion("A") should ===(3L)
val expected2 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta3), 3L, 3L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected2))
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
}
"merge deltas" in {
val delta1 = GSet.empty[String] + "a1"
val delta2 = GSet.empty[String] + "a2"
val delta3 = GSet.empty[String] + "a3"
val selector = new TestSelector(selfUniqueAddress, nodes.take(3)) {
override def nodesSliceSize(allNodesSize: Int): Int = 1
}
selector.update("A", delta1)
val expected1 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta1), 1L, 1L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected1))
selector.update("A", delta2)
2019-03-11 10:38:24 +01:00
val expected2 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta1.merge(delta2)), 1L, 2L)))
selector.collectPropagations() should ===(Map(nodes(1) -> expected2))
selector.update("A", delta3)
2019-03-13 10:56:20 +01:00
val expected3 = DeltaPropagation(
selfUniqueAddress,
false,
Map("A" -> Delta(DataEnvelope(delta1.merge(delta2).merge(delta3)), 1L, 3L)))
selector.collectPropagations() should ===(Map(nodes(2) -> expected3))
2019-03-11 10:38:24 +01:00
val expected4 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta2.merge(delta3)), 2L, 3L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected4))
val expected5 =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(delta3), 3L, 3L)))
selector.collectPropagations() should ===(Map(nodes(1) -> expected5))
selector.collectPropagations() should ===(Map.empty[UniqueAddress, DeltaPropagation])
}
"discard too large deltas" in {
val selector = new TestSelector(selfUniqueAddress, nodes.take(3)) {
override def nodesSliceSize(allNodesSize: Int): Int = 1
}
var data = PNCounterMap.empty[String]
(1 to 1000).foreach { n =>
val d = data.resetDelta.increment(selfUniqueAddress, (n % 2).toString, 1)
selector.update("A", d.delta.get)
data = d
}
2019-03-11 10:38:24 +01:00
val expected =
DeltaPropagation(selfUniqueAddress, false, Map("A" -> Delta(DataEnvelope(NoDeltaPlaceholder), 1L, 1000L)))
selector.collectPropagations() should ===(Map(nodes(0) -> expected))
}
"calculate right slice size" in {
val selector = new TestSelector(selfUniqueAddress, nodes)
selector.nodesSliceSize(0) should ===(0)
selector.nodesSliceSize(1) should ===(1)
(2 to 9).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(2)
}
}
(10 to 14).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(3)
}
}
(15 to 19).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(4)
}
}
(20 to 24).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(5)
}
}
(25 to 29).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(6)
}
}
(30 to 34).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(7)
}
}
(35 to 39).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(8)
}
}
(40 to 44).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(9)
}
}
(45 to 200).foreach { n =>
withClue(s"n=$n") {
selector.nodesSliceSize(n) should ===(10)
}
}
}
}
}