Browse Source

server: add tests for on-disk snapshot

Yicheng Qin 11 years ago
parent
commit
27c9a0535c
3 changed files with 61 additions and 1 deletions
  1. 59 0
      etcd/etcd_test.go
  2. 1 1
      etcd/participant.go
  3. 1 0
      raft/raft.go

+ 59 - 0
etcd/etcd_test.go

@@ -24,6 +24,7 @@ import (
 	"net/http/httptest"
 	"net/http/httptest"
 	"net/url"
 	"net/url"
 	"os"
 	"os"
+	"path"
 	"reflect"
 	"reflect"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
@@ -286,6 +287,64 @@ func TestRestoreSnapshotFromLeader(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestSaveSnapshot(t *testing.T) {
+	defer afterTest(t)
+
+	cl := testCluster{Size: 1}
+	cl.Start()
+	defer cl.Destroy()
+
+	n := cl.Node(0)
+	// TODO(xiangli): tunable compact; reduce testing time
+	for i := 0; i < defaultCompact; i++ {
+		n.Participant().Set("/foo", false, "bar", store.Permanent)
+	}
+	snapname := fmt.Sprintf("%016x-%016x-%016x.snap", n.Participant().clusterId, 1, defaultCompact)
+	snappath := path.Join(n.Config.DataDir, "snap", snapname)
+	if _, err := os.Stat(snappath); err != nil {
+		t.Errorf("err = %v, want nil", err)
+	}
+	walname := fmt.Sprintf("%016x-%016x.wal", 1, defaultCompact)
+	walpath := path.Join(n.Config.DataDir, "wal", walname)
+	if _, err := os.Stat(walpath); err != nil {
+		t.Errorf("err = %v, want nil", err)
+	}
+}
+
+func TestRestoreSnapshotFromDisk(t *testing.T) {
+	defer afterTest(t)
+
+	cl := testCluster{Size: 1}
+	cl.Start()
+	defer cl.Destroy()
+
+	lead, _ := cl.Leader()
+	for i := 0; i < defaultCompact+10; i++ {
+		cl.Participant(lead).Set(fmt.Sprint("/foo", i), false, fmt.Sprint("bar", i), store.Permanent)
+	}
+
+	cl.Stop()
+	cl.Restart()
+
+	lead, _ = cl.Leader()
+	// check store is recovered
+	for i := 0; i < defaultCompact+10; i++ {
+		ev, err := cl.Participant(lead).Store.Get(fmt.Sprint("/foo", i), false, false)
+		if err != nil {
+			t.Errorf("get err = %v", err)
+			continue
+		}
+		w := fmt.Sprint("bar", i)
+		if g := *ev.Node.Value; g != w {
+			t.Errorf("value = %v, want %v", g, w)
+		}
+	}
+	// check new proposal could be submitted
+	if _, err := cl.Participant(lead).Set("/foo", false, "bar", store.Permanent); err != nil {
+		t.Fatal(err)
+	}
+}
+
 type testCluster struct {
 type testCluster struct {
 	Size int
 	Size int
 	TLS  bool
 	TLS  bool

+ 1 - 1
etcd/participant.go

@@ -167,7 +167,7 @@ func newParticipant(c *conf.Config, client *v2client, peerHub *peerHub, tickDura
 		p.id = n.Id
 		p.id = n.Id
 		p.node.Node = raft.Recover(n.Id, s, n.Ents, n.State, defaultHeartbeat, defaultElection)
 		p.node.Node = raft.Recover(n.Id, s, n.Ents, n.State, defaultHeartbeat, defaultElection)
 		p.apply(p.node.Next())
 		p.apply(p.node.Next())
-		log.Printf("id=%x participant.load path=%s snap=%+v state=\"%+v\" len(ents)=%d", p.id, p.cfg.DataDir, s, n.State, len(n.Ents))
+		log.Printf("id=%x participant.load path=%s snapIndex=%d state=\"%+v\" len(ents)=%d", p.id, p.cfg.DataDir, snapIndex, n.State, len(n.Ents))
 		if w, err = wal.Open(walDir); err != nil {
 		if w, err = wal.Open(walDir); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}

+ 1 - 0
raft/raft.go

@@ -511,6 +511,7 @@ func (sm *stateMachine) restore(s Snapshot) bool {
 	for _, n := range s.Nodes {
 	for _, n := range s.Nodes {
 		if n == sm.id {
 		if n == sm.id {
 			sm.addIns(n, sm.raftLog.lastIndex(), sm.raftLog.lastIndex()+1)
 			sm.addIns(n, sm.raftLog.lastIndex(), sm.raftLog.lastIndex()+1)
+			sm.promotable = true
 		} else {
 		} else {
 			sm.addIns(n, 0, sm.raftLog.lastIndex()+1)
 			sm.addIns(n, 0, sm.raftLog.lastIndex()+1)
 		}
 		}