Fix FindMinSnapshotByGeneration() loop ref bug

This commit fixes an issue where the reference is taken
on the loop variable rather than the slice element when
computing the minimum snapshot within a generation so
it can cause the wrong snapshot to be chosen.
This commit is contained in:
Ben Johnson
2021-12-08 18:28:03 -07:00
parent 61c80cbfc2
commit d09f4ef618
3 changed files with 17 additions and 3 deletions

View File

@@ -213,11 +213,13 @@ func FilterSnapshotsAfter(a []SnapshotInfo, t time.Time) []SnapshotInfo {
// FindMinSnapshotByGeneration finds the snapshot with the lowest index in a generation. // FindMinSnapshotByGeneration finds the snapshot with the lowest index in a generation.
func FindMinSnapshotByGeneration(a []SnapshotInfo, generation string) *SnapshotInfo { func FindMinSnapshotByGeneration(a []SnapshotInfo, generation string) *SnapshotInfo {
var min *SnapshotInfo var min *SnapshotInfo
for _, snapshot := range a { for i := range a {
snapshot := &a[i]
if snapshot.Generation != generation { if snapshot.Generation != generation {
continue continue
} else if min == nil || snapshot.Index < min.Index { } else if min == nil || snapshot.Index < min.Index {
min = &snapshot min = snapshot
} }
} }
return min return min

View File

@@ -40,6 +40,16 @@ func TestChecksum(t *testing.T) {
}) })
} }
func TestFindMinSnapshotByGeneration(t *testing.T) {
infos := []litestream.SnapshotInfo{
{Generation: "29cf4bced74e92ab", Index: 0},
{Generation: "5dfeb4aa03232553", Index: 24},
}
if got, want := litestream.FindMinSnapshotByGeneration(infos, "29cf4bced74e92ab"), &infos[0]; got != want {
t.Fatalf("info=%#v, want %#v", got, want)
}
}
func MustDecodeHexString(s string) []byte { func MustDecodeHexString(s string) []byte {
b, err := hex.DecodeString(s) b, err := hex.DecodeString(s)
if err != nil { if err != nil {

View File

@@ -266,7 +266,9 @@ func (r *Replica) writeIndexSegments(ctx context.Context, segments []WALSegmentI
zw := lz4.NewWriter(pw) zw := lz4.NewWriter(pw)
// Write each segment out to the replica. // Write each segment out to the replica.
for _, info := range segments { for i := range segments {
info := &segments[i]
if err := func() error { if err := func() error {
// Ensure segments are in order and no bytes are skipped. // Ensure segments are in order and no bytes are skipped.
if pos != info.Pos() { if pos != info.Pos() {