From 3515fc8eb0b7ce06ef97dfbd00dc31f2f5fc815a Mon Sep 17 00:00:00 2001 From: Geeta Gharpure Date: Mon, 14 Aug 2023 23:28:31 +0000 Subject: [PATCH] Update to generate v2 snapshot from v3 state Signed-off-by: Geeta Gharpure --- server/etcdserver/server.go | 10 ++------- server/etcdserver/server_test.go | 31 +++++++++++---------------- server/etcdserver/snapshot_merge.go | 6 +----- tests/e2e/v2store_deprecation_test.go | 29 +++++++++++++++++++------ 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/server/etcdserver/server.go b/server/etcdserver/server.go index 4a2128104c9d..480540279052 100644 --- a/server/etcdserver/server.go +++ b/server/etcdserver/server.go @@ -2067,7 +2067,6 @@ func (s *EtcdServer) applyConfChange(cc raftpb.ConfChange, confState *raftpb.Con // TODO: non-blocking snapshot func (s *EtcdServer) snapshot(snapi uint64, confState raftpb.ConfState) { - clone := s.v2store.Clone() // commit kv to write metadata (for example: consistent index) to disk. // // This guarantees that Backend's consistent_index is >= index of last snapshot. @@ -2082,13 +2081,8 @@ func (s *EtcdServer) snapshot(snapi uint64, confState raftpb.ConfState) { s.GoAttach(func() { lg := s.Logger() - d, err := clone.SaveNoCopy() - // TODO: current store will never fail to do a snapshot - // what should we do if the store might fail? - if err != nil { - lg.Panic("failed to save v2 store", zap.Error(err)) - } - snap, err := s.r.raftStorage.CreateSnapshot(snapi, &confState, d) + // For backward compatibility, generate v2 snapshot from v3 state. + snap, err := s.r.raftStorage.CreateSnapshot(snapi, &confState, GetMembershipInfoInV2Format(lg, s.cluster)) if err != nil { // the snapshot was done asynchronously with the progress of raft. // raft might have already got a newer snapshot. diff --git a/server/etcdserver/server_test.go b/server/etcdserver/server_test.go index 54879285132b..c6f68b97909d 100644 --- a/server/etcdserver/server_test.go +++ b/server/etcdserver/server_test.go @@ -1047,7 +1047,10 @@ func TestSnapshot(t *testing.T) { srv.kv = mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}) srv.be = be - ch := make(chan struct{}, 2) + cl := membership.NewCluster(zaptest.NewLogger(t)) + srv.cluster = cl + + ch := make(chan struct{}, 1) go func() { gaction, _ := p.Wait(2) @@ -1066,24 +1069,11 @@ func TestSnapshot(t *testing.T) { } }() - go func() { - gaction, _ := st.Wait(2) - defer func() { ch <- struct{}{} }() - - if len(gaction) != 2 { - t.Errorf("len(action) = %d, want 2", len(gaction)) - } - if !reflect.DeepEqual(gaction[0], testutil.Action{Name: "Clone"}) { - t.Errorf("action = %s, want Clone", gaction[0]) - } - if !reflect.DeepEqual(gaction[1], testutil.Action{Name: "SaveNoCopy"}) { - t.Errorf("action = %s, want SaveNoCopy", gaction[1]) - } - }() - srv.snapshot(1, raftpb.ConfState{Voters: []uint64{1}}) <-ch - <-ch + if len(st.Action()) != 0 { + t.Errorf("no action expected on v2store. Got %d actions", len(st.Action())) + } } // TestSnapshotOrdering ensures raft persists snapshot onto disk before @@ -1098,7 +1088,8 @@ func TestSnapshotOrdering(t *testing.T) { n := newNopReadyNode() st := v2store.New() cl := membership.NewCluster(lg) - cl.SetStore(st) + be, _ := betesting.NewDefaultTmpBackend(t) + cl.SetBackend(schema.NewMembershipBackend(lg, be)) testdir := t.TempDir() @@ -1118,7 +1109,6 @@ func TestSnapshotOrdering(t *testing.T) { storage: p, raftStorage: rs, }) - be, _ := betesting.NewDefaultTmpBackend(t) ci := cindex.NewConsistentIndex(be) s := &EtcdServer{ lgMu: new(sync.RWMutex), @@ -1211,6 +1201,9 @@ func TestTriggerSnap(t *testing.T) { srv.kv = mvcc.New(zaptest.NewLogger(t), be, &lease.FakeLessor{}, mvcc.StoreConfig{}) srv.be = be + cl := membership.NewCluster(zaptest.NewLogger(t)) + srv.cluster = cl + srv.start() donec := make(chan struct{}) diff --git a/server/etcdserver/snapshot_merge.go b/server/etcdserver/snapshot_merge.go index 963ead5a7e24..5afbc626c184 100644 --- a/server/etcdserver/snapshot_merge.go +++ b/server/etcdserver/snapshot_merge.go @@ -31,11 +31,7 @@ import ( func (s *EtcdServer) createMergedSnapshotMessage(m raftpb.Message, snapt, snapi uint64, confState raftpb.ConfState) snap.Message { lg := s.Logger() // get a snapshot of v2 store as []byte - clone := s.v2store.Clone() - d, err := clone.SaveNoCopy() - if err != nil { - lg.Panic("failed to save v2 store data", zap.Error(err)) - } + d := GetMembershipInfoInV2Format(lg, s.cluster) // commit kv to write metadata(for example: consistent index). s.KV().Commit() diff --git a/tests/e2e/v2store_deprecation_test.go b/tests/e2e/v2store_deprecation_test.go index 432a61b2a841..bf94c58ba14e 100644 --- a/tests/e2e/v2store_deprecation_test.go +++ b/tests/e2e/v2store_deprecation_test.go @@ -18,15 +18,19 @@ import ( "bytes" "context" "fmt" + "reflect" "sort" "strings" "testing" + "github.com/coreos/go-semver/semver" "github.com/stretchr/testify/assert" + "go.uber.org/zap" "go.uber.org/zap/zaptest" "go.etcd.io/etcd/client/pkg/v3/fileutil" "go.etcd.io/etcd/server/v3/etcdserver" + "go.etcd.io/etcd/server/v3/etcdserver/api/membership" "go.etcd.io/etcd/server/v3/etcdserver/api/snap" "go.etcd.io/etcd/server/v3/etcdserver/api/v2store" "go.etcd.io/etcd/tests/v3/framework/config" @@ -125,15 +129,12 @@ func TestV2DeprecationSnapshotMatches(t *testing.T) { assert.NoError(t, epc.Close()) assertSnapshotsMatch(t, oldMemberDataDir, newMemberDataDir, func(data []byte) []byte { - // Patch cluster version - data = bytes.Replace(data, []byte("3.5.0"), []byte("X.X.X"), -1) - data = bytes.Replace(data, []byte("3.6.0"), []byte("X.X.X"), -1) // Patch members ids for i, mid := range members1 { - data = bytes.Replace(data, []byte(fmt.Sprintf("%x", mid)), []byte(fmt.Sprintf("member%d", i+1)), -1) + data = bytes.Replace(data, []byte(fmt.Sprintf("%x", mid)), []byte(fmt.Sprintf("%d", i+1)), -1) } for i, mid := range members2 { - data = bytes.Replace(data, []byte(fmt.Sprintf("%x", mid)), []byte(fmt.Sprintf("member%d", i+1)), -1) + data = bytes.Replace(data, []byte(fmt.Sprintf("%x", mid)), []byte(fmt.Sprintf("%d", i+1)), -1) } return data }) @@ -250,7 +251,23 @@ func assertSnapshotsMatch(t testing.TB, firstDataDir, secondDataDir string, patc if err != nil { t.Fatal(err) } - assert.Equal(t, openSnap(patch(firstSnapshot.Data)), openSnap(patch(secondSnapshot.Data))) + assertMembershipEqual(t, openSnap(patch(firstSnapshot.Data)), openSnap(patch(secondSnapshot.Data))) + } +} + +func assertMembershipEqual(t testing.TB, firstStore v2store.Store, secondStore v2store.Store) { + rc1 := membership.NewCluster(zaptest.NewLogger(t)) + rc1.SetStore(firstStore) + rc1.Recover(func(lg *zap.Logger, v *semver.Version) { return }) + + rc2 := membership.NewCluster(zaptest.NewLogger(t)) + rc2.SetStore(secondStore) + rc2.Recover(func(lg *zap.Logger, v *semver.Version) { return }) + + //membership should match + if g := rc1.Members(); !reflect.DeepEqual(g, rc2.Members()) { + t.Logf("memberids_from_last_version = %+v, member_ids_from_current_version = %+v", rc1.MemberIDs(), rc2.MemberIDs()) + t.Errorf("members_from_last_version_snapshot = %+v, members_from_current_version_snapshot %+v", rc1.Members(), rc2.Members()) } }