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/Makefile5
-rw-r--r--vendor/github.com/hashicorp/memberlist/README.md83
-rw-r--r--vendor/github.com/hashicorp/memberlist/config.go2
-rw-r--r--vendor/github.com/hashicorp/memberlist/memberlist.go33
-rw-r--r--vendor/github.com/hashicorp/memberlist/net.go27
-rw-r--r--vendor/github.com/hashicorp/memberlist/net_test.go27
6 files changed, 98 insertions, 79 deletions
diff --git a/vendor/github.com/hashicorp/memberlist/Makefile b/vendor/github.com/hashicorp/memberlist/Makefile
index 56ef6c28c..891e8364a 100644
--- a/vendor/github.com/hashicorp/memberlist/Makefile
+++ b/vendor/github.com/hashicorp/memberlist/Makefile
@@ -1,3 +1,4 @@
+DEPS = $(go list -f '{{range .Imports}}{{.}} {{end}}' ./...)
test: subnet
go test ./...
@@ -11,4 +12,8 @@ cov:
gocov test github.com/hashicorp/memberlist | gocov-html > /tmp/coverage.html
open /tmp/coverage.html
+deps:
+ go get -d -v ./...
+ echo $(DEPS) | xargs -n1 go get -d
+
.PNONY: test cov integ
diff --git a/vendor/github.com/hashicorp/memberlist/README.md b/vendor/github.com/hashicorp/memberlist/README.md
index fc605a59b..0adc075e8 100644
--- a/vendor/github.com/hashicorp/memberlist/README.md
+++ b/vendor/github.com/hashicorp/memberlist/README.md
@@ -23,6 +23,8 @@ Please check your installation with:
go version
```
+Run `make deps` to fetch dependencies before building
+
## Usage
Memberlist is surprisingly simple to use. An example is shown below:
@@ -63,82 +65,11 @@ For complete documentation, see the associated [Godoc](http://godoc.org/github.c
## Protocol
-memberlist is based on ["SWIM: Scalable Weakly-consistent Infection-style Process Group Membership Protocol"](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf),
-with a few minor adaptations, mostly to increase propagation speed and
+memberlist is based on ["SWIM: Scalable Weakly-consistent Infection-style Process Group Membership Protocol"](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf). However, we extend the protocol in a number of ways:
+
+* Several extensions are made to increase propagation speed and
convergence rate.
+* Another set of extensions, that we call Lifeguard, are made to make memberlist more robust in the presence of slow message processing (due to factors such as CPU starvation, and network delay or loss).
-A high level overview of the memberlist protocol (based on SWIM) is
-described below, but for details please read the full
-[SWIM paper](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf)
-followed by the memberlist source. We welcome any questions related
+For details on all of these extensions, please read our paper "[Lifeguard : SWIM-ing with Situational Awareness](https://arxiv.org/abs/1707.00788)", along with the memberlist source. We welcome any questions related
to the protocol on our issue tracker.
-
-### Protocol Description
-
-memberlist begins by joining an existing cluster or starting a new
-cluster. If starting a new cluster, additional nodes are expected to join
-it. New nodes in an existing cluster must be given the address of at
-least one existing member in order to join the cluster. The new member
-does a full state sync with the existing member over TCP and begins gossiping its
-existence to the cluster.
-
-Gossip is done over UDP with a configurable but fixed fanout and interval.
-This ensures that network usage is constant with regards to number of nodes, as opposed to
-exponential growth that can occur with traditional heartbeat mechanisms.
-Complete state exchanges with a random node are done periodically over
-TCP, but much less often than gossip messages. This increases the likelihood
-that the membership list converges properly since the full state is exchanged
-and merged. The interval between full state exchanges is configurable or can
-be disabled entirely.
-
-Failure detection is done by periodic random probing using a configurable interval.
-If the node fails to ack within a reasonable time (typically some multiple
-of RTT), then an indirect probe as well as a direct TCP probe are attempted. An
-indirect probe asks a configurable number of random nodes to probe the same node,
-in case there are network issues causing our own node to fail the probe. The direct
-TCP probe is used to help identify the common situation where networking is
-misconfigured to allow TCP but not UDP. Without the TCP probe, a UDP-isolated node
-would think all other nodes were suspect and could cause churn in the cluster when
-it attempts a TCP-based state exchange with another node. It is not desirable to
-operate with only TCP connectivity because convergence will be much slower, but it
-is enabled so that memberlist can detect this situation and alert operators.
-
-If both our probe, the indirect probes, and the direct TCP probe fail within a
-configurable time, then the node is marked "suspicious" and this knowledge is
-gossiped to the cluster. A suspicious node is still considered a member of
-cluster. If the suspect member of the cluster does not dispute the suspicion
-within a configurable period of time, the node is finally considered dead,
-and this state is then gossiped to the cluster.
-
-This is a brief and incomplete description of the protocol. For a better idea,
-please read the
-[SWIM paper](http://www.cs.cornell.edu/~asdas/research/dsn02-swim.pdf)
-in its entirety, along with the memberlist source code.
-
-### Changes from SWIM
-
-As mentioned earlier, the memberlist protocol is based on SWIM but includes
-minor changes, mostly to increase propagation speed and convergence rates.
-
-The changes from SWIM are noted here:
-
-* memberlist does a full state sync over TCP periodically. SWIM only propagates
- changes over gossip. While both eventually reach convergence, the full state
- sync increases the likelihood that nodes are fully converged more quickly,
- at the expense of more bandwidth usage. This feature can be totally disabled
- if you wish.
-
-* memberlist has a dedicated gossip layer separate from the failure detection
- protocol. SWIM only piggybacks gossip messages on top of probe/ack messages.
- memberlist also piggybacks gossip messages on top of probe/ack messages, but
- also will periodically send out dedicated gossip messages on their own. This
- feature lets you have a higher gossip rate (for example once per 200ms)
- and a slower failure detection rate (such as once per second), resulting
- in overall faster convergence rates and data propagation speeds. This feature
- can be totally disabed as well, if you wish.
-
-* memberlist stores around the state of dead nodes for a set amount of time,
- so that when full syncs are requested, the requester also receives information
- about dead nodes. Because SWIM doesn't do full syncs, SWIM deletes dead node
- state immediately upon learning that the node is dead. This change again helps
- the cluster converge more quickly.
diff --git a/vendor/github.com/hashicorp/memberlist/config.go b/vendor/github.com/hashicorp/memberlist/config.go
index 5cad4ed54..c85b1657a 100644
--- a/vendor/github.com/hashicorp/memberlist/config.go
+++ b/vendor/github.com/hashicorp/memberlist/config.go
@@ -235,7 +235,7 @@ func DefaultLANConfig() *Config {
TCPTimeout: 10 * time.Second, // Timeout after 10 seconds
IndirectChecks: 3, // Use 3 nodes for the indirect ping
RetransmitMult: 4, // Retransmit a message 4 * log(N+1) nodes
- SuspicionMult: 5, // Suspect a node for 5 * log(N+1) * Interval
+ SuspicionMult: 4, // Suspect a node for 4 * log(N+1) * Interval
SuspicionMaxTimeoutMult: 6, // For 10k nodes this will give a max timeout of 120 seconds
PushPullInterval: 30 * time.Second, // Low frequency
ProbeTimeout: 500 * time.Millisecond, // Reasonable RTT time for LAN
diff --git a/vendor/github.com/hashicorp/memberlist/memberlist.go b/vendor/github.com/hashicorp/memberlist/memberlist.go
index e4b0d7347..9ea195cfc 100644
--- a/vendor/github.com/hashicorp/memberlist/memberlist.go
+++ b/vendor/github.com/hashicorp/memberlist/memberlist.go
@@ -113,14 +113,43 @@ func newMemberlist(conf *Config) (*Memberlist, error) {
BindPort: conf.BindPort,
Logger: logger,
}
- nt, err := NewNetTransport(nc)
+
+ // See comment below for details about the retry in here.
+ makeNetRetry := func(limit int) (*NetTransport, error) {
+ for try := 0; try < limit; try++ {
+ nt, err := NewNetTransport(nc)
+ if 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")
+ }
+
+ // The dynamic bind port operation is inherently racy because
+ // even though we are using the kernel to find a port for us, we
+ // are attempting to bind multiple protocols (and potentially
+ // multiple addresses) with the same port number. We build in a
+ // few retries here since this often gets transient errors in
+ // busy unit tests.
+ limit := 1
+ if conf.BindPort == 0 {
+ limit = 10
+ }
+
+ nt, err := makeNetRetry(limit)
if err != nil {
return nil, fmt.Errorf("Could not set up network transport: %v", err)
}
-
if conf.BindPort == 0 {
port := nt.GetAutoBindPort()
conf.BindPort = port
+ conf.AdvertisePort = port
logger.Printf("[DEBUG] Using dynamic bind port %d", port)
}
transport = nt
diff --git a/vendor/github.com/hashicorp/memberlist/net.go b/vendor/github.com/hashicorp/memberlist/net.go
index 65a60159d..58e1fce20 100644
--- a/vendor/github.com/hashicorp/memberlist/net.go
+++ b/vendor/github.com/hashicorp/memberlist/net.go
@@ -55,6 +55,7 @@ const (
encryptMsg
nackRespMsg
hasCrcMsg
+ errMsg
)
// compressionType is used to specify the compression algorithm
@@ -105,6 +106,11 @@ type nackResp struct {
SeqNo uint32
}
+// err response is sent to relay the error from the remote end
+type errResp struct {
+ Error string
+}
+
// suspect is broadcast when we suspect a node is dead
type suspect struct {
Incarnation uint32
@@ -209,6 +215,19 @@ func (m *Memberlist) handleConn(conn net.Conn) {
if err != nil {
if err != io.EOF {
m.logger.Printf("[ERR] memberlist: failed to receive: %s %s", err, LogConn(conn))
+
+ resp := errResp{err.Error()}
+ out, err := encode(errMsg, &resp)
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to encode error response: %s", err)
+ return
+ }
+
+ err = m.rawSendMsgStream(conn, out.Bytes())
+ if err != nil {
+ m.logger.Printf("[ERR] memberlist: Failed to send error: %s %s", err, LogConn(conn))
+ return
+ }
}
return
}
@@ -726,6 +745,14 @@ func (m *Memberlist) sendAndReceiveState(addr string, join bool) ([]pushNodeStat
return nil, nil, err
}
+ if msgType == errMsg {
+ var resp errResp
+ if err := dec.Decode(&resp); err != nil {
+ return nil, nil, err
+ }
+ return nil, nil, fmt.Errorf("remote error: %v", resp.Error)
+ }
+
// Quit if not push/pull
if msgType != pushPullMsg {
err := fmt.Errorf("received invalid msgType (%d), expected pushPullMsg (%d) %s", msgType, pushPullMsg, LogConn(conn))
diff --git a/vendor/github.com/hashicorp/memberlist/net_test.go b/vendor/github.com/hashicorp/memberlist/net_test.go
index 80d3ebb36..860535855 100644
--- a/vendor/github.com/hashicorp/memberlist/net_test.go
+++ b/vendor/github.com/hashicorp/memberlist/net_test.go
@@ -785,3 +785,30 @@ func TestIngestPacket_CRC(t *testing.T) {
t.Fatalf("bad: %s", logs.String())
}
}
+
+func TestGossip_MismatchedKeys(t *testing.T) {
+ c1 := testConfig()
+ c2 := testConfig()
+
+ // Create two agents with different gossip keys
+ c1.SecretKey = []byte("4W6DGn2VQVqDEceOdmuRTQ==")
+ c2.SecretKey = []byte("XhX/w702/JKKK7/7OtM9Ww==")
+
+ m1, err := Create(c1)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ defer m1.Shutdown()
+
+ m2, err := Create(c2)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+ defer m2.Shutdown()
+
+ // Make sure we get this error on the joining side
+ _, err = m2.Join([]string{c1.BindAddr})
+ if err == nil || !strings.Contains(err.Error(), "No installed keys could decrypt the message") {
+ t.Fatalf("bad: %s", err)
+ }
+}