Browse Source

Merge upstream

David Fisher 12 years ago
parent
commit
9825976e06
37 changed files with 372 additions and 166 deletions
  1. 2 1
      .gitignore
  2. 1 1
      build
  3. 6 2
      command.go
  4. 24 19
      etcd_handlers.go
  5. 13 14
      raft_server.go
  6. 47 33
      raft_stats.go
  7. 19 0
      scripts/test-cluster
  8. 67 3
      third_party/code.google.com/p/goprotobuf/proto/all_test.go
  9. 13 3
      third_party/code.google.com/p/goprotobuf/proto/decode.go
  10. 56 22
      third_party/code.google.com/p/goprotobuf/proto/encode.go
  11. 4 4
      third_party/code.google.com/p/goprotobuf/proto/extensions.go
  12. 3 3
      third_party/code.google.com/p/goprotobuf/proto/testdata/test.pb.go
  13. 2 2
      third_party/code.google.com/p/goprotobuf/proto/text_parser.go
  14. 1 1
      third_party/code.google.com/p/goprotobuf/proto/text_test.go
  15. 2 2
      third_party/code.google.com/p/goprotobuf/protoc-gen-go/descriptor/descriptor.pb.go
  16. 21 0
      third_party/code.google.com/p/goprotobuf/protoc-gen-go/generator/generator.go
  17. 1 1
      third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.pb.go
  18. 1 1
      third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.pb.go.golden
  19. 1 1
      third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.proto
  20. 2 2
      third_party/github.com/coreos/go-raft/append_entries_request.go
  21. 3 3
      third_party/github.com/coreos/go-raft/append_entries_request_test.go
  22. 2 2
      third_party/github.com/coreos/go-raft/append_entries_response.go
  23. 3 3
      third_party/github.com/coreos/go-raft/append_entries_response_test.go
  24. 8 8
      third_party/github.com/coreos/go-raft/http_transporter.go
  25. 16 14
      third_party/github.com/coreos/go-raft/log.go
  26. 6 0
      third_party/github.com/coreos/go-raft/peer.go
  27. 2 2
      third_party/github.com/coreos/go-raft/request_vote_request.go
  28. 2 2
      third_party/github.com/coreos/go-raft/request_vote_response.go
  29. 14 4
      third_party/github.com/coreos/go-raft/server.go
  30. 1 1
      third_party/github.com/coreos/go-raft/server_test.go
  31. 2 2
      third_party/github.com/coreos/go-raft/snapshot_recovery_request.go
  32. 2 2
      third_party/github.com/coreos/go-raft/snapshot_recovery_response.go
  33. 2 2
      third_party/github.com/coreos/go-raft/snapshot_request.go
  34. 2 2
      third_party/github.com/coreos/go-raft/snapshot_response.go
  35. 2 2
      third_party/github.com/coreos/go-raft/test.go
  36. 2 2
      transporter.go
  37. 17 0
      util.go

+ 2 - 1
.gitignore

@@ -1,4 +1,5 @@
 src/
 src/
 pkg/
 pkg/
-./etcd
+/etcd
 release_version.go
 release_version.go
+/machine*

+ 1 - 1
build

@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 
 ETCD_PACKAGE=github.com/coreos/etcd
 ETCD_PACKAGE=github.com/coreos/etcd
 export GOPATH="${PWD}"
 export GOPATH="${PWD}"

+ 6 - 2
command.go

