diff --git a/manager/state/raft/storage/walwrap.go b/manager/state/raft/storage/walwrap.go index 2fd0a91804..48252059eb 100644 --- a/manager/state/raft/storage/walwrap.go +++ b/manager/state/raft/storage/walwrap.go @@ -174,7 +174,11 @@ func ReadRepairWAL( return nil, WALData{}, errors.Wrap(err, "failed to decrypt WAL") } // we can only repair ErrUnexpectedEOF and we never repair twice. - if repaired || err != io.ErrUnexpectedEOF { + if repaired || !errors.Is(err, io.ErrUnexpectedEOF) { + // TODO(thaJeztah): should ReadRepairWAL be updated to handle cases where + // some (last) of the files cannot be recovered? ("best effort" recovery?) + // Or should an informative error be produced to help the user (which could + // mean: remove the last file?). See TestReadRepairWAL for more details. return nil, WALData{}, errors.Wrap(err, "irreparable WAL error") } if !wal.Repair(nil, walDir) { diff --git a/manager/state/raft/storage/walwrap_test.go b/manager/state/raft/storage/walwrap_test.go index 6105315bee..9996c5b234 100644 --- a/manager/state/raft/storage/walwrap_test.go +++ b/manager/state/raft/storage/walwrap_test.go @@ -231,12 +231,24 @@ func TestReadRepairWAL(t *testing.T) { require.NoError(t, err) require.Len(t, files, 1) - fName := filepath.Join(tempdir, files[0].Name()) - fileContents, err := os.ReadFile(fName) - require.NoError(t, err) - info, err := files[0].Info() - require.NoError(t, err) - require.NoError(t, os.WriteFile(fName, fileContents[:200], info.Mode())) + // Corrupt the file by truncating it to replicate a broken state (partial + // write), but for this test, make sure that there's enough bytes left to + // read a record (24 bytes). The record size (recBytes) is calculated here; + // + // - https://github.com/etcd-io/etcd/blob/621cd7b9e5aa2ccf634b555e4ebe0037b8975066/server/wal/decoder.go#L83 + // - https://github.com/etcd-io/etcd/blob/621cd7b9e5aa2ccf634b555e4ebe0037b8975066/server/wal/decoder.go#L122-L131 + // + // Using a shorter length will make the test fail: + // + // wal: max entry size limit exceeded, recBytes: 24, fileSize(200) - offset(184) - padBytes(0) = entryLimit(16) + // + // So the file should be >= 208 bytes. + // + // For further details, see: + // + // - https://github.com/etcd-io/etcd/commit/621cd7b9e5aa2ccf634b555e4ebe0037b8975066 / https://github.com/etcd-io/etcd/pull/14127 (backport of https://github.com/etcd-io/etcd/pull/14122) + // - https://github.com/etcd-io/etcd/issues/14114 + require.NoError(t, os.Truncate(filepath.Join(tempdir, files[0].Name()), 300)) ogWAL, err := OriginalWAL.Open(tempdir, snapshot) require.NoError(t, err)