Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raft: synchronous raft conf change, safeguard on join/leave raft #131

Merged
merged 5 commits into from
Apr 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 75 additions & 32 deletions manager/state/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,99 @@ import (
"github.com/docker/swarm-v2/api"
)

// Cluster represents a set of active
// Cluster represents a raft cluster
type Cluster interface {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not defined these methods directly on the struct? Is there a plan to support multiple implementations of this interface?

// ID returns the cluster ID
ID() uint64
// Members returns a map of members identified by their raft ID
Members() map[uint64]*Member
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that map can be sorted.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is just a confusing description. It should say "indexed by their ID".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to return slice here to encourage a user to use it only for iteration and use GetMember for access by ID. But I'm okay with map too :)

// AddMember adds a member to the cluster memberlist
AddMember(*Member) error
// RemoveMember removes a member from the memberlist and add
// it to the remove set
RemoveMember(uint64) error
// Member retrieves a particular member based on ID, or nil if the
// member does not exist in the cluster
GetMember(id uint64) *Member
// IsIDRemoved checks whether the given ID has been removed from this
// cluster at some point in the past
IsIDRemoved(id uint64) bool
}

// cluster represents a set of active
// raft members
type Cluster struct {
lock sync.RWMutex
peers map[uint64]*Peer
type cluster struct {
id uint64

mu sync.RWMutex
members map[uint64]*Member

// removed contains the list of removed members,
// those ids cannot be reused
removed map[uint64]bool
}

// Peer represents a raft cluster peer
type Peer struct {
// Member represents a raft cluster member
type Member struct {
*api.RaftNode

Client *Raft
}

// NewCluster creates a new cluster neighbors
// list for a raft member
func NewCluster() *Cluster {
return &Cluster{
peers: make(map[uint64]*Peer),
func NewCluster() Cluster {
// TODO generate cluster ID

return &cluster{
members: make(map[uint64]*Member),
removed: make(map[uint64]bool),
}
}

// Peers returns the list of peers in the cluster
func (c *Cluster) Peers() map[uint64]*Peer {
peers := make(map[uint64]*Peer)
c.lock.RLock()
for k, v := range c.peers {
peers[k] = v
func (c *cluster) ID() uint64 {
return c.id
}

// Members returns the list of raft members in the cluster
func (c *cluster) Members() map[uint64]*Member {
members := make(map[uint64]*Member)
c.mu.RLock()
for k, v := range c.members {
members[k] = v
}
c.lock.RUnlock()
return peers
c.mu.RUnlock()
return members
}

// GetMember returns informations on a given member
func (c *cluster) GetMember(id uint64) *Member {
c.mu.RLock()
defer c.mu.RUnlock()
return c.members[id]
}

// GetPeer returns informations on a given peer
func (c *Cluster) GetPeer(id uint64) *Peer {
c.lock.RLock()
defer c.lock.RUnlock()
return c.peers[id]
// AddMember adds a node to the cluster memberlist
func (c *cluster) AddMember(member *Member) error {
c.mu.Lock()
defer c.mu.Unlock()
c.members[member.ID] = member
return nil
}

// AddPeer adds a node to our neighbors
func (c *Cluster) AddPeer(peer *Peer) {
c.lock.Lock()
c.peers[peer.ID] = peer
c.lock.Unlock()
// RemoveMember removes a node from the cluster memberlist
func (c *cluster) RemoveMember(id uint64) error {
c.mu.Lock()
defer c.mu.Unlock()
c.members[id].Client.Conn.Close()
c.removed[id] = true
delete(c.members, id)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should call Close on the grpc connection.

return nil
}

// RemovePeer removes a node from our neighbors
func (c *Cluster) RemovePeer(id uint64) {
c.lock.Lock()
delete(c.peers, id)
c.lock.Unlock()
// IsIDRemoved checks if a member is in the remove set
func (c *cluster) IsIDRemoved(id uint64) bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.removed[id]
}
Loading