فهرست منبع

wal: save latest state into new WAL

So we could always read out state when open at valid index.
Yicheng Qin 11 سال پیش
والد
کامیت
af0f34c595
2فایلهای تغییر یافته به همراه31 افزوده شده و 4 حذف شده
  1. 8 3
      wal/wal.go
  2. 23 1
      wal/wal_test.go

+ 8 - 3
wal/wal.go

@@ -56,8 +56,9 @@ var (
 // A just opened WAL is in read mode, and ready for reading records.
 // The WAL will be ready for appending after reading out all the previous records.
 type WAL struct {
-	dir      string // the living directory of the underlay files
-	metadata []byte // metadata recorded at the head of each WAL
+	dir      string           // the living directory of the underlay files
+	metadata []byte           // metadata recorded at the head of each WAL
+	state    raftpb.HardState // hardstate recorded at the head of WAL
 
 	ri      uint64   // index of entry to start reading
 	decoder *decoder // decoder to decode records
@@ -236,7 +237,10 @@ func (w *WAL) Cut() error {
 	if err := w.saveCrc(prevCrc); err != nil {
 		return err
 	}
-	return w.encoder.encode(&walpb.Record{Type: metadataType, Data: w.metadata})
+	if err := w.encoder.encode(&walpb.Record{Type: metadataType, Data: w.metadata}); err != nil {
+		return err
+	}
+	return w.SaveState(&w.state)
 }
 
 func (w *WAL) sync() error {
@@ -274,6 +278,7 @@ func (w *WAL) SaveState(s *raftpb.HardState) error {
 	if raft.IsEmptyHardState(*s) {
 		return nil
 	}
+	w.state = *s
 	b := pbutil.MustMarshal(s)
 	rec := &walpb.Record{Type: stateType, Data: b}
 	return w.encoder.encode(rec)

+ 23 - 1
wal/wal_test.go

@@ -142,12 +142,15 @@ func TestCut(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer w.Close()
 
 	// TODO(unihorn): remove this when cut can operate on an empty file
 	if err := w.SaveEntry(&raftpb.Entry{}); err != nil {
 		t.Fatal(err)
 	}
+	state := raftpb.HardState{Term: 1}
+	if err := w.SaveState(&state); err != nil {
+		t.Fatal(err)
+	}
 	if err := w.Cut(); err != nil {
 		t.Fatal(err)
 	}
@@ -167,6 +170,25 @@ func TestCut(t *testing.T) {
 	if g := path.Base(w.f.Name()); g != wname {
 		t.Errorf("name = %s, want %s", g, wname)
 	}
+	w.Close()
+
+	// check the state in the last WAL
+	f, err := os.Open(path.Join(p, wname))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	w = &WAL{
+		decoder: newDecoder(f),
+		ri:      2,
+	}
+	_, gst, _, err := w.ReadAll()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(gst, state) {
+		t.Errorf("state = %+v, want %+v", gst, state)
+	}
 }
 
 func TestRecover(t *testing.T) {