Skip to content

Commit d289b4c

Browse files
authored
Merge pull request #19730 from ahrtr/3.6_conf_verification_20250408
[release-3.6] add verification to check whether membership data is in sync between …
2 parents 4caf9fb + b4f7075 commit d289b4c

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

server/etcdserver/api/membership/cluster.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,14 @@ func (c *RaftCluster) IsReadyToPromoteMember(id uint64) bool {
767767
return true
768768
}
769769

770+
func (c *RaftCluster) MembersFromBackend() (map[types.ID]*Member, map[types.ID]bool) {
771+
return c.be.MustReadMembersFromBackend()
772+
}
773+
774+
func (c *RaftCluster) MembersFromStore() (map[types.ID]*Member, map[types.ID]bool) {
775+
return membersFromStore(c.lg, c.v2store)
776+
}
777+
770778
func membersFromStore(lg *zap.Logger, st v2store.Store) (map[types.ID]*Member, map[types.ID]bool) {
771779
members := make(map[types.ID]*Member)
772780
removed := make(map[types.ID]bool)

server/etcdserver/server.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"math"
2424
"net/http"
2525
"path"
26+
"reflect"
2627
"regexp"
2728
"strconv"
2829
"sync"
@@ -2133,9 +2134,49 @@ func (s *EtcdServer) applyConfChange(cc raftpb.ConfChange, confState *raftpb.Con
21332134
s.r.transport.UpdatePeer(m.ID, m.PeerURLs)
21342135
}
21352136
}
2137+
2138+
verify.Verify(func() {
2139+
s.verifyV3StoreInSyncWithV2Store(shouldApplyV3)
2140+
})
2141+
21362142
return false, nil
21372143
}
21382144

2145+
func (s *EtcdServer) verifyV3StoreInSyncWithV2Store(shouldApplyV3 membership.ShouldApplyV3) {
2146+
// If shouldApplyV3 == false, then it means v2store hasn't caught up with v3store.
2147+
if !shouldApplyV3 {
2148+
return
2149+
}
2150+
2151+
// clean up the Attributes, and we only care about the RaftAttributes
2152+
cleanAttributesFunc := func(members map[types.ID]*membership.Member) map[types.ID]*membership.Member {
2153+
processedMembers := make(map[types.ID]*membership.Member)
2154+
for id, m := range members {
2155+
clonedMember := m.Clone()
2156+
clonedMember.Attributes = membership.Attributes{}
2157+
processedMembers[id] = clonedMember
2158+
}
2159+
2160+
return processedMembers
2161+
}
2162+
2163+
v2Members, _ := s.cluster.MembersFromStore()
2164+
v3Members, _ := s.cluster.MembersFromBackend()
2165+
2166+
processedV2Members := cleanAttributesFunc(v2Members)
2167+
processedV3Members := cleanAttributesFunc(v3Members)
2168+
2169+
if match := reflect.DeepEqual(processedV2Members, processedV3Members); !match {
2170+
v2Data, v2Err := json.Marshal(processedV2Members)
2171+
v3Data, v3Err := json.Marshal(processedV3Members)
2172+
2173+
if v2Err != nil || v3Err != nil {
2174+
panic("members in v2store doesn't match v3store")
2175+
}
2176+
panic(fmt.Sprintf("members in v2store doesn't match v3store, v2store: %s, v3store: %s", string(v2Data), string(v3Data)))
2177+
}
2178+
}
2179+
21392180
// TODO: non-blocking snapshot
21402181
func (s *EtcdServer) snapshot(ep *etcdProgress, toDisk bool) {
21412182
lg := s.Logger()

0 commit comments

Comments
 (0)