forked from heyvito/eswim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoptions.go
189 lines (156 loc) · 6.83 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package eswim
import (
"fmt"
"github.com/heyvito/defip"
"go.uber.org/zap"
"math"
"net/netip"
"time"
)
// MustIPAddr parses a given IP address and returns a pointer to its netip.Addr
// representation. This can be used with HostAddresses struct.
// Panics in case the address cannot be parsed.
func MustIPAddr(addr string) *netip.Addr {
a := netip.MustParseAddr(addr)
return &a
}
var IgnoreFamilyAddr = &netip.Addr{}
// HostAddresses defines the set of IP addresses the library will use to
// operate. Those IPs are used to provide TCP and UDP listeners, and will also
// be used to announce this instance in the cluster. When an address has a nil
// value, the library tries to automatically pick an address corresponding to
// that family that contains a default gateway configured. In case a given
// family must be disabled, its value must be set to IgnoreFamilyAddr. The
// library provides the MustIPAddr function to return an address from a string.
type HostAddresses struct {
IPv4Address *netip.Addr
IPv6Address *netip.Addr
}
// Options represents a set of options to tuning and configuring the current
// server.
type Options struct {
// HostAddresses represent the set of addresses the library will use to
// communicate and advertise. See HostAddresses (struct) for more details.
HostAddresses HostAddresses
// IPv4MulticastAddress represents the Multicast IPv4 address to use when
// announcing or listening for bootstrap requests. An empty string disables
// IPv4. Defaults to a blank string.
IPv4MulticastAddress string
// IPv6MulticastAddress represents the Multicast IPv6 address to use when
// announcing or listening for bootstrap requests. An empty string disables
// IPv6. Defaults to a blank string.
IPv6MulticastAddress string
// MulticastPort represents the port this and other nodes will use to
// exchange bootstrap requests. Required.
MulticastPort uint16
// SWIMPort represents the port this node will use on both UDP and TCP
// protocols to exchange information with other nodes. Required.
SWIMPort uint16
// CryptoKey comprises a 16-byte cryptographic key shared among all other
// nodes to secure communication between them. Under development
// environments, this can be left empty as long as InsecureDisableCrypto is
// set. Optional. Defaults to an empty byte slice.
CryptoKey []byte
// InsecureDisableCrypto disables cryptographic facilities on this instance,
// effectively making all exchanged messages readable by third-parties. When
// this is set, the value of CryptoKey is ignored. This MUST NOT BE USED IN
// PRODUCTION. Defaults to false.
InsecureDisableCrypto bool
// IndirectPings determines how many nodes (at most) must be used to perform
// indirect pings. Defaults to 2.
IndirectPings int
// ProtocolPeriod defines the period between protocol periods on this node.
// This value must be consistent across other nodes, but a jitter is added
// in order to prevent synchronization. Defaults to 2 seconds.
ProtocolPeriod time.Duration
// UseAdaptivePingTimeout determines whether the protocol should use an
// adaptive ping timeout based on observations of RTT times of messages
// exchanged with other nodes. The timeout will be set to three times the
// 99th percentile value of observed RTTs. When enabled, any value defined
// by PingTimeout is ignored. Defaults to false.
UseAdaptivePingTimeout bool
// PingTimeout defines the amount of time to wait until assuming that a
// node is potentially at fault. In case a node does not answer a ping
// before this duration expires, it will automatically be considered
// suspect, and this information will be transmitted to other members of
// the current cluster. Defaults to half of ProtocolPeriod.
PingTimeout time.Duration
// SuspectPeriods determines for how many protocol periods a given node can
// stay as suspect. Note that a protocol period is also configured by
// ProtocolPeriod, effectively yielding a value of ProtocolPeriod *
// SuspectPeriods time units before notifying the cluster the node
// transitioned to a fault state. Defaults to 20.
SuspectPeriods uint16
// FullSyncProtocolRounds determines how many protocol rounds should the
// server wait between performing a full sync with another random node.
// A recommended value is around 300 rounds, depending on the chosen
// ProtocolPeriod. Defaults to 300. Setting this value to -1 disables this
// mechanism (not recommended).
FullSyncProtocolRounds int
// UDPMaxLength determines the maximum length of any given UDP packet. For
// most networks, a value of 1000~1200 is considered safe. Defaults to 1200.
UDPMaxLength int
// LogHandler represents a slog-compatible logger that will be used by this
// library. A nil logger will emit no messages. Defaults to a noop
// slog.Logger, which will discard all messages.
LogHandler *zap.Logger
// MaxEventTransmission represents a function responsible for calculating
// how many times at most a given event should be transmitted, based on the
// size of the current member list. After messages are transmitted that
// amount of times, it is discarded from the local buffer. Defaults to
// 3⌈max(log(N + 1), 1)⌉.
MaxEventTransmission func(clusterSize int) int
}
func (o *Options) normalize() error {
if o.LogHandler == nil {
o.LogHandler = zap.NewNop()
}
logger := o.LogHandler.With(zap.String("facility", "options"))
if !o.InsecureDisableCrypto && len(o.CryptoKey) != 16 {
return fmt.Errorf("CryptoKey must have 16 bytes")
}
if o.ProtocolPeriod == 0 {
o.ProtocolPeriod = 2 * time.Second
}
if o.PingTimeout == 0 {
o.PingTimeout = o.ProtocolPeriod / 2
}
if o.UDPMaxLength == 0 {
o.UDPMaxLength = 1200
}
if o.IndirectPings == 0 {
o.IndirectPings = 2
}
if o.SuspectPeriods == 0 {
o.SuspectPeriods = 20
}
if o.FullSyncProtocolRounds == 0 {
o.FullSyncProtocolRounds = 300
}
if o.MaxEventTransmission == nil {
o.MaxEventTransmission = func(n int) int {
return 3 * int(math.Ceil(max(math.Log(float64(n)+1), 1)))
}
}
if o.HostAddresses.IPv4Address == nil || o.HostAddresses.IPv6Address == nil {
if o.HostAddresses.IPv4Address == nil {
if ip, err := defip.FindDefaultIP(defip.NetRouteKindV4); err == nil {
o.HostAddresses.IPv4Address = ip
logger.Debug("Automatically selected IPv4", zap.String("addr", ip.String()))
} else {
logger.Warn("IPv4 has not been explicitly disabled, but no usable IPv4 could be found. Disabling...")
o.HostAddresses.IPv4Address = IgnoreFamilyAddr
}
}
if o.HostAddresses.IPv6Address == nil {
if ip, err := defip.FindDefaultIP(defip.NetRouteKindV6); err == nil {
o.HostAddresses.IPv6Address = ip
logger.Debug("Automatically selected IPv6", zap.String("addr", ip.String()))
} else {
logger.Warn("IPv6 has not been explicitly disabled, but no usable IPv6 could be found. Disabling...")
o.HostAddresses.IPv6Address = IgnoreFamilyAddr
}
}
}
return nil
}