cassandra-driver 1.0.0.beta.3-java → 1.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +51 -14
- data/lib/cassandra.rb +164 -78
- data/lib/cassandra/address_resolution.rb +36 -0
- data/lib/cassandra/address_resolution/policies.rb +2 -0
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
- data/lib/cassandra/address_resolution/policies/none.rb +35 -0
- data/lib/cassandra/auth.rb +1 -1
- data/lib/cassandra/auth/providers/password.rb +1 -1
- data/lib/cassandra/cluster.rb +18 -5
- data/lib/cassandra/cluster/client.rb +175 -101
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +5 -5
- data/lib/cassandra/cluster/connector.rb +142 -56
- data/lib/cassandra/cluster/control_connection.rb +385 -134
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +13 -2
- data/lib/cassandra/cluster/registry.rb +19 -9
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/compression.rb +1 -1
- data/lib/cassandra/compression/compressors/lz4.rb +1 -1
- data/lib/cassandra/compression/compressors/snappy.rb +1 -1
- data/lib/cassandra/driver.rb +29 -21
- data/lib/cassandra/errors.rb +325 -35
- data/lib/cassandra/execution/options.rb +13 -6
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/future.rb +7 -3
- data/lib/cassandra/keyspace.rb +5 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +13 -4
- data/lib/cassandra/load_balancing/policies/token_aware.rb +2 -4
- data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol.rb +0 -16
- data/lib/cassandra/protocol/cql_byte_buffer.rb +18 -18
- data/lib/cassandra/protocol/cql_protocol_handler.rb +78 -8
- data/lib/cassandra/protocol/frame_decoder.rb +2 -2
- data/lib/cassandra/protocol/frame_encoder.rb +1 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/protocol/response.rb +1 -1
- data/lib/cassandra/protocol/responses/detailed_error_response.rb +16 -1
- data/lib/cassandra/protocol/responses/error_response.rb +17 -0
- data/lib/cassandra/protocol/responses/event_response.rb +1 -1
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/type_converter.rb +4 -3
- data/lib/cassandra/reconnection.rb +1 -1
- data/lib/cassandra/result.rb +4 -6
- data/lib/cassandra/retry.rb +3 -5
- data/lib/cassandra/session.rb +14 -5
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +6 -1
- data/lib/cassandra/time_uuid.rb +21 -83
- data/lib/cassandra/util.rb +131 -1
- data/lib/cassandra/uuid.rb +6 -4
- data/lib/cassandra/uuid/generator.rb +207 -0
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +43 -49
- data/lib/cassandra/client.rb +0 -144
- data/lib/cassandra/client/batch.rb +0 -212
- data/lib/cassandra/client/client.rb +0 -591
- data/lib/cassandra/client/column_metadata.rb +0 -54
- data/lib/cassandra/client/connector.rb +0 -277
- data/lib/cassandra/client/execute_options_decoder.rb +0 -59
- data/lib/cassandra/client/peer_discovery.rb +0 -50
- data/lib/cassandra/client/prepared_statement.rb +0 -314
- data/lib/cassandra/client/query_result.rb +0 -230
- data/lib/cassandra/client/request_runner.rb +0 -71
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
@@ -17,14 +17,14 @@
|
|
17
17
|
#++
|
18
18
|
|
19
19
|
module Cassandra
|
20
|
-
|
20
|
+
class Cluster
|
21
21
|
# @private
|
22
|
-
class
|
22
|
+
class ConnectionPool
|
23
23
|
include Enumerable
|
24
24
|
|
25
25
|
def initialize
|
26
26
|
@connections = []
|
27
|
-
@lock = Mutex.new
|
27
|
+
@lock = ::Mutex.new
|
28
28
|
end
|
29
29
|
|
30
30
|
def add_connections(connections)
|
@@ -53,7 +53,7 @@ module Cassandra
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def random_connection
|
56
|
-
raise Errors::
|
56
|
+
raise Errors::IOError, 'Not connected' unless connected?
|
57
57
|
@lock.synchronize do
|
58
58
|
@connections.sample
|
59
59
|
end
|
@@ -61,7 +61,7 @@ module Cassandra
|
|
61
61
|
|
62
62
|
def each_connection(&callback)
|
63
63
|
return self unless block_given?
|
64
|
-
raise Errors::
|
64
|
+
raise Errors::IOError, 'Not connected' unless connected?
|
65
65
|
@lock.synchronize do
|
66
66
|
@connections.each(&callback)
|
67
67
|
end
|
@@ -22,13 +22,14 @@ module Cassandra
|
|
22
22
|
class Connector
|
23
23
|
include MonitorMixin
|
24
24
|
|
25
|
-
def initialize(logger, io_reactor, cluster_registry, connection_options)
|
26
|
-
@logger
|
27
|
-
@reactor
|
28
|
-
@registry
|
29
|
-
@
|
30
|
-
@
|
31
|
-
@
|
25
|
+
def initialize(logger, io_reactor, cluster_registry, connection_options, execution_options)
|
26
|
+
@logger = logger
|
27
|
+
@reactor = io_reactor
|
28
|
+
@registry = cluster_registry
|
29
|
+
@connection_options = connection_options
|
30
|
+
@execution_options = execution_options
|
31
|
+
@connections = ::Hash.new
|
32
|
+
@open_connections = ::Hash.new
|
32
33
|
|
33
34
|
mon_initialize
|
34
35
|
end
|
@@ -43,25 +44,17 @@ module Cassandra
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
|
-
@logger.info("Connecting ip=#{host.ip}")
|
47
|
-
|
48
47
|
f = do_connect(host)
|
49
48
|
|
50
49
|
f.on_failure do |error|
|
51
|
-
@logger.warn("Connection failed ip=#{host.ip} error=\"#{error.class.name}: #{error.message}\"")
|
52
50
|
connection_error(host, error)
|
53
51
|
end
|
54
52
|
|
55
53
|
f.on_value do |connection|
|
56
54
|
connection.on_closed do |cause|
|
57
|
-
message = "Disconnected ip=#{host.ip}"
|
58
|
-
message << " error=#{cause.message}" if cause
|
59
|
-
|
60
|
-
@logger.info(message)
|
61
55
|
disconnected(host, cause)
|
62
56
|
end
|
63
57
|
|
64
|
-
@logger.info("Connected ip=#{host.ip}")
|
65
58
|
connected(host)
|
66
59
|
end
|
67
60
|
|
@@ -75,22 +68,15 @@ module Cassandra
|
|
75
68
|
return Future.resolved
|
76
69
|
end
|
77
70
|
|
78
|
-
@logger.
|
71
|
+
@logger.debug("Checking if host #{host.ip} is up")
|
79
72
|
f = do_connect(host)
|
80
73
|
|
81
74
|
f.on_failure do |error|
|
82
|
-
@logger.info("Refreshed host status ip=#{host.ip}")
|
83
|
-
@logger.warn("Connection failed ip=#{host.ip} error=\"#{error.class.name}: #{error.message}\"")
|
84
75
|
connection_error(host, error)
|
85
76
|
end
|
86
77
|
|
87
78
|
f.on_value do |connection|
|
88
|
-
@logger.info("Refreshed host status ip=#{host.ip}")
|
89
79
|
connection.on_closed do |cause|
|
90
|
-
message = "Disconnected ip=#{host.ip}"
|
91
|
-
message << " error=#{cause.message}" if cause
|
92
|
-
|
93
|
-
@logger.info(message)
|
94
80
|
disconnected(host, cause)
|
95
81
|
end
|
96
82
|
|
@@ -99,7 +85,21 @@ module Cassandra
|
|
99
85
|
@open_connections[host] << connection
|
100
86
|
end
|
101
87
|
|
102
|
-
@
|
88
|
+
timer = @reactor.schedule_timer(UNCLAIMED_TIMEOUT)
|
89
|
+
timer.on_value do
|
90
|
+
close = false
|
91
|
+
|
92
|
+
synchronize do
|
93
|
+
open_connections = @open_connections[host]
|
94
|
+
if open_connections
|
95
|
+
close = !open_connections.delete(connection).nil?
|
96
|
+
@open_connections.delete(host) if open_connections.empty?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
connection.close if close
|
101
|
+
end
|
102
|
+
|
103
103
|
connected(host)
|
104
104
|
end
|
105
105
|
|
@@ -112,52 +112,128 @@ module Cassandra
|
|
112
112
|
|
113
113
|
private
|
114
114
|
|
115
|
-
NO_CONNECTIONS
|
115
|
+
NO_CONNECTIONS = Ione::Future.resolved([])
|
116
|
+
UNCLAIMED_TIMEOUT = 5 # close unclaimed connections in five seconds
|
116
117
|
|
117
118
|
def do_connect(host)
|
118
|
-
|
119
|
-
|
119
|
+
f = @reactor.connect(host.ip.to_s, @connection_options.port, {:timeout => @connection_options.connect_timeout, :ssl => @connection_options.ssl}) do |connection|
|
120
|
+
raise Errors::ClientError, 'Not connected, reactor stopped' unless connection
|
121
|
+
Protocol::CqlProtocolHandler.new(connection, @reactor, @connection_options.protocol_version, @connection_options.compressor, @connection_options.heartbeat_interval, @connection_options.idle_timeout)
|
122
|
+
end
|
123
|
+
f = f.flat_map do |connection|
|
124
|
+
request_options(connection).flat_map do |options|
|
125
|
+
compression = @connection_options.compression
|
126
|
+
supported_algorithms = options['COMPRESSION']
|
127
|
+
|
128
|
+
if compression && !supported_algorithms.include?(compression)
|
129
|
+
@logger.warn("Compression with #{compression.inspect} is not supported by host at #{host.ip}, supported algorithms are #{supported_algorithms.inspect}")
|
130
|
+
compression = nil
|
131
|
+
end
|
132
|
+
|
133
|
+
supported_cql_versions = options['CQL_VERSION']
|
134
|
+
cql_version = (supported_cql_versions && !supported_cql_versions.empty?) ? supported_cql_versions.first : '3.1.0'
|
135
|
+
|
136
|
+
startup_connection(connection, cql_version, compression)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
f.fallback do |error|
|
140
|
+
case error
|
141
|
+
when Errors::ProtocolError
|
120
142
|
synchronize do
|
121
|
-
if @
|
122
|
-
@logger.
|
123
|
-
@
|
143
|
+
if @connection_options.protocol_version > 1
|
144
|
+
@logger.info("Host #{host.ip} doesn't support protocol version #{@connection_options.protocol_version}, downgrading")
|
145
|
+
@connection_options.protocol_version -= 1
|
124
146
|
do_connect(host)
|
125
147
|
else
|
126
148
|
Ione::Future.failed(error)
|
127
149
|
end
|
128
150
|
end
|
129
|
-
|
151
|
+
when Error
|
130
152
|
Ione::Future.failed(error)
|
153
|
+
else
|
154
|
+
e = Errors::IOError.new(error.message)
|
155
|
+
e.set_backtrace(error.backtrace)
|
156
|
+
Ione::Future.failed(e)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def startup_connection(connection, cql_version, compression)
|
162
|
+
connection.send_request(Protocol::StartupRequest.new(cql_version, compression), @execution_options.timeout).flat_map do |r|
|
163
|
+
case r
|
164
|
+
when Protocol::AuthenticateResponse
|
165
|
+
if @connection_options.protocol_version == 1
|
166
|
+
credentials = @connection_options.credentials
|
167
|
+
if credentials
|
168
|
+
send_credentials(connection, credentials)
|
169
|
+
else
|
170
|
+
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
|
171
|
+
end
|
172
|
+
else
|
173
|
+
authenticator = @connection_options.create_authenticator(r.authentication_class)
|
174
|
+
if authenticator
|
175
|
+
challenge_response_cycle(connection, authenticator, authenticator.initial_response)
|
176
|
+
else
|
177
|
+
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
|
178
|
+
end
|
179
|
+
end
|
180
|
+
when Protocol::ReadyResponse
|
181
|
+
::Ione::Future.resolved(connection)
|
182
|
+
when Protocol::ErrorResponse
|
183
|
+
::Ione::Future.failed(r.to_error(VOID_STATEMENT))
|
184
|
+
else
|
185
|
+
::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
|
131
186
|
end
|
132
187
|
end
|
133
188
|
end
|
134
189
|
|
135
|
-
def
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
190
|
+
def request_options(connection)
|
191
|
+
connection.send_request(Protocol::OptionsRequest.new, @execution_options.timeout).map do |r|
|
192
|
+
case r
|
193
|
+
when Protocol::SupportedResponse
|
194
|
+
r.options
|
195
|
+
when Protocol::ErrorResponse
|
196
|
+
raise r.to_error(VOID_STATEMENT)
|
197
|
+
else
|
198
|
+
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def send_credentials(connection, credentials)
|
204
|
+
connection.send_request(Protocol::CredentialsRequest.new(credentials), @execution_options.timeout).map do |r|
|
205
|
+
case r
|
206
|
+
when Protocol::ReadyResponse
|
207
|
+
connection
|
208
|
+
when Protocol::ErrorResponse
|
209
|
+
raise r.to_error(VOID_STATEMENT)
|
210
|
+
else
|
211
|
+
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def challenge_response_cycle(connection, authenticator, token)
|
217
|
+
connection.send_request(Protocol::AuthResponseRequest.new(token), @execution_options.timeout).flat_map do |r|
|
218
|
+
case r
|
219
|
+
when Protocol::AuthChallengeResponse
|
220
|
+
token = authenticator.challenge_response(r.token)
|
221
|
+
challenge_response_cycle(pending_connection, authenticator, token)
|
222
|
+
when Protocol::AuthSuccessResponse
|
223
|
+
authenticator.authentication_successful(r.token) rescue nil
|
224
|
+
::Ione::Future.resolved(connection)
|
225
|
+
when Protocol::ErrorResponse
|
226
|
+
::Ione::Future.failed(r.to_error(VOID_STATEMENT))
|
227
|
+
else
|
228
|
+
::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
|
229
|
+
end
|
230
|
+
end
|
155
231
|
end
|
156
232
|
|
157
233
|
def create_additional_connections(host, count, established_connections, error = nil)
|
158
234
|
futures = count.times.map do
|
159
235
|
connect(host).recover do |e|
|
160
|
-
|
236
|
+
FailedConnection.new(e, host)
|
161
237
|
end
|
162
238
|
end
|
163
239
|
|
@@ -216,14 +292,19 @@ module Cassandra
|
|
216
292
|
connections -= 1
|
217
293
|
|
218
294
|
if connections == 0
|
219
|
-
notify = !error.nil?
|
295
|
+
notify = !error.nil?
|
220
296
|
@connections.delete(host)
|
221
297
|
else
|
222
298
|
@connections[host] = connections
|
223
299
|
end
|
224
300
|
end
|
225
301
|
|
226
|
-
@
|
302
|
+
@logger.debug("Host #{host.ip} closed connection (#{error.class.name}: #{error.message})") if error
|
303
|
+
|
304
|
+
if notify
|
305
|
+
@logger.warn("Host #{host.ip} closed all connections")
|
306
|
+
@registry.host_down(host.ip)
|
307
|
+
end
|
227
308
|
|
228
309
|
self
|
229
310
|
end
|
@@ -232,10 +313,15 @@ module Cassandra
|
|
232
313
|
notify = false
|
233
314
|
|
234
315
|
synchronize do
|
235
|
-
notify = !error.
|
316
|
+
notify = !error.nil? && !@connections.has_key?(host)
|
236
317
|
end
|
237
318
|
|
238
|
-
@
|
319
|
+
@logger.debug("Host #{host.ip} refused connection (#{error.class.name}: #{error.message})")
|
320
|
+
|
321
|
+
if notify
|
322
|
+
@logger.warn("Host #{host.ip} refused all connections")
|
323
|
+
@registry.host_down(host.ip)
|
324
|
+
end
|
239
325
|
|
240
326
|
self
|
241
327
|
end
|
@@ -22,7 +22,7 @@ module Cassandra
|
|
22
22
|
class ControlConnection
|
23
23
|
include MonitorMixin
|
24
24
|
|
25
|
-
def initialize(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, connector)
|
25
|
+
def initialize(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector)
|
26
26
|
@logger = logger
|
27
27
|
@io_reactor = io_reactor
|
28
28
|
@registry = cluster_registry
|
@@ -30,9 +30,15 @@ module Cassandra
|
|
30
30
|
@metadata = cluster_metadata
|
31
31
|
@load_balancing_policy = load_balancing_policy
|
32
32
|
@reconnection_policy = reconnection_policy
|
33
|
+
@address_resolver = address_resolution_policy
|
33
34
|
@connector = connector
|
34
35
|
@refreshing_statuses = Hash.new(false)
|
35
36
|
@status = :closed
|
37
|
+
@refreshing_schema = false
|
38
|
+
@refreshing_keyspaces = Hash.new(false)
|
39
|
+
@refreshing_tables = Hash.new
|
40
|
+
@refreshing_hosts = false
|
41
|
+
@refreshing_host = Hash.new(false)
|
36
42
|
|
37
43
|
mon_initialize
|
38
44
|
end
|
@@ -43,12 +49,14 @@ module Cassandra
|
|
43
49
|
@status = :connecting
|
44
50
|
end
|
45
51
|
|
46
|
-
@
|
47
|
-
|
48
|
-
@io_reactor.start.flat_map do
|
52
|
+
f = @io_reactor.start.flat_map do
|
49
53
|
plan = @load_balancing_policy.plan(nil, VOID_STATEMENT, VOID_OPTIONS)
|
50
54
|
connect_to_first_available(plan)
|
51
55
|
end
|
56
|
+
f.on_failure do |e|
|
57
|
+
close_async
|
58
|
+
end
|
59
|
+
f
|
52
60
|
end
|
53
61
|
|
54
62
|
def host_found(host)
|
@@ -56,31 +64,48 @@ module Cassandra
|
|
56
64
|
|
57
65
|
def host_lost(host)
|
58
66
|
synchronize do
|
59
|
-
@refreshing_statuses.delete(host)
|
67
|
+
timer = @refreshing_statuses.delete(host)
|
68
|
+
@io_reactor.cancel_timer(timer) if timer
|
60
69
|
end
|
70
|
+
|
71
|
+
nil
|
61
72
|
end
|
62
73
|
|
63
74
|
def host_up(host)
|
64
75
|
synchronize do
|
65
|
-
@refreshing_statuses.delete(host)
|
76
|
+
timer = @refreshing_statuses.delete(host)
|
77
|
+
@io_reactor.cancel_timer(timer) if timer
|
66
78
|
|
67
|
-
|
79
|
+
unless @connection || (@status == :closing || @status == :closed) || @load_balancing_policy.distance(host) == :ignore
|
80
|
+
return connect_to_first_available(@load_balancing_policy.plan(nil, VOID_STATEMENT, VOID_OPTIONS))
|
81
|
+
end
|
68
82
|
end
|
69
83
|
|
70
84
|
Ione::Future.resolved
|
71
85
|
end
|
72
86
|
|
73
87
|
def host_down(host)
|
88
|
+
schedule = nil
|
89
|
+
timer = nil
|
90
|
+
|
74
91
|
synchronize do
|
75
|
-
return Ione::Future.resolved if @refreshing_statuses[host]
|
92
|
+
return Ione::Future.resolved if @refreshing_statuses[host] || @load_balancing_policy.distance(host) == :ignore
|
93
|
+
|
94
|
+
schedule = @reconnection_policy.schedule
|
95
|
+
timeout = schedule.next
|
76
96
|
|
77
|
-
@logger.debug("Starting to continuously refresh status
|
78
|
-
|
97
|
+
@logger.debug("Starting to continuously refresh status of #{host.ip} in #{timeout} seconds")
|
98
|
+
|
99
|
+
@refreshing_statuses[host] = timer = @io_reactor.schedule_timer(timeout)
|
79
100
|
end
|
80
101
|
|
81
|
-
|
82
|
-
|
102
|
+
timer.on_value do
|
103
|
+
refresh_host_status(host).fallback do |e|
|
104
|
+
refresh_host_status_with_retry(timer, host, schedule)
|
105
|
+
end
|
83
106
|
end
|
107
|
+
|
108
|
+
nil
|
84
109
|
end
|
85
110
|
|
86
111
|
def close_async
|
@@ -116,19 +141,18 @@ module Cassandra
|
|
116
141
|
f = @io_reactor.schedule_timer(timeout)
|
117
142
|
f = f.flat_map do
|
118
143
|
if synchronize { @status == :reconnecting }
|
119
|
-
@logger.debug('Reestablishing control connection')
|
120
144
|
plan = @load_balancing_policy.plan(nil, VOID_STATEMENT, VOID_OPTIONS)
|
121
145
|
connect_to_first_available(plan)
|
122
146
|
else
|
123
|
-
@logger.debug('Stopping reconnection')
|
124
147
|
Ione::Future.resolved
|
125
148
|
end
|
126
149
|
end
|
127
|
-
f.fallback do
|
150
|
+
f.fallback do |e|
|
151
|
+
@logger.error("Control connection failed (#{e.class.name}: #{e.message})")
|
152
|
+
|
128
153
|
if synchronize { @status == :reconnecting }
|
129
154
|
reconnect_async(schedule)
|
130
155
|
else
|
131
|
-
@logger.debug('Stopping reconnection')
|
132
156
|
return Ione::Future.resolved
|
133
157
|
end
|
134
158
|
end
|
@@ -137,13 +161,20 @@ module Cassandra
|
|
137
161
|
def register_async
|
138
162
|
connection = @connection
|
139
163
|
|
140
|
-
return Ione::Future.failed(
|
141
|
-
|
142
|
-
@logger.debug('Registering for events')
|
143
|
-
|
144
|
-
connection.send_request(REGISTER).map do
|
145
|
-
@logger.debug('Registered for events')
|
164
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
146
165
|
|
166
|
+
f = connection.send_request(REGISTER)
|
167
|
+
f = f.map do |r|
|
168
|
+
case r
|
169
|
+
when Protocol::ReadyResponse
|
170
|
+
nil
|
171
|
+
when Protocol::ErrorResponse
|
172
|
+
raise r.to_error(VOID_STATEMENT)
|
173
|
+
else
|
174
|
+
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
175
|
+
end
|
176
|
+
end
|
177
|
+
f = f.map do
|
147
178
|
connection.on_event do |event|
|
148
179
|
@logger.debug("Event received #{event}")
|
149
180
|
|
@@ -151,21 +182,21 @@ module Cassandra
|
|
151
182
|
case event.change
|
152
183
|
when 'CREATED'
|
153
184
|
if event.table.empty?
|
154
|
-
|
185
|
+
refresh_schema_async_maybe_retry
|
155
186
|
else
|
156
|
-
|
187
|
+
refresh_keyspace_async_maybe_retry(event.keyspace)
|
157
188
|
end
|
158
189
|
when 'DROPPED'
|
159
190
|
if event.table.empty?
|
160
|
-
|
191
|
+
refresh_schema_async_maybe_retry
|
161
192
|
else
|
162
|
-
|
193
|
+
refresh_keyspace_async_maybe_retry(event.keyspace)
|
163
194
|
end
|
164
195
|
when 'UPDATED'
|
165
196
|
if event.table.empty?
|
166
|
-
|
197
|
+
refresh_keyspace_async_maybe_retry(event.keyspace)
|
167
198
|
else
|
168
|
-
|
199
|
+
refresh_table_async_maybe_retry(event.keyspace, event.table)
|
169
200
|
end
|
170
201
|
end
|
171
202
|
else
|
@@ -173,19 +204,19 @@ module Cassandra
|
|
173
204
|
when 'UP'
|
174
205
|
address = event.address
|
175
206
|
|
176
|
-
|
207
|
+
refresh_host_async_maybe_retry(address) if @registry.has_host?(address)
|
177
208
|
when 'DOWN'
|
178
209
|
@registry.host_down(event.address)
|
179
210
|
when 'NEW_NODE'
|
180
211
|
address = event.address
|
181
212
|
|
182
213
|
unless @registry.has_host?(address)
|
183
|
-
|
184
|
-
|
214
|
+
refresh_host_async_maybe_retry(address)
|
215
|
+
refresh_schema_async_maybe_retry
|
185
216
|
end
|
186
217
|
when 'REMOVED_NODE'
|
187
218
|
@registry.host_lost(event.address)
|
188
|
-
|
219
|
+
refresh_schema_async_maybe_retry
|
189
220
|
end
|
190
221
|
end
|
191
222
|
end
|
@@ -197,85 +228,246 @@ module Cassandra
|
|
197
228
|
def refresh_schema_async
|
198
229
|
connection = @connection
|
199
230
|
|
200
|
-
return Ione::Future.failed(
|
201
|
-
|
202
|
-
@logger.debug('Fetching schema metadata')
|
231
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
203
232
|
|
204
|
-
keyspaces = connection
|
205
|
-
tables = connection
|
206
|
-
columns = connection
|
233
|
+
keyspaces = send_select_request(connection, SELECT_KEYSPACES)
|
234
|
+
tables = send_select_request(connection, SELECT_TABLES)
|
235
|
+
columns = send_select_request(connection, SELECT_COLUMNS)
|
207
236
|
|
208
237
|
Ione::Future.all(keyspaces, tables, columns).map do |(keyspaces, tables, columns)|
|
209
|
-
@logger.debug('Fetched schema metadata')
|
210
|
-
|
211
238
|
host = @registry.host(connection.host)
|
212
239
|
|
213
|
-
@schema.update_keyspaces(host, keyspaces
|
240
|
+
@schema.update_keyspaces(host, keyspaces, tables, columns)
|
214
241
|
@metadata.rebuild_token_map
|
215
242
|
end
|
216
243
|
end
|
217
244
|
|
245
|
+
def refresh_schema_async_maybe_retry
|
246
|
+
synchronize do
|
247
|
+
return Ione::Future.resolved if @refreshing_schema
|
248
|
+
@refreshing_schema = true
|
249
|
+
end
|
250
|
+
|
251
|
+
refresh_schema_async.fallback do |e|
|
252
|
+
case e
|
253
|
+
when Errors::HostError
|
254
|
+
refresh_schema_async_retry(e, @reconnection_policy.schedule)
|
255
|
+
else
|
256
|
+
connection = @connection
|
257
|
+
connection && connection.close(e)
|
258
|
+
|
259
|
+
Ione::Future.resolved
|
260
|
+
end
|
261
|
+
end.map do
|
262
|
+
synchronize do
|
263
|
+
@refreshing_schema = false
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def refresh_schema_async_retry(error, schedule)
|
269
|
+
timeout = schedule.next
|
270
|
+
@logger.info("Failed to refresh schema (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
271
|
+
|
272
|
+
timer = @io_reactor.schedule_timer(timeout)
|
273
|
+
timer.flat_map do
|
274
|
+
refresh_schema_async.fallback do |e|
|
275
|
+
case e
|
276
|
+
when Errors::HostError
|
277
|
+
refresh_schema_async_retry(e, schedule)
|
278
|
+
else
|
279
|
+
connection = @connection
|
280
|
+
connection && connection.close(e)
|
281
|
+
|
282
|
+
Ione::Future.resolved
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def refresh_keyspace_async_maybe_retry(keyspace)
|
289
|
+
synchronize do
|
290
|
+
return Ione::Future.resolved if @refreshing_schema || @refreshing_keyspaces[keyspace]
|
291
|
+
@refreshing_keyspaces[keyspace] = true
|
292
|
+
end
|
293
|
+
|
294
|
+
refresh_keyspace_async(keyspace).fallback do |e|
|
295
|
+
case e
|
296
|
+
when Errors::HostError
|
297
|
+
refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
|
298
|
+
else
|
299
|
+
connection = @connection
|
300
|
+
connection && connection.close(e)
|
301
|
+
|
302
|
+
Ione::Future.resolved
|
303
|
+
end
|
304
|
+
end.map do
|
305
|
+
synchronize do
|
306
|
+
@refreshing_keyspaces.delete(host)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def refresh_keyspace_async_retry(keyspace, error, schedule)
|
312
|
+
timeout = schedule.next
|
313
|
+
@logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
314
|
+
|
315
|
+
timer = @io_reactor.schedule_timer(timeout)
|
316
|
+
timer.flat_map do
|
317
|
+
refresh_keyspace_async(keyspace).fallback do |e|
|
318
|
+
case e
|
319
|
+
when Errors::HostError
|
320
|
+
refresh_keyspace_async_retry(keyspace, e, schedule)
|
321
|
+
else
|
322
|
+
connection = @connection
|
323
|
+
connection && connection.close(e)
|
324
|
+
|
325
|
+
Ione::Future.resolved
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
218
331
|
def refresh_keyspace_async(keyspace)
|
219
332
|
connection = @connection
|
220
333
|
|
221
|
-
return Ione::Future.failed(
|
334
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
222
335
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
keyspaces = connection.send_request(Protocol::QueryRequest.new("SELECT * FROM system.schema_keyspaces WHERE keyspace_name = ?", params, nil, :one))
|
227
|
-
tables = connection.send_request(Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = ?", params, nil, :one))
|
228
|
-
columns = connection.send_request(Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = ?", params, nil, :one))
|
336
|
+
keyspaces = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_keyspaces WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
|
337
|
+
tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
|
338
|
+
columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
|
229
339
|
|
230
340
|
Ione::Future.all(keyspaces, tables, columns).map do |(keyspaces, tables, columns)|
|
231
|
-
@logger.debug("Fetched keyspace #{keyspace.inspect} metadata")
|
232
|
-
|
233
341
|
host = @registry.host(connection.host)
|
234
342
|
|
235
|
-
@schema.update_keyspace(host, keyspaces.
|
343
|
+
@schema.update_keyspace(host, keyspaces.first, tables, columns) unless keyspaces.empty?
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def refresh_table_async_maybe_retry(keyspace, table)
|
348
|
+
synchronize do
|
349
|
+
return Ione::Future.resolved if @refreshing_schema || @refreshing_keyspaces[keyspace] || @refreshing_tables[keyspace][table]
|
350
|
+
@refreshing_tables[keyspace] ||= ::Hash.new(false)
|
351
|
+
@refreshing_tables[keyspace][table] = true
|
352
|
+
end
|
353
|
+
|
354
|
+
refresh_table_async(keyspace, table).fallback do |e|
|
355
|
+
case e
|
356
|
+
when Errors::HostError
|
357
|
+
refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
|
358
|
+
else
|
359
|
+
connection = @connection
|
360
|
+
connection && connection.close(e)
|
361
|
+
|
362
|
+
Ione::Future.resolved
|
363
|
+
end
|
364
|
+
end.map do
|
365
|
+
synchronize do
|
366
|
+
@refreshing_tables[keyspace].delete(table)
|
367
|
+
@refreshing_tables.delete(keyspace) if @refreshing_tables[keyspace].empty?
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def refresh_table_async_retry(keyspace, table, error, schedule)
|
373
|
+
timeout = schedule.next
|
374
|
+
@logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
375
|
+
|
376
|
+
timer = @io_reactor.schedule_timer(timeout)
|
377
|
+
timer.flat_map do
|
378
|
+
refresh_keyspace_async(keyspace).fallback do |e|
|
379
|
+
case e
|
380
|
+
when Errors::HostError
|
381
|
+
refresh_keyspace_async_retry(keyspace, e, schedule)
|
382
|
+
else
|
383
|
+
connection = @connection
|
384
|
+
connection && connection.close(e)
|
385
|
+
|
386
|
+
Ione::Future.resolved
|
387
|
+
end
|
388
|
+
end
|
236
389
|
end
|
237
390
|
end
|
238
391
|
|
239
392
|
def refresh_table_async(keyspace, table)
|
240
393
|
connection = @connection
|
241
394
|
|
242
|
-
return Ione::Future.failed(
|
243
|
-
|
244
|
-
@logger.debug("Fetching table \"#{keyspace}.#{table}\" metadata")
|
395
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
245
396
|
|
246
397
|
params = [keyspace, table]
|
247
|
-
table = connection
|
248
|
-
columns = connection
|
398
|
+
table = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, nil, nil, :one))
|
399
|
+
columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, nil, nil, :one))
|
249
400
|
|
250
401
|
Ione::Future.all(table, columns).map do |(table, columns)|
|
251
|
-
@logger.debug("Fetched table \"#{keyspace}.#{table}\" metadata")
|
252
|
-
|
253
402
|
host = @registry.host(connection.host)
|
254
403
|
|
255
|
-
@schema.udpate_table(host, keyspace, table
|
404
|
+
@schema.udpate_table(host, keyspace, table, columns)
|
256
405
|
end
|
257
406
|
end
|
258
407
|
|
259
|
-
def
|
260
|
-
|
408
|
+
def refresh_hosts_async_maybe_retry
|
409
|
+
synchronize do
|
410
|
+
return Ione::Future.resolved if @refreshing_hosts
|
411
|
+
@refreshing_hosts = true
|
412
|
+
end
|
261
413
|
|
262
|
-
|
414
|
+
refresh_hosts_async.fallback do |e|
|
415
|
+
case e
|
416
|
+
when Errors::HostError
|
417
|
+
refresh_hosts_async_retry(e, @reconnection_policy.schedule)
|
418
|
+
else
|
419
|
+
connection = @connection
|
420
|
+
connection && connection.close(e)
|
263
421
|
|
264
|
-
|
422
|
+
Ione::Future.resolved
|
423
|
+
end
|
424
|
+
end.map do
|
425
|
+
synchronize do
|
426
|
+
@refreshing_hosts = false
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
265
430
|
|
266
|
-
|
267
|
-
|
431
|
+
def refresh_hosts_async_retry(error, schedule)
|
432
|
+
timeout = schedule.next
|
433
|
+
@logger.info("Failed to refresh hosts (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
434
|
+
|
435
|
+
timer = @io_reactor.schedule_timer(timeout)
|
436
|
+
timer.flat_map do
|
437
|
+
refresh_hosts_async.fallback do |e|
|
438
|
+
case e
|
439
|
+
when Errors::HostError
|
440
|
+
refresh_hosts_async_retry(e, schedule)
|
441
|
+
else
|
442
|
+
connection = @connection
|
443
|
+
connection && connection.close(e)
|
444
|
+
|
445
|
+
Ione::Future.resolved
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
268
450
|
|
269
|
-
|
270
|
-
|
271
|
-
peers = peers.rows
|
451
|
+
def refresh_hosts_async
|
452
|
+
connection = @connection
|
272
453
|
|
273
|
-
|
454
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
274
455
|
|
275
|
-
|
456
|
+
local = send_select_request(connection, SELECT_LOCAL)
|
457
|
+
peers = send_select_request(connection, SELECT_PEERS)
|
458
|
+
|
459
|
+
Ione::Future.all(local, peers).map do |(local, peers)|
|
460
|
+
@logger.debug("#{peers.size} peer(s) found")
|
276
461
|
|
277
462
|
ips = ::Set.new
|
278
463
|
|
464
|
+
unless local.empty?
|
465
|
+
ips << ip = IPAddr.new(connection.host)
|
466
|
+
data = local.first
|
467
|
+
@registry.host_found(ip, data)
|
468
|
+
@metadata.update(data)
|
469
|
+
end
|
470
|
+
|
279
471
|
peers.each do |data|
|
280
472
|
ip = peer_ip(data)
|
281
473
|
next unless ip
|
@@ -283,27 +475,11 @@ module Cassandra
|
|
283
475
|
@registry.host_found(ip, data)
|
284
476
|
end
|
285
477
|
|
286
|
-
ips << ip = IPAddr.new(connection.host)
|
287
|
-
data = local.first
|
288
|
-
@registry.host_found(ip, data)
|
289
|
-
|
290
|
-
futures = []
|
291
|
-
|
292
478
|
@registry.each_host do |host|
|
293
|
-
|
294
|
-
futures << refresh_host_status(host) if host.down?
|
295
|
-
else
|
296
|
-
@registry.host_lost(host.ip)
|
297
|
-
end
|
479
|
+
@registry.host_lost(host.ip) unless ips.include?(host.ip)
|
298
480
|
end
|
299
481
|
|
300
|
-
|
301
|
-
|
302
|
-
if futures.empty?
|
303
|
-
Ione::Future.resolved
|
304
|
-
else
|
305
|
-
Ione::Future.all(*futures)
|
306
|
-
end
|
482
|
+
nil
|
307
483
|
end
|
308
484
|
end
|
309
485
|
|
@@ -311,46 +487,87 @@ module Cassandra
|
|
311
487
|
@connector.refresh_status(host)
|
312
488
|
end
|
313
489
|
|
314
|
-
def refresh_host_status_with_retry(host, schedule)
|
315
|
-
|
490
|
+
def refresh_host_status_with_retry(original_timer, host, schedule)
|
491
|
+
timer = nil
|
316
492
|
|
317
|
-
|
493
|
+
synchronize do
|
494
|
+
timer = @refreshing_statuses[host]
|
318
495
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
496
|
+
# host must have been lost/up or timer was rescheduled
|
497
|
+
return Ione::Future.resolved if timer.nil? || timer != original_timer
|
498
|
+
|
499
|
+
timeout = schedule.next
|
500
|
+
|
501
|
+
@logger.debug("Checking host #{host.ip} in #{timeout} seconds")
|
502
|
+
|
503
|
+
@refreshing_statuses[host] = timer = @io_reactor.schedule_timer(timeout)
|
504
|
+
end
|
505
|
+
|
506
|
+
timer.on_value do
|
507
|
+
refresh_host_status(host).fallback do |e|
|
508
|
+
refresh_host_status_with_retry(timer, host, schedule)
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
def refresh_host_async_maybe_retry(host)
|
514
|
+
synchronize do
|
515
|
+
return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[host]
|
516
|
+
@refreshing_host[host] = true
|
517
|
+
end
|
518
|
+
|
519
|
+
refresh_host_async(host).fallback do |e|
|
520
|
+
case e
|
521
|
+
when Errors::HostError
|
522
|
+
refresh_host_async_retry(host, e, @reconnection_policy.schedule)
|
325
523
|
else
|
524
|
+
connection = @connection
|
525
|
+
connection && connection.close(e)
|
526
|
+
|
326
527
|
Ione::Future.resolved
|
327
528
|
end
|
529
|
+
end.map do
|
530
|
+
synchronize do
|
531
|
+
@refreshing_host.delete(host)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def refresh_host_async_retry(host, error, schedule)
|
537
|
+
timeout = schedule.next
|
538
|
+
@logger.info("Failed to refresh host #{host.ip.to_s} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
539
|
+
|
540
|
+
timer = @io_reactor.schedule_timer(timeout)
|
541
|
+
timer.flat_map do
|
542
|
+
refresh_host_async(host).fallback do |e|
|
543
|
+
case e
|
544
|
+
when Errors::HostError
|
545
|
+
refresh_host_async_retry(host, e, schedule)
|
546
|
+
else
|
547
|
+
connection = @connection
|
548
|
+
connection && connection.close(e)
|
549
|
+
|
550
|
+
Ione::Future.resolved
|
551
|
+
end
|
552
|
+
end
|
328
553
|
end
|
329
554
|
end
|
330
555
|
|
331
556
|
def refresh_host_async(address)
|
332
557
|
connection = @connection
|
333
|
-
return Ione::Future.failed(
|
558
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
334
559
|
|
335
560
|
ip = address.to_s
|
336
561
|
|
337
|
-
@logger.debug('Fetching node information for %s' % ip)
|
338
|
-
|
339
562
|
if ip == connection.host
|
340
563
|
request = SELECT_LOCAL
|
341
564
|
else
|
342
|
-
request = Protocol::QueryRequest.new(
|
565
|
+
request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" % address, nil, nil, :one)
|
343
566
|
end
|
344
567
|
|
345
|
-
connection
|
346
|
-
@logger.debug('Fetched node information for %s' % ip)
|
347
|
-
|
348
|
-
rows = response.rows
|
349
|
-
|
568
|
+
send_select_request(connection, request).map do |rows|
|
350
569
|
unless rows.empty?
|
351
570
|
@registry.host_found(address, rows.first)
|
352
|
-
host = @registry.host(address)
|
353
|
-
refresh_host_status(host) if host.down?
|
354
571
|
end
|
355
572
|
|
356
573
|
self
|
@@ -359,33 +576,50 @@ module Cassandra
|
|
359
576
|
|
360
577
|
def connect_to_first_available(plan, errors = nil)
|
361
578
|
unless plan.has_next?
|
362
|
-
@
|
363
|
-
|
579
|
+
if errors.nil? && synchronize { @refreshing_statuses.empty? }
|
580
|
+
@logger.fatal(<<-MSG)
|
581
|
+
Control connection failed and is unlikely to recover.
|
582
|
+
|
583
|
+
This usually means that all hosts are ignored by current load
|
584
|
+
balancing policy, most likely because they changed datacenters.
|
585
|
+
Reconnections attempts will continue getting scheduled to
|
586
|
+
repeat this message in the logs.
|
587
|
+
MSG
|
588
|
+
end
|
589
|
+
|
590
|
+
return Ione::Future.failed(Errors::NoHostsAvailable.new(errors))
|
364
591
|
end
|
365
592
|
|
366
593
|
host = plan.next
|
367
|
-
@logger.debug("
|
594
|
+
@logger.debug("Connecting to #{host.ip}")
|
595
|
+
|
368
596
|
f = connect_to_host(host)
|
369
597
|
f = f.flat_map do |connection|
|
370
598
|
synchronize do
|
371
599
|
@status = :connected
|
372
600
|
|
373
|
-
@logger.debug("Control connection established ip=#{connection.host}")
|
374
601
|
@connection = connection
|
375
602
|
|
376
|
-
connection.on_closed do
|
603
|
+
connection.on_closed do |cause|
|
377
604
|
reconnect = false
|
378
605
|
|
379
606
|
synchronize do
|
380
|
-
if
|
381
|
-
@status
|
382
|
-
|
383
|
-
|
384
|
-
|
607
|
+
if connection == @connection
|
608
|
+
if @status == :closing
|
609
|
+
@status = :closed
|
610
|
+
else
|
611
|
+
@status = :reconnecting
|
612
|
+
reconnect = true
|
613
|
+
end
|
614
|
+
|
615
|
+
if cause
|
616
|
+
@logger.info("Control connection closed (#{cause.class.name}: #{cause.message})")
|
617
|
+
else
|
618
|
+
@logger.info("Control connection closed")
|
619
|
+
end
|
620
|
+
|
621
|
+
@connection = nil
|
385
622
|
end
|
386
|
-
|
387
|
-
@logger.debug("Control connection closed ip=#{connection.host}")
|
388
|
-
@connection = nil
|
389
623
|
end
|
390
624
|
|
391
625
|
reconnect_async(@reconnection_policy.schedule) if reconnect
|
@@ -394,23 +628,26 @@ module Cassandra
|
|
394
628
|
|
395
629
|
register_async
|
396
630
|
end
|
397
|
-
f = f.flat_map {
|
398
|
-
f = f.flat_map {
|
399
|
-
f.fallback do |error|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
Ione::Future.failed(Errors::AuthenticationError.new(error.message))
|
405
|
-
else
|
406
|
-
Ione::Future.failed(error)
|
407
|
-
end
|
408
|
-
else
|
631
|
+
f = f.flat_map { refresh_hosts_async_maybe_retry }
|
632
|
+
f = f.flat_map { refresh_schema_async_maybe_retry }
|
633
|
+
f = f.fallback do |error|
|
634
|
+
@logger.debug("Connection to #{host.ip} failed (#{error.class.name}: #{error.message})")
|
635
|
+
|
636
|
+
case error
|
637
|
+
when Errors::HostError
|
409
638
|
errors ||= {}
|
410
639
|
errors[host] = error
|
411
640
|
connect_to_first_available(plan, errors)
|
641
|
+
else
|
642
|
+
Ione::Future.failed(error)
|
412
643
|
end
|
413
644
|
end
|
645
|
+
|
646
|
+
f.on_complete do |f|
|
647
|
+
@logger.info('Control connection established') if f.resolved?
|
648
|
+
end
|
649
|
+
|
650
|
+
f
|
414
651
|
end
|
415
652
|
|
416
653
|
def connect_to_host(host)
|
@@ -420,7 +657,21 @@ module Cassandra
|
|
420
657
|
def peer_ip(data)
|
421
658
|
ip = data['rpc_address']
|
422
659
|
ip = data['peer'] if ip == '0.0.0.0'
|
423
|
-
|
660
|
+
|
661
|
+
@address_resolver.resolve(ip)
|
662
|
+
end
|
663
|
+
|
664
|
+
def send_select_request(connection, request)
|
665
|
+
connection.send_request(request).map do |r|
|
666
|
+
case r
|
667
|
+
when Protocol::RowsResultResponse
|
668
|
+
r.rows
|
669
|
+
when Protocol::ErrorResponse
|
670
|
+
raise r.to_error(VOID_STATEMENT)
|
671
|
+
else
|
672
|
+
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
673
|
+
end
|
674
|
+
end
|
424
675
|
end
|
425
676
|
end
|
426
677
|
end
|