refactor: extract entry merging from ring merging

This commit is contained in:
Matthias Radestock committed 2016-04-17 12:40:34 +01:00
1 parent 27632b118f
commit 4a01d23025
1 file changed
+75 -62
+75 -62
View File
@@ -217,69 +217,10 @@ func (r *Ring) Merge(gossip Ring) (bool, error) {
return false, ErrDifferentRange
}
// Now merge their ring with yours, in a temporary ring.
var result entries
addToResult := func(e entry) { result = append(result, &e) }
var updated bool
result, updated, err := r.Entries.merge(gossip.Entries, r.Peer)
var mine, theirs *entry
var previousOwner *mesh.PeerName
// i is index into r.Entries; j is index into gossip.Entries
var i, j int
for i < len(r.Entries) && j < len(gossip.Entries) {
mine, theirs = r.Entries[i], gossip.Entries[j]
switch {
case mine.Token < theirs.Token:
addToResult(*mine)
previousOwner = &mine.Peer
i++
case mine.Token > theirs.Token:
// insert, checking that a range owned by us hasn't been split
if previousOwner != nil && *previousOwner == r.Peer && theirs.Peer != r.Peer {
return false, errEntryInMyRange(theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
j++
case mine.Token == theirs.Token:
// merge
switch {
case mine.Version >= theirs.Version:
if mine.Version == theirs.Version && !mine.Equal(theirs) {
return false, errInconsistentEntry(mine, theirs)
}
addToResult(*mine)
previousOwner = &mine.Peer
case mine.Version < theirs.Version:
if mine.Peer == r.Peer { // We shouldn't receive updates to our own tokens
return false, errNewerVersion(mine, theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
}
i++
j++
}
}
// At this point, either i is at the end of r or j is at the end
// of gossip, so copy over the remaining entries.
for ; i < len(r.Entries); i++ {
mine = r.Entries[i]
addToResult(*mine)
}
for ; j < len(gossip.Entries); j++ {
theirs = gossip.Entries[j]
if previousOwner != nil && *previousOwner == r.Peer && theirs.Peer != r.Peer {
return false, errEntryInMyRange(theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
if err != nil {
return false, err
}
if err := r.checkEntries(result); err != nil {
@@ -293,6 +234,78 @@ func (r *Ring) Merge(gossip Ring) (bool, error) {
return updated, nil
}
// Merge other entries into ours, and complain when that stomps on
// entries belonging to ourPeer. Returns the merged entries and an
// indication whether the merge resulted in any changes, i.e. the
// result differs from the original.
func (es entries) merge(other entries, ourPeer mesh.PeerName) (entries, bool, error) {
var result entries
addToResult := func(e entry) { result = append(result, &e) }
var updated bool
var mine, theirs *entry
var previousOwner *mesh.PeerName
// i is index into es; j is index into other
var i, j int
for i < len(es) && j < len(other) {
mine, theirs = es[i], other[j]
switch {
case mine.Token < theirs.Token:
addToResult(*mine)
previousOwner = &mine.Peer
i++
case mine.Token > theirs.Token:
// insert, checking that a range owned by us hasn't been split
if previousOwner != nil && *previousOwner == ourPeer && theirs.Peer != ourPeer {
return result, false, errEntryInMyRange(theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
j++
case mine.Token == theirs.Token:
// merge
switch {
case mine.Version >= theirs.Version:
if mine.Version == theirs.Version && !mine.Equal(theirs) {
return result, false, errInconsistentEntry(mine, theirs)
}
addToResult(*mine)
previousOwner = &mine.Peer
case mine.Version < theirs.Version:
if mine.Peer == ourPeer { // We shouldn't receive updates to our own tokens
return result, false, errNewerVersion(mine, theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
}
i++
j++
}
}
// At this point, either i is at the end of es or j is at the end
// of other, so copy over the remaining entries.
for ; i < len(es); i++ {
mine = es[i]
addToResult(*mine)
}
for ; j < len(other); j++ {
theirs = other[j]
if previousOwner != nil && *previousOwner == ourPeer && theirs.Peer != ourPeer {
return result, false, errEntryInMyRange(theirs)
}
addToResult(*theirs)
updated = true
previousOwner = nil
}
return result, updated, nil
}
// Empty returns true if the ring has no entries
func (r *Ring) Empty() bool {
return len(r.Entries) == 0