Prune version clocks based on merged tombstones when merging #23318

This commit is contained in:
Johan Andrén 2017-07-11 16:29:32 +01:00 committed by GitHub
parent a15e459922
commit be5a0207bb
2 changed files with 43 additions and 6 deletions

View file

@ -154,10 +154,9 @@ private[cluster] final case class Gossip(
// 1. merge sets of tombstones
val mergedTombstones = tombstones ++ that.tombstones
val newTombstonedNodes = mergedTombstones.keySet diff that.tombstones.keySet
// 2. merge vector clocks (but remove entries for tombstoned nodes)
val mergedVClock = newTombstonedNodes.foldLeft(this.version merge that.version) { (vclock, node)
val mergedVClock = mergedTombstones.keys.foldLeft(this.version merge that.version) { (vclock, node)
vclock.prune(VectorClock.Node(Gossip.vclockName(node)))
}

View file

@ -339,16 +339,25 @@ class GossipSpec extends WordSpec with Matchers {
// TODO test coverage for when leaderOf returns None - I have not been able to figure it out
"clear out a bunch of stuff when removing a node" in {
val g = Gossip(members = SortedSet(dc1a1, dc1b1, dc2d2))
val g = Gossip(
members = SortedSet(dc1a1, dc1b1, dc2d2),
overview = GossipOverview(reachability =
Reachability.empty
.unreachable(dc1b1.uniqueAddress, dc2d2.uniqueAddress)
.unreachable(dc2d2.uniqueAddress, dc1b1.uniqueAddress)
))
.:+(VectorClock.Node(Gossip.vclockName(dc1b1.uniqueAddress)))
.:+(VectorClock.Node(Gossip.vclockName(dc2d2.uniqueAddress)))
.remove(dc1b1.uniqueAddress, System.currentTimeMillis())
g.seenBy should not contain (dc1b1.uniqueAddress)
g.overview.reachability.records.exists(_.observer == dc1b1.uniqueAddress) should be(false)
g.overview.reachability.records.exists(_.subject == dc1b1.uniqueAddress) should be(false)
g.version.versions should have size (0)
g.overview.reachability.records.map(_.observer) should not contain (dc1b1.uniqueAddress)
g.overview.reachability.records.map(_.subject) should not contain (dc1b1.uniqueAddress)
// sort order should be kept
g.members.toList should ===(List(dc1a1, dc2d2))
g.version.versions.keySet should not contain (VectorClock.Node(Gossip.vclockName(dc1b1.uniqueAddress)))
g.version.versions.keySet should contain(VectorClock.Node(Gossip.vclockName(dc2d2.uniqueAddress)))
}
"not reintroduce members from out-of data center gossip when merging" in {
@ -379,6 +388,35 @@ class GossipSpec extends WordSpec with Matchers {
merged1.version.versions.keys should not contain (VectorClock.Node(vclockName(dc2d1.uniqueAddress)))
}
"correctly prune vector clocks based on tombstones when merging" in {
val gdc1 = Gossip(members = SortedSet(dc1a1, dc1b1, dc2c1, dc2d1))
.:+(VectorClock.Node(vclockName(dc1a1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc1b1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc2c1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc2d1.uniqueAddress)))
.remove(dc1b1.uniqueAddress, System.currentTimeMillis())
gdc1.version.versions.keySet should not contain (VectorClock.Node(vclockName(dc1b1.uniqueAddress)))
val gdc2 = Gossip(members = SortedSet(dc1a1, dc1b1, dc2c1, dc2d1))
.seen(dc1a1.uniqueAddress)
.:+(VectorClock.Node(vclockName(dc1a1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc1b1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc2c1.uniqueAddress)))
.:+(VectorClock.Node(vclockName(dc2d1.uniqueAddress)))
.remove(dc2c1.uniqueAddress, System.currentTimeMillis())
gdc2.version.versions.keySet should not contain (VectorClock.Node(vclockName(dc2c1.uniqueAddress)))
// when we merge the two, the nodes should not be reintroduced
val merged1 = gdc2 merge gdc1
merged1.members should ===(SortedSet(dc1a1, dc2d1))
merged1.version.versions.keySet should ===(Set(
VectorClock.Node(vclockName(dc1a1.uniqueAddress)),
VectorClock.Node(vclockName(dc2d1.uniqueAddress))))
}
"prune old tombstones" in {
val timestamp = 352684800
val g = Gossip(members = SortedSet(dc1a1, dc1b1))