cassandra-driver 1.0.0.rc.1-java → 1.1.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 +58 -18
- data/lib/cassandra.rb +132 -93
- data/lib/cassandra/auth.rb +3 -3
- data/lib/cassandra/cluster.rb +65 -39
- data/lib/cassandra/cluster/client.rb +67 -28
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
- data/lib/cassandra/cluster/connector.rb +101 -30
- data/lib/cassandra/cluster/control_connection.rb +160 -96
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +26 -11
- data/lib/cassandra/cluster/schema.rb +22 -1
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/driver.rb +46 -12
- data/lib/cassandra/errors.rb +5 -5
- data/lib/cassandra/execution/options.rb +42 -8
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/executors.rb +111 -0
- data/lib/cassandra/future.rb +88 -64
- data/lib/cassandra/keyspace.rb +12 -0
- data/lib/cassandra/load_balancing.rb +10 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
- data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
- data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
- data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/result.rb +34 -9
- data/lib/cassandra/session.rb +6 -0
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +5 -0
- data/lib/cassandra/util.rb +130 -0
- data/lib/cassandra/version.rb +1 -1
- metadata +40 -50
- 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 -273
- 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 -70
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
data/lib/cassandra/auth.rb
CHANGED
@@ -18,9 +18,9 @@
|
|
18
18
|
|
19
19
|
module Cassandra
|
20
20
|
module Auth
|
21
|
-
# An auth provider is a factory for {Cassandra::Auth::Authenticator} instances
|
22
|
-
#
|
23
|
-
#
|
21
|
+
# An auth provider is a factory for {Cassandra::Auth::Authenticator authenticator} instances (or objects matching that interface). Its
|
22
|
+
# {#create_authenticator} will be called once for each connection that
|
23
|
+
# requires authentication.
|
24
24
|
#
|
25
25
|
# If the authentication requires keeping state, keep that in the
|
26
26
|
# authenticator instances, not in the auth provider.
|
data/lib/cassandra/cluster.rb
CHANGED
@@ -17,8 +17,7 @@
|
|
17
17
|
#++
|
18
18
|
|
19
19
|
module Cassandra
|
20
|
-
# Cluster represents a cassandra cluster. It serves as a {Cassandra::Session}
|
21
|
-
# factory and a collection of metadata.
|
20
|
+
# Cluster represents a cassandra cluster. It serves as a {Cassandra::Session session factory} factory and a collection of metadata.
|
22
21
|
#
|
23
22
|
# @see Cassandra::Cluster#connect Creating a new session
|
24
23
|
# @see Cassandra::Cluster#each_host Getting all peers in the cluster
|
@@ -26,46 +25,11 @@ module Cassandra
|
|
26
25
|
class Cluster
|
27
26
|
extend Forwardable
|
28
27
|
|
29
|
-
# @!method host(address)
|
30
|
-
# Find a host by its address
|
31
|
-
# @param address [IPAddr, String] ip address
|
32
|
-
# @return [Cassandra::Host, nil] host or nil
|
33
|
-
#
|
34
|
-
# @!method has_host?(address)
|
35
|
-
# Determine if a host by a given address exists
|
36
|
-
# @param address [IPAddr, String] ip address
|
37
|
-
# @return [Boolean] true or false
|
38
|
-
def_delegators :@registry, :host, :has_host?
|
39
|
-
|
40
|
-
# @!method keyspace(name)
|
41
|
-
# Find a keyspace by name
|
42
|
-
# @param name [String] keyspace name
|
43
|
-
# @return [Cassandra::Keyspace, nil] keyspace or nil
|
44
|
-
#
|
45
|
-
# @!method has_keyspace?(name)
|
46
|
-
# Determine if a keyspace by a given name exists
|
47
|
-
# @param name [String] keyspace name
|
48
|
-
# @return [Boolean] true or false
|
49
|
-
def_delegators :@schema, :keyspace, :has_keyspace?
|
50
|
-
|
51
|
-
# @!method name
|
52
|
-
# Return cluster's name
|
53
|
-
# @return [String] cluster's name
|
54
|
-
#
|
55
|
-
# @!method find_replicas(keyspace, statement)
|
56
|
-
# Return replicas for a given statement and keyspace
|
57
|
-
# @note an empty list is returned when statement/keyspace information is
|
58
|
-
# not enough to determine replica list.
|
59
|
-
# @param keyspace [String] keyspace name
|
60
|
-
# @param statement [Cassandra::Statement] statement for which to find
|
61
|
-
# replicas
|
62
|
-
# @return [Array<Cassandra::Host>] a list of replicas
|
63
|
-
def_delegators :@metadata, :name, :find_replicas
|
64
|
-
|
65
28
|
# @private
|
66
|
-
def initialize(logger, io_reactor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory)
|
29
|
+
def initialize(logger, io_reactor, executor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory)
|
67
30
|
@logger = logger
|
68
31
|
@io_reactor = io_reactor
|
32
|
+
@executor = executor
|
69
33
|
@control_connection = control_connection
|
70
34
|
@registry = cluster_registry
|
71
35
|
@schema = cluster_schema
|
@@ -78,8 +42,26 @@ module Cassandra
|
|
78
42
|
@address_resolver = address_resolution_policy
|
79
43
|
@connector = connector
|
80
44
|
@futures = futures_factory
|
45
|
+
|
46
|
+
@control_connection.on_close do |cause|
|
47
|
+
@load_balancing_policy.teardown(self) rescue nil
|
48
|
+
end
|
81
49
|
end
|
82
50
|
|
51
|
+
# @!method name
|
52
|
+
# Return cluster's name
|
53
|
+
# @return [String] cluster's name
|
54
|
+
#
|
55
|
+
# @!method find_replicas(keyspace, statement)
|
56
|
+
# Return replicas for a given statement and keyspace
|
57
|
+
# @note an empty list is returned when statement/keyspace information is
|
58
|
+
# not enough to determine replica list.
|
59
|
+
# @param keyspace [String] keyspace name
|
60
|
+
# @param statement [Cassandra::Statement] statement for which to find
|
61
|
+
# replicas
|
62
|
+
# @return [Array<Cassandra::Host>] a list of replicas
|
63
|
+
def_delegators :@metadata, :name, :find_replicas
|
64
|
+
|
83
65
|
# Register a cluster state listener. State listener will start receiving
|
84
66
|
# notifications about topology and schema changes
|
85
67
|
#
|
@@ -115,6 +97,17 @@ module Cassandra
|
|
115
97
|
end
|
116
98
|
alias :hosts :each_host
|
117
99
|
|
100
|
+
# @!method host(address)
|
101
|
+
# Find a host by its address
|
102
|
+
# @param address [IPAddr, String] ip address
|
103
|
+
# @return [Cassandra::Host, nil] host or nil
|
104
|
+
#
|
105
|
+
# @!method has_host?(address)
|
106
|
+
# Determine if a host by a given address exists
|
107
|
+
# @param address [IPAddr, String] ip address
|
108
|
+
# @return [Boolean] true or false
|
109
|
+
def_delegators :@registry, :host, :has_host?
|
110
|
+
|
118
111
|
# Yield or enumerate each keyspace defined in this cluster
|
119
112
|
# @overload each_keyspace
|
120
113
|
# @yieldparam keyspace [Cassandra::Keyspace] current keyspace
|
@@ -128,6 +121,35 @@ module Cassandra
|
|
128
121
|
end
|
129
122
|
alias :keyspaces :each_keyspace
|
130
123
|
|
124
|
+
# @!method keyspace(name)
|
125
|
+
# Find a keyspace by name
|
126
|
+
# @param name [String] keyspace name
|
127
|
+
# @return [Cassandra::Keyspace, nil] keyspace or nil
|
128
|
+
#
|
129
|
+
# @!method has_keyspace?(name)
|
130
|
+
# Determine if a keyspace by a given name exists
|
131
|
+
# @param name [String] keyspace name
|
132
|
+
# @return [Boolean] true or false
|
133
|
+
def_delegators :@schema, :keyspace, :has_keyspace?
|
134
|
+
|
135
|
+
# @!method refresh_schema_async
|
136
|
+
# Trigger an asynchronous schema metadata refresh
|
137
|
+
# @return [Cassandra::Future<nil>] a future that will be fulfilled when
|
138
|
+
# schema metadata has been refreshed
|
139
|
+
def_delegator :@control_connection, :refresh_schema_async_maybe_retry, \
|
140
|
+
:refresh_schema_async
|
141
|
+
|
142
|
+
# Synchronously refresh schema metadata
|
143
|
+
#
|
144
|
+
# @return [nil] nothing
|
145
|
+
# @raise [Cassandra::Errors::ClientError] when cluster is disconnected
|
146
|
+
# @raise [Cassandra::Error] other unexpected errors
|
147
|
+
#
|
148
|
+
# @see Cassandra::Cluster#refresh_schema_async
|
149
|
+
def refresh_schema
|
150
|
+
refresh_schema_async.get
|
151
|
+
end
|
152
|
+
|
131
153
|
# Asynchronously create a new session, optionally scoped to a keyspace
|
132
154
|
#
|
133
155
|
# @param keyspace [String] optional keyspace to scope session to
|
@@ -195,6 +217,8 @@ module Cassandra
|
|
195
217
|
else
|
196
218
|
f.on_failure {|e| promise.break(e)}
|
197
219
|
end
|
220
|
+
|
221
|
+
@executor.shutdown
|
198
222
|
end
|
199
223
|
|
200
224
|
promise.future
|
@@ -217,8 +241,10 @@ module Cassandra
|
|
217
241
|
end
|
218
242
|
|
219
243
|
require 'cassandra/cluster/client'
|
244
|
+
require 'cassandra/cluster/connection_pool'
|
220
245
|
require 'cassandra/cluster/connector'
|
221
246
|
require 'cassandra/cluster/control_connection'
|
247
|
+
require 'cassandra/cluster/failed_connection'
|
222
248
|
require 'cassandra/cluster/metadata'
|
223
249
|
require 'cassandra/cluster/options'
|
224
250
|
require 'cassandra/cluster/registry'
|
@@ -63,11 +63,12 @@ module Cassandra
|
|
63
63
|
@connected_future = begin
|
64
64
|
@logger.info('Creating session')
|
65
65
|
@registry.add_listener(self)
|
66
|
+
@schema.add_listener(self)
|
66
67
|
|
67
68
|
futures = @connecting_hosts.map do |(host, distance)|
|
68
69
|
f = connect_to_host(host, distance)
|
69
70
|
f.recover do |error|
|
70
|
-
|
71
|
+
FailedConnection.new(error, host)
|
71
72
|
end
|
72
73
|
end
|
73
74
|
|
@@ -100,6 +101,7 @@ module Cassandra
|
|
100
101
|
|
101
102
|
@closed_future = begin
|
102
103
|
@registry.remove_listener(self)
|
104
|
+
@schema.remove_listener(self)
|
103
105
|
|
104
106
|
if state == :connecting
|
105
107
|
f = @connected_future.recover.flat_map { close_connections }
|
@@ -138,7 +140,7 @@ module Cassandra
|
|
138
140
|
end
|
139
141
|
|
140
142
|
def host_down(host)
|
141
|
-
|
143
|
+
pool = nil
|
142
144
|
|
143
145
|
synchronize do
|
144
146
|
return Ione::Future.resolved if !@connections.has_key?(host) && !@connecting_hosts.include?(host)
|
@@ -147,18 +149,30 @@ module Cassandra
|
|
147
149
|
@prepared_statements.delete(host)
|
148
150
|
@preparing_statements.delete(host)
|
149
151
|
|
150
|
-
|
152
|
+
pool = @connections.delete(host)
|
151
153
|
end
|
152
154
|
|
153
|
-
if
|
154
|
-
Ione::Future.all(*
|
155
|
+
if pool
|
156
|
+
Ione::Future.all(*pool.snapshot.map! {|c| c.close}).map(nil)
|
155
157
|
else
|
156
158
|
Ione::Future.resolved
|
157
159
|
end
|
158
160
|
end
|
159
161
|
|
160
|
-
def
|
161
|
-
|
162
|
+
def keyspace_created(keyspace)
|
163
|
+
end
|
164
|
+
|
165
|
+
def keyspace_changed(keyspace)
|
166
|
+
end
|
167
|
+
|
168
|
+
def keyspace_dropped(keyspace)
|
169
|
+
@keyspace = nil if @keyspace == keyspace.name
|
170
|
+
nil
|
171
|
+
end
|
172
|
+
|
173
|
+
|
174
|
+
def query(statement, options)
|
175
|
+
request = Protocol::QueryRequest.new(statement.cql, statement.params, nil, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?)
|
162
176
|
timeout = options.timeout
|
163
177
|
promise = @futures.promise
|
164
178
|
|
@@ -184,10 +198,10 @@ module Cassandra
|
|
184
198
|
promise.future
|
185
199
|
end
|
186
200
|
|
187
|
-
def execute(statement, options
|
201
|
+
def execute(statement, options)
|
188
202
|
timeout = options.timeout
|
189
203
|
result_metadata = statement.result_metadata
|
190
|
-
request = Protocol::ExecuteRequest.new(nil, statement.params_metadata, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, paging_state, options.trace?)
|
204
|
+
request = Protocol::ExecuteRequest.new(nil, statement.params_metadata, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?)
|
191
205
|
promise = @futures.promise
|
192
206
|
|
193
207
|
keyspace = @keyspace
|
@@ -331,19 +345,46 @@ module Cassandra
|
|
331
345
|
return NO_CONNECTIONS
|
332
346
|
end
|
333
347
|
|
334
|
-
|
348
|
+
pool = nil
|
349
|
+
existing_connections = 0
|
350
|
+
|
351
|
+
synchronize do
|
352
|
+
pool = @connections[host]
|
353
|
+
end
|
354
|
+
|
355
|
+
existing_connections = pool.size if pool
|
356
|
+
pool = nil
|
357
|
+
missing_connections = (pool_size - existing_connections)
|
358
|
+
return Ione::Future.resolved if missing_connections <= 0
|
359
|
+
|
360
|
+
f = @connector.connect_many(host, missing_connections)
|
335
361
|
|
336
362
|
f.on_value do |connections|
|
337
|
-
|
363
|
+
pool = nil
|
338
364
|
|
339
365
|
synchronize do
|
340
366
|
@connecting_hosts.delete(host)
|
341
367
|
@prepared_statements[host] = {}
|
342
368
|
@preparing_statements[host] = {}
|
343
|
-
|
369
|
+
pool = @connections[host] ||= ConnectionPool.new
|
344
370
|
end
|
345
371
|
|
346
|
-
|
372
|
+
pool.add_connections(connections)
|
373
|
+
|
374
|
+
connections.each do |connection|
|
375
|
+
connection.on_closed do
|
376
|
+
distance = nil
|
377
|
+
|
378
|
+
synchronize do
|
379
|
+
if !(@state == :closed || @state == :closing) && !@connecting_hosts.include?(host) && @connections.include?(host)
|
380
|
+
distance = @load_balancing_policy.distance(host)
|
381
|
+
@connecting_hosts[host] = distance unless distance == :ignore
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
connect_to_host_maybe_retry(host, distance).map(nil) if distance
|
386
|
+
end
|
387
|
+
end
|
347
388
|
end
|
348
389
|
|
349
390
|
f
|
@@ -356,16 +397,16 @@ module Cassandra
|
|
356
397
|
end
|
357
398
|
|
358
399
|
hosts << host = plan.next
|
359
|
-
|
360
|
-
synchronize {
|
400
|
+
pool = nil
|
401
|
+
synchronize { pool = @connections[host] }
|
361
402
|
|
362
|
-
unless
|
403
|
+
unless pool
|
363
404
|
errors ||= {}
|
364
405
|
errors[host] = NOT_CONNECTED
|
365
406
|
return execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
366
407
|
end
|
367
408
|
|
368
|
-
connection =
|
409
|
+
connection = pool.random_connection
|
369
410
|
|
370
411
|
if keyspace && connection.keyspace != keyspace
|
371
412
|
switch = switch_keyspace(connection, keyspace, timeout)
|
@@ -430,16 +471,16 @@ module Cassandra
|
|
430
471
|
end
|
431
472
|
|
432
473
|
hosts << host = plan.next
|
433
|
-
|
434
|
-
synchronize {
|
474
|
+
pool = nil
|
475
|
+
synchronize { pool = @connections[host] }
|
435
476
|
|
436
|
-
unless
|
477
|
+
unless pool
|
437
478
|
errors ||= {}
|
438
479
|
errors[host] = NOT_CONNECTED
|
439
480
|
return batch_by_plan(promise, keyspace, statement, options, plan, timeout, errors, hosts)
|
440
481
|
end
|
441
482
|
|
442
|
-
connection =
|
483
|
+
connection = pool.random_connection
|
443
484
|
|
444
485
|
if keyspace && connection.keyspace != keyspace
|
445
486
|
switch = switch_keyspace(connection, keyspace, timeout)
|
@@ -529,16 +570,16 @@ module Cassandra
|
|
529
570
|
end
|
530
571
|
|
531
572
|
hosts << host = plan.next
|
532
|
-
|
533
|
-
synchronize {
|
573
|
+
pool = nil
|
574
|
+
synchronize { pool = @connections[host] }
|
534
575
|
|
535
|
-
unless
|
576
|
+
unless pool
|
536
577
|
errors ||= {}
|
537
578
|
errors[host] = NOT_CONNECTED
|
538
579
|
return send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
539
580
|
end
|
540
581
|
|
541
|
-
connection =
|
582
|
+
connection = pool.random_connection
|
542
583
|
|
543
584
|
if keyspace && connection.keyspace != keyspace
|
544
585
|
switch = switch_keyspace(connection, keyspace, timeout)
|
@@ -671,9 +712,7 @@ module Cassandra
|
|
671
712
|
when Protocol::RowsResultResponse
|
672
713
|
promise.fulfill(Results::Paged.new(r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
673
714
|
when Protocol::SchemaChangeResultResponse
|
674
|
-
if r.change == 'DROPPED' && r.
|
675
|
-
@keyspace = nil
|
676
|
-
end
|
715
|
+
@schema.delete_keyspace(r.keyspace) if r.change == 'DROPPED' && r.table.empty?
|
677
716
|
|
678
717
|
@logger.debug('Waiting for schema to propagate to all hosts after a change')
|
679
718
|
wait_for_schema_agreement(connection, @reconnection_policy.schedule).on_complete do |f|
|
@@ -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)
|
@@ -59,6 +59,12 @@ module Cassandra
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
def size
|
63
|
+
@lock.synchronize do
|
64
|
+
@connections.size
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
62
68
|
def each_connection(&callback)
|
63
69
|
return self unless block_given?
|
64
70
|
raise Errors::IOError, 'Not connected' unless connected?
|
@@ -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
|
@@ -115,13 +116,33 @@ module Cassandra
|
|
115
116
|
UNCLAIMED_TIMEOUT = 5 # close unclaimed connections in five seconds
|
116
117
|
|
117
118
|
def do_connect(host)
|
118
|
-
|
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|
|
119
140
|
case error
|
120
141
|
when Errors::ProtocolError
|
121
142
|
synchronize do
|
122
|
-
if @
|
123
|
-
@logger.info("Host #{host.ip} doesn't support protocol version #{@
|
124
|
-
@
|
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
|
125
146
|
do_connect(host)
|
126
147
|
else
|
127
148
|
Ione::Future.failed(error)
|
@@ -137,32 +158,82 @@ module Cassandra
|
|
137
158
|
end
|
138
159
|
end
|
139
160
|
|
140
|
-
def
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
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}"))
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
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
|
145
200
|
end
|
201
|
+
end
|
146
202
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
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
|
160
231
|
end
|
161
232
|
|
162
233
|
def create_additional_connections(host, count, established_connections, error = nil)
|
163
234
|
futures = count.times.map do
|
164
235
|
connect(host).recover do |e|
|
165
|
-
|
236
|
+
FailedConnection.new(e, host)
|
166
237
|
end
|
167
238
|
end
|
168
239
|
|