diff --git a/CHANGELOG-3.5.md b/CHANGELOG-3.5.md index 14e6663f01f..1b6c51698f6 100644 --- a/CHANGELOG-3.5.md +++ b/CHANGELOG-3.5.md @@ -73,6 +73,11 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.4.0...v3.5.0) and - [Embed Etcd does not override global/grpc logger](https://github.com/etcd-io/etcd/pull/12861) be default any longer. If desired, please call `embed.Config::SetupGlobalLoggers()` explicitly. - Client errors of `context cancelled` or `context deadline exceeded` are exposed as `codes.Canceled` and `codes.DeadlineExceeded`, instead of `codes.Unknown`. +### Storage format changes +- [WAL log's snapshots persists raftpb.ConfState](https://github.com/etcd-io/etcd/pull/12735) +- [Backend persists raftpb.ConfState](https://github.com/etcd-io/etcd/pull/12962) in the `meta` bucket `confState` key. +- Backend persists downgrade in the `cluster` bucket + ### Security - Add [`TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` and `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` to `etcd --cipher-suites`](https://github.com/etcd-io/etcd/pull/11864). diff --git a/server/etcdserver/api/membership/cluster.go b/server/etcdserver/api/membership/cluster.go index b570bc699f6..d42612a696c 100644 --- a/server/etcdserver/api/membership/cluster.go +++ b/server/etcdserver/api/membership/cluster.go @@ -694,6 +694,7 @@ func clusterVersionFromStore(lg *zap.Logger, st v2store.Store) *semver.Version { return semver.Must(semver.NewVersion(*e.Node.Value)) } +// The field is populated since etcd v3.5. func clusterVersionFromBackend(lg *zap.Logger, be backend.Backend) *semver.Version { ckey := backendClusterVersionKey() tx := be.ReadTx() @@ -712,6 +713,7 @@ func clusterVersionFromBackend(lg *zap.Logger, be backend.Backend) *semver.Versi return semver.Must(semver.NewVersion(string(vals[0]))) } +// The field is populated since etcd v3.5. func downgradeInfoFromBackend(lg *zap.Logger, be backend.Backend) *DowngradeInfo { dkey := backendDowngradeKey() tx := be.ReadTx() diff --git a/server/etcdserver/api/membership/confstate.go b/server/etcdserver/api/membership/confstate.go new file mode 100644 index 00000000000..9bfc71b379c --- /dev/null +++ b/server/etcdserver/api/membership/confstate.go @@ -0,0 +1,63 @@ +// Copyright 2021 The etcd Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package membership + +import ( + "encoding/json" + "log" + + "go.etcd.io/etcd/raft/v3/raftpb" + "go.etcd.io/etcd/server/v3/mvcc" + "go.etcd.io/etcd/server/v3/mvcc/backend" + "go.uber.org/zap" +) + +var ( + confStateKey = []byte("confState") +) + +// MustUnsafeSaveConfStateToBackend persists confState using given transaction (tx). +// confState in backend is persisted since etcd v3.5. +func MustUnsafeSaveConfStateToBackend(lg *zap.Logger, tx backend.BatchTx, confState *raftpb.ConfState) { + confStateBytes, err := json.Marshal(confState) + if err != nil { + lg.Panic("Cannot marshal raftpb.ConfState", zap.Stringer("conf-state", confState), zap.Error(err)) + } + + tx.UnsafePut(mvcc.MetaBucketName, confStateKey, confStateBytes) +} + +// UnsafeConfStateFromBackend retrieves ConfState from the backend. +// Returns nil if confState in backend is not persisted (e.g. backend writen by