func newMemberCollection(ms []*etcdserver.Member) httptypes.MemberCollection { c := httptypes.MemberCollection(make([]httptypes.Member, len(ms))) for i, m := range ms { tm := httptypes.Member{ ID: strutil.IDAsHex(m.ID), Name: m.Name, PeerURLs: make([]string, len(m.PeerURLs)), ClientURLs: make([]string, len(m.ClientURLs)), } copy(tm.PeerURLs, m.PeerURLs) copy(tm.ClientURLs, m.ClientURLs) c[i] = tm } return c }
// send uses the given client to send a message to a member in the given // ClusterStore, retrying up to 3 times for each message. The given // ServerStats and LeaderStats are updated appropriately func send(c *http.Client, cl *Cluster, m raftpb.Message, ss *stats.ServerStats, ls *stats.LeaderStats) { cid := cl.ID() // TODO (xiangli): reasonable retry logic for i := 0; i < 3; i++ { memb := cl.Member(m.To) if memb == nil { // TODO: unknown peer id.. what do we do? I // don't think his should ever happen, need to // look into this further. log.Printf("etcdhttp: no member for %d", m.To) return } u := fmt.Sprintf("%s%s", memb.PickPeerURL(), raftPrefix) // TODO: don't block. we should be able to have 1000s // of messages out at a time. data, err := m.Marshal() if err != nil { log.Println("etcdhttp: dropping message:", err) return // drop bad message } if m.Type == raftpb.MsgApp { ss.SendAppendReq(len(data)) } to := strutil.IDAsHex(m.To) fs := ls.Follower(to) start := time.Now() sent := httpPost(c, u, cid, data) end := time.Now() if sent { fs.Succ(end.Sub(start)) return } fs.Fail() // TODO: backoff } }
func removedMemberStoreKey(id uint64) string { return path.Join(storeRemovedMembersPrefix, strutil.IDAsHex(id)) }
func (s *EtcdServer) UpdateRecvApp(from uint64, length int64) { s.stats.RecvAppendReq(strutil.IDAsHex(from), int(length)) }
// NewServer creates a new EtcdServer from the supplied configuration. The // configuration is considered static for the lifetime of the EtcdServer. func NewServer(cfg *ServerConfig) *EtcdServer { if err := os.MkdirAll(cfg.SnapDir(), privateDirMode); err != nil { log.Fatalf("etcdserver: cannot create snapshot directory: %v", err) } ss := snap.New(cfg.SnapDir()) st := store.New() var w *wal.WAL var n raft.Node var id uint64 haveWAL := wal.Exist(cfg.WALDir()) switch { case !haveWAL && cfg.ClusterState == ClusterStateValueExisting: cl, err := GetClusterFromPeers(cfg.Cluster.PeerURLs()) if err != nil { log.Fatal(err) } if err := cfg.Cluster.ValidateAndAssignIDs(cl.Members()); err != nil { log.Fatalf("etcdserver: %v", err) } cfg.Cluster.SetID(cl.id) cfg.Cluster.SetStore(st) id, n, w = startNode(cfg, nil) case !haveWAL && cfg.ClusterState == ClusterStateValueNew: if err := cfg.VerifyBootstrapConfig(); err != nil { log.Fatalf("etcdserver: %v", err) } m := cfg.Cluster.MemberByName(cfg.Name) if cfg.ShouldDiscover() { d, err := discovery.New(cfg.DiscoveryURL, m.ID, cfg.Cluster.String()) if err != nil { log.Fatalf("etcdserver: cannot init discovery %v", err) } s, err := d.Discover() if err != nil { log.Fatalf("etcdserver: %v", err) } if cfg.Cluster, err = NewClusterFromString(cfg.Cluster.name, s); err != nil { log.Fatalf("etcdserver: %v", err) } } cfg.Cluster.SetStore(st) id, n, w = startNode(cfg, cfg.Cluster.MemberIDs()) case haveWAL: if cfg.ShouldDiscover() { log.Printf("etcdserver: warn: ignoring discovery: etcd has already been initialized and has a valid log in %q", cfg.WALDir()) } var index uint64 snapshot, err := ss.Load() if err != nil && err != snap.ErrNoSnapshot { log.Fatal(err) } if snapshot != nil { log.Printf("etcdserver: recovering from snapshot at index %d", snapshot.Index) st.Recovery(snapshot.Data) index = snapshot.Index } cfg.Cluster = NewClusterFromStore(cfg.Cluster.name, st) id, n, w = restartNode(cfg, index, snapshot) default: log.Fatalf("etcdserver: unsupported bootstrap config") } sstats := &stats.ServerStats{ Name: cfg.Name, ID: strutil.IDAsHex(id), } lstats := stats.NewLeaderStats(strutil.IDAsHex(id)) s := &EtcdServer{ store: st, node: n, id: id, attributes: Attributes{Name: cfg.Name, ClientURLs: cfg.ClientURLs.StringSlice()}, Cluster: cfg.Cluster, storage: struct { *wal.WAL *snap.Snapshotter }{w, ss}, stats: sstats, lstats: lstats, send: Sender(cfg.Transport, cfg.Cluster, sstats, lstats), Ticker: time.Tick(100 * time.Millisecond), SyncTicker: time.Tick(500 * time.Millisecond), snapCount: cfg.SnapCount, } return s }