Skip to content

Commit 875fcda

Browse files
author
Anthony Romano
committed
wal: fsync directory after wal file rename
Fixes etcd-io#6368
1 parent 0b63502 commit 875fcda

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

wal/wal.go

+50-3
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ var (
6969
// A just opened WAL is in read mode, and ready for reading records.
7070
// The WAL will be ready for appending after reading out all the previous records.
7171
type WAL struct {
72-
dir string // the living directory of the underlay files
72+
dir string // the living directory of the underlay files
73+
74+
// dirFile is a fd for the wal directory for syncing on Rename
75+
dirFile *os.File
76+
7377
metadata []byte // metadata recorded at the head of each WAL
7478
state raftpb.HardState // hardstate recorded at the head of WAL
7579

@@ -131,7 +135,24 @@ func Create(dirpath string, metadata []byte) (*WAL, error) {
131135
return nil, err
132136
}
133137

134-
return w.renameWal(tmpdirpath)
138+
w, err = w.renameWal(tmpdirpath)
139+
if err != nil {
140+
return nil, err
141+
}
142+
143+
// directory was renamed; sync parent dir to persist rename
144+
pdir, perr := openSyncDir(path.Dir(w.dir))
145+
if perr != nil {
146+
return nil, perr
147+
}
148+
if perr = fileutil.Fsync(pdir); perr != nil {
149+
return nil, perr
150+
}
151+
if perr = pdir.Close(); err != nil {
152+
return nil, perr
153+
}
154+
155+
return w, nil
135156
}
136157

137158
// Open opens the WAL at the given snap.
@@ -141,7 +162,14 @@ func Create(dirpath string, metadata []byte) (*WAL, error) {
141162
// the given snap. The WAL cannot be appended to before reading out all of its
142163
// previous records.
143164
func Open(dirpath string, snap walpb.Snapshot) (*WAL, error) {
144-
return openAtIndex(dirpath, snap, true)
165+
w, err := openAtIndex(dirpath, snap, true)
166+
if err != nil {
167+
return nil, err
168+
}
169+
if err = w.openDir(); err != nil {
170+
return nil, err
171+
}
172+
return w, nil
145173
}
146174

147175
// OpenForRead only opens the wal files for read.
@@ -373,6 +401,10 @@ func (w *WAL) cut() error {
373401
if err = os.Rename(newTail.Name(), fpath); err != nil {
374402
return err
375403
}
404+
if err = fileutil.Fsync(w.dirFile); err != nil {
405+
return err
406+
}
407+
376408
newTail.Close()
377409

378410
if newTail, err = fileutil.LockFile(fpath, os.O_WRONLY, fileutil.PrivateFileMode); err != nil {
@@ -467,6 +499,7 @@ func (w *WAL) Close() error {
467499
return err
468500
}
469501
}
502+
470503
for _, l := range w.locks {
471504
if l == nil {
472505
continue
@@ -475,6 +508,11 @@ func (w *WAL) Close() error {
475508
plog.Errorf("failed to unlock during closing wal: %s", err)
476509
}
477510
}
511+
512+
if err := w.dirFile.Close(); err != nil {
513+
return err
514+
}
515+
478516
return nil
479517
}
480518

@@ -574,6 +612,15 @@ func (w *WAL) seq() uint64 {
574612
return seq
575613
}
576614

615+
func (w *WAL) openDir() error {
616+
df, derr := openSyncDir(w.dir)
617+
if derr != nil {
618+
return derr
619+
}
620+
w.dirFile = df
621+
return nil
622+
}
623+
577624
func mustSync(st, prevst raftpb.HardState, entsnum int) bool {
578625
// Persistent state on all servers:
579626
// (Updated on stable storage before responding to RPCs)

wal/wal_unix.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,7 @@ func (w *WAL) renameWal(tmpdirpath string) (*WAL, error) {
3434
}
3535

3636
w.fp = newFilePipeline(w.dir, SegmentSizeBytes)
37-
return w, nil
37+
return w, w.openDir()
3838
}
39+
40+
func openSyncDir(dir string) (*os.File, error) { return os.Open(dir) }

wal/wal_windows.go

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package wal
1717
import (
1818
"os"
1919

20+
"github.com/coreos/etcd/pkg/fileutil"
2021
"github.com/coreos/etcd/wal/walpb"
2122
)
2223

@@ -37,5 +38,10 @@ func (w *WAL) renameWal(tmpdirpath string) (*WAL, error) {
3738
newWAL.Close()
3839
return nil, err
3940
}
41+
4042
return newWAL, nil
4143
}
44+
45+
func openSyncDir(dir string) (*os.File, error) {
46+
return os.OpenFile(w.dir, os.O_WRONLY, fileutil.PrivateFileMode)
47+
}

0 commit comments

Comments
 (0)