-
Notifications
You must be signed in to change notification settings - Fork 650
Expand file tree
/
Copy pathcluster.go
More file actions
472 lines (402 loc) · 20.2 KB
/
Copy pathcluster.go
File metadata and controls
472 lines (402 loc) · 20.2 KB
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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Content before git sha 34fdeebefcbf183ed7f916f931aa0586fdaa1b40
* Copyright (c) 2012, The Gocql authors,
* provided under the BSD-3-Clause License.
* See the NOTICE file distributed with this work for additional information.
*/
package gocql
import (
"context"
"errors"
"net"
"time"
)
// PoolConfig configures the connection pool used by the driver, it defaults to
// using a round-robin host selection policy and a round-robin connection selection
// policy for each host.
type PoolConfig struct {
// HostSelectionPolicy sets the policy for selecting which host to use for a
// given query (default: RoundRobinHostPolicy())
// It is not supported to use a single HostSelectionPolicy in multiple sessions
// (even if you close the old session before using in a new session).
HostSelectionPolicy HostSelectionPolicy
}
// MetadataCacheMode controls how the driver reads and caches schema metadata from Cassandra system tables.
// This affects the behavior of Session.KeyspaceMetadata and token-aware host selection policies.
//
// See the individual mode constants (Full, KeyspaceOnly, Disabled) for detailed behavior of each mode.
type MetadataCacheMode int
const (
// Full mode reads and caches all schema metadata including keyspaces, tables, columns,
// functions, aggregates, user-defined types, and materialized views.
//
// Token-aware routing works normally (if TokenAwareHostPolicy is used) with full replica information.
// Session.KeyspaceMetadata returns cached metadata without querying system tables.
//
// It enables SchemaChangeListener to be notified about all schema changes.
Full MetadataCacheMode = iota
// KeyspaceOnly mode reads and caches only keyspace metadata (replication strategy and options).
// This enables token-aware routing (if TokenAwareHostPolicy is used) without the overhead of caching detailed schema information.
//
// Token-aware routing works normally (if TokenAwareHostPolicy is used) with full replica information.
// Session.KeyspaceMetadata returns cached keyspace metadata, but Tables, Functions, Aggregates,
// MaterializedViews, and UserTypes fields will be nil.
//
// If CacheMode is Full, schema change listeners will be notified about all schema changes.
//
// Having other then KeyspaceChangeListener of schema events registered will result in an error during session creation.
KeyspaceOnly
// Disabled mode completely disables schema metadata caching.
//
// Token-aware routing falls back to the configured fallback policy (e.g., RoundRobinHostPolicy,
// DCAwareRoundRobinPolicy) since replica information is not available.
// Session.KeyspaceMetadata queries system tables on every call instead of using a cache.
//
// Having schema change listeners will result in an error during session creation.
Disabled
)
func (p PoolConfig) buildPool(session *Session) *policyConnPool {
return newPolicyConnPool(session)
}
// ClusterConfig is a struct to configure the default cluster implementation
// of gocql. It has a variety of attributes that can be used to modify the
// behavior to fit the most common use cases. Applications that require a
// different setup must implement their own cluster.
type ClusterConfig struct {
// addresses for the initial connections. It is recommended to use the value set in
// the Cassandra config for broadcast_address or listen_address, an IP address not
// a domain name. This is because events from Cassandra will use the configured IP
// address, which is used to index connected hosts. If the domain name specified
// resolves to more than 1 IP address then the driver may connect multiple times to
// the same host, and will not mark the node being down or up from events.
Hosts []string
// CQL version (default: 3.0.0)
CQLVersion string
// ProtoVersion sets the version of the native protocol to use, this will
// enable features in the driver for specific protocol versions, generally this
// should be set to a known version (2,3,4) for the cluster being connected to.
//
// If it is 0 or unset (the default) then the driver will attempt to discover the
// highest supported protocol for the cluster. In clusters with nodes of different
// versions the protocol selected is not defined (ie, it can be any of the supported in the cluster)
ProtoVersion int
// Timeout limits the time spent on the client side while executing a query.
// Specifically, query or batch execution will return an error if the client does not receive a response
// from the server within the Timeout period.
// Timeout is also used to configure the read timeout on the underlying network connection.
// Client Timeout should always be higher than the request timeouts configured on the server,
// so that retries don't overload the server.
// Timeout has a default value of 11 seconds, which is higher than default server timeout for most query types.
// Timeout is not applied to requests during initial connection setup, see ConnectTimeout.
Timeout time.Duration
// ConnectTimeout limits the time spent during connection setup.
// During initial connection setup, internal queries, AUTH requests will return an error if the client
// does not receive a response within the ConnectTimeout period.
// ConnectTimeout is applied to the connection setup queries independently.
// ConnectTimeout also limits the duration of dialing a new TCP connection
// in case there is no Dialer nor HostDialer configured.
// ConnectTimeout has a default value of 11 seconds.
ConnectTimeout time.Duration
// WriteTimeout limits the time the driver waits to write a request to a network connection.
// WriteTimeout should be lower than or equal to Timeout.
// WriteTimeout defaults to the value of Timeout.
WriteTimeout time.Duration
// Port used when dialing.
// Default: 9042
Port int
// Initial keyspace. Optional.
Keyspace string
// The size of the connection pool for each host.
// The pool filling runs in separate gourutine during the session initialization phase.
// gocql will always try to get 1 connection on each host pool
// during session initialization AND it will attempt
// to fill each pool afterward asynchronously if NumConns > 1.
// Notice: There is no guarantee that pool filling will be finished in the initialization phase.
// Also, it describes a maximum number of connections at the same time.
// Default: 2
NumConns int
// Default consistency level.
// Default: Quorum
Consistency Consistency
// Compression algorithm.
// Default: nil
Compressor Compressor
// Default: nil
Authenticator Authenticator
// An Authenticator factory. Can be used to create alternative authenticators.
// Default: nil
AuthProvider func(h *HostInfo) (Authenticator, error)
// Default retry policy to use for queries.
// Default: no retries.
RetryPolicy RetryPolicy
// ConvictionPolicy decides whether to mark host as down based on the error and host info.
// Default: SimpleConvictionPolicy
ConvictionPolicy ConvictionPolicy
// Default reconnection policy to use for reconnecting before trying to mark host as down.
ReconnectionPolicy ReconnectionPolicy
// The keepalive period to use, enabled if > 0 (default: 0)
// SocketKeepalive is used to set up the default dialer and is ignored if Dialer or HostDialer is provided.
SocketKeepalive time.Duration
// Maximum cache size for prepared statements globally for gocql.
// Default: 1000
MaxPreparedStmts int
// Maximum cache size for query info about statements for each session.
// Default: 1000
MaxRoutingKeyInfo int
// Default page size to use for created sessions.
// Default: 5000
PageSize int
// Consistency for the serial part of queries, values can be either SERIAL or LOCAL_SERIAL.
// Default: unset
SerialConsistency Consistency
// SslOpts configures TLS use when HostDialer is not set.
// SslOpts is ignored if HostDialer is set.
SslOpts *SslOptions
// Sends a client side timestamp for all requests which overrides the timestamp at which it arrives at the server.
// Default: true, only enabled for protocol 3 and above.
DefaultTimestamp bool
// PoolConfig configures the underlying connection pool, allowing the
// configuration of host selection and connection selection policies.
PoolConfig PoolConfig
// If not zero, gocql attempt to reconnect known DOWN nodes in every ReconnectInterval.
ReconnectInterval time.Duration
// The maximum amount of time to wait for schema agreement in a cluster after
// receiving a schema change frame. (default: 60s)
MaxWaitSchemaAgreement time.Duration
// HostFilter will filter all incoming events for host, any which don't pass
// the filter will be ignored. If set will take precedence over any options set
// via Discovery
HostFilter HostFilter
// AddressTranslator will translate addresses found on peer discovery and/or
// node change events.
AddressTranslator AddressTranslator
// If IgnorePeerAddr is true and the address in system.peers does not match
// the supplied host by either initial hosts or discovered via events then the
// host will be replaced with the supplied address.
//
// For example if an event comes in with host=10.0.0.1 but when looking up that
// address in system.local or system.peers returns 127.0.0.1, the peer will be
// set to 10.0.0.1 which is what will be used to connect to.
IgnorePeerAddr bool
// If DisableInitialHostLookup then the driver will not attempt to get host info
// from the system.peers table, this will mean that the driver will connect to
// hosts supplied and will not attempt to lookup the hosts information, this will
// mean that data_center, rack and token information will not be available and as
// such host filtering and token aware query routing will not be available.
DisableInitialHostLookup bool
// Configure events the driver will register for
Events struct {
// Disable registering for status events (host up/down)
DisableNodeStatusEvents bool
// Disable registering for topology events (node added/removed/moved)
DisableTopologyEvents bool
// Disable registering for schema events (keyspace/table/function removed/created/updated)
DisableSchemaEvents bool
}
// DisableSkipMetadata will override the internal result metadata cache so that the driver does not
// send skip_metadata for queries, this means that the result will always contain
// the metadata to parse the rows and will not reuse the metadata from the prepared
// statement.
//
// See https://issues.apache.org/jira/browse/CASSANDRA-10786
DisableSkipMetadata bool
// ExecAttemptInterceptor will set the provided interceptor on all queries/batches created from this session.
// Use it to intercept queries by providing an implementation of ExecAttemptInterceptor.
ExecAttemptInterceptor ExecAttemptInterceptor
// QueryObserver will set the provided query observer on all queries created from this session.
// Use it to collect metrics / stats from queries by providing an implementation of QueryObserver.
QueryObserver QueryObserver
// BatchObserver will set the provided batch observer on all queries created from this session.
// Use it to collect metrics / stats from batch queries by providing an implementation of BatchObserver.
BatchObserver BatchObserver
// ConnectObserver will set the provided connect observer on all queries
// created from this session.
ConnectObserver ConnectObserver
// FrameHeaderObserver will set the provided frame header observer on all frames' headers created from this session.
// Use it to collect metrics / stats from frames by providing an implementation of FrameHeaderObserver.
FrameHeaderObserver FrameHeaderObserver
// StreamObserver will be notified of stream state changes.
// This can be used to track in-flight protocol requests and responses.
StreamObserver StreamObserver
// Default idempotence for queries
DefaultIdempotence bool
// The time to wait for frames before flushing the frames connection to Cassandra.
// Can help reduce syscall overhead by making less calls to write. Set to 0 to
// disable.
//
// (default: 200 microseconds)
WriteCoalesceWaitTime time.Duration
// Dialer will be used to establish all connections created for this Cluster.
// If not provided, a default dialer configured with ConnectTimeout will be used.
// Dialer is ignored if HostDialer is provided.
Dialer Dialer
// HostDialer will be used to establish all connections for this Cluster.
// If not provided, Dialer will be used instead.
HostDialer HostDialer
// StructuredLogger for this ClusterConfig.
//
// There are 3 built in implementations of StructuredLogger:
// - std library "log" package: gocql.NewLogger
// - zerolog: gocqlzerolog.NewZerologLogger
// - zap: gocqlzap.NewZapLogger
//
// You can also provide your own logger implementation of the StructuredLogger interface.
Logger StructuredLogger
// Tracer will be used for all queries. Alternatively it can be set of on a
// per query basis.
// default: nil
Tracer Tracer
// NextPagePrefetch sets the default threshold for pre-fetching new pages. If
// there are only p*pageSize rows remaining, the next page will be requested
// automatically. This value can also be changed on a per-query basis.
// default: 0.25.
NextPagePrefetch float64
// RegisteredTypes will be copied for all sessions created from this Cluster.
// If not provided, a copy of GlobalTypes will be used.
RegisteredTypes *RegisteredTypes
// internal config for testing
disableControlConn bool
// Metadata configures driver's internal metadata caching and event listening.
Metadata MetadataConfig
}
// Dialer is the interface that wraps the DialContext method for establishing network connections to Cassandra nodes.
//
// This interface allows customization of how gocql establishes TCP connections, which is useful for:
// connecting through proxies or load balancers, custom TLS configurations, custom timeouts/keep-alive
// settings, service mesh integration, testing with mocked connections, and corporate network routing.
type Dialer interface {
DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}
// NewCluster generates a new config for the default cluster implementation.
//
// The supplied hosts are used to initially connect to the cluster then the rest of
// the ring will be automatically discovered. It is recommended to use the value set in
// the Cassandra config for broadcast_address or listen_address, an IP address not
// a domain name. This is because events from Cassandra will use the configured IP
// address, which is used to index connected hosts. If the domain name specified
// resolves to more than 1 IP address then the driver may connect multiple times to
// the same host, and will not mark the node being down or up from events.
func NewCluster(hosts ...string) *ClusterConfig {
cfg := &ClusterConfig{
Hosts: hosts,
CQLVersion: "3.0.0",
Timeout: 11 * time.Second,
ConnectTimeout: 11 * time.Second,
Port: 9042,
NumConns: 2,
Consistency: Quorum,
MaxPreparedStmts: defaultMaxPreparedStmts,
MaxRoutingKeyInfo: 1000,
PageSize: 5000,
DefaultTimestamp: true,
MaxWaitSchemaAgreement: 60 * time.Second,
ReconnectInterval: 60 * time.Second,
ConvictionPolicy: &SimpleConvictionPolicy{},
ReconnectionPolicy: &ConstantReconnectionPolicy{MaxRetries: 3, Interval: 1 * time.Second},
WriteCoalesceWaitTime: 200 * time.Microsecond,
NextPagePrefetch: 0.25,
Metadata: MetadataConfig{
CacheMode: Full,
},
}
return cfg
}
func (cfg *ClusterConfig) newLogger() StructuredLogger {
if cfg.Logger != nil {
return cfg.Logger
}
return NewLogger(LogLevelNone)
}
// CreateSession initializes the cluster based on this config and returns a
// session object that can be used to interact with the database.
func (cfg *ClusterConfig) CreateSession() (*Session, error) {
return NewSession(*cfg)
}
// translateAddressPort is a helper method that will use the given AddressTranslator
// if defined, to translate the given address and port into a possibly new address
// and port, If no AddressTranslator or if an error occurs, the given address and
// port will be returned.
func (cfg *ClusterConfig) translateAddressPort(addr net.IP, port int, logger StructuredLogger) (net.IP, int) {
if cfg.AddressTranslator == nil || len(addr) == 0 {
return addr, port
}
newAddr, newPort := cfg.AddressTranslator.Translate(addr, port)
logger.Debug("Translating address.",
NewLogFieldIP("old_addr", addr), NewLogFieldInt("old_port", port),
NewLogFieldIP("new_addr", newAddr), NewLogFieldInt("new_port", newPort))
return newAddr, newPort
}
func (cfg *ClusterConfig) filterHost(host *HostInfo) bool {
return !(cfg.HostFilter == nil || cfg.HostFilter.Accept(host))
}
// MetadataConfig configures driver's internal metadata caching and event listening.
type MetadataConfig struct {
// CacheMode controls how the driver reads and caches schema metadata from Cassandra system tables.
//
// Also, it affects the behavior of schema change listeners.
//
// If CacheMode is [KeyspaceOnly], only [KeyspaceChangeListener] will be notified,
// having other listeners registered will result in an error during session creation.
//
// If CacheMode is [Disabled], having these listeners will result in an error during session creation.
//
// See [MetadataCacheMode] for more details.
CacheMode MetadataCacheMode
// HostListener will be notified when host state and topology changes occur.
//
// Thread Safety: Topology change callbacks are sequential, but host status callbacks can be concurrent.
// If your listener implements both TopologyChangeListener and HostStatusChangeListener, it must be
// thread-safe as these event types can run simultaneously from different sources.
//
// Consider using [HostListenersMux] if you need to register multiple listeners for the same type of host state and topology change.
HostListener HostListenersConfig
// SchemaListener will be notified when schema changes occur.
//
// Consider using [SchemaListenersMux] if you need to register multiple listeners for the same type of schema change.
SchemaListener SchemaListenersConfig
// SessionReadyListener will be notified when the session is ready to be used.
// This is meant to be implemented by Host and Schema listeners but it can also be used as
// a generic callback for when the session is ready regardless of whether a metadata listener is implemented or not.
//
// Consider using [SessionReadyListenersMux] if you need to register multiple listeners for the same session ready event.
SessionReadyListener SessionReadyListener
}
type HostListenersConfig struct {
// HostStateChangeListener will be notified about host state events (UP, DOWN).
HostStateChangeListener HostStatusChangeListener
// TopologyChangeListener will be notified about topology change events
// (NEW_NODE, REMOVED_NODE).
TopologyChangeListener TopologyChangeListener
}
type SchemaListenersConfig struct {
KeyspaceChangeListener KeyspaceChangeListener
TableChangeListener TableChangeListener
UserTypeChangeListener UserTypeChangeListener
FunctionChangeListener FunctionChangeListener
AggregateChangeListener AggregateChangeListener
}
var (
// ErrNoHosts is returned when no hosts are provided to the cluster configuration.
ErrNoHosts = errors.New("no hosts provided")
// ErrNoConnectionsStarted is returned when no connections could be established during session creation.
ErrNoConnectionsStarted = errors.New("no connections were made when creating the session")
// Deprecated: Never used or returned by the driver.
ErrHostQueryFailed = errors.New("unable to populate Hosts")
)