cassandra-driver 1.0.0.beta.3-java → 1.0.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|