vendor: go.etcd.io/etcd/* v3.6.15

server: fix fsync snap directory when saving a received snapshot db

release notes: https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md#v3615-2026-09-22

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn committed 2026-10-02 09:30:09 +02:00
1 parent c8e265787b
commit fb58aea8e1
7 files changed
+67 -27

No files matched your search

+4 -4
View File
@@ -274,10 +274,10 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300 // indirect
github.com/zmap/zlint/v3 v3.5.0 // indirect
go.etcd.io/etcd/api/v3 v3.6.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.14 // indirect
go.etcd.io/etcd/pkg/v3 v3.6.14 // indirect
go.etcd.io/etcd/server/v3 v3.6.14 // indirect
go.etcd.io/etcd/api/v3 v3.6.15 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.15 // indirect
go.etcd.io/etcd/pkg/v3 v3.6.15 // indirect
go.etcd.io/etcd/server/v3 v3.6.15 // indirect
go.etcd.io/raft/v3 v3.6.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.71.0 // indirect
+8 -8
View File
@@ -708,14 +708,14 @@ github.com/zmap/zlint/v3 v3.5.0 h1:Eh2B5t6VKgVH0DFmTwOqE50POvyDhUaU9T2mJOe1vfQ=
github.com/zmap/zlint/v3 v3.5.0/go.mod h1:JkNSrsDJ8F4VRtBZcYUQSvnWFL7utcjDIn+FE64mlBI=
go.etcd.io/bbolt v1.5.0 h1:S7GAl7Fxv12yohbwFfIbQCGDWbQbtDGPET4P/bD4lxU=
go.etcd.io/bbolt v1.5.0/go.mod h1:mkltfYE5aUHQxUct9N9V+Kp7aSjFqjgrhcXIS70Lrdk=
go.etcd.io/etcd/api/v3 v3.6.14 h1:3EEwTzQPiCyhLtacyl2ZkC0pMJWowghi61nJ9JSpO1w=
go.etcd.io/etcd/api/v3 v3.6.14/go.mod h1:L4HXnXoJ5NqXSxiwB4RihT5gGJJVvHEEOpEZ37g1Uj4=
go.etcd.io/etcd/client/pkg/v3 v3.6.14 h1:kqZf/BCRDWk9u5cNwBn1mTA+4GIZAU0POFPHmWHvo/I=
go.etcd.io/etcd/client/pkg/v3 v3.6.14/go.mod h1:Po3WXW01VRS7/gSDf8xjiY2rJTLmAwq/YmKAEz6u1+E=
go.etcd.io/etcd/pkg/v3 v3.6.14 h1:MAgY3G8aKMcjBIRay/4JjvCceuRAiEERrxTzkMtBlaA=
go.etcd.io/etcd/pkg/v3 v3.6.14/go.mod h1:grZHgzt+JCM8hnwSFrEAGxcl/VXksW0dRXfU0R2RmF8=
go.etcd.io/etcd/server/v3 v3.6.14 h1:LfN38zdvhpYnmyHG6shLWkfmMukkoyM19KUEZx1ywpM=
go.etcd.io/etcd/server/v3 v3.6.14/go.mod h1:yj1SNtvmNLLl7JUQY3vpaUBm24qAzTVixJn/1OKG6i4=
go.etcd.io/etcd/api/v3 v3.6.15 h1:Nysf/QR7vx8bx5oUR/yeMdy0YqtXoeELxn6UvNANrsQ=
go.etcd.io/etcd/api/v3 v3.6.15/go.mod h1:LlBr6CBsOUN/D011XFeIysDxI7JTQuegCX4DgseoOIw=
go.etcd.io/etcd/client/pkg/v3 v3.6.15 h1:6nqIEsCDLjZDh1fgHuQCSjVFv7pzdSYUq8zzpr9V/28=
go.etcd.io/etcd/client/pkg/v3 v3.6.15/go.mod h1:kCC9d5MnlhpVsgf2JVt2c3ydApI6sZo40vlnr79jGKU=
go.etcd.io/etcd/pkg/v3 v3.6.15 h1:LyJ+AOftel5J97A6i5eiDSplXH89y2TpeaHunUBe2sg=
go.etcd.io/etcd/pkg/v3 v3.6.15/go.mod h1:Cka235NdNGX93CscaD5LtEApThVO2HHnBl76pwmWGQs=
go.etcd.io/etcd/server/v3 v3.6.15 h1:IFlqNq0ia29PAcT73gfZjaYO/R+QCOavhenkAP4Y1N0=
go.etcd.io/etcd/server/v3 v3.6.15/go.mod h1:zuF7XwGYkIj7fFtUMYp+AFpa+SdnNj05sbsabmUnGrY=
go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ=
go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+1 -1
View File
@@ -26,7 +26,7 @@ import (
var (
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
MinClusterVersion = "3.0.0"
Version = "3.6.14"
Version = "3.6.15"
APIVersion = "unknown"
// Git SHA Value will be set during build
+5
View File
@@ -74,6 +74,11 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
}
}
if err = os.Remove(f); err != nil {
if flock {
if closeErr := l.Close(); closeErr != nil {
lg.Error("failed to unlock/close", zap.String("path", l.Name()), zap.Error(closeErr))
}
}
lg.Error("failed to remove file", zap.String("path", f), zap.Error(err))
errC <- err
return
+35 -2
View File
@@ -30,8 +30,10 @@ import (
var ErrNoDBSnapshot = errors.New("snap: snapshot file doesn't exist")
// SaveDBFrom saves snapshot of the database from the given reader. It
// guarantees the save operation is atomic.
// SaveDBFrom atomically saves a database snapshot from r. Before a successful
// return, it syncs the file and containing directory so the rename is durable
// on storage that honors fsync. The receiver processes the Raft message only
// afterward, so its WAL snapshot record cannot precede snap.db.
func (s *Snapshotter) SaveDBFrom(r io.Reader, id uint64) (int64, error) {
start := time.Now()
@@ -54,6 +56,11 @@ func (s *Snapshotter) SaveDBFrom(r io.Reader, id uint64) (int64, error) {
fn := s.dbFilePath(id)
if fileutil.Exist(fn) {
os.Remove(f.Name())
// A prior SaveDBFrom can have renamed this file and crashed before
// syncing the directory. Sync again before reporting success.
if err = s.fsyncDir(s.dir); err != nil {
return n, err
}
return n, nil
}
err = os.Rename(f.Name(), fn)
@@ -62,6 +69,19 @@ func (s *Snapshotter) SaveDBFrom(r io.Reader, id uint64) (int64, error) {
return n, err
}
// gofail: var snapDBRenameBeforeDirSync struct{}
// The file is synced above. Sync the directory to make the renamed entry
// durable before the snapshot receiver processes the Raft message.
if err = s.fsyncDir(s.dir); err != nil {
s.lg.Warn(
"failed to fsync snap directory after saving database snapshot",
zap.String("path", fn),
zap.Error(err),
)
return n, err
}
s.lg.Info(
"saved database snapshot to disk",
zap.String("path", fn),
@@ -97,3 +117,16 @@ func (s *Snapshotter) DBFilePath(id uint64) (string, error) {
func (s *Snapshotter) dbFilePath(id uint64) string {
return filepath.Join(s.dir, fmt.Sprintf("%016x.snap.db", id))
}
// fsyncSnapDir makes a renamed snapshot database durable. On Linux, syncing
// the file alone does not necessarily persist its containing directory entry.
func fsyncSnapDir(dir string) error {
// gofail: var snapDBDirSyncError string
// return errors.New(snapDBDirSyncError)
d, err := fileutil.OpenDir(dir)
if err != nil {
return err
}
defer d.Close()
return fileutil.Fsync(d)
}
+6 -4
View File
@@ -51,8 +51,9 @@ var (
)
type Snapshotter struct {
lg *zap.Logger
dir string
lg *zap.Logger
dir string
fsyncDir func(string) error
}
func New(lg *zap.Logger, dir string) *Snapshotter {
@@ -60,8 +61,9 @@ func New(lg *zap.Logger, dir string) *Snapshotter {
lg = zap.NewNop()
}
return &Snapshotter{
lg: lg,
dir: dir,
lg: lg,
dir: dir,
fsyncDir: fsyncSnapDir,
}
}
+8 -8
View File
@@ -1764,26 +1764,26 @@ go.etcd.io/bbolt
go.etcd.io/bbolt/errors
go.etcd.io/bbolt/internal/common
go.etcd.io/bbolt/internal/freelist
# go.etcd.io/etcd/api/v3 v3.6.14
## explicit; go 1.25.0
# go.etcd.io/etcd/api/v3 v3.6.15
## explicit; go 1.26
go.etcd.io/etcd/api/v3/authpb
go.etcd.io/etcd/api/v3/etcdserverpb
go.etcd.io/etcd/api/v3/membershippb
go.etcd.io/etcd/api/v3/mvccpb
go.etcd.io/etcd/api/v3/version
go.etcd.io/etcd/api/v3/versionpb
# go.etcd.io/etcd/client/pkg/v3 v3.6.14
## explicit; go 1.25.0
# go.etcd.io/etcd/client/pkg/v3 v3.6.15
## explicit; go 1.26
go.etcd.io/etcd/client/pkg/v3/fileutil
go.etcd.io/etcd/client/pkg/v3/verify
# go.etcd.io/etcd/pkg/v3 v3.6.14
## explicit; go 1.25.0
# go.etcd.io/etcd/pkg/v3 v3.6.15
## explicit; go 1.26
go.etcd.io/etcd/pkg/v3/crc
go.etcd.io/etcd/pkg/v3/idutil
go.etcd.io/etcd/pkg/v3/ioutil
go.etcd.io/etcd/pkg/v3/pbutil
# go.etcd.io/etcd/server/v3 v3.6.14
## explicit; go 1.25.0
# go.etcd.io/etcd/server/v3 v3.6.15
## explicit; go 1.26
go.etcd.io/etcd/server/v3/etcdserver/api/snap
go.etcd.io/etcd/server/v3/etcdserver/api/snap/snappb
go.etcd.io/etcd/server/v3/storage/wal