@@ -63,7 +63,7 @@ func (v *Versions) Marshal() ([]byte, error) {
63
63
64
64
// Merge merges two versions. This is used when CASing or merging versions from other nodes.
65
65
// v is the local version and should be mutated to include the changes from incoming.
66
- // The returned value is the change to broadcast, in our case they are similar .
66
+ // The returned value is the change to broadcast.
67
67
func (v * Versions ) Merge (incoming memberlist.Mergeable , localCAS bool ) (memberlist.Mergeable , error ) {
68
68
if incoming == nil {
69
69
return nil , nil
@@ -87,39 +87,41 @@ func (v *Versions) Merge(incoming memberlist.Mergeable, localCAS bool) (memberli
87
87
if v .Instances == nil {
88
88
v .Instances = make (map [string ]* versionv1.InstanceVersion )
89
89
}
90
- change := false
91
- // Delete all the instances that are not in the other.
92
- missing := []string {}
93
- for k := range v .Instances {
94
- if _ , ok := other .Instances [k ]; ! ok {
95
- missing = append (missing , k )
96
- }
97
- }
98
- for _ , k := range missing {
99
- change = true
100
- delete (v .Instances , k )
101
- }
90
+ var updated []string
102
91
103
92
// Copy over all the instances with newer timestamps.
104
93
for k , new := range other .Instances {
105
94
current , ok := v .Instances [k ]
106
- if ! ok {
95
+ if ! ok || new . Timestamp > current . Timestamp {
107
96
v .Instances [k ] = new .CloneVT ()
108
- change = true
109
- continue
110
- }
111
- if current .EqualVT (new ) {
112
- continue
113
- }
114
- if new .Timestamp > current .Timestamp {
97
+ updated = append (updated , k )
98
+ } else if new .Timestamp == current .Timestamp && ! current .Left && new .Left {
115
99
v .Instances [k ] = new .CloneVT ()
116
- change = true
100
+ updated = append ( updated , k )
117
101
}
102
+
118
103
}
119
- if ! change {
104
+
105
+ if localCAS {
106
+ // Mark left all the instances that are not in the other.
107
+ for k , current := range v .Instances {
108
+ if _ , ok := other .Instances [k ]; ! ok && ! current .Left {
109
+ current .Left = true
110
+ current .Timestamp = time .Now ().UnixNano ()
111
+ updated = append (updated , k )
112
+ }
113
+ }
114
+ }
115
+ // No updated members, no need to broadcast.
116
+ if len (updated ) == 0 {
120
117
return nil , nil
121
118
}
122
- return v , nil
119
+ // Return the changes to broadcast.
120
+ changes := newVersions ().(* Versions )
121
+ for _ , k := range updated {
122
+ changes .Instances [k ] = v .Instances [k ].CloneVT ()
123
+ }
124
+ return changes , nil
123
125
}
124
126
125
127
// MergeContent describes content of this Mergeable.
@@ -133,14 +135,25 @@ func (d *Versions) MergeContent() []string {
133
135
}
134
136
135
137
// RemoveTombstones is not required for version keys.
136
- func (c * Versions ) RemoveTombstones (limit time.Time ) (total , removed int ) {
137
- return 0 , 0
138
+ func (v * Versions ) RemoveTombstones (limit time.Time ) (total , removed int ) {
139
+ for n , inst := range v .Instances {
140
+ if inst .Left {
141
+ if limit .IsZero () || time .Unix (inst .Timestamp , 0 ).Before (limit ) {
142
+ // remove it
143
+ delete (v .Instances , n )
144
+ removed ++
145
+ } else {
146
+ total ++
147
+ }
148
+ }
149
+ }
150
+ return
138
151
}
139
152
140
153
// Implements memberlist.Mergeable.
141
- func (c * Versions ) Clone () memberlist.Mergeable {
154
+ func (v * Versions ) Clone () memberlist.Mergeable {
142
155
return & Versions {
143
- Versions : c .CloneVT (),
156
+ Versions : v .CloneVT (),
144
157
}
145
158
}
146
159
0 commit comments