diff --git a/wal/wal.go b/wal/wal.go index f253ab435..87efa45ff 100644 --- a/wal/wal.go +++ b/wal/wal.go @@ -60,6 +60,7 @@ var ( ErrSnapshotNotFound = errors.New("wal: snapshot not found") ErrSliceOutOfRange = errors.New("wal: slice bounds out of range") ErrMaxWALEntrySizeLimitExceeded = errors.New("wal: max entry size limit exceeded") + ErrDecoderNotFound = errors.New("wal: decoder not found") crcTable = crc32.MakeTable(crc32.Castagnoli) ) @@ -92,7 +93,8 @@ type WAL struct { } // Create creates a WAL ready for appending records. The given metadata is -// recorded at the head of each WAL file, and can be retrieved with ReadAll. +// recorded at the head of each WAL file, and can be retrieved with ReadAll +// after the file is Open. func Create(lg *zap.Logger, dirpath string, metadata []byte) (*WAL, error) { if Exist(dirpath) { return nil, os.ErrExist @@ -406,6 +408,10 @@ func (w *WAL) ReadAll() (metadata []byte, state raftpb.HardState, ents []raftpb. defer w.mu.Unlock() rec := &walpb.Record{} + + if w.decoder == nil { + return nil, state, nil, ErrDecoderNotFound + } decoder := w.decoder var match bool diff --git a/wal/wal_test.go b/wal/wal_test.go index ee0574ef1..4acd6f8e9 100644 --- a/wal/wal_test.go +++ b/wal/wal_test.go @@ -979,3 +979,24 @@ func TestRenameFail(t *testing.T) { t.Fatalf("expected error, got %v", werr) } } + +// TestReadAllFail ensure ReadAll error if used without opening the WAL +func TestReadAllFail(t *testing.T) { + dir, err := ioutil.TempDir(os.TempDir(), "waltest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // create initial WAL + f, err := Create(zap.NewExample(), dir, []byte("metadata")) + if err != nil { + t.Fatal(err) + } + f.Close() + // try to read without opening the WAL + _, _, _, err = f.ReadAll() + if err == nil || err != ErrDecoderNotFound { + t.Fatalf("err = %v, want ErrDecoderNotFound", err) + } +}