From 7397e14c0ac636477ab48dbacd88ac5e3ed1a75e Mon Sep 17 00:00:00 2001 From: Anthony Romano Date: Mon, 14 Mar 2016 17:21:14 -0700 Subject: [PATCH] fileutil, wal: refactor file locking File lock interface was more verbose than it needed to be while simultaneously making it difficult to support systems (e.g., Windows) that only permit locked writes on a single fd holding the lock. --- pkg/fileutil/lock.go | 23 ++--- pkg/fileutil/lock_plan9.go | 62 +++-------- pkg/fileutil/lock_solaris.go | 81 +++++---------- pkg/fileutil/lock_test.go | 31 +++--- pkg/fileutil/lock_unix.go | 60 ++++------- pkg/fileutil/lock_windows.go | 42 ++------ pkg/fileutil/purge.go | 19 +--- pkg/fileutil/purge_test.go | 13 +-- wal/decoder.go | 10 +- wal/repair.go | 1 - wal/wal.go | 192 ++++++++++++++++------------------- wal/wal_test.go | 24 ++--- 12 files changed, 202 insertions(+), 356 deletions(-) diff --git a/pkg/fileutil/lock.go b/pkg/fileutil/lock.go index bf411d3a1..da2b92c73 100644 --- a/pkg/fileutil/lock.go +++ b/pkg/fileutil/lock.go @@ -14,16 +14,13 @@ package fileutil -type Lock interface { - // Name returns the name of the file. - Name() string - // TryLock acquires exclusivity on the lock without blocking. - TryLock() error - // Lock acquires exclusivity on the lock. - Lock() error - // Unlock unlocks the lock. - Unlock() error - // Destroy should be called after Unlock to clean up - // the resources. - Destroy() error -} +import ( + "errors" + "os" +) + +var ( + ErrLocked = errors.New("fileutil: file already locked") +) + +type LockedFile struct{ *os.File } diff --git a/pkg/fileutil/lock_plan9.go b/pkg/fileutil/lock_plan9.go index bd2bc8676..1c924a7e5 100644 --- a/pkg/fileutil/lock_plan9.go +++ b/pkg/fileutil/lock_plan9.go @@ -15,65 +15,31 @@ package fileutil import ( - "errors" "os" "syscall" "time" ) -var ( - ErrLocked = errors.New("file already locked") -) - -type lock struct { - fname string - file *os.File +func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + if err := os.Chmod(path, syscall.DMEXCL|0600); err != nil { + return nil, err + } + f, err := os.Open(path, flag, perm) + if err != nil { + return nil, ErrLocked + } + return &LockedFile{f}, nil } -func (l *lock) Name() string { - return l.fname -} - -func (l *lock) TryLock() error { - err := os.Chmod(l.fname, syscall.DMEXCL|0600) - if err != nil { - return err +func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + if err := os.Chmod(path, syscall.DMEXCL|0600); err != nil { + return nil, err } - - f, err := os.Open(l.fname) - if err != nil { - return ErrLocked - } - - l.file = f - return nil -} - -func (l *lock) Lock() error { - err := os.Chmod(l.fname, syscall.DMEXCL|0600) - if err != nil { - return err - } - for { - f, err := os.Open(l.fname) + f, err := os.OpenFile(path, flag, perm) if err == nil { - l.file = f - return nil + return &LockedFile{f}, nil } time.Sleep(10 * time.Millisecond) } } - -func (l *lock) Unlock() error { - return l.file.Close() -} - -func (l *lock) Destroy() error { - return nil -} - -func NewLock(file string) (Lock, error) { - l := &lock{fname: file} - return l, nil -} diff --git a/pkg/fileutil/lock_solaris.go b/pkg/fileutil/lock_solaris.go index e3b0a0176..0d5375aee 100644 --- a/pkg/fileutil/lock_solaris.go +++ b/pkg/fileutil/lock_solaris.go @@ -17,25 +17,11 @@ package fileutil import ( - "errors" "os" "syscall" ) -var ( - ErrLocked = errors.New("file already locked") -) - -type lock struct { - fd int - file *os.File -} - -func (l *lock) Name() string { - return l.file.Name() -} - -func (l *lock) TryLock() error { +func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { var lock syscall.Flock_t lock.Start = 0 lock.Len = 0 @@ -43,45 +29,34 @@ func (l *lock) TryLock() error { lock.Type = syscall.F_WRLCK lock.Whence = 0 lock.Pid = 0 - err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) - if err != nil && err == syscall.EAGAIN { - return ErrLocked - } - return err -} - -func (l *lock) Lock() error { - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Type = syscall.F_WRLCK - lock.Whence = 0 - lock.Pid = 0 - return syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) -} - -func (l *lock) Unlock() error { - var lock syscall.Flock_t - lock.Start = 0 - lock.Len = 0 - lock.Type = syscall.F_UNLCK - lock.Whence = 0 - err := syscall.FcntlFlock(uintptr(l.fd), syscall.F_SETLK, &lock) - if err != nil && err == syscall.EAGAIN { - return ErrLocked - } - return err -} - -func (l *lock) Destroy() error { - return l.file.Close() -} - -func NewLock(file string) (Lock, error) { - f, err := os.OpenFile(file, os.O_WRONLY, 0600) + f, err := os.OpenFile(path, flag, perm) if err != nil { return nil, err } - l := &lock{int(f.Fd()), f} - return l, nil + if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &lock); err != nil { + f.Close() + if err == syscall.EAGAIN { + err = ErrLocked + } + return nil, err + } + return &LockedFile{f}, nil +} + +func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + var lock syscall.Flock_t + lock.Start = 0 + lock.Len = 0 + lock.Pid = 0 + lock.Type = syscall.F_WRLCK + lock.Whence = 0 + f, err := os.OpenFile(path, flag, perm) + if err != nil { + return nil, err + } + if err = syscall.FcntlFlock(f.Fd(), syscall.F_SETLKW, &lock); err != nil { + f.Close() + return nil, err + } + return &LockedFile{f}, nil } diff --git a/pkg/fileutil/lock_test.go b/pkg/fileutil/lock_test.go index abd4a1037..d05605684 100644 --- a/pkg/fileutil/lock_test.go +++ b/pkg/fileutil/lock_test.go @@ -35,44 +35,38 @@ func TestLockAndUnlock(t *testing.T) { }() // lock the file - l, err := NewLock(f.Name()) - if err != nil { - t.Fatal(err) - } - defer l.Destroy() - err = l.Lock() + l, err := LockFile(f.Name(), os.O_WRONLY, 0600) if err != nil { t.Fatal(err) } // try lock a locked file - dupl, err := NewLock(f.Name()) - if err != nil { + if _, err = TryLockFile(f.Name(), os.O_WRONLY, 0600); err != ErrLocked { t.Fatal(err) } - err = dupl.TryLock() - if err != ErrLocked { - t.Errorf("err = %v, want %v", err, ErrLocked) - } // unlock the file - err = l.Unlock() - if err != nil { + if err = l.Close(); err != nil { t.Fatal(err) } // try lock the unlocked file - err = dupl.TryLock() + dupl, err := TryLockFile(f.Name(), os.O_WRONLY, 0600) if err != nil { t.Errorf("err = %v, want %v", err, nil) } - defer dupl.Destroy() // blocking on locked file locked := make(chan struct{}, 1) go func() { - l.Lock() + bl, blerr := LockFile(f.Name(), os.O_WRONLY, 0600) + if blerr != nil { + t.Fatal(blerr) + } locked <- struct{}{} + if blerr = bl.Close(); blerr != nil { + t.Fatal(blerr) + } }() select { @@ -82,8 +76,7 @@ func TestLockAndUnlock(t *testing.T) { } // unlock - err = dupl.Unlock() - if err != nil { + if err = dupl.Close(); err != nil { t.Fatal(err) } diff --git a/pkg/fileutil/lock_unix.go b/pkg/fileutil/lock_unix.go index 4f90e42ac..aa5127ef5 100644 --- a/pkg/fileutil/lock_unix.go +++ b/pkg/fileutil/lock_unix.go @@ -17,49 +17,33 @@ package fileutil import ( - "errors" "os" "syscall" ) -var ( - ErrLocked = errors.New("file already locked") -) - -type lock struct { - fd int - file *os.File -} - -func (l *lock) Name() string { - return l.file.Name() -} - -func (l *lock) TryLock() error { - err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB) - if err != nil && err == syscall.EWOULDBLOCK { - return ErrLocked - } - return err -} - -func (l *lock) Lock() error { - return syscall.Flock(l.fd, syscall.LOCK_EX) -} - -func (l *lock) Unlock() error { - return syscall.Flock(l.fd, syscall.LOCK_UN) -} - -func (l *lock) Destroy() error { - return l.file.Close() -} - -func NewLock(file string) (Lock, error) { - f, err := os.Open(file) +func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + f, err := os.OpenFile(path, flag, perm) if err != nil { return nil, err } - l := &lock{int(f.Fd()), f} - return l, nil + if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil { + f.Close() + if err == syscall.EWOULDBLOCK { + err = ErrLocked + } + return nil, err + } + return &LockedFile{f}, nil +} + +func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + f, err := os.OpenFile(path, flag, perm) + if err != nil { + return nil, err + } + if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil { + f.Close() + return nil, err + } + return &LockedFile{f}, err } diff --git a/pkg/fileutil/lock_windows.go b/pkg/fileutil/lock_windows.go index ddca9a669..d94106ac7 100644 --- a/pkg/fileutil/lock_windows.go +++ b/pkg/fileutil/lock_windows.go @@ -16,45 +16,17 @@ package fileutil -import ( - "errors" - "os" -) +import "os" -var ( - ErrLocked = errors.New("file already locked") -) - -type lock struct { - fd int - file *os.File +func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + return LockFile(path, flag, perm) } -func (l *lock) Name() string { - return l.file.Name() -} - -func (l *lock) TryLock() error { - return nil -} - -func (l *lock) Lock() error { - return nil -} - -func (l *lock) Unlock() error { - return nil -} - -func (l *lock) Destroy() error { - return l.file.Close() -} - -func NewLock(file string) (Lock, error) { - f, err := os.Open(file) +func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) { + // TODO make this actually work + f, err := os.OpenFile(path, flag, perm) if err != nil { return nil, err } - l := &lock{int(f.Fd()), f} - return l, nil + return &LockedFile{f}, nil } diff --git a/pkg/fileutil/purge.go b/pkg/fileutil/purge.go index 375aa9719..0d1bd99c0 100644 --- a/pkg/fileutil/purge.go +++ b/pkg/fileutil/purge.go @@ -40,32 +40,19 @@ func PurgeFile(dirname string, suffix string, max uint, interval time.Duration, sort.Strings(newfnames) for len(newfnames) > int(max) { f := path.Join(dirname, newfnames[0]) - l, err := NewLock(f) - if err != nil { - errC <- err - return - } - err = l.TryLock() + l, err := TryLockFile(f, os.O_WRONLY, 0600) if err != nil { break } - err = os.Remove(f) - if err != nil { + if err = os.Remove(f); err != nil { errC <- err return } - err = l.Unlock() - if err != nil { + if err = l.Close(); err != nil { plog.Errorf("error unlocking %s when purging file (%v)", l.Name(), err) errC <- err return } - err = l.Destroy() - if err != nil { - plog.Errorf("error destroying lock %s when purging file (%v)", l.Name(), err) - errC <- err - return - } plog.Infof("purged file %s successfully", f) newfnames = newfnames[1:] } diff --git a/pkg/fileutil/purge_test.go b/pkg/fileutil/purge_test.go index b11a4b05f..b3fa9ab27 100644 --- a/pkg/fileutil/purge_test.go +++ b/pkg/fileutil/purge_test.go @@ -80,7 +80,7 @@ func TestPurgeFile(t *testing.T) { close(stop) } -func TestPurgeFileHoldingLock(t *testing.T) { +func TestPurgeFileHoldingLockFile(t *testing.T) { dir, err := ioutil.TempDir("", "purgefile") if err != nil { t.Fatal(err) @@ -95,8 +95,8 @@ func TestPurgeFileHoldingLock(t *testing.T) { } // create a purge barrier at 5 - l, err := NewLock(path.Join(dir, fmt.Sprintf("%d.test", 5))) - err = l.Lock() + p := path.Join(dir, fmt.Sprintf("%d.test", 5)) + l, err := LockFile(p, os.O_WRONLY, 0600) if err != nil { t.Fatal(err) } @@ -127,12 +127,7 @@ func TestPurgeFileHoldingLock(t *testing.T) { } // remove the purge barrier - err = l.Unlock() - if err != nil { - t.Fatal(err) - } - err = l.Destroy() - if err != nil { + if err = l.Close(); err != nil { t.Fatal(err) } diff --git a/wal/decoder.go b/wal/decoder.go index f75c919fb..d2fda68c6 100644 --- a/wal/decoder.go +++ b/wal/decoder.go @@ -31,14 +31,12 @@ type decoder struct { mu sync.Mutex br *bufio.Reader - c io.Closer crc hash.Hash32 } -func newDecoder(rc io.ReadCloser) *decoder { +func newDecoder(r io.Reader) *decoder { return &decoder{ - br: bufio.NewReader(rc), - c: rc, + br: bufio.NewReader(r), crc: crc.New(0, crcTable), } } @@ -80,10 +78,6 @@ func (d *decoder) lastCRC() uint32 { return d.crc.Sum32() } -func (d *decoder) close() error { - return d.c.Close() -} - func mustUnmarshalEntry(d []byte) raftpb.Entry { var e raftpb.Entry pbutil.MustUnmarshal(&e, d) diff --git a/wal/repair.go b/wal/repair.go index bcc22ef08..eceebff3c 100644 --- a/wal/repair.go +++ b/wal/repair.go @@ -36,7 +36,6 @@ func Repair(dirpath string) bool { rec := &walpb.Record{} decoder := newDecoder(f) - defer decoder.close() for { err := decoder.decode(rec) switch err { diff --git a/wal/wal.go b/wal/wal.go index 99f1a9c11..52efd0a2e 100644 --- a/wal/wal.go +++ b/wal/wal.go @@ -70,16 +70,15 @@ type WAL struct { metadata []byte // metadata recorded at the head of each WAL state raftpb.HardState // hardstate recorded at the head of WAL - start walpb.Snapshot // snapshot to start reading - decoder *decoder // decoder to decode records + start walpb.Snapshot // snapshot to start reading + decoder *decoder // decoder to decode records + readClose io.Closer // closer for decode reader mu sync.Mutex - f *os.File // underlay file opened for appending, sync - seq uint64 // sequence of the wal file currently used for writes enti uint64 // index of the last entry saved to the wal encoder *encoder // encoder to encode records - locks []fileutil.Lock // the file locks the WAL is holding (the name is increasing) + locks []*fileutil.LockedFile // the locked files the WAL holds (the name is increasing) } // Create creates a WAL ready for appending records. The given metadata is @@ -94,26 +93,17 @@ func Create(dirpath string, metadata []byte) (*WAL, error) { } p := path.Join(dirpath, walName(0, 0)) - f, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) + f, err := fileutil.LockFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600) if err != nil { return nil, err } - l, err := fileutil.NewLock(f.Name()) - if err != nil { - return nil, err - } - if err = l.Lock(); err != nil { - return nil, err - } w := &WAL{ dir: dirpath, metadata: metadata, - seq: 0, - f: f, encoder: newEncoder(f, 0), } - w.locks = append(w.locks, l) + w.locks = append(w.locks, f) if err := w.saveCrc(0); err != nil { return nil, err } @@ -157,60 +147,56 @@ func openAtIndex(dirpath string, snap walpb.Snapshot, write bool) (*WAL, error) return nil, ErrFileNotFound } - // open the wal files for reading + // open the wal files rcs := make([]io.ReadCloser, 0) - ls := make([]fileutil.Lock, 0) + ls := make([]*fileutil.LockedFile, 0) for _, name := range names[nameIndex:] { - f, err := os.Open(path.Join(dirpath, name)) - if err != nil { - return nil, err - } - l, err := fileutil.NewLock(f.Name()) - if err != nil { - return nil, err - } - err = l.TryLock() - if err != nil { - if write { + p := path.Join(dirpath, name) + if write { + l, err := fileutil.TryLockFile(p, os.O_RDWR, 0600) + if err != nil { + MultiReadCloser(rcs...).Close() return nil, err } + ls = append(ls, l) + rcs = append(rcs, l) + } else { + rf, err := os.OpenFile(p, os.O_RDONLY, 0600) + if err != nil { + return nil, err + } + ls = append(ls, nil) + rcs = append(rcs, rf) } - rcs = append(rcs, f) - ls = append(ls, l) } + rc := MultiReadCloser(rcs...) + c := rc + if write { + // write reuses the file descriptors from read; don't close so + // WAL can append without dropping the file lock + c = nil + } // create a WAL ready for reading w := &WAL{ - dir: dirpath, - start: snap, - decoder: newDecoder(rc), - locks: ls, + dir: dirpath, + start: snap, + decoder: newDecoder(rc), + readClose: c, + locks: ls, } if write { - // open the last wal file for appending - seq, _, err := parseWalName(names[len(names)-1]) - if err != nil { + if _, _, err := parseWalName(path.Base(w.tail().Name())); err != nil { rc.Close() return nil, err } - last := path.Join(dirpath, names[len(names)-1]) - - f, err := os.OpenFile(last, os.O_WRONLY|os.O_APPEND, 0) - if err != nil { - rc.Close() - return nil, err - } - err = fileutil.Preallocate(f, segmentSizeBytes) - if err != nil { + if err := fileutil.Preallocate(w.tail().File, segmentSizeBytes); err != nil { rc.Close() plog.Errorf("failed to allocate space when creating new wal file (%v)", err) return nil, err } - - w.f = f - w.seq = seq } return w, nil @@ -275,7 +261,7 @@ func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb. } } - switch w.f { + switch w.tail() { case nil: // We do not have to read out all entries in read mode. // The last record maybe a partial written one, so @@ -298,17 +284,20 @@ func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb. } // close decoder, disable reading - w.decoder.close() + if w.readClose != nil { + w.readClose.Close() + w.readClose = nil + } w.start = walpb.Snapshot{} w.metadata = metadata - if w.f != nil { + if w.tail() != nil { // create encoder (chain crc with the decoder), enable appending - w.encoder = newEncoder(w.f, w.decoder.lastCRC()) - w.decoder = nil + w.encoder = newEncoder(w.tail(), w.decoder.lastCRC()) lastIndexSaved.Set(float64(w.enti)) } + w.decoder = nil return metadata, state, ents, err } @@ -321,23 +310,20 @@ func (w *WAL) cut() error { if err := w.sync(); err != nil { return err } - if err := w.f.Close(); err != nil { - return err - } - fpath := path.Join(w.dir, walName(w.seq+1, w.enti+1)) + fpath := path.Join(w.dir, walName(w.seq()+1, w.enti+1)) ftpath := fpath + ".tmp" // create a temp wal file with name sequence + 1, or truncate the existing one - ft, err := os.OpenFile(ftpath, os.O_WRONLY|os.O_APPEND|os.O_CREATE|os.O_TRUNC, 0600) + newTail, err := fileutil.LockFile(ftpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } // update writer and save the previous crc - w.f = ft + w.locks = append(w.locks, newTail) prevCrc := w.encoder.crc.Sum32() - w.encoder = newEncoder(w.f, prevCrc) + w.encoder = newEncoder(w.tail(), prevCrc) if err = w.saveCrc(prevCrc); err != nil { return err } @@ -347,47 +333,28 @@ func (w *WAL) cut() error { if err = w.saveState(&w.state); err != nil { return err } - // close temp wal file + // atomically move temp wal file to wal file if err = w.sync(); err != nil { return err } - if err = w.f.Close(); err != nil { - return err - } - - // atomically move temp wal file to wal file if err = os.Rename(ftpath, fpath); err != nil { return err } + newTail.Close() - // open the wal file and update writer again - f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_APPEND, 0600) - if err != nil { + if newTail, err = fileutil.LockFile(fpath, os.O_WRONLY|os.O_APPEND, 0600); err != nil { return err } - if err = fileutil.Preallocate(f, segmentSizeBytes); err != nil { + w.locks[len(w.locks)-1] = newTail + + prevCrc = w.encoder.crc.Sum32() + w.encoder = newEncoder(w.tail(), prevCrc) + + if err = fileutil.Preallocate(w.tail().File, segmentSizeBytes); err != nil { plog.Errorf("failed to allocate space when creating new wal file (%v)", err) return err } - w.f = f - prevCrc = w.encoder.crc.Sum32() - w.encoder = newEncoder(w.f, prevCrc) - - // lock the new wal file - l, err := fileutil.NewLock(f.Name()) - if err != nil { - return err - } - - if err := l.Lock(); err != nil { - return err - } - w.locks = append(w.locks, l) - - // increase the wal seq - w.seq++ - plog.Infof("segmented wal file %v is created", fpath) return nil } @@ -399,7 +366,7 @@ func (w *WAL) sync() error { } } start := time.Now() - err := fileutil.Fdatasync(w.f) + err := fileutil.Fdatasync(w.tail().File) syncDurations.Observe(float64(time.Since(start)) / float64(time.Second)) return err } @@ -438,8 +405,10 @@ func (w *WAL) ReleaseLockTo(index uint64) error { } for i := 0; i < smaller; i++ { - w.locks[i].Unlock() - w.locks[i].Destroy() + if w.locks[i] == nil { + continue + } + w.locks[i].Close() } w.locks = w.locks[smaller:] @@ -450,22 +419,17 @@ func (w *WAL) Close() error { w.mu.Lock() defer w.mu.Unlock() - if w.f != nil { + if w.tail() != nil { if err := w.sync(); err != nil { return err } - if err := w.f.Close(); err != nil { - return err - } } for _, l := range w.locks { - err := l.Unlock() - if err != nil { - plog.Errorf("failed to unlock during closing wal: %s", err) + if l == nil { + continue } - err = l.Destroy() - if err != nil { - plog.Errorf("failed to destroy lock during closing wal: %s", err) + if err := l.Close(); err != nil { + plog.Errorf("failed to unlock during closing wal: %s", err) } } return nil @@ -514,7 +478,7 @@ func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error { return err } - fstat, err := w.f.Stat() + fstat, err := w.tail().Stat() if err != nil { return err } @@ -524,6 +488,7 @@ func (w *WAL) Save(st raftpb.HardState, ents []raftpb.Entry) error { } return nil } + // TODO: add a test for this code path when refactoring the tests return w.cut() } @@ -549,6 +514,25 @@ func (w *WAL) saveCrc(prevCrc uint32) error { return w.encoder.encode(&walpb.Record{Type: crcType, Crc: prevCrc}) } +func (w *WAL) tail() *fileutil.LockedFile { + if len(w.locks) > 0 { + return w.locks[len(w.locks)-1] + } + return nil +} + +func (w *WAL) seq() uint64 { + t := w.tail() + if t == nil { + return 0 + } + seq, _, err := parseWalName(path.Base(t.Name())) + if err != nil { + plog.Fatalf("bad wal name %s (%v)", t.Name(), err) + } + return seq +} + func mustSync(st, prevst raftpb.HardState, entsnum int) bool { // Persistent state on all servers: // (Updated on stable storage before responding to RPCs) diff --git a/wal/wal_test.go b/wal/wal_test.go index c13afe46d..67ec8e200 100644 --- a/wal/wal_test.go +++ b/wal/wal_test.go @@ -38,11 +38,11 @@ func TestNew(t *testing.T) { if err != nil { t.Fatalf("err = %v, want nil", err) } - if g := path.Base(w.f.Name()); g != walName(0, 0) { + if g := path.Base(w.tail().Name()); g != walName(0, 0) { t.Errorf("name = %+v, want %+v", g, walName(0, 0)) } defer w.Close() - gd, err := ioutil.ReadFile(w.f.Name()) + gd, err := ioutil.ReadFile(w.tail().Name()) if err != nil { t.Fatalf("err = %v, want nil", err) } @@ -100,11 +100,11 @@ func TestOpenAtIndex(t *testing.T) { if err != nil { t.Fatalf("err = %v, want nil", err) } - if g := path.Base(w.f.Name()); g != walName(0, 0) { + if g := path.Base(w.tail().Name()); g != walName(0, 0) { t.Errorf("name = %+v, want %+v", g, walName(0, 0)) } - if w.seq != 0 { - t.Errorf("seq = %d, want %d", w.seq, 0) + if w.seq() != 0 { + t.Errorf("seq = %d, want %d", w.seq(), 0) } w.Close() @@ -119,11 +119,11 @@ func TestOpenAtIndex(t *testing.T) { if err != nil { t.Fatalf("err = %v, want nil", err) } - if g := path.Base(w.f.Name()); g != wname { + if g := path.Base(w.tail().Name()); g != wname { t.Errorf("name = %+v, want %+v", g, wname) } - if w.seq != 2 { - t.Errorf("seq = %d, want %d", w.seq, 2) + if w.seq() != 2 { + t.Errorf("seq = %d, want %d", w.seq(), 2) } w.Close() @@ -160,7 +160,7 @@ func TestCut(t *testing.T) { t.Fatal(err) } wname := walName(1, 1) - if g := path.Base(w.f.Name()); g != wname { + if g := path.Base(w.tail().Name()); g != wname { t.Errorf("name = %s, want %s", g, wname) } @@ -176,7 +176,7 @@ func TestCut(t *testing.T) { t.Fatal(err) } wname = walName(2, 2) - if g := path.Base(w.f.Name()); g != wname { + if g := path.Base(w.tail().Name()); g != wname { t.Errorf("name = %s, want %s", g, wname) } @@ -416,10 +416,10 @@ func TestOpenForRead(t *testing.T) { defer os.RemoveAll(p) // create WAL w, err := Create(p, nil) - defer w.Close() if err != nil { t.Fatal(err) } + defer w.Close() // make 10 separate files for i := 0; i < 10; i++ { es := []raftpb.Entry{{Index: uint64(i)}} @@ -436,10 +436,10 @@ func TestOpenForRead(t *testing.T) { // All are available for read w2, err := OpenForRead(p, walpb.Snapshot{}) - defer w2.Close() if err != nil { t.Fatal(err) } + defer w2.Close() _, _, ents, err := w2.ReadAll() if err != nil { t.Fatalf("err = %v, want nil", err)