// updates the member list with the slice of changes, applying selectively func (m *memberlist) Update(changes []Change) (applied []Change) { if m.node.Stopped() || len(changes) == 0 { return nil } m.node.emit(MemberlistChangesReceivedEvent{changes}) m.members.Lock() for _, change := range changes { member, ok := m.members.byAddress[change.Address] // first time member has been seen, take change wholesale if !ok { m.Apply(change) applied = append(applied, change) continue } // if change is local override, reassert member is alive if member.localOverride(m.node.Address(), change) { m.node.emit(RefuteUpdateEvent{}) overrideChange := Change{ Source: change.Source, SourceIncarnation: change.SourceIncarnation, Address: change.Address, Incarnation: nowInMillis(m.node.clock), Status: Alive, Timestamp: util.Timestamp(time.Now()), } m.Apply(overrideChange) applied = append(applied, overrideChange) continue } // if non-local override, apply change wholesale if member.nonLocalOverride(change) { m.Apply(change) applied = append(applied, change) } } m.members.Unlock() if len(applied) > 0 { oldChecksum := m.Checksum() m.ComputeChecksum() m.node.emit(MemberlistChangesAppliedEvent{ Changes: applied, OldChecksum: oldChecksum, NewChecksum: m.Checksum(), NumMembers: m.NumMembers(), }) m.node.handleChanges(applied) m.node.rollup.TrackUpdates(applied) } return applied }
func (r *updateRollup) AddUpdates(changes []Change) { r.buffer.Lock() timestamp := time.Now() for _, change := range changes { change.Timestamp = util.Timestamp(timestamp) r.buffer.updates[change.Address] = append(r.buffer.updates[change.Address], change) } r.buffer.Unlock() }
// makes a change to the member list func (m *memberlist) MakeChange(address string, incarnation int64, status string) []Change { if m.local == nil { m.local = &Member{ Address: m.node.Address(), Incarnation: util.TimeNowMS(), Status: Alive, } } return m.Update([]Change{Change{ Source: m.local.Address, SourceIncarnation: m.local.Incarnation, Address: address, Incarnation: incarnation, Status: status, Timestamp: util.Timestamp(time.Now()), }}) }
"github.com/gl-works/ringpop-go/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/uber/tchannel-go" ) var testNow = time.Now() var testInc = util.TimeNowMS() var testSuspect = Change{ Address: "127.0.0.1:3002", Incarnation: testInc, Source: "127.0.0.1:3001", SourceIncarnation: testInc, Status: Suspect, Timestamp: util.Timestamp(testNow), } type dummyIter struct{} func (dummyIter) Next() (*Member, bool) { return &Member{ Address: "127.0.0.1:3010", Status: Alive, Incarnation: testInc, }, true } type testNode struct { node *Node channel *tchannel.Channel