Browse Source

Merge pull request #1839 from yichengq/245

wal: save latest state into new WAL
Yicheng Qin 11 years ago
parent
commit
29982dc935
2 changed files with 31 additions and 4 deletions
  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.
 // 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.
 // The WAL will be ready for appending after reading out all the previous records.
 type WAL struct {
 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
 	ri      uint64   // index of entry to start reading
 	decoder *decoder // decoder to decode records
 	decoder *decoder // decoder to decode records
@@ -236,7 +237,10 @@ func (w *WAL) Cut() error {
 	if err := w.saveCrc(prevCrc); err != nil {
 	if err := w.saveCrc(prevCrc); err != nil {
 		return err
 		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 {
 func (w *WAL) sync() error {
@@ -274,6 +278,7 @@ func (w *WAL) SaveState(s *raftpb.HardState) error {
 	if raft.IsEmptyHardState(*s) {
 	if raft.IsEmptyHardState(*s) {
 		return nil
 		return nil
 	}
 	}
+	w.state = *s
 	b := pbutil.MustMarshal(s)
 	b := pbutil.MustMarshal(s)
 	rec := &walpb.Record{Type: stateType, Data: b}
 	rec := &walpb.Record{Type: stateType, Data: b}
 	return w.encoder.encode(rec)
 	return w.encoder.encode(rec)

+ 23 - 1
wal/wal_test.go

@@ -142,12 +142,15 @@ func TestCut(t *testing.T) {
 	if err != nil {
 	if err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
-	defer w.Close()
 
 
 	// TODO(unihorn): remove this when cut can operate on an empty file
 	// TODO(unihorn): remove this when cut can operate on an empty file
 	if err := w.SaveEntry(&raftpb.Entry{}); err != nil {
 	if err := w.SaveEntry(&raftpb.Entry{}); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
+	state := raftpb.HardState{Term: 1}
+	if err := w.SaveState(&state); err != nil {
+		t.Fatal(err)
+	}
 	if err := w.Cut(); err != nil {
 	if err := w.Cut(); err != nil {
 		t.Fatal(err)
 		t.Fatal(err)
 	}
 	}
@@ -167,6 +170,25 @@ func TestCut(t *testing.T) {
 	if g := path.Base(w.f.Name()); g != wname {
 	if g := path.Base(w.f.Name()); g != wname {
 		t.Errorf("name = %s, want %s", 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) {
 func TestRecover(t *testing.T) {