@@ -170,8 +170,10 @@ func (c *JoinCommand) Apply(raftServer *raft.Server) (interface{}, error) {
 	value := fmt.Sprintf("raft=%s&etcd=%s&raftVersion=%s", c.RaftURL, c.EtcdURL, c.RaftVersion)
 	value := fmt.Sprintf("raft=%s&etcd=%s&raftVersion=%s", c.RaftURL, c.EtcdURL, c.RaftVersion)
 	etcdStore.Set(key, value, time.Unix(0, 0), raftServer.CommitIndex())
 	etcdStore.Set(key, value, time.Unix(0, 0), raftServer.CommitIndex())
 
 
+	// add peer stats
 	if c.Name != r.Name() {
 	if c.Name != r.Name() {
-		r.peersStats[c.Name] = &raftPeerStats{MinLatency: 1 << 63}
+		r.peersStats.Peers[c.Name] = &raftPeerStats{}
+		r.peersStats.Peers[c.Name].Latency.Minimum = 1 << 63
 	}
 	}
 
 
 	return b, err
 	return b, err
@@ -198,7 +200,9 @@ func (c *RemoveCommand) Apply(raftServer *raft.Server) (interface{}, error) {
 	key := path.Join("_etcd/machines", c.Name)
 	key := path.Join("_etcd/machines", c.Name)
 
 
 	_, err := etcdStore.Delete(key, raftServer.CommitIndex())
 	_, err := etcdStore.Delete(key, raftServer.CommitIndex())
-	delete(r.peersStats, c.Name)
+
+	// delete from stats
+	delete(r.peersStats.Peers, c.Name)
 
 
 	if err != nil {
 	if err != nil {
 		return []byte{0}, err
 		return []byte{0}, err

+ 24 - 19
etcd_handlers.go

@@ -22,7 +22,7 @@ func NewEtcdMuxer() *http.ServeMux {
 	etcdMux.Handle("/"+version+"/watch/", errorHandler(WatchHttpHandler))
 	etcdMux.Handle("/"+version+"/watch/", errorHandler(WatchHttpHandler))
 	etcdMux.Handle("/"+version+"/leader", errorHandler(LeaderHttpHandler))
 	etcdMux.Handle("/"+version+"/leader", errorHandler(LeaderHttpHandler))
 	etcdMux.Handle("/"+version+"/machines", errorHandler(MachinesHttpHandler))
 	etcdMux.Handle("/"+version+"/machines", errorHandler(MachinesHttpHandler))
-	etcdMux.Handle("/"+version+"/stats", errorHandler(StatsHttpHandler))
+	etcdMux.Handle("/"+version+"/stats/", errorHandler(StatsHttpHandler))
 	etcdMux.Handle("/version", errorHandler(VersionHttpHandler))
 	etcdMux.Handle("/version", errorHandler(VersionHttpHandler))
 	etcdMux.HandleFunc("/test/", TestHttpHandler)
 	etcdMux.HandleFunc("/test/", TestHttpHandler)
 	return etcdMux
 	return etcdMux
@@ -167,22 +167,8 @@ func dispatch(c Command, w http.ResponseWriter, req *http.Request, etcd bool) er
 			return etcdErr.NewError(300, "")
 			return etcdErr.NewError(300, "")
 		}
 		}
 
 
-		// tell the client where is the leader
-		path := req.URL.Path
+		redirect(leader, etcd, w, req)
 
 
-		var url string
-
-		if etcd {
-			etcdAddr, _ := nameToEtcdURL(leader)
-			url = etcdAddr + path
-		} else {
-			raftAddr, _ := nameToRaftURL(leader)
-			url = raftAddr + path
-		}
-
-		debugf("Redirect to %s", url)
-
-		http.Redirect(w, req, url, http.StatusTemporaryRedirect)
 		return nil
 		return nil
 	}
 	}
 	return etcdErr.NewError(300, "")
 	return etcdErr.NewError(300, "")
@@ -227,9 +213,28 @@ func VersionHttpHandler(w http.ResponseWriter, req *http.Request) error {
 
 
 // Handler to return the basic stats of etcd
 // Handler to return the basic stats of etcd
 func StatsHttpHandler(w http.ResponseWriter, req *http.Request) error {
 func StatsHttpHandler(w http.ResponseWriter, req *http.Request) error {
-	w.WriteHeader(http.StatusOK)
-	w.Write(etcdStore.Stats())
-	w.Write(r.Stats())
+	option := req.URL.Path[len("/v1/stats/"):]
+
+	switch option {
+	case "self":
+		w.WriteHeader(http.StatusOK)
+		w.Write(r.Stats())
+	case "leader":
+		if r.State() == raft.Leader {
+			w.Write(r.PeerStats())
+		} else {
+			leader := r.Leader()
+			// current no leader
+			if leader == "" {
+				return etcdErr.NewError(300, "")
+			}
+			redirect(leader, true, w, req)
+		}
+	case "store":
+		w.WriteHeader(http.StatusOK)
+		w.Write(etcdStore.Stats())
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 13 - 14
raft_server.go

@@ -24,7 +24,7 @@ type raftServer struct {
 	listenHost  string
 	listenHost  string
 	tlsConf     *TLSConfig
 	tlsConf     *TLSConfig
 	tlsInfo     *TLSInfo
 	tlsInfo     *TLSInfo
-	peersStats  map[string]*raftPeerStats
+	peersStats  *raftPeersStats
 	serverStats *raftServerStats
 	serverStats *raftServerStats
 }
 }
 
 
@@ -36,7 +36,7 @@ func newRaftServer(name string, url string, listenHost string, tlsConf *TLSConfi
 	raftTransporter := newTransporter(tlsConf.Scheme, tlsConf.Client, ElectionTimeout)
 	raftTransporter := newTransporter(tlsConf.Scheme, tlsConf.Client, ElectionTimeout)
 
 
 	// Create raft server
 	// Create raft server
-	server, err := raft.NewServer(name, dirPath, raftTransporter, etcdStore, nil)
+	server, err := raft.NewServer(name, dirPath, raftTransporter, etcdStore, nil, "")
 
 
 	check(err)
 	check(err)
 
 
@@ -48,7 +48,10 @@ func newRaftServer(name string, url string, listenHost string, tlsConf *TLSConfi
 		listenHost: listenHost,
 		listenHost: listenHost,
 		tlsConf:    tlsConf,
 		tlsConf:    tlsConf,
 		tlsInfo:    tlsInfo,
 		tlsInfo:    tlsInfo,
-		peersStats: make(map[string]*raftPeerStats),
+		peersStats: &raftPeersStats{
+			Leader: name,
+			Peers:  make(map[string]*raftPeerStats),
+		},
 		serverStats: &raftServerStats{
 		serverStats: &raftServerStats{
 			StartTime: time.Now(),
 			StartTime: time.Now(),
 			sendRateQueue: &statsQueue{
 			sendRateQueue: &statsQueue{
@@ -63,7 +66,6 @@ func newRaftServer(name string, url string, listenHost string, tlsConf *TLSConfi
 
 
 // Start the raft server
 // Start the raft server
 func (r *raftServer) ListenAndServe() {
 func (r *raftServer) ListenAndServe() {
-
 	// Setup commands.
 	// Setup commands.
 	registerCommands()
 	registerCommands()
 
 
@@ -282,7 +284,7 @@ func joinByMachine(s *raft.Server, machine string, scheme string) error {
 }
 }
 
 
 func (r *raftServer) Stats() []byte {
 func (r *raftServer) Stats() []byte {
-	r.serverStats.LeaderUptime = time.Now().Sub(r.serverStats.leaderStartTime).String()
+	r.serverStats.LeaderInfo.Uptime = time.Now().Sub(r.serverStats.LeaderInfo.startTime).String()
 
 
 	queue := r.serverStats.sendRateQueue
 	queue := r.serverStats.sendRateQueue
 
 
@@ -292,20 +294,17 @@ func (r *raftServer) Stats() []byte {
 
 
 	r.serverStats.RecvingPkgRate, r.serverStats.RecvingBandwidthRate = queue.Rate()
 	r.serverStats.RecvingPkgRate, r.serverStats.RecvingBandwidthRate = queue.Rate()
 
 
-	sBytes, err := json.Marshal(r.serverStats)
+	b, _ := json.Marshal(r.serverStats)
 
 
-	if err != nil {
-		warn(err)
-	}
+	return b
+}
 
 
+func (r *raftServer) PeerStats() []byte {
 	if r.State() == raft.Leader {
 	if r.State() == raft.Leader {
-		pBytes, _ := json.Marshal(r.peersStats)
-
-		b := append(sBytes, pBytes...)
+		b, _ := json.Marshal(r.peersStats)
 		return b
 		return b
 	}
 	}
-
-	return sBytes
+	return nil
 }
 }
 
 
 // Register commands to raft server
 // Register commands to raft server

+ 47 - 33
raft_stats.go

@@ -33,10 +33,14 @@ func (ps *packageStats) Time() time.Time {
 }
 }
 
 
 type raftServerStats struct {
 type raftServerStats struct {
-	State        string    `json:"state"`
-	StartTime    time.Time `json:"startTime"`
-	Leader       string    `json:"leader"`
-	LeaderUptime string    `json:"leaderUptime"`
+	State     string    `json:"state"`
+	StartTime time.Time `json:"startTime"`
+
+	LeaderInfo struct {
+		Name      string `json:"leader"`
+		Uptime    string `json:"uptime"`
+		startTime time.Time
+	} `json:"leaderInfo"`
 
 
 	RecvAppendRequestCnt uint64  `json:"recvAppendRequestCnt,"`
 	RecvAppendRequestCnt uint64  `json:"recvAppendRequestCnt,"`
 	RecvingPkgRate       float64 `json:"recvPkgRate,omitempty"`
 	RecvingPkgRate       float64 `json:"recvPkgRate,omitempty"`
@@ -46,16 +50,15 @@ type raftServerStats struct {
 	SendingPkgRate       float64 `json:"sendPkgRate,omitempty"`
 	SendingPkgRate       float64 `json:"sendPkgRate,omitempty"`
 	SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`
 	SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"`
 
 
-	leaderStartTime time.Time
-	sendRateQueue   *statsQueue
-	recvRateQueue   *statsQueue
+	sendRateQueue *statsQueue
+	recvRateQueue *statsQueue
 }
 }
 
 
 func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) {
 func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) {
 	ss.State = raft.Follower
 	ss.State = raft.Follower
-	if leaderName != ss.Leader {
-		ss.Leader = leaderName
-		ss.leaderStartTime = time.Now()
+	if leaderName != ss.LeaderInfo.Name {
+		ss.LeaderInfo.Name = leaderName
+		ss.LeaderInfo.startTime = time.Now()
 	}
 	}
 
 
 	ss.recvRateQueue.Insert(NewPackageStats(time.Now(), pkgSize))
 	ss.recvRateQueue.Insert(NewPackageStats(time.Now(), pkgSize))
@@ -64,55 +67,66 @@ func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) {
 
 
 func (ss *raftServerStats) SendAppendReq(pkgSize int) {
 func (ss *raftServerStats) SendAppendReq(pkgSize int) {
 	now := time.Now()
 	now := time.Now()
+
 	if ss.State != raft.Leader {
 	if ss.State != raft.Leader {
 		ss.State = raft.Leader
 		ss.State = raft.Leader
-		ss.Leader = r.Name()
-		ss.leaderStartTime = now
+		ss.LeaderInfo.Name = r.Name()
+		ss.LeaderInfo.startTime = now
 	}
 	}
 
 
-	ss.sendRateQueue.Insert(NewPackageStats(time.Now(), pkgSize))
+	ss.sendRateQueue.Insert(NewPackageStats(now, pkgSize))
 
 
 	ss.SendAppendRequestCnt++
 	ss.SendAppendRequestCnt++
 }
 }
 
 
+type raftPeersStats struct {
+	Leader string                    `json:"leader"`
+	Peers  map[string]*raftPeerStats `json:"peers"`
+}
+
 type raftPeerStats struct {
 type raftPeerStats struct {
-	Latency          float64 `json:"latency"`
-	AvgLatency       float64 `json:"averageLatency"`
-	avgLatencySquare float64
-	SdvLatency       float64 `json:"sdvLatency"`
-	MinLatency       float64 `json:"minLatency"`
-	MaxLatency       float64 `json:"maxLatency"`
-	FailCnt          uint64  `json:"failsCount"`
-	SuccCnt          uint64  `json:"successCount"`
+	Latency struct {
+		Current           float64 `json:"current"`
+		Average           float64 `json:"average"`
+		averageSquare     float64
+		StandardDeviation float64 `json:"standardDeviation"`
+		Minimum           float64 `json:"minimum"`
+		Maximum           float64 `json:"maximum"`
+	} `json:"latency"`
+
+	Counts struct {
+		Fail    uint64 `json:"fail"`
+		Success uint64 `json:"success"`
+	} `json:"counts"`
 }
 }
 
 
 // Succ function update the raftPeerStats with a successful send
 // Succ function update the raftPeerStats with a successful send
 func (ps *raftPeerStats) Succ(d time.Duration) {
 func (ps *raftPeerStats) Succ(d time.Duration) {
-	total := float64(ps.SuccCnt) * ps.AvgLatency
-	totalSquare := float64(ps.SuccCnt) * ps.avgLatencySquare
+	total := float64(ps.Counts.Success) * ps.Latency.Average
+	totalSquare := float64(ps.Counts.Success) * ps.Latency.averageSquare
 
 
-	ps.SuccCnt++
+	ps.Counts.Success++
 
 
-	ps.Latency = float64(d) / (1000000.0)
+	ps.Latency.Current = float64(d) / (1000000.0)
 
 
-	if ps.Latency > ps.MaxLatency {
-		ps.MaxLatency = ps.Latency
+	if ps.Latency.Current > ps.Latency.Maximum {
+		ps.Latency.Maximum = ps.Latency.Current
 	}
 	}
 
 
-	if ps.Latency < ps.MinLatency {
-		ps.MinLatency = ps.Latency
+	if ps.Latency.Current < ps.Latency.Minimum {
+		ps.Latency.Minimum = ps.Latency.Current
 	}
 	}
 
 
-	ps.AvgLatency = (total + ps.Latency) / float64(ps.SuccCnt)
-	ps.avgLatencySquare = (totalSquare + ps.Latency*ps.Latency) / float64(ps.SuccCnt)
+	ps.Latency.Average = (total + ps.Latency.Current) / float64(ps.Counts.Success)
+	ps.Latency.averageSquare = (totalSquare + ps.Latency.Current * ps.Latency.Current) / float64(ps.Counts.Success)
 
 
 	// sdv = sqrt(avg(x^2) - avg(x)^2)
 	// sdv = sqrt(avg(x^2) - avg(x)^2)
-	ps.SdvLatency = math.Sqrt(ps.avgLatencySquare - ps.AvgLatency*ps.AvgLatency)
+	ps.Latency.StandardDeviation = math.Sqrt(ps.Latency.averageSquare - ps.Latency.Average*ps.Latency.Average)
 }
 }
 
 
 // Fail function update the raftPeerStats with a unsuccessful send
 // Fail function update the raftPeerStats with a unsuccessful send
 func (ps *raftPeerStats) Fail() {
 func (ps *raftPeerStats) Fail() {
-	ps.FailCnt++
+	ps.Counts.Fail++
 }
 }
 
 
 type statsQueue struct {
 type statsQueue struct {

+ 19 - 0
scripts/test-cluster

@@ -0,0 +1,19 @@
+#!/bin/bash
+SESSION=etcd-cluster
+
+tmux new-session -d -s $SESSION
+
+# Setup a window for tailing log files
+tmux new-window -t $SESSION:1 -n 'machines'
+tmux split-window -h
+tmux select-pane -t 0
+tmux send-keys "./etcd -s 127.0.0.1:7001 -c 127.0.0.1:4001 -d machine1 -n machine1" C-m
+
+for i in 2 3; do
+	tmux select-pane -t 0
+	tmux split-window -v
+	tmux send-keys "./etcd -cors='*' -s 127.0.0.1:700${i} -c 127.0.0.1:400${i} -C 127.0.0.1:7001 -d machine${i} -n machine${i}" C-m
+done
+
+# Attach to session
+tmux attach-session -t $SESSION

+ 67 - 3
third_party/code.google.com/p/goprotobuf/proto/all_test.go

@@ -431,7 +431,7 @@ func TestRequiredBit(t *testing.T) {
 	err := o.Marshal(pb)
 	err := o.Marshal(pb)
 	if err == nil {
 	if err == nil {
 		t.Error("did not catch missing required fields")
 		t.Error("did not catch missing required fields")
-	} else if strings.Index(err.Error(), "GoTest") < 0 {
+	} else if strings.Index(err.Error(), "Kind") < 0 {
 		t.Error("wrong error type:", err)
 		t.Error("wrong error type:", err)
 	}
 	}
 }
 }
@@ -1205,7 +1205,7 @@ func TestRequiredFieldEnforcement(t *testing.T) {
 	_, err := Marshal(pb)
 	_, err := Marshal(pb)
 	if err == nil {
 	if err == nil {
 		t.Error("marshal: expected error, got nil")
 		t.Error("marshal: expected error, got nil")
-	} else if strings.Index(err.Error(), "GoTestField") < 0 {
+	} else if strings.Index(err.Error(), "Label") < 0 {
 		t.Errorf("marshal: bad error type: %v", err)
 		t.Errorf("marshal: bad error type: %v", err)
 	}
 	}
 
 
@@ -1216,7 +1216,7 @@ func TestRequiredFieldEnforcement(t *testing.T) {
 	err = Unmarshal(buf, pb)
 	err = Unmarshal(buf, pb)
 	if err == nil {
 	if err == nil {
 		t.Error("unmarshal: expected error, got nil")
 		t.Error("unmarshal: expected error, got nil")
-	} else if strings.Index(err.Error(), "GoTestField") < 0 {
+	} else if strings.Index(err.Error(), "{Unknown}") < 0 {
 		t.Errorf("unmarshal: bad error type: %v", err)
 		t.Errorf("unmarshal: bad error type: %v", err)
 	}
 	}
 }
 }
@@ -1670,6 +1670,70 @@ func TestEncodingSizes(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestErrRequiredNotSet(t *testing.T) {
+	pb := initGoTest(false)
+	pb.RequiredField.Label = nil
+	pb.F_Int32Required = nil
+	pb.F_Int64Required = nil
+
+	expected := "0807" + // field 1, encoding 0, value 7
+		"2206" + "120474797065" + // field 4, encoding 2 (GoTestField)
+		"5001" + // field 10, encoding 0, value 1
+		"6d20000000" + // field 13, encoding 5, value 0x20
+		"714000000000000000" + // field 14, encoding 1, value 0x40
+		"78a019" + // field 15, encoding 0, value 0xca0 = 3232
+		"8001c032" + // field 16, encoding 0, value 0x1940 = 6464
+		"8d0100004a45" + // field 17, encoding 5, value 3232.0
+		"9101000000000040b940" + // field 18, encoding 1, value 6464.0
+		"9a0106" + "737472696e67" + // field 19, encoding 2, string "string"
+		"b304" + // field 70, encoding 3, start group
+		"ba0408" + "7265717569726564" + // field 71, encoding 2, string "required"
+		"b404" + // field 70, encoding 4, end group
+		"aa0605" + "6279746573" + // field 101, encoding 2, string "bytes"
+		"b0063f" + // field 102, encoding 0, 0x3f zigzag32
+		"b8067f" // field 103, encoding 0, 0x7f zigzag64
+
+	o := old()
+	bytes, err := Marshal(pb)
+	if _, ok := err.(*ErrRequiredNotSet); !ok {
+		fmt.Printf("marshal-1 err = %v, want *ErrRequiredNotSet", err)
+		o.DebugPrint("", bytes)
+		t.Fatalf("expected = %s", expected)
+	}
+	if strings.Index(err.Error(), "RequiredField.Label") < 0 {
+		t.Errorf("marshal-1 wrong err msg: %v", err)
+	}
+	if !equal(bytes, expected, t) {
+		o.DebugPrint("neq 1", bytes)
+		t.Fatalf("expected = %s", expected)
+	}
+
+	// Now test Unmarshal by recreating the original buffer.
+	pbd := new(GoTest)
+	err = Unmarshal(bytes, pbd)
+	if _, ok := err.(*ErrRequiredNotSet); !ok {
+		t.Fatalf("unmarshal err = %v, want *ErrRequiredNotSet", err)
+		o.DebugPrint("", bytes)
+		t.Fatalf("string = %s", expected)
+	}
+	if strings.Index(err.Error(), "RequiredField.{Unknown}") < 0 {
+		t.Errorf("unmarshal wrong err msg: %v", err)
+	}
+	bytes, err = Marshal(pbd)
+	if _, ok := err.(*ErrRequiredNotSet); !ok {
+		t.Errorf("marshal-2 err = %v, want *ErrRequiredNotSet", err)
+		o.DebugPrint("", bytes)
+		t.Fatalf("string = %s", expected)
+	}
+	if strings.Index(err.Error(), "RequiredField.Label") < 0 {
+		t.Errorf("marshal-2 wrong err msg: %v", err)
+	}
+	if !equal(bytes, expected, t) {
+		o.DebugPrint("neq 2", bytes)
+		t.Fatalf("string = %s", expected)
+	}
+}
+
 func fuzzUnmarshal(t *testing.T, data []byte) {
 func fuzzUnmarshal(t *testing.T, data []byte) {
 	defer func() {
 	defer func() {
 		if e := recover(); e != nil {
 		if e := recover(); e != nil {

+ 13 - 3
third_party/code.google.com/p/goprotobuf/proto/decode.go

@@ -46,7 +46,7 @@ import (
 // ErrWrongType occurs when the wire encoding for the field disagrees with
 // ErrWrongType occurs when the wire encoding for the field disagrees with
 // that specified in the type being decoded.  This is usually caused by attempting
 // that specified in the type being decoded.  This is usually caused by attempting
 // to convert an encoded protocol buffer into a struct of the wrong type.
 // to convert an encoded protocol buffer into a struct of the wrong type.
-var ErrWrongType = errors.New("field/encoding mismatch: wrong type for field")
+var ErrWrongType = errors.New("proto: field/encoding mismatch: wrong type for field")
 
 
 // errOverflow is returned when an integer is too large to be represented.
 // errOverflow is returned when an integer is too large to be represented.
 var errOverflow = errors.New("proto: integer overflow")
 var errOverflow = errors.New("proto: integer overflow")
@@ -353,6 +353,7 @@ func (p *Buffer) Unmarshal(pb Message) error {
 
 
 // unmarshalType does the work of unmarshaling a structure.
 // unmarshalType does the work of unmarshaling a structure.
 func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
 func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group bool, base structPointer) error {
+	var state errorState
 	required, reqFields := prop.reqCount, uint64(0)
 	required, reqFields := prop.reqCount, uint64(0)
 
 
 	var err error
 	var err error
@@ -406,7 +407,10 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group
 				continue
 				continue
 			}
 			}
 		}
 		}
-		err = dec(o, p, base)
+		decErr := dec(o, p, base)
+		if decErr != nil && !state.shouldContinue(decErr, p) {
+			err = decErr
+		}
 		if err == nil && p.Required {
 		if err == nil && p.Required {
 			// Successfully decoded a required field.
 			// Successfully decoded a required field.
 			if tag <= 64 {
 			if tag <= 64 {
@@ -430,8 +434,14 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group
 		if is_group {
 		if is_group {
 			return io.ErrUnexpectedEOF
 			return io.ErrUnexpectedEOF
 		}
 		}
+		if state.err != nil {
+			return state.err
+		}
 		if required > 0 {
 		if required > 0 {
-			return &ErrRequiredNotSet{st}
+			// Not enough information to determine the exact field. If we use extra
+			// CPU, we could determine the field only if the missing required field
+			// has a tag <= 64 and we check reqFields.
+			return &ErrRequiredNotSet{"{Unknown}"}
 		}
 		}
 	}
 	}
 	return err
 	return err

+ 56 - 22
third_party/code.google.com/p/goprotobuf/proto/encode.go

@@ -37,6 +37,7 @@ package proto
 
 
 import (
 import (
 	"errors"
 	"errors"
+	"fmt"
 	"reflect"
 	"reflect"
 	"sort"
 	"sort"
 )
 )
@@ -46,12 +47,16 @@ import (
 // all been initialized. It is also the error returned if Unmarshal is
 // all been initialized. It is also the error returned if Unmarshal is
 // called with an encoded protocol buffer that does not include all the
 // called with an encoded protocol buffer that does not include all the
 // required fields.
 // required fields.
+//
+// When printed, ErrRequiredNotSet reports the first unset required field in a
+// message. If the field cannot be precisely determined, it is reported as
+// "{Unknown}".
 type ErrRequiredNotSet struct {
 type ErrRequiredNotSet struct {
-	t reflect.Type
+	field string
 }
 }
 
 
 func (e *ErrRequiredNotSet) Error() string {
 func (e *ErrRequiredNotSet) Error() string {
-	return "proto: required fields not set in " + e.t.String()
+	return fmt.Sprintf("proto: required field %q not set", e.field)
 }
 }
 
 
 var (
 var (
@@ -175,7 +180,8 @@ func Marshal(pb Message) ([]byte, error) {
 	}
 	}
 	p := NewBuffer(nil)
 	p := NewBuffer(nil)
 	err := p.Marshal(pb)
 	err := p.Marshal(pb)
-	if err != nil {
+	var state errorState
+	if err != nil && !state.shouldContinue(err, nil) {
 		return nil, err
 		return nil, err
 	}
 	}
 	return p.buf, err
 	return p.buf, err
@@ -274,6 +280,7 @@ func isNil(v reflect.Value) bool {
 
 
 // Encode a message struct.
 // Encode a message struct.
 func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
 func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
+	var state errorState
 	structp := structPointer_GetStructPointer(base, p.field)
 	structp := structPointer_GetStructPointer(base, p.field)
 	if structPointer_IsNil(structp) {
 	if structPointer_IsNil(structp) {
 		return ErrNil
 		return ErrNil
@@ -283,7 +290,7 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
 	if p.isMarshaler {
 	if p.isMarshaler {
 		m := structPointer_Interface(structp, p.stype).(Marshaler)
 		m := structPointer_Interface(structp, p.stype).(Marshaler)
 		data, err := m.Marshal()
 		data, err := m.Marshal()
-		if err != nil {
+		if err != nil && !state.shouldContinue(err, nil) {
 			return err
 			return err
 		}
 		}
 		o.buf = append(o.buf, p.tagcode...)
 		o.buf = append(o.buf, p.tagcode...)
@@ -300,18 +307,19 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
 
 
 	nbuf := o.buf
 	nbuf := o.buf
 	o.buf = obuf
 	o.buf = obuf
-	if err != nil {
+	if err != nil && !state.shouldContinue(err, nil) {
 		o.buffree(nbuf)
 		o.buffree(nbuf)
 		return err
 		return err
 	}
 	}
 	o.buf = append(o.buf, p.tagcode...)
 	o.buf = append(o.buf, p.tagcode...)
 	o.EncodeRawBytes(nbuf)
 	o.EncodeRawBytes(nbuf)
 	o.buffree(nbuf)
 	o.buffree(nbuf)
-	return nil
+	return state.err
 }
 }
 
 
 // Encode a group struct.
 // Encode a group struct.
 func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
 func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
+	var state errorState
 	b := structPointer_GetStructPointer(base, p.field)
 	b := structPointer_GetStructPointer(base, p.field)
 	if structPointer_IsNil(b) {
 	if structPointer_IsNil(b) {
 		return ErrNil
 		return ErrNil
@@ -319,11 +327,11 @@ func (o *Buffer) enc_struct_group(p *Properties, base structPointer) error {
 
 
 	o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
 	o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
 	err := o.enc_struct(p.stype, p.sprop, b)
 	err := o.enc_struct(p.stype, p.sprop, b)
-	if err != nil {
+	if err != nil && !state.shouldContinue(err, nil) {
 		return err
 		return err
 	}
 	}
 	o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
 	o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
-	return nil
+	return state.err
 }
 }
 
 
 // Encode a slice of bools ([]bool).
 // Encode a slice of bools ([]bool).
@@ -470,6 +478,7 @@ func (o *Buffer) enc_slice_string(p *Properties, base structPointer) error {
 
 
 // Encode a slice of message structs ([]*struct).
 // Encode a slice of message structs ([]*struct).
 func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error {
 func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) error {
+	var state errorState
 	s := structPointer_StructPointerSlice(base, p.field)
 	s := structPointer_StructPointerSlice(base, p.field)
 	l := s.Len()
 	l := s.Len()
 
 
@@ -483,7 +492,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
 		if p.isMarshaler {
 		if p.isMarshaler {
 			m := structPointer_Interface(structp, p.stype).(Marshaler)
 			m := structPointer_Interface(structp, p.stype).(Marshaler)
 			data, err := m.Marshal()
 			data, err := m.Marshal()
-			if err != nil {
+			if err != nil && !state.shouldContinue(err, nil) {
 				return err
 				return err
 			}
 			}
 			o.buf = append(o.buf, p.tagcode...)
 			o.buf = append(o.buf, p.tagcode...)
@@ -498,7 +507,7 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
 
 
 		nbuf := o.buf
 		nbuf := o.buf
 		o.buf = obuf
 		o.buf = obuf
-		if err != nil {
+		if err != nil && !state.shouldContinue(err, nil) {
 			o.buffree(nbuf)
 			o.buffree(nbuf)
 			if err == ErrNil {
 			if err == ErrNil {
 				return ErrRepeatedHasNil
 				return ErrRepeatedHasNil
@@ -510,11 +519,12 @@ func (o *Buffer) enc_slice_struct_message(p *Properties, base structPointer) err
 
 
 		o.buffree(nbuf)
 		o.buffree(nbuf)
 	}
 	}
-	return nil
+	return state.err
 }
 }
 
 
 // Encode a slice of group structs ([]*struct).
 // Encode a slice of group structs ([]*struct).
 func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error {
 func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error {
+	var state errorState
 	s := structPointer_StructPointerSlice(base, p.field)
 	s := structPointer_StructPointerSlice(base, p.field)
 	l := s.Len()
 	l := s.Len()
 
 
@@ -528,7 +538,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error
 
 
 		err := o.enc_struct(p.stype, p.sprop, b)
 		err := o.enc_struct(p.stype, p.sprop, b)
 
 
-		if err != nil {
+		if err != nil && !state.shouldContinue(err, nil) {
 			if err == ErrNil {
 			if err == ErrNil {
 				return ErrRepeatedHasNil
 				return ErrRepeatedHasNil
 			}
 			}
@@ -537,7 +547,7 @@ func (o *Buffer) enc_slice_struct_group(p *Properties, base structPointer) error
 
 
 		o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
 		o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
 	}
 	}
-	return nil
+	return state.err
 }
 }
 
 
 // Encode an extension map.
 // Encode an extension map.
@@ -569,7 +579,7 @@ func (o *Buffer) enc_map(p *Properties, base structPointer) error {
 
 
 // Encode a struct.
 // Encode a struct.
 func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structPointer) error {
 func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structPointer) error {
-	required := prop.reqCount
+	var state errorState
 	// Encode fields in tag order so that decoders may use optimizations
 	// Encode fields in tag order so that decoders may use optimizations
 	// that depend on the ordering.
 	// that depend on the ordering.
 	// http://code.google.com/apis/protocolbuffers/docs/encoding.html#order
 	// http://code.google.com/apis/protocolbuffers/docs/encoding.html#order
@@ -577,19 +587,15 @@ func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structP
 		p := prop.Prop[i]
 		p := prop.Prop[i]
 		if p.enc != nil {
 		if p.enc != nil {
 			err := p.enc(o, p, base)
 			err := p.enc(o, p, base)
-			if err != nil {
+			if err != nil && !state.shouldContinue(err, p) {
 				if err != ErrNil {
 				if err != ErrNil {
 					return err
 					return err
+				} else if p.Required && state.err == nil {
+					state.err = &ErrRequiredNotSet{p.Name}
 				}
 				}
-			} else if p.Required {
-				required--
 			}
 			}
 		}
 		}
 	}
 	}
-	// See if we encoded all required fields.
-	if required > 0 {
-		return &ErrRequiredNotSet{t}
-	}
 
 
 	// Add unrecognized fields at the end.
 	// Add unrecognized fields at the end.
 	if prop.unrecField.IsValid() {
 	if prop.unrecField.IsValid() {
@@ -599,5 +605,33 @@ func (o *Buffer) enc_struct(t reflect.Type, prop *StructProperties, base structP
 		}
 		}
 	}
 	}
 
 
-	return nil
+	return state.err
+}
+
+// errorState maintains the first error that occurs and updates that error
+// with additional context.
+type errorState struct {
+	err error
+}
+
+// shouldContinue reports whether encoding should continue upon encountering the
+// given error. If the error is ErrRequiredNotSet, shouldContinue returns true
+// and, if this is the first appearance of that error, remembers it for future
+// reporting.
+//
+// If prop is not nil, it may update any error with additional context about the
+// field with the error.
+func (s *errorState) shouldContinue(err error, prop *Properties) bool {
+	// Ignore unset required fields.
+	reqNotSet, ok := err.(*ErrRequiredNotSet)
+	if !ok {
+		return false
+	}
+	if s.err == nil {
+		if prop != nil {
+			err = &ErrRequiredNotSet{prop.Name + "." + reqNotSet.field}
+		}
+		s.err = err
+	}
+	return true
 }
 }

+ 4 - 4
third_party/code.google.com/p/goprotobuf/proto/extensions.go

@@ -109,11 +109,11 @@ func isExtensionField(pb extendableProto, field int32) bool {
 func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
 func checkExtensionTypes(pb extendableProto, extension *ExtensionDesc) error {
 	// Check the extended type.
 	// Check the extended type.
 	if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
 	if a, b := reflect.TypeOf(pb), reflect.TypeOf(extension.ExtendedType); a != b {
-		return errors.New("bad extended type; " + b.String() + " does not extend " + a.String())
+		return errors.New("proto: bad extended type; " + b.String() + " does not extend " + a.String())
 	}
 	}
 	// Check the range.
 	// Check the range.
 	if !isExtensionField(pb, extension.Field) {
 	if !isExtensionField(pb, extension.Field) {
-		return errors.New("bad extension number; not in declared ranges")
+		return errors.New("proto: bad extension number; not in declared ranges")
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -272,7 +272,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
 func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
 func GetExtensions(pb Message, es []*ExtensionDesc) (extensions []interface{}, err error) {
 	epb, ok := pb.(extendableProto)
 	epb, ok := pb.(extendableProto)
 	if !ok {
 	if !ok {
-		err = errors.New("not an extendable proto")
+		err = errors.New("proto: not an extendable proto")
 		return
 		return
 	}
 	}
 	extensions = make([]interface{}, len(es))
 	extensions = make([]interface{}, len(es))
@@ -292,7 +292,7 @@ func SetExtension(pb extendableProto, extension *ExtensionDesc, value interface{
 	}
 	}
 	typ := reflect.TypeOf(extension.ExtensionType)
 	typ := reflect.TypeOf(extension.ExtensionType)
 	if typ != reflect.TypeOf(value) {
 	if typ != reflect.TypeOf(value) {
-		return errors.New("bad extension value type")
+		return errors.New("proto: bad extension value type")
 	}
 	}
 
 
 	pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}
 	pb.ExtensionMap()[extension.Field] = Extension{desc: extension, value: value}

+ 3 - 3
third_party/code.google.com/p/goprotobuf/proto/testdata/test.pb.go

@@ -244,7 +244,7 @@ func (m *GoEnum) GetFoo() FOO {
 	if m != nil && m.Foo != nil {
 	if m != nil && m.Foo != nil {
 		return *m.Foo
 		return *m.Foo
 	}
 	}
-	return 0
+	return FOO_FOO1
 }
 }
 
 
 type GoTestField struct {
 type GoTestField struct {
@@ -378,7 +378,7 @@ func (m *GoTest) GetKind() GoTest_KIND {
 	if m != nil && m.Kind != nil {
 	if m != nil && m.Kind != nil {
 		return *m.Kind
 		return *m.Kind
 	}
 	}
-	return 0
+	return GoTest_VOID
 }
 }
 
 
 func (m *GoTest) GetTable() string {
 func (m *GoTest) GetTable() string {
@@ -1289,7 +1289,7 @@ func (m *MyMessage) GetBikeshed() MyMessage_Color {
 	if m != nil && m.Bikeshed != nil {
 	if m != nil && m.Bikeshed != nil {
 		return *m.Bikeshed
 		return *m.Bikeshed
 	}
 	}
-	return 0
+	return MyMessage_RED
 }
 }
 
 
 func (m *MyMessage) GetSomegroup() *MyMessage_SomeGroup {
 func (m *MyMessage) GetSomegroup() *MyMessage_SomeGroup {

+ 2 - 2
third_party/code.google.com/p/goprotobuf/proto/text_parser.go

@@ -193,8 +193,8 @@ func (p *textParser) advance() {
 }
 }
 
 
 var (
 var (
-	errBadUTF8 = errors.New("bad UTF-8")
-	errBadHex  = errors.New("bad hexadecimal")
+	errBadUTF8 = errors.New("proto: bad UTF-8")
+	errBadHex  = errors.New("proto: bad hexadecimal")
 )
 )
 
 
 func unquoteC(s string, quote rune) (string, error) {
 func unquoteC(s string, quote rune) (string, error) {

+ 1 - 1
third_party/code.google.com/p/goprotobuf/proto/text_test.go

@@ -303,7 +303,7 @@ type limitedWriter struct {
 	limit int
 	limit int
 }
 }
 
 
-var outOfSpace = errors.New("insufficient space")
+var outOfSpace = errors.New("proto: insufficient space")
 
 
 func (w *limitedWriter) Write(p []byte) (n int, err error) {
 func (w *limitedWriter) Write(p []byte) (n int, err error) {
 	var avail = w.limit - w.b.Len()
 	var avail = w.limit - w.b.Len()

+ 2 - 2
third_party/code.google.com/p/goprotobuf/protoc-gen-go/descriptor/descriptor.pb.go

@@ -487,14 +487,14 @@ func (m *FieldDescriptorProto) GetLabel() FieldDescriptorProto_Label {
 	if m != nil && m.Label != nil {
 	if m != nil && m.Label != nil {
 		return *m.Label
 		return *m.Label
 	}
 	}
-	return 0
+	return FieldDescriptorProto_LABEL_OPTIONAL
 }
 }
 
 
 func (m *FieldDescriptorProto) GetType() FieldDescriptorProto_Type {
 func (m *FieldDescriptorProto) GetType() FieldDescriptorProto_Type {
 	if m != nil && m.Type != nil {
 	if m != nil && m.Type != nil {
 		return *m.Type
 		return *m.Type
 	}
 	}
-	return 0
+	return FieldDescriptorProto_TYPE_DOUBLE
 }
 }
 
 
 func (m *FieldDescriptorProto) GetTypeName() string {
 func (m *FieldDescriptorProto) GetTypeName() string {

+ 21 - 0
third_party/code.google.com/p/goprotobuf/protoc-gen-go/generator/generator.go

@@ -1664,6 +1664,27 @@ func (g *Generator) generateMessage(message *Descriptor) {
 				g.P("return false")
 				g.P("return false")
 			case descriptor.FieldDescriptorProto_TYPE_STRING:
 			case descriptor.FieldDescriptorProto_TYPE_STRING:
 				g.P(`return ""`)
 				g.P(`return ""`)
+			case descriptor.FieldDescriptorProto_TYPE_ENUM:
+				// The default default for an enum is the first value in the enum,
+				// not zero.
+				obj := g.ObjectNamed(field.GetTypeName())
+				var enum *EnumDescriptor
+				if id, ok := obj.(*ImportedDescriptor); ok {
+					// The enum type has been publicly imported.
+					enum, _ = id.o.(*EnumDescriptor)
+				} else {
+					enum, _ = obj.(*EnumDescriptor)
+				}
+				if enum == nil {
+					log.Printf("don't know how to generate getter for %s", field.GetName())
+					continue
+				}
+				if len(enum.Value) == 0 {
+					g.P("return 0 // empty enum")
+				} else {
+					first := enum.Value[0].GetName()
+					g.P("return ", g.DefaultPackageName(obj)+enum.prefix()+first)
+				}
 			default:
 			default:
 				g.P("return 0")
 				g.P("return 0")
 			}
 			}

+ 1 - 1
third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.pb.go

@@ -199,7 +199,7 @@ func (m *Request) GetHue() Request_Color {
 	if m != nil && m.Hue != nil {
 	if m != nil && m.Hue != nil {
 		return *m.Hue
 		return *m.Hue
 	}
 	}
-	return 0
+	return Request_RED
 }
 }
 
 
 func (m *Request) GetHat() HatType {
 func (m *Request) GetHat() HatType {

+ 1 - 1
third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.pb.go.golden

@@ -199,7 +199,7 @@ func (m *Request) GetHue() Request_Color {
 	if m != nil && m.Hue != nil {
 	if m != nil && m.Hue != nil {
 		return *m.Hue
 		return *m.Hue
 	}
 	}
-	return 0
+	return Request_RED
 }
 }
 
 
 func (m *Request) GetHat() HatType {
 func (m *Request) GetHat() HatType {

+ 1 - 1
third_party/code.google.com/p/goprotobuf/protoc-gen-go/testdata/my_test/test.proto

@@ -58,7 +58,7 @@ message Request {
   }
   }
   repeated int64 key = 1;
   repeated int64 key = 1;
 //  optional imp.ImportedMessage imported_message = 2;
 //  optional imp.ImportedMessage imported_message = 2;
-  optional Color hue = 3;
+  optional Color hue = 3; // no default
   optional HatType hat = 4 [default=FEDORA];
   optional HatType hat = 4 [default=FEDORA];
 //  optional imp.ImportedMessage.Owner owner = 6;
 //  optional imp.ImportedMessage.Owner owner = 6;
   optional float deadline = 7 [default=inf];
   optional float deadline = 7 [default=inf];

+ 2 - 2
third_party/github.com/coreos/go-raft/append_entries_request.go

@@ -31,7 +31,7 @@ func newAppendEntriesRequest(term uint64, prevLogIndex uint64, prevLogTerm uint6
 
 
 // Encodes the AppendEntriesRequest to a buffer. Returns the number of bytes
 // Encodes the AppendEntriesRequest to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (req *AppendEntriesRequest) encode(w io.Writer) (int, error) {
+func (req *AppendEntriesRequest) Encode(w io.Writer) (int, error) {
 
 
 	protoEntries := make([]*protobuf.ProtoAppendEntriesRequest_ProtoLogEntry, len(req.Entries))
 	protoEntries := make([]*protobuf.ProtoAppendEntriesRequest_ProtoLogEntry, len(req.Entries))
 
 
@@ -63,7 +63,7 @@ func (req *AppendEntriesRequest) encode(w io.Writer) (int, error) {
 
 
 // Decodes the AppendEntriesRequest from a buffer. Returns the number of bytes read and
 // Decodes the AppendEntriesRequest from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (req *AppendEntriesRequest) decode(r io.Reader) (int, error) {
+func (req *AppendEntriesRequest) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 3 - 3
third_party/github.com/coreos/go-raft/append_entries_request_test.go

@@ -10,7 +10,7 @@ func BenchmarkAppendEntriesRequestEncoding(b *testing.B) {
 	b.ResetTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {
 		var buf bytes.Buffer
 		var buf bytes.Buffer
-		req.encode(&buf)
+		req.Encode(&buf)
 	}
 	}
 	b.SetBytes(int64(len(tmp)))
 	b.SetBytes(int64(len(tmp)))
 }
 }
@@ -19,7 +19,7 @@ func BenchmarkAppendEntriesRequestDecoding(b *testing.B) {
 	req, buf := createTestAppendEntriesRequest(2000)
 	req, buf := createTestAppendEntriesRequest(2000)
 	b.ResetTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {
-		req.decode(bytes.NewReader(buf))
+		req.Decode(bytes.NewReader(buf))
 	}
 	}
 	b.SetBytes(int64(len(buf)))
 	b.SetBytes(int64(len(buf)))
 }
 }
@@ -34,7 +34,7 @@ func createTestAppendEntriesRequest(entryCount int) (*AppendEntriesRequest, []by
 	req := newAppendEntriesRequest(1, 1, 1, 1, "leader", entries)
 	req := newAppendEntriesRequest(1, 1, 1, 1, "leader", entries)
 
 
 	var buf bytes.Buffer
 	var buf bytes.Buffer
-	req.encode(&buf)
+	req.Encode(&buf)
 
 
 	return req, buf.Bytes()
 	return req, buf.Bytes()
 }
 }

+ 2 - 2
third_party/github.com/coreos/go-raft/append_entries_response.go

@@ -30,7 +30,7 @@ func newAppendEntriesResponse(term uint64, success bool, index uint64, commitInd
 
 
 // Encodes the AppendEntriesResponse to a buffer. Returns the number of bytes
 // Encodes the AppendEntriesResponse to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (resp *AppendEntriesResponse) encode(w io.Writer) (int, error) {
+func (resp *AppendEntriesResponse) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoAppendEntriesResponse{
 	pb := &protobuf.ProtoAppendEntriesResponse{
 		Term:        proto.Uint64(resp.Term),
 		Term:        proto.Uint64(resp.Term),
 		Index:       proto.Uint64(resp.Index),
 		Index:       proto.Uint64(resp.Index),
@@ -47,7 +47,7 @@ func (resp *AppendEntriesResponse) encode(w io.Writer) (int, error) {
 
 
 // Decodes the AppendEntriesResponse from a buffer. Returns the number of bytes read and
 // Decodes the AppendEntriesResponse from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (resp *AppendEntriesResponse) decode(r io.Reader) (int, error) {
+func (resp *AppendEntriesResponse) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 3 - 3
third_party/github.com/coreos/go-raft/append_entries_response_test.go

@@ -10,7 +10,7 @@ func BenchmarkAppendEntriesResponseEncoding(b *testing.B) {
 	b.ResetTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {
 		var buf bytes.Buffer
 		var buf bytes.Buffer
-		req.encode(&buf)
+		req.Encode(&buf)
 	}
 	}
 	b.SetBytes(int64(len(tmp)))
 	b.SetBytes(int64(len(tmp)))
 }
 }
@@ -19,7 +19,7 @@ func BenchmarkAppendEntriesResponseDecoding(b *testing.B) {
 	req, buf := createTestAppendEntriesResponse(2000)
 	req, buf := createTestAppendEntriesResponse(2000)
 	b.ResetTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {
-		req.decode(bytes.NewReader(buf))
+		req.Decode(bytes.NewReader(buf))
 	}
 	}
 	b.SetBytes(int64(len(buf)))
 	b.SetBytes(int64(len(buf)))
 }
 }
@@ -28,7 +28,7 @@ func createTestAppendEntriesResponse(entryCount int) (*AppendEntriesResponse, []
 	resp := newAppendEntriesResponse(1, true, 1, 1)
 	resp := newAppendEntriesResponse(1, true, 1, 1)
 
 
 	var buf bytes.Buffer
 	var buf bytes.Buffer
-	resp.encode(&buf)
+	resp.Encode(&buf)
 
 
 	return resp, buf.Bytes()
 	return resp, buf.Bytes()
 }
 }

+ 8 - 8
third_party/github.com/coreos/go-raft/http_transporter.go

@@ -89,7 +89,7 @@ func (t *HTTPTransporter) Install(server *Server, mux HTTPMuxer) {
 // Sends an AppendEntries RPC to a peer.
 // Sends an AppendEntries RPC to a peer.
 func (t *HTTPTransporter) SendAppendEntriesRequest(server *Server, peer *Peer, req *AppendEntriesRequest) *AppendEntriesResponse {
 func (t *HTTPTransporter) SendAppendEntriesRequest(server *Server, peer *Peer, req *AppendEntriesRequest) *AppendEntriesResponse {
 	var b bytes.Buffer
 	var b bytes.Buffer
-	if _, err := req.encode(&b); err != nil {
+	if _, err := req.Encode(&b); err != nil {
 		traceln("transporter.ae.encoding.error:", err)
 		traceln("transporter.ae.encoding.error:", err)
 		return nil
 		return nil
 	}
 	}
@@ -106,7 +106,7 @@ func (t *HTTPTransporter) SendAppendEntriesRequest(server *Server, peer *Peer, r
 	defer httpResp.Body.Close()
 	defer httpResp.Body.Close()
 
 
 	resp := &AppendEntriesResponse{}
 	resp := &AppendEntriesResponse{}
-	if _, err = resp.decode(httpResp.Body); err != nil && err != io.EOF {
+	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
 		traceln("transporter.ae.decoding.error:", err)
 		traceln("transporter.ae.decoding.error:", err)
 		return nil
 		return nil
 	}
 	}
@@ -117,7 +117,7 @@ func (t *HTTPTransporter) SendAppendEntriesRequest(server *Server, peer *Peer, r
 // Sends a RequestVote RPC to a peer.
 // Sends a RequestVote RPC to a peer.
 func (t *HTTPTransporter) SendVoteRequest(server *Server, peer *Peer, req *RequestVoteRequest) *RequestVoteResponse {
 func (t *HTTPTransporter) SendVoteRequest(server *Server, peer *Peer, req *RequestVoteRequest) *RequestVoteResponse {
 	var b bytes.Buffer
 	var b bytes.Buffer
-	if _, err := req.encode(&b); err != nil {
+	if _, err := req.Encode(&b); err != nil {
 		traceln("transporter.rv.encoding.error:", err)
 		traceln("transporter.rv.encoding.error:", err)
 		return nil
 		return nil
 	}
 	}
@@ -134,7 +134,7 @@ func (t *HTTPTransporter) SendVoteRequest(server *Server, peer *Peer, req *Reque
 	defer httpResp.Body.Close()
 	defer httpResp.Body.Close()
 
 
 	resp := &RequestVoteResponse{}
 	resp := &RequestVoteResponse{}
-	if _, err = resp.decode(httpResp.Body); err != nil && err != io.EOF {
+	if _, err = resp.Decode(httpResp.Body); err != nil && err != io.EOF {
 		traceln("transporter.rv.decoding.error:", err)
 		traceln("transporter.rv.decoding.error:", err)
 		return nil
 		return nil
 	}
 	}
@@ -162,13 +162,13 @@ func (t *HTTPTransporter) appendEntriesHandler(server *Server) http.HandlerFunc
 		traceln(server.Name(), "RECV /appendEntries")
 		traceln(server.Name(), "RECV /appendEntries")
 
 
 		req := &AppendEntriesRequest{}
 		req := &AppendEntriesRequest{}
-		if _, err := req.decode(r.Body); err != nil {
+		if _, err := req.Decode(r.Body); err != nil {
 			http.Error(w, "", http.StatusBadRequest)
 			http.Error(w, "", http.StatusBadRequest)
 			return
 			return
 		}
 		}
 
 
 		resp := server.AppendEntries(req)
 		resp := server.AppendEntries(req)
-		if _, err := resp.encode(w); err != nil {
+		if _, err := resp.Encode(w); err != nil {
 			http.Error(w, "", http.StatusInternalServerError)
 			http.Error(w, "", http.StatusInternalServerError)
 			return
 			return
 		}
 		}
@@ -181,13 +181,13 @@ func (t *HTTPTransporter) requestVoteHandler(server *Server) http.HandlerFunc {
 		traceln(server.Name(), "RECV /requestVote")
 		traceln(server.Name(), "RECV /requestVote")
 
 
 		req := &RequestVoteRequest{}
 		req := &RequestVoteRequest{}
-		if _, err := req.decode(r.Body); err != nil {
+		if _, err := req.Decode(r.Body); err != nil {
 			http.Error(w, "", http.StatusBadRequest)
 			http.Error(w, "", http.StatusBadRequest)
 			return
 			return
 		}
 		}
 
 
 		resp := server.RequestVote(req)
 		resp := server.RequestVote(req)
-		if _, err := resp.encode(w); err != nil {
+		if _, err := resp.Encode(w); err != nil {
 			http.Error(w, "", http.StatusInternalServerError)
 			http.Error(w, "", http.StatusInternalServerError)
 			return
 			return
 		}
 		}

+ 16 - 14
third_party/github.com/coreos/go-raft/log.go

@@ -180,26 +180,23 @@ func (l *Log) open(path string) error {
 			}
 			}
 			break
 			break
 		}
 		}
-
-		// Append entry.
-		l.entries = append(l.entries, entry)
-
-		if entry.Index <= l.commitIndex {
-			command, err := newCommand(entry.CommandName, entry.Command)
-			if err != nil {
-				continue
+		if entry.Index > l.startIndex {
+			// Append entry.
+			l.entries = append(l.entries, entry)
+			if entry.Index <= l.commitIndex {
+				command, err := newCommand(entry.CommandName, entry.Command)
+				if err != nil {
+					continue
+				}
+				l.ApplyFunc(command)
 			}
 			}
-			l.ApplyFunc(command)
+			debugln("open.log.append log index ", entry.Index)
 		}
 		}
 
 
-		debugln("open.log.append log index ", entry.Index)
-
 		readBytes += int64(n)
 		readBytes += int64(n)
 	}
 	}
 	l.results = make([]*logResult, len(l.entries))
 	l.results = make([]*logResult, len(l.entries))
 
 
-	l.compact(l.startIndex, l.startTerm)
-
 	debugln("open.log.recovery number of log ", len(l.entries))
 	debugln("open.log.recovery number of log ", len(l.entries))
 	return nil
 	return nil
 }
 }
@@ -273,6 +270,8 @@ func (l *Log) getEntriesAfter(index uint64, maxLogEntriesPerRequest uint64) ([]*
 	entries := l.entries[index-l.startIndex:]
 	entries := l.entries[index-l.startIndex:]
 	length := len(entries)
 	length := len(entries)
 
 
+	traceln("log.entriesAfter: startIndex:", l.startIndex, " lenght", len(l.entries))
+
 	if uint64(length) < maxLogEntriesPerRequest {
 	if uint64(length) < maxLogEntriesPerRequest {
 		// Determine the term at the given entry and return a subslice.
 		// Determine the term at the given entry and return a subslice.
 		return entries, l.entries[index-1-l.startIndex].Term
 		return entries, l.entries[index-1-l.startIndex].Term
@@ -353,7 +352,10 @@ func (l *Log) lastInfo() (index uint64, term uint64) {
 func (l *Log) updateCommitIndex(index uint64) {
 func (l *Log) updateCommitIndex(index uint64) {
 	l.mutex.Lock()
 	l.mutex.Lock()
 	defer l.mutex.Unlock()
 	defer l.mutex.Unlock()
-	l.commitIndex = index
+	if index > l.commitIndex {
+		l.commitIndex = index
+	}
+	debugln("update.commit.index ", index)
 }
 }
 
 
 // Updates the commit index and writes entries after that index to the stable storage.
 // Updates the commit index and writes entries after that index to the stable storage.

+ 6 - 0
third_party/github.com/coreos/go-raft/peer.go

@@ -255,6 +255,12 @@ func (p *Peer) sendSnapshotRecoveryRequest() {
 	req := newSnapshotRecoveryRequest(p.server.name, p.server.lastSnapshot)
 	req := newSnapshotRecoveryRequest(p.server.name, p.server.lastSnapshot)
 	debugln("peer.snap.recovery.send: ", p.Name)
 	debugln("peer.snap.recovery.send: ", p.Name)
 	resp := p.server.Transporter().SendSnapshotRecoveryRequest(p.server, p, req)
 	resp := p.server.Transporter().SendSnapshotRecoveryRequest(p.server, p, req)
+
+	if resp == nil {
+		debugln("peer.snap.recovery.timeout: ", p.Name)
+		return
+	}
+
 	if resp.Success {
 	if resp.Success {
 		p.prevLogIndex = req.LastIndex
 		p.prevLogIndex = req.LastIndex
 	} else {
 	} else {

+ 2 - 2
third_party/github.com/coreos/go-raft/request_vote_request.go

@@ -28,7 +28,7 @@ func newRequestVoteRequest(term uint64, candidateName string, lastLogIndex uint6
 
 
 // Encodes the RequestVoteRequest to a buffer. Returns the number of bytes
 // Encodes the RequestVoteRequest to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (req *RequestVoteRequest) encode(w io.Writer) (int, error) {
+func (req *RequestVoteRequest) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoRequestVoteRequest{
 	pb := &protobuf.ProtoRequestVoteRequest{
 		Term:          proto.Uint64(req.Term),
 		Term:          proto.Uint64(req.Term),
 		LastLogIndex:  proto.Uint64(req.LastLogIndex),
 		LastLogIndex:  proto.Uint64(req.LastLogIndex),
@@ -45,7 +45,7 @@ func (req *RequestVoteRequest) encode(w io.Writer) (int, error) {
 
 
 // Decodes the RequestVoteRequest from a buffer. Returns the number of bytes read and
 // Decodes the RequestVoteRequest from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (req *RequestVoteRequest) decode(r io.Reader) (int, error) {
+func (req *RequestVoteRequest) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 2 - 2
third_party/github.com/coreos/go-raft/request_vote_response.go

@@ -24,7 +24,7 @@ func newRequestVoteResponse(term uint64, voteGranted bool) *RequestVoteResponse
 
 
 // Encodes the RequestVoteResponse to a buffer. Returns the number of bytes
 // Encodes the RequestVoteResponse to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (resp *RequestVoteResponse) encode(w io.Writer) (int, error) {
+func (resp *RequestVoteResponse) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoRequestVoteResponse{
 	pb := &protobuf.ProtoRequestVoteResponse{
 		Term:        proto.Uint64(resp.Term),
 		Term:        proto.Uint64(resp.Term),
 		VoteGranted: proto.Bool(resp.VoteGranted),
 		VoteGranted: proto.Bool(resp.VoteGranted),
@@ -40,7 +40,7 @@ func (resp *RequestVoteResponse) encode(w io.Writer) (int, error) {
 
 
 // Decodes the RequestVoteResponse from a buffer. Returns the number of bytes read and
 // Decodes the RequestVoteResponse from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (resp *RequestVoteResponse) decode(r io.Reader) (int, error) {
+func (resp *RequestVoteResponse) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 14 - 4
third_party/github.com/coreos/go-raft/server.go

@@ -80,6 +80,8 @@ type Server struct {
 	lastSnapshot            *Snapshot
 	lastSnapshot            *Snapshot
 	stateMachine            StateMachine
 	stateMachine            StateMachine
 	maxLogEntriesPerRequest uint64
 	maxLogEntriesPerRequest uint64
+
+	connectionString string
 }
 }
 
 
 // An event to be processed by the server's event loop.
 // An event to be processed by the server's event loop.
@@ -96,7 +98,7 @@ type event struct {
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 // Creates a new server with a log at the given path.
 // Creates a new server with a log at the given path.
-func NewServer(name string, path string, transporter Transporter, stateMachine StateMachine, context interface{}) (*Server, error) {
+func NewServer(name string, path string, transporter Transporter, stateMachine StateMachine, context interface{}, connectionString string) (*Server, error) {
 	if name == "" {
 	if name == "" {
 		return nil, errors.New("raft.Server: Name cannot be blank")
 		return nil, errors.New("raft.Server: Name cannot be blank")
 	}
 	}
@@ -117,6 +119,7 @@ func NewServer(name string, path string, transporter Transporter, stateMachine S
 		electionTimeout:         DefaultElectionTimeout,
 		electionTimeout:         DefaultElectionTimeout,
 		heartbeatTimeout:        DefaultHeartbeatTimeout,
 		heartbeatTimeout:        DefaultHeartbeatTimeout,
 		maxLogEntriesPerRequest: MaxLogEntriesPerRequest,
 		maxLogEntriesPerRequest: MaxLogEntriesPerRequest,
+		connectionString:        connectionString,
 	}
 	}
 
 
 	// Setup apply function.
 	// Setup apply function.
@@ -1009,10 +1012,17 @@ func (s *Server) TakeSnapshot() error {
 		state = []byte{0}
 		state = []byte{0}
 	}
 	}
 
 
-	var peers []*Peer
+	peers := make([]*Peer, len(s.peers)+1)
 
 
+	i := 0
 	for _, peer := range s.peers {
 	for _, peer := range s.peers {
-		peers = append(peers, peer.clone())
+		peers[i] = peer.clone()
+		i++
+	}
+
+	peers[i] = &Peer{
+		Name:             s.Name(),
+		ConnectionString: s.connectionString,
 	}
 	}
 
 
 	s.currentSnapshot = &Snapshot{lastIndex, lastTerm, peers, state, path}
 	s.currentSnapshot = &Snapshot{lastIndex, lastTerm, peers, state, path}
@@ -1253,7 +1263,7 @@ func (s *Server) readConf() error {
 		return err
 		return err
 	}
 	}
 
 
-	s.log.commitIndex = conf.CommitIndex
+	s.log.updateCommitIndex(conf.CommitIndex)
 
 
 	return nil
 	return nil
 }
 }

+ 1 - 1
third_party/github.com/coreos/go-raft/server_test.go

@@ -428,7 +428,7 @@ func TestServerRecoverFromPreviousLogAndConf(t *testing.T) {
 	for _, name := range names {
 	for _, name := range names {
 		server := servers[name]
 		server := servers[name]
 		if server.CommitIndex() != 17 {
 		if server.CommitIndex() != 17 {
-			t.Fatalf("%s commitIndex is invalid [%d/%d]", name, server.CommitIndex(), 16)
+			t.Fatalf("%s commitIndex is invalid [%d/%d]", name, server.CommitIndex(), 17)
 		}
 		}
 		server.Stop()
 		server.Stop()
 	}
 	}

+ 2 - 2
third_party/github.com/coreos/go-raft/snapshot_recovery_request.go

@@ -35,7 +35,7 @@ func newSnapshotRecoveryRequest(leaderName string, snapshot *Snapshot) *Snapshot
 
 
 // Encodes the SnapshotRecoveryRequest to a buffer. Returns the number of bytes
 // Encodes the SnapshotRecoveryRequest to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (req *SnapshotRecoveryRequest) encode(w io.Writer) (int, error) {
+func (req *SnapshotRecoveryRequest) Encode(w io.Writer) (int, error) {
 
 
 	protoPeers := make([]*protobuf.ProtoSnapshotRecoveryRequest_ProtoPeer, len(req.Peers))
 	protoPeers := make([]*protobuf.ProtoSnapshotRecoveryRequest_ProtoPeer, len(req.Peers))
 
 
@@ -63,7 +63,7 @@ func (req *SnapshotRecoveryRequest) encode(w io.Writer) (int, error) {
 
 
 // Decodes the SnapshotRecoveryRequest from a buffer. Returns the number of bytes read and
 // Decodes the SnapshotRecoveryRequest from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (req *SnapshotRecoveryRequest) decode(r io.Reader) (int, error) {
+func (req *SnapshotRecoveryRequest) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 2 - 2
third_party/github.com/coreos/go-raft/snapshot_recovery_response.go

@@ -31,7 +31,7 @@ func newSnapshotRecoveryResponse(term uint64, success bool, commitIndex uint64)
 
 
 // Encodes the SnapshotRecoveryResponse to a buffer. Returns the number of bytes
 // Encodes the SnapshotRecoveryResponse to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (req *SnapshotRecoveryResponse) encode(w io.Writer) (int, error) {
+func (req *SnapshotRecoveryResponse) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoSnapshotRecoveryResponse{
 	pb := &protobuf.ProtoSnapshotRecoveryResponse{
 		Term:        proto.Uint64(req.Term),
 		Term:        proto.Uint64(req.Term),
 		Success:     proto.Bool(req.Success),
 		Success:     proto.Bool(req.Success),
@@ -47,7 +47,7 @@ func (req *SnapshotRecoveryResponse) encode(w io.Writer) (int, error) {
 
 
 // Decodes the SnapshotRecoveryResponse from a buffer. Returns the number of bytes read and
 // Decodes the SnapshotRecoveryResponse from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (req *SnapshotRecoveryResponse) decode(r io.Reader) (int, error) {
+func (req *SnapshotRecoveryResponse) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 2 - 2
third_party/github.com/coreos/go-raft/snapshot_request.go

@@ -31,7 +31,7 @@ func newSnapshotRequest(leaderName string, snapshot *Snapshot) *SnapshotRequest
 
 
 // Encodes the SnapshotRequest to a buffer. Returns the number of bytes
 // Encodes the SnapshotRequest to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (req *SnapshotRequest) encode(w io.Writer) (int, error) {
+func (req *SnapshotRequest) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoSnapshotRequest{
 	pb := &protobuf.ProtoSnapshotRequest{
 		LeaderName: proto.String(req.LeaderName),
 		LeaderName: proto.String(req.LeaderName),
 		LastIndex:  proto.Uint64(req.LastIndex),
 		LastIndex:  proto.Uint64(req.LastIndex),
@@ -47,7 +47,7 @@ func (req *SnapshotRequest) encode(w io.Writer) (int, error) {
 
 
 // Decodes the SnapshotRequest from a buffer. Returns the number of bytes read and
 // Decodes the SnapshotRequest from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (req *SnapshotRequest) decode(r io.Reader) (int, error) {
+func (req *SnapshotRequest) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 2 - 2
third_party/github.com/coreos/go-raft/snapshot_response.go

@@ -27,7 +27,7 @@ func newSnapshotResponse(success bool) *SnapshotResponse {
 
 
 // Encodes the SnapshotResponse to a buffer. Returns the number of bytes
 // Encodes the SnapshotResponse to a buffer. Returns the number of bytes
 // written and any error that may have occurred.
 // written and any error that may have occurred.
-func (resp *SnapshotResponse) encode(w io.Writer) (int, error) {
+func (resp *SnapshotResponse) Encode(w io.Writer) (int, error) {
 	pb := &protobuf.ProtoSnapshotResponse{
 	pb := &protobuf.ProtoSnapshotResponse{
 		Success: proto.Bool(resp.Success),
 		Success: proto.Bool(resp.Success),
 	}
 	}
@@ -41,7 +41,7 @@ func (resp *SnapshotResponse) encode(w io.Writer) (int, error) {
 
 
 // Decodes the SnapshotResponse from a buffer. Returns the number of bytes read and
 // Decodes the SnapshotResponse from a buffer. Returns the number of bytes read and
 // any error that occurs.
 // any error that occurs.
-func (resp *SnapshotResponse) decode(r io.Reader) (int, error) {
+func (resp *SnapshotResponse) Decode(r io.Reader) (int, error) {
 	data, err := ioutil.ReadAll(r)
 	data, err := ioutil.ReadAll(r)
 
 
 	if err != nil {
 	if err != nil {

+ 2 - 2
third_party/github.com/coreos/go-raft/test.go

@@ -65,12 +65,12 @@ func newTestServer(name string, transporter Transporter) *Server {
 	if err := os.MkdirAll(p, 0644); err != nil {
 	if err := os.MkdirAll(p, 0644); err != nil {
 		panic(err.Error())
 		panic(err.Error())
 	}
 	}
-	server, _ := NewServer(name, p, transporter, nil, nil)
+	server, _ := NewServer(name, p, transporter, nil, nil, "")
 	return server
 	return server
 }
 }
 
 
 func newTestServerWithPath(name string, transporter Transporter, p string) *Server {
 func newTestServerWithPath(name string, transporter Transporter, p string) *Server {
-	server, _ := NewServer(name, p, transporter, nil, nil)
+	server, _ := NewServer(name, p, transporter, nil, nil, "")
 	return server
 	return server
 }
 }
 
 

+ 2 - 2
transporter.go

@@ -66,7 +66,7 @@ func (t *transporter) SendAppendEntriesRequest(server *raft.Server, peer *raft.P
 
 
 	debugf("Send LogEntries to %s ", u)
 	debugf("Send LogEntries to %s ", u)
 
 
-	thisPeerStats, ok := r.peersStats[peer.Name]
+	thisPeerStats, ok := r.peersStats.Peers[peer.Name]
 
 
 	start := time.Now()
 	start := time.Now()
 
 
@@ -85,7 +85,7 @@ func (t *transporter) SendAppendEntriesRequest(server *raft.Server, peer *raft.P
 		}
 		}
 	}
 	}
 
 
-	r.peersStats[peer.Name] = thisPeerStats
+	r.peersStats.Peers[peer.Name] = thisPeerStats
 
 
 	if resp != nil {
 	if resp != nil {
 		defer resp.Body.Close()
 		defer resp.Body.Close()

+ 17 - 0
util.go

@@ -128,6 +128,23 @@ func sanitizeListenHost(listen string, advertised string) string {
 	return net.JoinHostPort(listen, aport)
 	return net.JoinHostPort(listen, aport)
 }
 }
 
 
+func redirect(node string, etcd bool, w http.ResponseWriter, req *http.Request) {
+	var url string
+	path := req.URL.Path
+
+	if etcd {
+		etcdAddr, _ := nameToEtcdURL(node)
+		url = etcdAddr + path
+	} else {
+		raftAddr, _ := nameToRaftURL(node)
+		url = raftAddr + path
+	}
+
+	debugf("Redirect to %s", url)
+
+	http.Redirect(w, req, url, http.StatusTemporaryRedirect)
+}
+
 func check(err error) {
 func check(err error) {
 	if err != nil {
 	if err != nil {
 		fatal(err)
 		fatal(err)