summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/hashicorp/memberlist
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/memberlist')
-rw-r--r--vendor/github.com/hashicorp/memberlist/memberlist.go49
-rw-r--r--vendor/github.com/hashicorp/memberlist/memberlist_test.go4
-rw-r--r--vendor/github.com/hashicorp/memberlist/state.go4
3 files changed, 33 insertions, 24 deletions
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist.go b/vendor/github.com/hashicorp/memberlist/memberlist.go
index 9ea195cfc..d5c175e5b 100644
--- a/vendor/github.com/hashicorp/memberlist/memberlist.go
+++ b/vendor/github.com/hashicorp/memberlist/memberlist.go
@@ -22,9 +22,10 @@ import (
"strconv"
"strings"
"sync"
+ "sync/atomic"
"time"
- "github.com/hashicorp/go-multierror"
+ multierror "github.com/hashicorp/go-multierror"
sockaddr "github.com/hashicorp/go-sockaddr"
"github.com/miekg/dns"
)
@@ -35,11 +36,14 @@ type Memberlist struct {
numNodes uint32 // Number of known nodes (estimate)
config *Config
- shutdown bool
+ shutdown int32 // Used as an atomic boolean value
shutdownCh chan struct{}
- leave bool
+ leave int32 // Used as an atomic boolean value
leaveBroadcast chan struct{}
+ shutdownLock sync.Mutex // Serializes calls to Shutdown
+ leaveLock sync.Mutex // Serializes calls to Leave
+
transport Transport
handoff chan msgHandoff
@@ -116,19 +120,19 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
// See comment below for details about the retry in here.
makeNetRetry := func(limit int) (*NetTransport, error) {
+ var err error
for try := 0; try < limit; try++ {
- nt, err := NewNetTransport(nc)
- if err == nil {
+ var nt *NetTransport
+ if nt, err = NewNetTransport(nc); err == nil {
return nt, nil
}
-
if strings.Contains(err.Error(), "address already in use") {
logger.Printf("[DEBUG] Got bind error: %v", err)
continue
}
}
- return nil, fmt.Errorf("ran out of tries to obtain an address")
+ return nil, fmt.Errorf("failed to obtain an address: %v", err)
}
// The dynamic bind port operation is inherently racy because
@@ -554,18 +558,17 @@ func (m *Memberlist) NumMembers() (alive int) {
// This method is safe to call multiple times, but must not be called
// after the cluster is already shut down.
func (m *Memberlist) Leave(timeout time.Duration) error {
- m.nodeLock.Lock()
- // We can't defer m.nodeLock.Unlock() because m.deadNode will also try to
- // acquire a lock so we need to Unlock before that.
+ m.leaveLock.Lock()
+ defer m.leaveLock.Unlock()
- if m.shutdown {
- m.nodeLock.Unlock()
+ if m.hasShutdown() {
panic("leave after shutdown")
}
- if !m.leave {
- m.leave = true
+ if !m.hasLeft() {
+ atomic.StoreInt32(&m.leave, 1)
+ m.nodeLock.Lock()
state, ok := m.nodeMap[m.config.Name]
m.nodeLock.Unlock()
if !ok {
@@ -591,8 +594,6 @@ func (m *Memberlist) Leave(timeout time.Duration) error {
return fmt.Errorf("timeout waiting for leave broadcast")
}
}
- } else {
- m.nodeLock.Unlock()
}
return nil
@@ -634,10 +635,10 @@ func (m *Memberlist) ProtocolVersion() uint8 {
//
// This method is safe to call multiple times.
func (m *Memberlist) Shutdown() error {
- m.nodeLock.Lock()
- defer m.nodeLock.Unlock()
+ m.shutdownLock.Lock()
+ defer m.shutdownLock.Unlock()
- if m.shutdown {
+ if m.hasShutdown() {
return nil
}
@@ -647,8 +648,16 @@ func (m *Memberlist) Shutdown() error {
m.transport.Shutdown()
// Now tear down everything else.
- m.shutdown = true
+ atomic.StoreInt32(&m.shutdown, 1)
close(m.shutdownCh)
m.deschedule()
return nil
}
+
+func (m *Memberlist) hasShutdown() bool {
+ return atomic.LoadInt32(&m.shutdown) == 1
+}
+
+func (m *Memberlist) hasLeft() bool {
+ return atomic.LoadInt32(&m.leave) == 1
+}
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist_test.go b/vendor/github.com/hashicorp/memberlist/memberlist_test.go
index 964112dfd..ecda7fb55 100644
--- a/vendor/github.com/hashicorp/memberlist/memberlist_test.go
+++ b/vendor/github.com/hashicorp/memberlist/memberlist_test.go
@@ -424,11 +424,11 @@ func TestMemberList_ResolveAddr_TCP_First(t *testing.T) {
}
port := uint16(m.config.BindPort)
expected := []ipPort{
- ipPort{net.ParseIP("127.0.0.1"), port},
+ ipPort{net.ParseIP("127.0.0.1").To4(), port},
ipPort{net.ParseIP("2001:db8:a0b:12f0::1"), port},
}
if !reflect.DeepEqual(ips, expected) {
- t.Fatalf("bad: %#v", ips)
+ t.Fatalf("bad: %#v expected: %#v", ips, expected)
}
}
}
diff --git a/vendor/github.com/hashicorp/memberlist/state.go b/vendor/github.com/hashicorp/memberlist/state.go
index 8513361b1..29fe5f1cf 100644
--- a/vendor/github.com/hashicorp/memberlist/state.go
+++ b/vendor/github.com/hashicorp/memberlist/state.go
@@ -835,7 +835,7 @@ func (m *Memberlist) aliveNode(a *alive, notify chan struct{}, bootstrap bool) {
// in-queue to be processed but blocked by the locks above. If we let
// that aliveMsg process, it'll cause us to re-join the cluster. This
// ensures that we don't.
- if m.leave && a.Node == m.config.Name {
+ if m.hasLeft() && a.Node == m.config.Name {
return
}
@@ -1111,7 +1111,7 @@ func (m *Memberlist) deadNode(d *dead) {
// Check if this is us
if state.Name == m.config.Name {
// If we are not leaving we need to refute
- if !m.leave {
+ if !m.hasLeft() {
m.refute(state, d.Incarnation)
m.logger.Printf("[WARN] memberlist: Refuting a dead message (from: %s)", d.From)
return // Do not mark ourself dead