diff --git a/log_test.go b/log_test.go index c53f4bf3..90ae9388 100644 --- a/log_test.go +++ b/log_test.go @@ -24,26 +24,26 @@ import ( ) func TestFindConflict(t *testing.T) { - previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}} + previousEnts := index(1).terms(1, 2, 3) tests := []struct { ents []pb.Entry wconflict uint64 }{ // no conflict, empty ent - {[]pb.Entry{}, 0}, + {nil, 0}, // no conflict - {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0}, - {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0}, - {[]pb.Entry{{Index: 3, Term: 3}}, 0}, + {index(1).terms(1, 2, 3), 0}, + {index(2).terms(2, 3), 0}, + {index(3).terms(3), 0}, // no conflict, but has new entries - {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4}, - {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4}, - {[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4}, - {[]pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4}, + {index(1).terms(1, 2, 3, 4, 4), 4}, + {index(2).terms(2, 3, 4, 5), 4}, + {index(3).terms(3, 4, 4), 4}, + {index(4).terms(4, 4), 4}, // conflicts with existing entries - {[]pb.Entry{{Index: 1, Term: 4}, {Index: 2, Term: 4}}, 1}, - {[]pb.Entry{{Index: 2, Term: 1}, {Index: 3, Term: 4}, {Index: 4, Term: 4}}, 2}, - {[]pb.Entry{{Index: 3, Term: 1}, {Index: 4, Term: 2}, {Index: 5, Term: 4}, {Index: 6, Term: 4}}, 3}, + {index(1).terms(4, 4), 1}, + {index(2).terms(1, 4, 4), 2}, + {index(3).terms(1, 2, 4, 4), 3}, } for i, tt := range tests { @@ -56,13 +56,6 @@ func TestFindConflict(t *testing.T) { } func TestFindConflictByTerm(t *testing.T) { - ents := func(fromIndex uint64, terms []uint64) []pb.Entry { - e := make([]pb.Entry, 0, len(terms)) - for i, term := range terms { - e = append(e, pb.Entry{Term: term, Index: fromIndex + uint64(i)}) - } - return e - } for _, tt := range []struct { ents []pb.Entry // ents[0] contains the (index, term) of the snapshot index uint64 @@ -70,28 +63,28 @@ func TestFindConflictByTerm(t *testing.T) { want uint64 }{ // Log starts from index 1. - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 100, term: 2, want: 100}, // ErrUnavailable - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 5, term: 6, want: 5}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 5, term: 5, want: 5}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 5, term: 4, want: 2}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 5, term: 2, want: 2}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 5, term: 1, want: 0}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 1, term: 2, want: 1}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 1, term: 1, want: 0}, - {ents: ents(0, []uint64{0, 2, 2, 5, 5, 5}), index: 0, term: 0, want: 0}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 100, term: 2, want: 100}, // ErrUnavailable + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 5, term: 6, want: 5}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 5, term: 5, want: 5}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 5, term: 4, want: 2}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 5, term: 2, want: 2}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 5, term: 1, want: 0}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 1, term: 2, want: 1}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 1, term: 1, want: 0}, + {ents: index(0).terms(0, 2, 2, 5, 5, 5), index: 0, term: 0, want: 0}, // Log with compacted entries. - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 30, term: 3, want: 30}, // ErrUnavailable - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 14, term: 9, want: 14}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 14, term: 4, want: 14}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 14, term: 3, want: 12}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 14, term: 2, want: 9}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 11, term: 5, want: 11}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 10, term: 5, want: 10}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 10, term: 3, want: 10}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 10, term: 2, want: 9}, - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 9, term: 2, want: 9}, // ErrCompacted - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 4, term: 2, want: 4}, // ErrCompacted - {ents: ents(10, []uint64{3, 3, 3, 4, 4, 4}), index: 0, term: 0, want: 0}, // ErrCompacted + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 30, term: 3, want: 30}, // ErrUnavailable + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 14, term: 9, want: 14}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 14, term: 4, want: 14}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 14, term: 3, want: 12}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 14, term: 2, want: 9}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 11, term: 5, want: 11}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 10, term: 5, want: 10}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 10, term: 3, want: 10}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 10, term: 2, want: 9}, + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 9, term: 2, want: 9}, // ErrCompacted + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 4, term: 2, want: 4}, // ErrCompacted + {ents: index(10).terms(3, 3, 3, 4, 4, 4), index: 0, term: 0, want: 0}, // ErrCompacted } { t.Run("", func(t *testing.T) { st := NewMemoryStorage() @@ -113,7 +106,7 @@ func TestFindConflictByTerm(t *testing.T) { } func TestIsUpToDate(t *testing.T) { - previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}} + previousEnts := index(1).terms(1, 2, 3) raftLog := newLog(NewMemoryStorage(), raftLogger) raftLog.append(previousEnts...) tests := []struct { @@ -143,7 +136,7 @@ func TestIsUpToDate(t *testing.T) { } func TestAppend(t *testing.T) { - previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}} + previousEnts := index(1).terms(1, 2) tests := []struct { ents []pb.Entry windex uint64 @@ -151,29 +144,29 @@ func TestAppend(t *testing.T) { wunstable uint64 }{ { - []pb.Entry{}, + nil, 2, - []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, + index(1).terms(1, 2), 3, }, { - []pb.Entry{{Index: 3, Term: 2}}, + index(3).terms(2), 3, - []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 2}}, + index(1).terms(1, 2, 2), 3, }, // conflicts with index 1 { - []pb.Entry{{Index: 1, Term: 2}}, + index(1).terms(2), 1, - []pb.Entry{{Index: 1, Term: 2}}, + index(1).terms(2), 1, }, // conflicts with index 2 { - []pb.Entry{{Index: 2, Term: 3}, {Index: 3, Term: 3}}, + index(2).terms(3, 3), 3, - []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 3}, {Index: 3, Term: 3}}, + index(1).terms(1, 3, 3), 2, }, } @@ -203,7 +196,7 @@ func TestAppend(t *testing.T) { // // return false func TestLogMaybeAppend(t *testing.T) { - previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}} + previousEnts := index(1).terms(1, 2, 3) lastindex := uint64(3) lastterm := uint64(3) commit := uint64(1) @@ -222,13 +215,13 @@ func TestLogMaybeAppend(t *testing.T) { // not match: term is different { entryID{term: lastterm - 1, index: lastindex}, lastindex, - []pb.Entry{{Index: lastindex + 1, Term: 4}}, + index(lastindex + 1).terms(4), 0, false, commit, false, }, // not match: index out of bound { entryID{term: lastterm, index: lastindex + 1}, lastindex, - []pb.Entry{{Index: lastindex + 2, Term: 4}}, + index(lastindex + 2).terms(4), 0, false, commit, false, }, // match with the last existing entry @@ -254,43 +247,43 @@ func TestLogMaybeAppend(t *testing.T) { }, { entryID{term: lastterm, index: lastindex}, lastindex, - []pb.Entry{{Index: lastindex + 1, Term: 4}}, + index(lastindex + 1).terms(4), lastindex + 1, true, lastindex, false, }, { entryID{term: lastterm, index: lastindex}, lastindex + 1, - []pb.Entry{{Index: lastindex + 1, Term: 4}}, + index(lastindex + 1).terms(4), lastindex + 1, true, lastindex + 1, false, }, { entryID{term: lastterm, index: lastindex}, lastindex + 2, - []pb.Entry{{Index: lastindex + 1, Term: 4}}, + index(lastindex + 1).terms(4), lastindex + 1, true, lastindex + 1, false, // do not increase commit higher than lastnewi }, { entryID{term: lastterm, index: lastindex}, lastindex + 2, - []pb.Entry{{Index: lastindex + 1, Term: 4}, {Index: lastindex + 2, Term: 4}}, + index(lastindex+1).terms(4, 4), lastindex + 2, true, lastindex + 2, false, }, // match with the entry in the middle { entryID{term: lastterm - 1, index: lastindex - 1}, lastindex, - []pb.Entry{{Index: lastindex, Term: 4}}, + index(lastindex).terms(4), lastindex, true, lastindex, false, }, { entryID{term: lastterm - 2, index: lastindex - 2}, lastindex, - []pb.Entry{{Index: lastindex - 1, Term: 4}}, + index(lastindex - 1).terms(4), lastindex - 1, true, lastindex - 1, false, }, { entryID{term: lastterm - 3, index: lastindex - 3}, lastindex, - []pb.Entry{{Index: lastindex - 2, Term: 4}}, + index(lastindex - 2).terms(4), lastindex - 2, true, lastindex - 2, true, // conflict with existing committed entry }, { entryID{term: lastterm - 2, index: lastindex - 2}, lastindex, - []pb.Entry{{Index: lastindex - 1, Term: 4}, {Index: lastindex, Term: 4}}, + index(lastindex-1).terms(4, 4), lastindex, true, lastindex, false, }, } @@ -332,24 +325,19 @@ func TestLogMaybeAppend(t *testing.T) { // TestCompactionSideEffects ensures that all the log related functionality works correctly after // a compaction. func TestCompactionSideEffects(t *testing.T) { - var i uint64 // Populate the log with 1000 entries; 750 in stable storage and 250 in unstable. lastIndex := uint64(1000) unstableIndex := uint64(750) storage := NewMemoryStorage() - for i = 1; i <= unstableIndex; i++ { - storage.Append([]pb.Entry{{Term: i, Index: i}}) - } + require.NoError(t, storage.Append(index(1).termRange(1, unstableIndex+1))) raftLog := newLog(storage, raftLogger) - for i = unstableIndex; i < lastIndex; i++ { - raftLog.append(pb.Entry{Term: i + 1, Index: i + 1}) - } + raftLog.append(index(unstableIndex+1).termRange(unstableIndex+1, lastIndex+1)...) require.True(t, raftLog.maybeCommit(raftLog.lastEntryID())) raftLog.appliedTo(raftLog.committed, 0 /* size */) offset := uint64(500) - storage.Compact(offset) + require.NoError(t, storage.Compact(offset)) require.Equal(t, lastIndex, raftLog.lastIndex()) for j := offset; j <= raftLog.lastIndex(); j++ { @@ -377,11 +365,7 @@ func TestHasNextCommittedEnts(t *testing.T) { snap := pb.Snapshot{ Metadata: pb.SnapshotMetadata{Term: 1, Index: 3}, } - ents := []pb.Entry{ - {Term: 1, Index: 4}, - {Term: 1, Index: 5}, - {Term: 1, Index: 6}, - } + ents := index(4).terms(1, 1, 1) tests := []struct { applied uint64 applying uint64 @@ -435,11 +419,7 @@ func TestNextCommittedEnts(t *testing.T) { snap := pb.Snapshot{ Metadata: pb.SnapshotMetadata{Term: 1, Index: 3}, } - ents := []pb.Entry{ - {Term: 1, Index: 4}, - {Term: 1, Index: 5}, - {Term: 1, Index: 6}, - } + ents := index(4).terms(1, 1, 1) tests := []struct { applied uint64 applying uint64 @@ -494,11 +474,7 @@ func TestAcceptApplying(t *testing.T) { snap := pb.Snapshot{ Metadata: pb.SnapshotMetadata{Term: 1, Index: 3}, } - ents := []pb.Entry{ - {Term: 1, Index: 4}, - {Term: 1, Index: 5}, - {Term: 1, Index: 6}, - } + ents := index(4).terms(1, 1, 1) tests := []struct { index uint64 allowUnstable bool @@ -549,11 +525,7 @@ func TestAppliedTo(t *testing.T) { snap := pb.Snapshot{ Metadata: pb.SnapshotMetadata{Term: 1, Index: 3}, } - ents := []pb.Entry{ - {Term: 1, Index: 4}, - {Term: 1, Index: 5}, - {Term: 1, Index: 6}, - } + ents := index(4).terms(1, 1, 1) tests := []struct { index uint64 size entryEncodingSize @@ -599,7 +571,7 @@ func TestAppliedTo(t *testing.T) { // TestNextUnstableEnts ensures unstableEntries returns the unstable part of the // entries correctly. func TestNextUnstableEnts(t *testing.T) { - previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}} + previousEnts := index(1).terms(1, 2) tests := []struct { unstable uint64 wents []pb.Entry @@ -629,7 +601,7 @@ func TestNextUnstableEnts(t *testing.T) { } func TestCommitTo(t *testing.T) { - previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}, {Term: 3, Index: 3}} + previousEnts := index(1).terms(1, 2, 3) commit := uint64(2) tests := []struct { commit uint64 @@ -670,7 +642,7 @@ func TestStableTo(t *testing.T) { for i, tt := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { raftLog := newLog(NewMemoryStorage(), raftLogger) - raftLog.append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}...) + raftLog.append(index(1).terms(1, 2)...) raftLog.stableTo(entryID{term: tt.stablet, index: tt.stablei}) require.Equal(t, tt.wunstable, raftLog.unstable.offset) }) @@ -694,13 +666,13 @@ func TestStableToWithSnap(t *testing.T) { {snapi, snapt + 1, nil, snapi + 1}, {snapi - 1, snapt + 1, nil, snapi + 1}, - {snapi + 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 2}, - {snapi, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1}, - {snapi - 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1}, + {snapi + 1, snapt, index(snapi + 1).terms(snapt), snapi + 2}, + {snapi, snapt, index(snapi + 1).terms(snapt), snapi + 1}, + {snapi - 1, snapt, index(snapi + 1).terms(snapt), snapi + 1}, - {snapi + 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1}, - {snapi, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1}, - {snapi - 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1}, + {snapi + 1, snapt + 1, index(snapi + 1).terms(snapt), snapi + 1}, + {snapi, snapt + 1, index(snapi + 1).terms(snapt), snapi + 1}, + {snapi - 1, snapt + 1, index(snapi + 1).terms(snapt), snapi + 1}, } for i, tt := range tests { t.Run(fmt.Sprint(i), func(t *testing.T) { @@ -711,7 +683,6 @@ func TestStableToWithSnap(t *testing.T) { raftLog.stableTo(entryID{term: tt.stablet, index: tt.stablei}) require.Equal(t, tt.wunstable, raftLog.unstable.offset) }) - } } @@ -738,9 +709,7 @@ func TestCompaction(t *testing.T) { } }() storage := NewMemoryStorage() - for i := uint64(1); i <= tt.lastIndex; i++ { - storage.Append([]pb.Entry{{Index: i}}) - } + require.NoError(t, storage.Append(index(1).termRange(1, tt.lastIndex+1))) raftLog := newLog(storage, raftLogger) raftLog.maybeCommit(entryID{term: 0, index: tt.lastIndex}) // TODO(pav-kv): this is a no-op @@ -753,7 +722,6 @@ func TestCompaction(t *testing.T) { } require.Equal(t, tt.wleft[j], len(raftLog.allEntries())) } - }) } } @@ -779,9 +747,7 @@ func TestIsOutOfBounds(t *testing.T) { storage := NewMemoryStorage() storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset}}) l := newLog(storage, raftLogger) - for i := uint64(1); i <= num; i++ { - l.append(pb.Entry{Index: i + offset}) - } + l.append(index(offset+1).termRange(offset+1, offset+num+1)...) first := offset + 1 tests := []struct { @@ -853,9 +819,7 @@ func TestTerm(t *testing.T) { storage := NewMemoryStorage() storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset, Term: 1}}) l := newLog(storage, raftLogger) - for i := uint64(1); i < num; i++ { - l.append(pb.Entry{Index: offset + i, Term: i}) - } + l.append(index(offset+1).termRange(1, num)...) for i, tt := range []struct { idx uint64 @@ -916,11 +880,7 @@ func TestSlice(t *testing.T) { halfe := pb.Entry{Index: half, Term: half} entries := func(from, to uint64) []pb.Entry { - res := make([]pb.Entry, 0, to-from) - for i := from; i < to; i++ { - res = append(res, pb.Entry{Index: i, Term: i}) - } - return res + return index(from).termRange(from, to) } storage := NewMemoryStorage() @@ -1005,11 +965,7 @@ func TestScan(t *testing.T) { last := offset + num half := offset + num/2 entries := func(from, to uint64) []pb.Entry { - res := make([]pb.Entry, 0, to-from) - for i := from; i < to; i++ { - res = append(res, pb.Entry{Index: i, Term: i}) - } - return res + return index(from).termRange(from, to) } entrySize := entsSize(entries(half, half+1)) @@ -1063,3 +1019,31 @@ func mustTerm(term uint64, err error) uint64 { } return term } + +// index is a helper type for generating slices of pb.Entry. The value of index +// is the first entry index in the generated slices. +type index uint64 + +// terms generates a slice of entries at indices [index, index+len(terms)), with +// the given terms of each entry. Terms must be non-decreasing. +func (i index) terms(terms ...uint64) []pb.Entry { + index := uint64(i) + entries := make([]pb.Entry, 0, len(terms)) + for _, term := range terms { + entries = append(entries, pb.Entry{Term: term, Index: index}) + index++ + } + return entries +} + +// termRange generates a slice of to-from entries, at consecutive indices +// starting from i, and consecutive terms in [from, to). +func (i index) termRange(from, to uint64) []pb.Entry { + index := uint64(i) + entries := make([]pb.Entry, 0, to-from) + for term := from; term < to; term++ { + entries = append(entries, pb.Entry{Term: term, Index: index}) + index++ + } + return entries +} diff --git a/log_unstable_test.go b/log_unstable_test.go index 39c3f1ac..3ef9087f 100644 --- a/log_unstable_test.go +++ b/log_unstable_test.go @@ -34,7 +34,7 @@ func TestUnstableMaybeFirstIndex(t *testing.T) { }{ // no snapshot { - []pb.Entry{{Index: 5, Term: 1}}, 5, nil, + index(5).terms(1), 5, nil, false, 0, }, { @@ -43,7 +43,7 @@ func TestUnstableMaybeFirstIndex(t *testing.T) { }, // has snapshot { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, true, 5, }, { @@ -78,11 +78,11 @@ func TestMaybeLastIndex(t *testing.T) { }{ // last in entries { - []pb.Entry{{Index: 5, Term: 1}}, 5, nil, + index(5).terms(1), 5, nil, true, 5, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, true, 5, }, // last in snapshot @@ -124,38 +124,38 @@ func TestUnstableMaybeTerm(t *testing.T) { }{ // term from entries { - []pb.Entry{{Index: 5, Term: 1}}, 5, nil, + index(5).terms(1), 5, nil, 5, true, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, nil, + index(5).terms(1), 5, nil, 6, false, 0, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, nil, + index(5).terms(1), 5, nil, 4, false, 0, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, true, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 6, false, 0, }, // term from snapshot { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 4, true, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 3, false, 0, }, @@ -193,7 +193,7 @@ func TestUnstableMaybeTerm(t *testing.T) { func TestUnstableRestore(t *testing.T) { u := unstable{ - entries: []pb.Entry{{Index: 5, Term: 1}}, + entries: index(5).terms(1), offset: 5, offsetInProgress: 6, snapshot: &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, @@ -220,17 +220,17 @@ func TestUnstableNextEntries(t *testing.T) { }{ // nothing in progress { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 5, - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, + index(5).terms(1, 1), 5, 5, + index(5).terms(1, 1), }, // partially in progress { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 6, - []pb.Entry{{Index: 6, Term: 1}}, + index(5).terms(1, 1), 5, 6, + index(6).terms(1), }, // everything in progress { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 7, + index(5).terms(1, 1), 5, 7, nil, // nil, not empty slice }, } @@ -303,25 +303,25 @@ func TestUnstableAcceptInProgress(t *testing.T) { 5, false, }, { - []pb.Entry{{Index: 5, Term: 1}}, nil, + index(5).terms(1), nil, 5, // entries not in progress false, // snapshot not already in progress 6, false, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, nil, + index(5).terms(1, 1), nil, 5, // entries not in progress false, // snapshot not already in progress 7, false, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, nil, + index(5).terms(1, 1), nil, 6, // in-progress to the first entry false, // snapshot not already in progress 7, false, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, nil, + index(5).terms(1, 1), nil, 7, // in-progress to the second entry false, // snapshot not already in progress 7, false, @@ -334,25 +334,25 @@ func TestUnstableAcceptInProgress(t *testing.T) { 5, true, }, { - []pb.Entry{{Index: 5, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, // entries not in progress false, // snapshot not already in progress 6, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, // entries not in progress false, // snapshot not already in progress 7, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 6, // in-progress to the first entry false, // snapshot not already in progress 7, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 7, // in-progress to the second entry false, // snapshot not already in progress 7, true, @@ -364,25 +364,25 @@ func TestUnstableAcceptInProgress(t *testing.T) { 5, true, }, { - []pb.Entry{{Index: 5, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, // entries not in progress true, // snapshot already in progress 6, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, // entries not in progress true, // snapshot already in progress 7, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 6, // in-progress to the first entry true, // snapshot already in progress 7, true, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 7, // in-progress to the second entry true, // snapshot already in progress 7, true, @@ -422,63 +422,63 @@ func TestUnstableStableTo(t *testing.T) { 0, 0, 0, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, nil, + index(5).terms(1), 5, 6, nil, 5, 1, // stable to the first entry 6, 6, 0, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 6, nil, + index(5).terms(1, 1), 5, 6, nil, 5, 1, // stable to the first entry 6, 6, 1, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 7, nil, + index(5).terms(1, 1), 5, 7, nil, 5, 1, // stable to the first entry and in-progress ahead 6, 7, 1, }, { - []pb.Entry{{Index: 6, Term: 2}}, 6, 7, nil, + index(6).terms(2), 6, 7, nil, 6, 1, // stable to the first entry and term mismatch 6, 7, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, nil, + index(5).terms(1), 5, 6, nil, 4, 1, // stable to old entry 5, 6, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, nil, + index(5).terms(1), 5, 6, nil, 4, 2, // stable to old entry 5, 6, 1, }, // with snapshot { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, 1, // stable to the first entry 6, 6, 0, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, 1, // stable to the first entry 6, 6, 1, }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, 7, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1, 1), 5, 7, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 5, 1, // stable to the first entry and in-progress ahead 6, 7, 1, }, { - []pb.Entry{{Index: 6, Term: 2}}, 6, 7, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 5, Term: 1}}, + index(6).terms(2), 6, 7, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 5, Term: 1}}, 6, 1, // stable to the first entry and term mismatch 6, 7, 1, }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, + index(5).terms(1), 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}}, 4, 1, // stable to snapshot 5, 6, 1, }, { - []pb.Entry{{Index: 5, Term: 2}}, 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 2}}, + index(5).terms(2), 5, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 2}}, 4, 1, // stable to old entry 5, 6, 1, }, @@ -515,51 +515,51 @@ func TestUnstableTruncateAndAppend(t *testing.T) { }{ // append to the end { - []pb.Entry{{Index: 5, Term: 1}}, 5, 5, nil, - []pb.Entry{{Index: 6, Term: 1}, {Index: 7, Term: 1}}, - 5, 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, + index(5).terms(1), 5, 5, nil, + index(6).terms(1, 1), + 5, 5, index(5).terms(1, 1, 1), }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, nil, - []pb.Entry{{Index: 6, Term: 1}, {Index: 7, Term: 1}}, - 5, 6, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, + index(5).terms(1), 5, 6, nil, + index(6).terms(1, 1), + 5, 6, index(5).terms(1, 1, 1), }, // replace the unstable entries { - []pb.Entry{{Index: 5, Term: 1}}, 5, 5, nil, - []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, - 5, 5, []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, + index(5).terms(1), 5, 5, nil, + index(5).terms(2, 2), + 5, 5, index(5).terms(2, 2), }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 5, nil, - []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}}, - 4, 4, []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}}, + index(5).terms(1), 5, 5, nil, + index(4).terms(2, 2, 2), + 4, 4, index(4).terms(2, 2, 2), }, { - []pb.Entry{{Index: 5, Term: 1}}, 5, 6, nil, - []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, - 5, 5, []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}}, + index(5).terms(1), 5, 6, nil, + index(5).terms(2, 2), + 5, 5, index(5).terms(2, 2), }, // truncate the existing entries and append { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, 5, nil, - []pb.Entry{{Index: 6, Term: 2}}, - 5, 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 2}}, + index(5).terms(1, 1, 1), 5, 5, nil, + index(6).terms(2), + 5, 5, index(5).terms(1, 2), }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, 5, nil, - []pb.Entry{{Index: 7, Term: 2}, {Index: 8, Term: 2}}, - 5, 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 2}, {Index: 8, Term: 2}}, + index(5).terms(1, 1, 1), 5, 5, nil, + index(7).terms(2, 2), + 5, 5, index(5).terms(1, 1, 2, 2), }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, 6, nil, - []pb.Entry{{Index: 6, Term: 2}}, - 5, 6, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 2}}, + index(5).terms(1, 1, 1), 5, 6, nil, + index(6).terms(2), + 5, 6, index(5).terms(1, 2), }, { - []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, 7, nil, - []pb.Entry{{Index: 6, Term: 2}}, - 5, 6, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 2}}, + index(5).terms(1, 1, 1), 5, 7, nil, + index(6).terms(2), + 5, 6, index(5).terms(1, 2), }, } diff --git a/raft_paper_test.go b/raft_paper_test.go index a49ea02c..eff31f63 100644 --- a/raft_paper_test.go +++ b/raft_paper_test.go @@ -654,27 +654,27 @@ func TestFollowerAppendEntries(t *testing.T) { }{ { 2, 2, - []pb.Entry{{Term: 3, Index: 3}}, - []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}, {Term: 3, Index: 3}}, - []pb.Entry{{Term: 3, Index: 3}}, + index(3).terms(3), + index(1).terms(1, 2, 3), + index(3).terms(3), }, { 1, 1, - []pb.Entry{{Term: 3, Index: 2}, {Term: 4, Index: 3}}, - []pb.Entry{{Term: 1, Index: 1}, {Term: 3, Index: 2}, {Term: 4, Index: 3}}, - []pb.Entry{{Term: 3, Index: 2}, {Term: 4, Index: 3}}, + index(2).terms(3, 4), + index(1).terms(1, 3, 4), + index(2).terms(3, 4), }, { 0, 0, - []pb.Entry{{Term: 1, Index: 1}}, - []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}, + index(1).terms(1), + index(1).terms(1, 2), nil, }, { 0, 0, - []pb.Entry{{Term: 3, Index: 1}}, - []pb.Entry{{Term: 3, Index: 1}}, - []pb.Entry{{Term: 3, Index: 1}}, + index(1).terms(3), + index(1).terms(3), + index(1).terms(3), }, } for i, tt := range tests { @@ -698,55 +698,16 @@ func TestFollowerAppendEntries(t *testing.T) { // into consistency with its own. // Reference: section 5.3, figure 7 func TestLeaderSyncFollowerLog(t *testing.T) { - ents := []pb.Entry{ - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, {Term: 4, Index: 5}, - {Term: 5, Index: 6}, {Term: 5, Index: 7}, - {Term: 6, Index: 8}, {Term: 6, Index: 9}, {Term: 6, Index: 10}, - } + ents := index(0).terms(0, 1, 1, 1, 4, 4, 5, 5, 6, 6, 6) term := uint64(8) - tests := [][]pb.Entry{ - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, {Term: 4, Index: 5}, - {Term: 5, Index: 6}, {Term: 5, Index: 7}, - {Term: 6, Index: 8}, {Term: 6, Index: 9}, - }, - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, - }, - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, {Term: 4, Index: 5}, - {Term: 5, Index: 6}, {Term: 5, Index: 7}, - {Term: 6, Index: 8}, {Term: 6, Index: 9}, {Term: 6, Index: 10}, {Term: 6, Index: 11}, - }, - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, {Term: 4, Index: 5}, - {Term: 5, Index: 6}, {Term: 5, Index: 7}, - {Term: 6, Index: 8}, {Term: 6, Index: 9}, {Term: 6, Index: 10}, - {Term: 7, Index: 11}, {Term: 7, Index: 12}, - }, - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 4, Index: 4}, {Term: 4, Index: 5}, {Term: 4, Index: 6}, {Term: 4, Index: 7}, - }, - { - {}, - {Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}, - {Term: 2, Index: 4}, {Term: 2, Index: 5}, {Term: 2, Index: 6}, - {Term: 3, Index: 7}, {Term: 3, Index: 8}, {Term: 3, Index: 9}, {Term: 3, Index: 10}, {Term: 3, Index: 11}, - }, - } - for i, tt := range tests { + for i, tt := range [][]pb.Entry{ + index(0).terms(0, 1, 1, 1, 4, 4, 5, 5, 6, 6), + index(0).terms(0, 1, 1, 1, 4, 4), + index(0).terms(0, 1, 1, 1, 4, 4, 5, 5, 6, 6, 6, 6), + index(0).terms(0, 1, 1, 1, 4, 4, 5, 5, 6, 6, 6, 7, 7), + index(0).terms(0, 1, 1, 1, 4, 4, 4, 4), + index(0).terms(0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3), + } { leadStorage := newTestMemoryStorage(withPeers(1, 2, 3)) leadStorage.Append(ents) lead := newTestRaft(1, 10, 1, leadStorage) @@ -780,8 +741,8 @@ func TestVoteRequest(t *testing.T) { ents []pb.Entry wterm uint64 }{ - {[]pb.Entry{{Term: 1, Index: 1}}, 2}, - {[]pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}, 3}, + {index(1).terms(1), 2}, + {index(1).terms(1, 2), 3}, } for j, tt := range tests { r := newTestRaft(1, 10, 1, newTestMemoryStorage(withPeers(1, 2, 3))) @@ -832,17 +793,18 @@ func TestVoter(t *testing.T) { wreject bool }{ // same logterm - {[]pb.Entry{{Term: 1, Index: 1}}, 1, 1, false}, - {[]pb.Entry{{Term: 1, Index: 1}}, 1, 2, false}, - {[]pb.Entry{{Term: 1, Index: 1}, {Term: 1, Index: 2}}, 1, 1, true}, + {index(1).terms(1), 1, 1, false}, + {index(1).terms(1), 1, 2, false}, + {index(1).terms(1, 1), 1, 1, true}, // candidate higher logterm - {[]pb.Entry{{Term: 1, Index: 1}}, 2, 1, false}, - {[]pb.Entry{{Term: 1, Index: 1}}, 2, 2, false}, + {index(1).terms(1), 2, 1, false}, + {index(1).terms(1), 2, 2, false}, {[]pb.Entry{{Term: 1, Index: 1}, {Term: 1, Index: 2}}, 2, 1, false}, // voter higher logterm - {[]pb.Entry{{Term: 2, Index: 1}}, 1, 1, true}, - {[]pb.Entry{{Term: 2, Index: 1}}, 1, 2, true}, - {[]pb.Entry{{Term: 2, Index: 1}, {Term: 1, Index: 2}}, 1, 1, true}, + {index(1).terms(2), 1, 1, true}, + {index(1).terms(2), 1, 2, true}, + {index(1).terms(2, 2), 1, 1, true}, + {index(1).terms(1, 1), 1, 1, true}, } for i, tt := range tests { storage := newTestMemoryStorage(withPeers(1, 2)) diff --git a/raft_test.go b/raft_test.go index 3bbf00a0..f2cb0a76 100644 --- a/raft_test.go +++ b/raft_test.go @@ -1048,18 +1048,14 @@ func TestOldMessages(t *testing.T) { tt.send(pb.Message{From: 2, To: 2, Type: pb.MsgHup}) tt.send(pb.Message{From: 1, To: 1, Type: pb.MsgHup}) // pretend we're an old leader trying to make progress; this entry is expected to be ignored. - tt.send(pb.Message{From: 2, To: 1, Type: pb.MsgApp, Term: 2, Entries: []pb.Entry{{Index: 3, Term: 2}}}) + tt.send(pb.Message{From: 2, To: 1, Type: pb.MsgApp, Term: 2, Entries: index(3).terms(2)}) // commit a new entry tt.send(pb.Message{From: 1, To: 1, Type: pb.MsgProp, Entries: []pb.Entry{{Data: []byte("somedata")}}}) + ents := index(0).terms(0, 1, 2, 3, 3) + ents[4].Data = []byte("somedata") ilog := &raftLog{ - storage: &MemoryStorage{ - ents: []pb.Entry{ - {}, {Data: nil, Term: 1, Index: 1}, - {Data: nil, Term: 2, Index: 2}, {Data: nil, Term: 3, Index: 3}, - {Data: []byte("somedata"), Term: 3, Index: 4}, - }, - }, + storage: &MemoryStorage{ents: ents}, unstable: unstable{offset: 5}, committed: 4, } @@ -1183,24 +1179,24 @@ func TestCommit(t *testing.T) { w uint64 }{ // single - {[]uint64{1}, []pb.Entry{{Index: 1, Term: 1}}, 1, 1}, - {[]uint64{1}, []pb.Entry{{Index: 1, Term: 1}}, 2, 0}, - {[]uint64{2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 2, 2}, - {[]uint64{1}, []pb.Entry{{Index: 1, Term: 2}}, 2, 1}, + {[]uint64{1}, index(1).terms(1), 1, 1}, + {[]uint64{1}, index(1).terms(1), 2, 0}, + {[]uint64{2}, index(1).terms(1, 2), 2, 2}, + {[]uint64{1}, index(1).terms(2), 2, 1}, // odd - {[]uint64{2, 1, 1}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 1, 1}, - {[]uint64{2, 1, 1}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}, 2, 0}, - {[]uint64{2, 1, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 2, 2}, - {[]uint64{2, 1, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}, 2, 0}, + {[]uint64{2, 1, 1}, index(1).terms(1, 2), 1, 1}, + {[]uint64{2, 1, 1}, index(1).terms(1, 1), 2, 0}, + {[]uint64{2, 1, 2}, index(1).terms(1, 2), 2, 2}, + {[]uint64{2, 1, 2}, index(1).terms(1, 1), 2, 0}, // even - {[]uint64{2, 1, 1, 1}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 1, 1}, - {[]uint64{2, 1, 1, 1}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}, 2, 0}, - {[]uint64{2, 1, 1, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 1, 1}, - {[]uint64{2, 1, 1, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}, 2, 0}, - {[]uint64{2, 1, 2, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, 2, 2}, - {[]uint64{2, 1, 2, 2}, []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}, 2, 0}, + {[]uint64{2, 1, 1, 1}, index(1).terms(1, 2), 1, 1}, + {[]uint64{2, 1, 1, 1}, index(1).terms(1, 1), 2, 0}, + {[]uint64{2, 1, 1, 2}, index(1).terms(1, 2), 1, 1}, + {[]uint64{2, 1, 1, 2}, index(1).terms(1, 1), 2, 0}, + {[]uint64{2, 1, 2, 2}, index(1).terms(1, 2), 2, 2}, + {[]uint64{2, 1, 2, 2}, index(1).terms(1, 1), 2, 0}, } for i, tt := range tests { @@ -1307,7 +1303,7 @@ func TestHandleMsgApp(t *testing.T) { for i, tt := range tests { storage := newTestMemoryStorage(withPeers(1)) - storage.Append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}) + require.NoError(t, storage.Append(index(1).terms(1, 2))) sm := newTestRaft(1, 10, 1, storage) sm.becomeFollower(2, None) @@ -1341,7 +1337,7 @@ func TestHandleHeartbeat(t *testing.T) { for i, tt := range tests { storage := newTestMemoryStorage(withPeers(1, 2)) - storage.Append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}) + require.NoError(t, storage.Append(index(1).terms(1, 2, 3))) sm := newTestRaft(1, 5, 1, storage) sm.becomeFollower(2, 2) sm.raftLog.commitTo(commit) @@ -1362,7 +1358,7 @@ func TestHandleHeartbeat(t *testing.T) { // TestHandleHeartbeatResp ensures that we re-send log entries when we get a heartbeat response. func TestHandleHeartbeatResp(t *testing.T) { storage := newTestMemoryStorage(withPeers(1, 2)) - storage.Append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}) + require.NoError(t, storage.Append(index(1).terms(1, 2, 3))) sm := newTestRaft(1, 5, 1, storage) sm.becomeCandidate() sm.becomeLeader() @@ -1558,13 +1554,6 @@ func testRecvMsgVote(t *testing.T, msgType pb.MessageType) { {StateCandidate, 3, 3, 1, true}, } - max := func(a, b uint64) uint64 { - if a > b { - return a - } - return b - } - for i, tt := range tests { sm := newTestRaft(1, 10, 1, newTestMemoryStorage(withPeers(1))) sm.state = tt.state @@ -1578,7 +1567,7 @@ func testRecvMsgVote(t *testing.T, msgType pb.MessageType) { } sm.Vote = tt.voteFor sm.raftLog = &raftLog{ - storage: &MemoryStorage{ents: []pb.Entry{{}, {Index: 1, Term: 2}, {Index: 2, Term: 2}}}, + storage: &MemoryStorage{ents: index(0).terms(0, 2, 2)}, unstable: unstable{offset: 3}, } @@ -2517,7 +2506,7 @@ func TestReadOnlyForNewLeader(t *testing.T) { peers := make([]stateMachine, 0) for _, c := range nodeConfigs { storage := newTestMemoryStorage(withPeers(1, 2, 3)) - storage.Append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 1}}) + require.NoError(t, storage.Append(index(1).terms(1, 1))) storage.SetHardState(pb.HardState{Term: 1, Commit: c.committed}) if c.compactIndex != 0 { storage.Compact(c.compactIndex) @@ -2618,7 +2607,7 @@ func TestLeaderAppResp(t *testing.T) { // thus the last log term must be 1 to be committed. sm := newTestRaft(1, 10, 1, newTestMemoryStorage(withPeers(1, 2, 3))) sm.raftLog = &raftLog{ - storage: &MemoryStorage{ents: []pb.Entry{{}, {Index: 1, Term: 1}, {Index: 2, Term: 1}}}, + storage: &MemoryStorage{ents: index(0).terms(0, 1, 1)}, unstable: unstable{offset: 3}, } sm.becomeCandidate() @@ -2732,7 +2721,7 @@ func TestRecvMsgBeat(t *testing.T) { for i, tt := range tests { sm := newTestRaft(1, 10, 1, newTestMemoryStorage(withPeers(1, 2, 3))) - sm.raftLog = &raftLog{storage: &MemoryStorage{ents: []pb.Entry{{}, {Index: 1, Term: 1}, {Index: 2, Term: 1}}}} + sm.raftLog = &raftLog{storage: &MemoryStorage{ents: index(0).terms(0, 1, 1)}} sm.Term = 1 sm.state = tt.state switch tt.state { @@ -2758,7 +2747,7 @@ func TestRecvMsgBeat(t *testing.T) { } func TestLeaderIncreaseNext(t *testing.T) { - previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}} + previousEnts := index(1).terms(1, 2, 3) tests := []struct { // progress state tracker.StateType @@ -2891,7 +2880,7 @@ func TestSendAppendForProgressSnapshot(t *testing.T) { } func TestRecvMsgUnreachable(t *testing.T) { - previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}} + previousEnts := index(1).terms(1, 2, 3) s := newTestMemoryStorage(withPeers(1, 2)) s.Append(previousEnts) r := newTestRaft(1, 10, 1, s) @@ -3126,7 +3115,7 @@ func TestLearnerReceiveSnapshot(t *testing.T) { } func TestRestoreIgnoreSnapshot(t *testing.T) { - previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 1, Index: 2}, {Term: 1, Index: 3}} + previousEnts := index(1).terms(1, 1, 1) commit := uint64(1) storage := newTestMemoryStorage(withPeers(1, 2)) sm := newTestRaft(1, 10, 1, storage) @@ -4512,28 +4501,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=7,logTerm=4, entries=...); // After rejected leader appends (type=MsgApp,index=3,logTerm=2). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 4, Index: 4}, - {Term: 4, Index: 5}, - {Term: 4, Index: 6}, - {Term: 4, Index: 7}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 3, Index: 4}, - {Term: 3, Index: 5}, - {Term: 3, Index: 6}, - {Term: 3, Index: 7}, - {Term: 3, Index: 8}, - {Term: 3, Index: 9}, - {Term: 3, Index: 10}, - {Term: 3, Index: 11}, - }, + leaderLog: index(1).terms(1, 2, 2, 4, 4, 4, 4), + followerLog: index(1).terms(1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), rejectHintTerm: 3, rejectHintIndex: 7, nextAppendTerm: 2, @@ -4543,29 +4512,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=8,logTerm=5, entries=...); // After rejected leader appends (type=MsgApp,index=4,logTerm=3). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 3, Index: 4}, - {Term: 4, Index: 5}, - {Term: 4, Index: 6}, - {Term: 4, Index: 7}, - {Term: 5, Index: 8}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 3, Index: 4}, - {Term: 3, Index: 5}, - {Term: 3, Index: 6}, - {Term: 3, Index: 7}, - {Term: 3, Index: 8}, - {Term: 3, Index: 9}, - {Term: 3, Index: 10}, - {Term: 3, Index: 11}, - }, + leaderLog: index(1).terms(1, 2, 2, 3, 4, 4, 4, 5), + followerLog: index(1).terms(1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3), rejectHintTerm: 3, rejectHintIndex: 8, nextAppendTerm: 3, @@ -4575,18 +4523,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=4,logTerm=1, entries=...); // After rejected leader appends (type=MsgApp,index=1,logTerm=1). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 1, Index: 3}, - {Term: 1, Index: 4}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 4, Index: 4}, - }, + leaderLog: index(1).terms(1, 1, 1, 1), + followerLog: index(1).terms(1, 2, 2, 4), rejectHintTerm: 1, rejectHintIndex: 1, nextAppendTerm: 1, @@ -4597,20 +4535,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=6,logTerm=1, entries=...); // After rejected leader appends (type=MsgApp,index=1,logTerm=1). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 1, Index: 3}, - {Term: 1, Index: 4}, - {Term: 1, Index: 5}, - {Term: 1, Index: 6}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 4, Index: 4}, - }, + leaderLog: index(1).terms(1, 1, 1, 1, 1, 1), + followerLog: index(1).terms(1, 2, 2, 4), rejectHintTerm: 1, rejectHintIndex: 1, nextAppendTerm: 1, @@ -4621,20 +4547,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=4,logTerm=1, entries=...); // After rejected leader appends (type=MsgApp,index=1,logTerm=1). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 1, Index: 3}, - {Term: 1, Index: 4}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 4, Index: 4}, - {Term: 4, Index: 5}, - {Term: 4, Index: 6}, - }, + leaderLog: index(1).terms(1, 1, 1, 1), + followerLog: index(1).terms(1, 2, 2, 4, 4, 4), rejectHintTerm: 1, rejectHintIndex: 1, nextAppendTerm: 1, @@ -4644,19 +4558,8 @@ func TestFastLogRejection(t *testing.T) { // Firstly leader appends (type=MsgApp,index=5,logTerm=5, entries=...); // After rejected leader appends (type=MsgApp,index=4,logTerm=4). { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 1, Index: 3}, - {Term: 4, Index: 4}, - {Term: 5, Index: 5}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 1, Index: 3}, - {Term: 4, Index: 4}, - }, + leaderLog: index(1).terms(1, 1, 1, 4, 5), + followerLog: index(1).terms(1, 1, 1, 4), rejectHintTerm: 4, rejectHintIndex: 4, nextAppendTerm: 4, @@ -4664,25 +4567,8 @@ func TestFastLogRejection(t *testing.T) { }, // Test case from example comment in stepLeader (on leader). { - leaderLog: []pb.Entry{ - {Term: 2, Index: 1}, - {Term: 5, Index: 2}, - {Term: 5, Index: 3}, - {Term: 5, Index: 4}, - {Term: 5, Index: 5}, - {Term: 5, Index: 6}, - {Term: 5, Index: 7}, - {Term: 5, Index: 8}, - {Term: 5, Index: 9}, - }, - followerLog: []pb.Entry{ - {Term: 2, Index: 1}, - {Term: 4, Index: 2}, - {Term: 4, Index: 3}, - {Term: 4, Index: 4}, - {Term: 4, Index: 5}, - {Term: 4, Index: 6}, - }, + leaderLog: index(1).terms(2, 5, 5, 5, 5, 5, 5, 5, 5), + followerLog: index(1).terms(2, 4, 4, 4, 4, 4), rejectHintTerm: 4, rejectHintIndex: 6, nextAppendTerm: 2, @@ -4690,23 +4576,8 @@ func TestFastLogRejection(t *testing.T) { }, // Test case from example comment in handleAppendEntries (on follower). { - leaderLog: []pb.Entry{ - {Term: 2, Index: 1}, - {Term: 2, Index: 2}, - {Term: 2, Index: 3}, - {Term: 2, Index: 4}, - {Term: 2, Index: 5}, - }, - followerLog: []pb.Entry{ - {Term: 2, Index: 1}, - {Term: 4, Index: 2}, - {Term: 4, Index: 3}, - {Term: 4, Index: 4}, - {Term: 4, Index: 5}, - {Term: 4, Index: 6}, - {Term: 4, Index: 7}, - {Term: 4, Index: 8}, - }, + leaderLog: index(1).terms(2, 2, 2, 2, 2), + followerLog: index(1).terms(2, 4, 4, 4, 4, 4, 4, 4), rejectHintTerm: 2, rejectHintIndex: 1, nextAppendTerm: 2, @@ -4719,19 +4590,9 @@ func TestFastLogRejection(t *testing.T) { // MsgAppResp rejection will return same index=3, with logTerm=0. The leader // will rollback by one entry, and send MsgApp with index=2,logTerm=1. { - leaderLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 3, Index: 3}, - }, - followerLog: []pb.Entry{ - {Term: 1, Index: 1}, - {Term: 1, Index: 2}, - {Term: 3, Index: 3}, - {Term: 3, Index: 4}, - {Term: 3, Index: 5}, // <- this entry and below are compacted - }, - followerCompact: 5, + leaderLog: index(1).terms(1, 1, 3), + followerLog: index(1).terms(1, 1, 3, 3, 3), + followerCompact: 5, // entries <= index 5 are compacted rejectHintTerm: 0, rejectHintIndex: 3, nextAppendTerm: 1, diff --git a/storage_test.go b/storage_test.go index db39ccb7..44cf6023 100644 --- a/storage_test.go +++ b/storage_test.go @@ -24,7 +24,7 @@ import ( ) func TestStorageTerm(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) tests := []struct { i uint64 @@ -56,7 +56,7 @@ func TestStorageTerm(t *testing.T) { } func TestStorageEntries(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}} + ents := index(3).terms(3, 4, 5, 6) tests := []struct { lo, hi, maxsize uint64 @@ -65,18 +65,18 @@ func TestStorageEntries(t *testing.T) { }{ {2, 6, math.MaxUint64, ErrCompacted, nil}, {3, 4, math.MaxUint64, ErrCompacted, nil}, - {4, 5, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}}}, - {4, 6, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, - {4, 7, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}}, + {4, 5, math.MaxUint64, nil, index(4).terms(4)}, + {4, 6, math.MaxUint64, nil, index(4).terms(4, 5)}, + {4, 7, math.MaxUint64, nil, index(4).terms(4, 5, 6)}, // even if maxsize is zero, the first entry should be returned - {4, 7, 0, nil, []pb.Entry{{Index: 4, Term: 4}}}, + {4, 7, 0, nil, index(4).terms(4)}, // limit to 2 - {4, 7, uint64(ents[1].Size() + ents[2].Size()), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, + {4, 7, uint64(ents[1].Size() + ents[2].Size()), nil, index(4).terms(4, 5)}, // limit to 2 - {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()/2), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, - {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size() - 1), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, + {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()/2), nil, index(4).terms(4, 5)}, + {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size() - 1), nil, index(4).terms(4, 5)}, // all - {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}}, + {4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()), nil, index(4).terms(4, 5, 6)}, } for _, tt := range tests { @@ -90,21 +90,21 @@ func TestStorageEntries(t *testing.T) { } func TestStorageLastIndex(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) s := &MemoryStorage{ents: ents} last, err := s.LastIndex() require.NoError(t, err) require.Equal(t, uint64(5), last) - require.NoError(t, s.Append([]pb.Entry{{Index: 6, Term: 5}})) + require.NoError(t, s.Append(index(6).terms(5))) last, err = s.LastIndex() require.NoError(t, err) require.Equal(t, uint64(6), last) } func TestStorageFirstIndex(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) s := &MemoryStorage{ents: ents} first, err := s.FirstIndex() @@ -118,7 +118,7 @@ func TestStorageFirstIndex(t *testing.T) { } func TestStorageCompact(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) tests := []struct { i uint64 @@ -145,7 +145,7 @@ func TestStorageCompact(t *testing.T) { } func TestStorageCreateSnapshot(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) cs := &pb.ConfState{Voters: []uint64{1, 2, 3}} data := []byte("data") @@ -170,7 +170,7 @@ func TestStorageCreateSnapshot(t *testing.T) { } func TestStorageAppend(t *testing.T) { - ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}} + ents := index(3).terms(3, 4, 5) tests := []struct { entries []pb.Entry @@ -178,42 +178,42 @@ func TestStorageAppend(t *testing.T) { wentries []pb.Entry }{ { - []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}, + index(1).terms(1, 2), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}, + index(3).terms(3, 4, 5), }, { - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}, + index(3).terms(3, 4, 5), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}, + index(3).terms(3, 4, 5), }, { - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 6}, {Index: 5, Term: 6}}, + index(3).terms(3, 6, 6), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 6}, {Index: 5, Term: 6}}, + index(3).terms(3, 6, 6), }, { - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}}, + index(3).terms(3, 4, 5, 5), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}}, + index(3).terms(3, 4, 5, 5), }, // Truncate incoming entries, truncate the existing entries and append. { - []pb.Entry{{Index: 2, Term: 3}, {Index: 3, Term: 3}, {Index: 4, Term: 5}}, + index(2).terms(3, 3, 5), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 5}}, + index(3).terms(3, 5), }, // Truncate the existing entries and append. { - []pb.Entry{{Index: 4, Term: 5}}, + index(4).terms(5), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 5}}, + index(3).terms(3, 5), }, // Direct append. { - []pb.Entry{{Index: 6, Term: 5}}, + index(6).terms(5), nil, - []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}}, + index(3).terms(3, 4, 5, 5), }, }