cassandra-driver 2.1.7-java → 3.0.0.beta.1-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 +31 -53
- data/lib/cassandra.rb +22 -3
- data/lib/cassandra/aggregate.rb +109 -0
- data/lib/cassandra/argument.rb +51 -0
- data/lib/cassandra/auth/providers/password.rb +7 -4
- data/lib/cassandra/cluster.rb +14 -3
- data/lib/cassandra/cluster/client.rb +56 -34
- data/lib/cassandra/cluster/connector.rb +6 -6
- data/lib/cassandra/cluster/control_connection.rb +204 -251
- data/lib/cassandra/cluster/metadata.rb +2 -0
- data/lib/cassandra/cluster/schema.rb +131 -209
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +104 -0
- data/lib/cassandra/cluster/schema/fetchers.rb +1174 -0
- data/lib/cassandra/cluster/schema/{type_parser.rb → fqcn_type_parser.rb} +7 -3
- data/lib/cassandra/column.rb +2 -2
- data/lib/cassandra/driver.rb +27 -9
- data/lib/cassandra/errors.rb +179 -25
- data/lib/cassandra/execution/info.rb +8 -1
- data/lib/cassandra/execution/options.rb +34 -0
- data/lib/cassandra/execution/trace.rb +42 -10
- data/lib/cassandra/function.rb +150 -0
- data/lib/cassandra/future.rb +66 -35
- data/lib/cassandra/host.rb +7 -4
- data/lib/cassandra/keyspace.rb +112 -13
- data/lib/cassandra/load_balancing.rb +1 -1
- data/lib/cassandra/protocol.rb +9 -3
- data/lib/cassandra/protocol/coder.rb +434 -155
- data/lib/cassandra/protocol/cql_byte_buffer.rb +43 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -1
- data/lib/cassandra/protocol/request.rb +4 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +5 -1
- data/lib/cassandra/protocol/requests/batch_request.rb +7 -2
- data/lib/cassandra/protocol/requests/credentials_request.rb +5 -1
- data/lib/cassandra/protocol/requests/execute_request.rb +16 -10
- data/lib/cassandra/protocol/requests/prepare_request.rb +12 -3
- data/lib/cassandra/protocol/requests/query_request.rb +20 -11
- data/lib/cassandra/protocol/responses/already_exists_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/error_response.rb +14 -14
- data/lib/cassandra/protocol/responses/function_failure_error_response.rb +41 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +12 -9
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +5 -3
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +43 -0
- data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/ready_response.rb +5 -1
- data/lib/cassandra/protocol/responses/result_response.rb +3 -3
- data/lib/cassandra/protocol/responses/rows_result_response.rb +2 -2
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +25 -24
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +20 -23
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
- data/lib/cassandra/protocol/responses/unavailable_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/unprepared_error_response.rb +4 -4
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +45 -0
- data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +4 -4
- data/lib/cassandra/protocol/v1.rb +38 -13
- data/lib/cassandra/protocol/v3.rb +34 -29
- data/lib/cassandra/protocol/v4.rb +334 -0
- data/lib/cassandra/result.rb +10 -9
- data/lib/cassandra/retry.rb +17 -3
- data/lib/cassandra/retry/policies/default.rb +9 -3
- data/lib/cassandra/session.rb +15 -7
- data/lib/cassandra/statement.rb +5 -0
- data/lib/cassandra/statements/batch.rb +36 -12
- data/lib/cassandra/statements/bound.rb +2 -1
- data/lib/cassandra/statements/prepared.rb +106 -35
- data/lib/cassandra/statements/simple.rb +4 -2
- data/lib/cassandra/table.rb +70 -105
- data/lib/cassandra/time.rb +98 -0
- data/lib/cassandra/time_uuid.rb +1 -1
- data/lib/cassandra/tuple.rb +7 -0
- data/lib/cassandra/types.rb +472 -272
- data/lib/cassandra/udt.rb +10 -0
- data/lib/cassandra/util.rb +32 -1
- data/lib/cassandra/uuid.rb +6 -1
- data/lib/cassandra/uuid/generator.rb +7 -7
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- data/lib/datastax/cassandra.rb +5 -2
- metadata +27 -17
@@ -208,8 +208,10 @@ module Cassandra
|
|
208
208
|
return @futures.error(Errors::ClientError.new("Positional arguments are not supported by the current version of Apache Cassandra")) if !statement.params.empty? && @connection_options.protocol_version == 1
|
209
209
|
|
210
210
|
timestamp = nil
|
211
|
-
timestamp = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
212
|
-
|
211
|
+
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
212
|
+
payload = nil
|
213
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
214
|
+
request = Protocol::QueryRequest.new(statement.cql, statement.params, statement.params_types, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, statement.params_names, timestamp, payload)
|
213
215
|
timeout = options.timeout
|
214
216
|
promise = @futures.promise
|
215
217
|
|
@@ -222,7 +224,9 @@ module Cassandra
|
|
222
224
|
end
|
223
225
|
|
224
226
|
def prepare(cql, options)
|
225
|
-
|
227
|
+
payload = nil
|
228
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
229
|
+
request = Protocol::PrepareRequest.new(cql, options.trace?, payload)
|
226
230
|
timeout = options.timeout
|
227
231
|
promise = @futures.promise
|
228
232
|
|
@@ -237,10 +241,12 @@ module Cassandra
|
|
237
241
|
|
238
242
|
def execute(statement, options)
|
239
243
|
timestamp = nil
|
240
|
-
timestamp = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
244
|
+
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
245
|
+
payload = nil
|
246
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
241
247
|
timeout = options.timeout
|
242
248
|
result_metadata = statement.result_metadata
|
243
|
-
request = Protocol::ExecuteRequest.new(nil, statement.params_types, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, timestamp)
|
249
|
+
request = Protocol::ExecuteRequest.new(nil, statement.params_types, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, timestamp, payload)
|
244
250
|
promise = @futures.promise
|
245
251
|
|
246
252
|
keyspace = @keyspace
|
@@ -255,9 +261,11 @@ module Cassandra
|
|
255
261
|
return @futures.error(Errors::ClientError.new("Batch statements are not supported by the current version of Apache Cassandra")) if @connection_options.protocol_version < 2
|
256
262
|
|
257
263
|
timestamp = nil
|
258
|
-
timestamp = Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
264
|
+
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
265
|
+
payload = nil
|
266
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
259
267
|
timeout = options.timeout
|
260
|
-
request = Protocol::BatchRequest.new(BATCH_TYPES[statement.type], options.consistency, options.trace?, options.serial_consistency, timestamp)
|
268
|
+
request = Protocol::BatchRequest.new(BATCH_TYPES[statement.type], options.consistency, options.trace?, options.serial_consistency, timestamp, payload)
|
261
269
|
keyspace = @keyspace
|
262
270
|
plan = @load_balancing_policy.plan(keyspace, statement, options)
|
263
271
|
promise = @futures.promise
|
@@ -467,8 +475,7 @@ module Cassandra
|
|
467
475
|
prepare_and_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
468
476
|
else
|
469
477
|
s.on_failure do |e|
|
470
|
-
|
471
|
-
when Errors::HostError
|
478
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
472
479
|
errors ||= {}
|
473
480
|
errors[host] = e
|
474
481
|
execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -502,8 +509,7 @@ module Cassandra
|
|
502
509
|
do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
503
510
|
else
|
504
511
|
prepare.on_failure do |e|
|
505
|
-
|
506
|
-
when Errors::HostError
|
512
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
507
513
|
errors ||= {}
|
508
514
|
errors[host] = e
|
509
515
|
execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -514,6 +520,8 @@ module Cassandra
|
|
514
520
|
end
|
515
521
|
end
|
516
522
|
end
|
523
|
+
rescue => e
|
524
|
+
promise.break(e)
|
517
525
|
end
|
518
526
|
|
519
527
|
def batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors = nil, hosts = [])
|
@@ -541,8 +549,7 @@ module Cassandra
|
|
541
549
|
batch_and_send_request_by_plan(host, connection, promise, keyspace, statement, request, options, plan, timeout, errors, hosts)
|
542
550
|
else
|
543
551
|
s.on_failure do |e|
|
544
|
-
|
545
|
-
when Errors::HostError
|
552
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
546
553
|
errors ||= {}
|
547
554
|
errors[host] = e
|
548
555
|
batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -601,8 +608,7 @@ module Cassandra
|
|
601
608
|
do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
602
609
|
else
|
603
610
|
f.on_failure do |e|
|
604
|
-
|
605
|
-
when Errors::HostError
|
611
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
606
612
|
errors ||= {}
|
607
613
|
errors[host] = e
|
608
614
|
batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -640,8 +646,7 @@ module Cassandra
|
|
640
646
|
do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
641
647
|
else
|
642
648
|
s.on_failure do |e|
|
643
|
-
|
644
|
-
when Errors::HostError
|
649
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
645
650
|
errors ||= {}
|
646
651
|
errors[host] = e
|
647
652
|
send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -693,8 +698,7 @@ module Cassandra
|
|
693
698
|
do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
694
699
|
else
|
695
700
|
prepare.on_failure do |e|
|
696
|
-
|
697
|
-
when Errors::HostError
|
701
|
+
if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
698
702
|
errors ||= {}
|
699
703
|
errors[host] = e
|
700
704
|
execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
@@ -705,10 +709,9 @@ module Cassandra
|
|
705
709
|
end
|
706
710
|
end
|
707
711
|
when Protocol::ErrorResponse
|
708
|
-
error = r.to_error(statement)
|
712
|
+
error = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
|
709
713
|
|
710
|
-
|
711
|
-
when Errors::HostError
|
714
|
+
if error.is_a?(Errors::HostError) || (error.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
712
715
|
errors ||= {}
|
713
716
|
errors[host] = error
|
714
717
|
|
@@ -725,7 +728,7 @@ module Cassandra
|
|
725
728
|
end
|
726
729
|
when Protocol::SetKeyspaceResultResponse
|
727
730
|
@keyspace = r.keyspace
|
728
|
-
promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
731
|
+
promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
729
732
|
when Protocol::PreparedResultResponse
|
730
733
|
cql = request.cql
|
731
734
|
synchronize do
|
@@ -733,12 +736,16 @@ module Cassandra
|
|
733
736
|
@preparing_statements[host].delete(cql)
|
734
737
|
end
|
735
738
|
|
736
|
-
|
739
|
+
metadata = r.metadata
|
740
|
+
pk_idx = r.pk_idx
|
741
|
+
pk_idx ||= @schema.get_pk_idx(metadata)
|
742
|
+
|
743
|
+
promise.fulfill(Statements::Prepared.new(r.custom_payload, r.warnings, cql, metadata, r.result_metadata, pk_idx, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @connection_options))
|
737
744
|
when Protocol::RawRowsResultResponse
|
738
745
|
r.materialize(statement.result_metadata)
|
739
|
-
promise.fulfill(Results::Paged.new(r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
746
|
+
promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
740
747
|
when Protocol::RowsResultResponse
|
741
|
-
promise.fulfill(Results::Paged.new(r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
748
|
+
promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
742
749
|
when Protocol::SchemaChangeResultResponse
|
743
750
|
@schema.delete_keyspace(r.keyspace) if r.change == 'DROPPED' && r.target == Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
744
751
|
|
@@ -749,10 +756,10 @@ module Cassandra
|
|
749
756
|
@logger.error("Schema agreement failure (#{e.class.name}: #{e.message})")
|
750
757
|
end
|
751
758
|
end
|
752
|
-
promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
759
|
+
promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
753
760
|
end
|
754
761
|
else
|
755
|
-
promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
762
|
+
promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
756
763
|
end
|
757
764
|
|
758
765
|
if decision
|
@@ -760,12 +767,25 @@ module Cassandra
|
|
760
767
|
when Retry::Decisions::Retry
|
761
768
|
request.consistency = decision.consistency
|
762
769
|
do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts, retries + 1)
|
770
|
+
when Retry::Decisions::TryNextHost
|
771
|
+
errors ||= {}
|
772
|
+
errors[host] = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
|
773
|
+
case request
|
774
|
+
when Protocol::QueryRequest, Protocol::PrepareRequest
|
775
|
+
send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
776
|
+
when Protocol::ExecuteRequest
|
777
|
+
execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
778
|
+
when Protocol::BatchRequest
|
779
|
+
batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
|
780
|
+
else
|
781
|
+
promise.break(e)
|
782
|
+
end
|
763
783
|
when Retry::Decisions::Ignore
|
764
|
-
promise.fulfill(Results::Void.new(r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
784
|
+
promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
765
785
|
when Retry::Decisions::Reraise
|
766
|
-
promise.break(r.to_error(statement))
|
786
|
+
promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
|
767
787
|
else
|
768
|
-
promise.break(r.to_error(statement))
|
788
|
+
promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
|
769
789
|
end
|
770
790
|
end
|
771
791
|
rescue => e
|
@@ -788,6 +808,8 @@ module Cassandra
|
|
788
808
|
end
|
789
809
|
end
|
790
810
|
end
|
811
|
+
rescue => e
|
812
|
+
promise.break(e)
|
791
813
|
end
|
792
814
|
|
793
815
|
def wait_for_schema_agreement(connection, schedule)
|
@@ -848,7 +870,7 @@ module Cassandra
|
|
848
870
|
@keyspace = r.keyspace
|
849
871
|
nil
|
850
872
|
when Protocol::ErrorResponse
|
851
|
-
raise r.to_error(Statements::Simple.new("USE #{Util.escape_name(keyspace)}"))
|
873
|
+
raise r.to_error(nil, Statements::Simple.new("USE #{Util.escape_name(keyspace)}"), VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
852
874
|
else
|
853
875
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
854
876
|
end
|
@@ -884,7 +906,7 @@ module Cassandra
|
|
884
906
|
end
|
885
907
|
id
|
886
908
|
when Protocol::ErrorResponse
|
887
|
-
raise r.to_error(VOID_STATEMENT)
|
909
|
+
raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
888
910
|
else
|
889
911
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
890
912
|
end
|
@@ -903,7 +925,7 @@ module Cassandra
|
|
903
925
|
when Protocol::RowsResultResponse
|
904
926
|
r.rows
|
905
927
|
when Protocol::ErrorResponse
|
906
|
-
raise r.to_error(VOID_STATEMENT)
|
928
|
+
raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
907
929
|
else
|
908
930
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
909
931
|
end
|
@@ -181,20 +181,20 @@ module Cassandra
|
|
181
181
|
if credentials
|
182
182
|
send_credentials(connection, credentials)
|
183
183
|
else
|
184
|
-
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
|
184
|
+
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate', nil, nil, nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
|
185
185
|
end
|
186
186
|
else
|
187
187
|
authenticator = @connection_options.create_authenticator(r.authentication_class)
|
188
188
|
if authenticator
|
189
189
|
challenge_response_cycle(connection, authenticator, authenticator.initial_response)
|
190
190
|
else
|
191
|
-
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate'))
|
191
|
+
Ione::Future.failed(Errors::AuthenticationError.new('Server requested authentication, but client was not configured to authenticate', nil, nil, nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
|
192
192
|
end
|
193
193
|
end
|
194
194
|
when Protocol::ReadyResponse
|
195
195
|
::Ione::Future.resolved(connection)
|
196
196
|
when Protocol::ErrorResponse
|
197
|
-
::Ione::Future.failed(r.to_error(VOID_STATEMENT))
|
197
|
+
::Ione::Future.failed(r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
|
198
198
|
else
|
199
199
|
::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
|
200
200
|
end
|
@@ -207,7 +207,7 @@ module Cassandra
|
|
207
207
|
when Protocol::SupportedResponse
|
208
208
|
r.options
|
209
209
|
when Protocol::ErrorResponse
|
210
|
-
raise r.to_error(VOID_STATEMENT)
|
210
|
+
raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
211
211
|
else
|
212
212
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
213
213
|
end
|
@@ -220,7 +220,7 @@ module Cassandra
|
|
220
220
|
when Protocol::ReadyResponse
|
221
221
|
connection
|
222
222
|
when Protocol::ErrorResponse
|
223
|
-
raise r.to_error(VOID_STATEMENT)
|
223
|
+
raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
224
224
|
else
|
225
225
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
226
226
|
end
|
@@ -237,7 +237,7 @@ module Cassandra
|
|
237
237
|
authenticator.authentication_successful(r.token) rescue nil
|
238
238
|
::Ione::Future.resolved(connection)
|
239
239
|
when Protocol::ErrorResponse
|
240
|
-
::Ione::Future.failed(r.to_error(VOID_STATEMENT))
|
240
|
+
::Ione::Future.failed(r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0))
|
241
241
|
else
|
242
242
|
::Ione::Future.failed(Errors::InternalError.new("Unexpected response #{r.inspect}"))
|
243
243
|
end
|
@@ -22,7 +22,10 @@ module Cassandra
|
|
22
22
|
class ControlConnection
|
23
23
|
include MonitorMixin
|
24
24
|
|
25
|
-
def initialize(logger, io_reactor, cluster_registry, cluster_schema,
|
25
|
+
def initialize(logger, io_reactor, cluster_registry, cluster_schema,
|
26
|
+
cluster_metadata, load_balancing_policy,
|
27
|
+
reconnection_policy, address_resolution_policy, connector,
|
28
|
+
connection_options, schema_fetcher)
|
26
29
|
@logger = logger
|
27
30
|
@io_reactor = io_reactor
|
28
31
|
@registry = cluster_registry
|
@@ -33,6 +36,7 @@ module Cassandra
|
|
33
36
|
@address_resolver = address_resolution_policy
|
34
37
|
@connector = connector
|
35
38
|
@connection_options = connection_options
|
39
|
+
@schema_fetcher = schema_fetcher
|
36
40
|
@refreshing_statuses = ::Hash.new(false)
|
37
41
|
@status = :closed
|
38
42
|
@refreshing_hosts = false
|
@@ -129,32 +133,14 @@ module Cassandra
|
|
129
133
|
@closed_promise.fulfill
|
130
134
|
end
|
131
135
|
|
132
|
-
def refresh_schema_async_maybe_retry
|
133
|
-
refresh_schema_async.fallback do |e|
|
134
|
-
case e
|
135
|
-
when Errors::HostError
|
136
|
-
refresh_schema_async_retry(e, @reconnection_policy.schedule)
|
137
|
-
else
|
138
|
-
connection = @connection
|
139
|
-
connection && connection.close(e)
|
140
|
-
|
141
|
-
Ione::Future.failed(e)
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
136
|
def inspect
|
147
137
|
"#<#{self.class.name}:0x#{self.object_id.to_s(16)}>"
|
148
138
|
end
|
149
139
|
|
150
140
|
private
|
151
141
|
|
152
|
-
SELECT_LOCAL
|
153
|
-
SELECT_PEERS
|
154
|
-
SELECT_KEYSPACES = Protocol::QueryRequest.new('SELECT * FROM system.schema_keyspaces', EMPTY_LIST, EMPTY_LIST, :one)
|
155
|
-
SELECT_TABLES = Protocol::QueryRequest.new('SELECT * FROM system.schema_columnfamilies', EMPTY_LIST, EMPTY_LIST, :one)
|
156
|
-
SELECT_COLUMNS = Protocol::QueryRequest.new('SELECT * FROM system.schema_columns', EMPTY_LIST, EMPTY_LIST, :one)
|
157
|
-
SELECT_TYPES = Protocol::QueryRequest.new('SELECT * FROM system.schema_usertypes', EMPTY_LIST, EMPTY_LIST, :one)
|
142
|
+
SELECT_LOCAL = Protocol::QueryRequest.new('SELECT rack, data_center, host_id, release_version, tokens, partitioner FROM system.local', EMPTY_LIST, EMPTY_LIST, :one)
|
143
|
+
SELECT_PEERS = Protocol::QueryRequest.new('SELECT peer, rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers', EMPTY_LIST, EMPTY_LIST, :one)
|
158
144
|
|
159
145
|
def reconnect_async(schedule)
|
160
146
|
timeout = schedule.next
|
@@ -199,7 +185,7 @@ module Cassandra
|
|
199
185
|
when Protocol::ReadyResponse
|
200
186
|
nil
|
201
187
|
when Protocol::ErrorResponse
|
202
|
-
raise r.to_error(VOID_STATEMENT)
|
188
|
+
raise r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
203
189
|
else
|
204
190
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
205
191
|
end
|
@@ -215,7 +201,12 @@ module Cassandra
|
|
215
201
|
when 'UP'
|
216
202
|
address = event.address
|
217
203
|
|
218
|
-
|
204
|
+
if @registry.has_host?(address)
|
205
|
+
@registry.host_up(address)
|
206
|
+
else
|
207
|
+
refresh_host_async_maybe_retry(address)
|
208
|
+
refresh_maybe_retry(:schema)
|
209
|
+
end
|
219
210
|
when 'DOWN'
|
220
211
|
@registry.host_down(event.address)
|
221
212
|
when 'NEW_NODE'
|
@@ -223,11 +214,11 @@ module Cassandra
|
|
223
214
|
|
224
215
|
unless @registry.has_host?(address)
|
225
216
|
refresh_host_async_maybe_retry(address)
|
226
|
-
|
217
|
+
refresh_maybe_retry(:schema)
|
227
218
|
end
|
228
219
|
when 'REMOVED_NODE'
|
229
220
|
@registry.host_lost(event.address)
|
230
|
-
|
221
|
+
refresh_maybe_retry(:schema)
|
231
222
|
end
|
232
223
|
end
|
233
224
|
end
|
@@ -243,222 +234,117 @@ module Cassandra
|
|
243
234
|
|
244
235
|
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
245
236
|
|
246
|
-
|
247
|
-
|
248
|
-
columns = send_select_request(connection, SELECT_COLUMNS)
|
249
|
-
|
250
|
-
if @connection_options.protocol_version > 2
|
251
|
-
types = send_select_request(connection, SELECT_TYPES)
|
252
|
-
else
|
253
|
-
types = Ione::Future.resolved(EMPTY_LIST)
|
254
|
-
end
|
255
|
-
|
256
|
-
Ione::Future.all(keyspaces, tables, columns, types).map do |(keyspaces, tables, columns, types)|
|
257
|
-
host = @registry.host(connection.host)
|
258
|
-
|
259
|
-
@schema.update_keyspaces(host, keyspaces, tables, columns, types)
|
237
|
+
@schema_fetcher.fetch(connection).map do |keyspaces|
|
238
|
+
@schema.replace(keyspaces)
|
260
239
|
@metadata.rebuild_token_map
|
261
240
|
@logger.info("Schema refreshed")
|
262
241
|
end
|
263
242
|
end
|
264
243
|
|
265
|
-
def
|
266
|
-
|
267
|
-
@logger.info("Failed to refresh schema (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
244
|
+
def refresh_keyspace_async(keyspace_name)
|
245
|
+
connection = @connection
|
268
246
|
|
269
|
-
|
270
|
-
timer.flat_map do
|
271
|
-
refresh_schema_async.fallback do |e|
|
272
|
-
case e
|
273
|
-
when Errors::HostError
|
274
|
-
refresh_schema_async_retry(e, schedule)
|
275
|
-
else
|
276
|
-
connection = @connection
|
277
|
-
connection && connection.close(e)
|
247
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
278
248
|
|
279
|
-
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
end
|
249
|
+
@logger.info("Refreshing keyspace \"#{keyspace_name}\"")
|
284
250
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
when Errors::HostError
|
289
|
-
refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
|
251
|
+
@schema_fetcher.fetch_keyspace(connection, keyspace_name).map do |keyspace|
|
252
|
+
if keyspace
|
253
|
+
@schema.replace_keyspace(keyspace)
|
290
254
|
else
|
291
|
-
|
292
|
-
connection && connection.close(e)
|
293
|
-
|
294
|
-
Ione::Future.failed(e)
|
255
|
+
@schema.delete_keyspace(keyspace_name)
|
295
256
|
end
|
296
|
-
end
|
297
|
-
end
|
298
257
|
|
299
|
-
|
300
|
-
timeout = schedule.next
|
301
|
-
@logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
302
|
-
|
303
|
-
timer = @io_reactor.schedule_timer(timeout)
|
304
|
-
timer.flat_map do
|
305
|
-
refresh_keyspace_async(keyspace).fallback do |e|
|
306
|
-
case e
|
307
|
-
when Errors::HostError
|
308
|
-
refresh_keyspace_async_retry(keyspace, e, schedule)
|
309
|
-
else
|
310
|
-
connection = @connection
|
311
|
-
connection && connection.close(e)
|
312
|
-
|
313
|
-
Ione::Future.failed(e)
|
314
|
-
end
|
315
|
-
end
|
258
|
+
@logger.info("Refreshed keyspace \"#{keyspace_name}\"")
|
316
259
|
end
|
317
260
|
end
|
318
261
|
|
319
|
-
def
|
262
|
+
def refresh_table_async(keyspace_name, table_name)
|
320
263
|
connection = @connection
|
321
264
|
|
322
265
|
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
323
266
|
|
324
|
-
|
325
|
-
tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
|
326
|
-
columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
|
327
|
-
|
328
|
-
if @connection_options.protocol_version > 2
|
329
|
-
types = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_usertypes WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
|
330
|
-
else
|
331
|
-
types = Ione::Future.resolved(EMPTY_LIST)
|
332
|
-
end
|
333
|
-
|
334
|
-
Ione::Future.all(keyspaces, tables, columns, types).map do |(keyspaces, tables, columns, types)|
|
335
|
-
host = @registry.host(connection.host)
|
267
|
+
@logger.info("Refreshing table \"#{keyspace_name}.#{table_name}\"")
|
336
268
|
|
337
|
-
|
338
|
-
|
269
|
+
@schema_fetcher.fetch_table(connection, keyspace_name, table_name).map do |table|
|
270
|
+
if table
|
271
|
+
@schema.replace_table(table)
|
339
272
|
else
|
340
|
-
@schema.
|
341
|
-
end
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
def refresh_table_async_maybe_retry(keyspace, table)
|
346
|
-
refresh_table_async(keyspace, table).fallback do |e|
|
347
|
-
case e
|
348
|
-
when Errors::HostError
|
349
|
-
refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
|
350
|
-
else
|
351
|
-
connection = @connection
|
352
|
-
connection && connection.close(e)
|
353
|
-
|
354
|
-
Ione::Future.failed(e)
|
273
|
+
@schema.delete_table(keyspace_name, table_name)
|
355
274
|
end
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
|
-
def refresh_table_async_retry(keyspace, table, error, schedule)
|
360
|
-
timeout = schedule.next
|
361
|
-
@logger.info("Failed to refresh keyspace #{keyspace} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
362
|
-
|
363
|
-
timer = @io_reactor.schedule_timer(timeout)
|
364
|
-
timer.flat_map do
|
365
|
-
refresh_keyspace_async(keyspace).fallback do |e|
|
366
|
-
case e
|
367
|
-
when Errors::HostError
|
368
|
-
refresh_keyspace_async_retry(keyspace, e, schedule)
|
369
|
-
else
|
370
|
-
connection = @connection
|
371
|
-
connection && connection.close(e)
|
372
275
|
|
373
|
-
|
374
|
-
end
|
375
|
-
end
|
276
|
+
@logger.info("Refreshed table \"#{keyspace_name}.#{table_name}\"")
|
376
277
|
end
|
377
278
|
end
|
378
279
|
|
379
|
-
def
|
280
|
+
def refresh_type_async(keyspace_name, type_name)
|
380
281
|
connection = @connection
|
381
282
|
|
382
283
|
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
383
284
|
|
384
|
-
|
385
|
-
tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
|
386
|
-
columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
|
285
|
+
@logger.info("Refreshing user-defined type \"#{keyspace_name}.#{type_name}\"")
|
387
286
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
if tables.empty?
|
392
|
-
@schema.delete_table(keyspace, table)
|
287
|
+
@schema_fetcher.fetch_type(connection, keyspace_name, type_name).map do |type|
|
288
|
+
if type
|
289
|
+
@schema.replace_type(type)
|
393
290
|
else
|
394
|
-
@schema.
|
291
|
+
@schema.delete_type(keyspace_name, type_name)
|
395
292
|
end
|
396
|
-
end
|
397
|
-
end
|
398
293
|
|
399
|
-
|
400
|
-
refresh_type_async(keyspace, type).fallback do |e|
|
401
|
-
case e
|
402
|
-
when Errors::HostError
|
403
|
-
refresh_keyspace_async_retry(keyspace, e, @reconnection_policy.schedule)
|
404
|
-
else
|
405
|
-
connection = @connection
|
406
|
-
connection && connection.close(e)
|
407
|
-
|
408
|
-
Ione::Future.failed(e)
|
409
|
-
end
|
294
|
+
@logger.info("Refreshed user-defined type \"#{keyspace_name}.#{type_name}\"")
|
410
295
|
end
|
411
296
|
end
|
412
297
|
|
413
|
-
def
|
414
|
-
|
415
|
-
@logger.info("Failed to refresh type #{keyspace}.#{type} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
298
|
+
def refresh_function_async(keyspace_name, function_name, function_args)
|
299
|
+
connection = @connection
|
416
300
|
|
417
|
-
|
418
|
-
timer.flat_map do
|
419
|
-
refresh_keyspace_async(keyspace).fallback do |e|
|
420
|
-
case e
|
421
|
-
when Errors::HostError
|
422
|
-
refresh_keyspace_async_retry(keyspace, e, schedule)
|
423
|
-
else
|
424
|
-
connection = @connection
|
425
|
-
connection && connection.close(e)
|
301
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
426
302
|
|
427
|
-
|
428
|
-
|
303
|
+
@logger.info("Refreshing user-defined function \"#{keyspace_name}.#{function_name}\"")
|
304
|
+
|
305
|
+
# function_args is an array of string, and we need an array of parsed types.
|
306
|
+
parsed_function_args = @schema_fetcher.parse_argument_types(connection, keyspace_name, function_args)
|
307
|
+
@schema_fetcher.fetch_function(connection, keyspace_name, function_name, parsed_function_args).map do |function|
|
308
|
+
if function
|
309
|
+
@schema.replace_function(function)
|
310
|
+
else
|
311
|
+
@schema.delete_function(keyspace_name, function_name, parsed_function_args)
|
429
312
|
end
|
313
|
+
|
314
|
+
@logger.info("Refreshed user-defined function \"#{keyspace_name}.#{function_name}(#{function_args.join(',')})\"")
|
430
315
|
end
|
431
316
|
end
|
432
317
|
|
433
|
-
def
|
318
|
+
def refresh_aggregate_async(keyspace_name, aggregate_name, aggregate_args)
|
434
319
|
connection = @connection
|
435
320
|
|
436
321
|
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
437
322
|
|
438
|
-
|
439
|
-
types = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_usertypes WHERE keyspace_name = '%s' AND type_name = '%s'" % params, EMPTY_LIST, EMPTY_LIST, :one))
|
440
|
-
|
441
|
-
types.map do |types|
|
442
|
-
host = @registry.host(connection.host)
|
323
|
+
@logger.info("Refreshing user-defined aggregate \"#{keyspace_name}.#{aggregate_name}\"")
|
443
324
|
|
444
|
-
|
445
|
-
|
325
|
+
# aggregate_args is an array of string, and we need an array of parsed types.
|
326
|
+
parsed_aggregate_args = @schema_fetcher.parse_argument_types(connection, keyspace_name, aggregate_args)
|
327
|
+
@schema_fetcher.fetch_aggregate(connection, keyspace_name, aggregate_name, parsed_aggregate_args).map do |aggregate|
|
328
|
+
if aggregate
|
329
|
+
@schema.replace_aggregate(aggregate)
|
446
330
|
else
|
447
|
-
@schema.
|
331
|
+
@schema.delete_aggregate(keyspace_name, aggregate_name, parsed_aggregate_args)
|
448
332
|
end
|
333
|
+
|
334
|
+
@logger.info("Refreshed user-defined aggregate \"#{keyspace_name}.#{aggregate_name}(#{aggregate_args.join(',')})\"")
|
449
335
|
end
|
450
336
|
end
|
451
337
|
|
452
|
-
def
|
338
|
+
def refresh_peers_async_maybe_retry
|
453
339
|
synchronize do
|
454
340
|
return Ione::Future.resolved if @refreshing_hosts
|
455
341
|
@refreshing_hosts = true
|
456
342
|
end
|
457
343
|
|
458
|
-
|
344
|
+
refresh_peers_async.fallback do |e|
|
459
345
|
case e
|
460
|
-
when Errors::HostError
|
461
|
-
|
346
|
+
when Errors::HostError, Errors::TimeoutError
|
347
|
+
refresh_peers_async_retry(e, @reconnection_policy.schedule)
|
462
348
|
else
|
463
349
|
connection = @connection
|
464
350
|
connection && connection.close(e)
|
@@ -472,16 +358,16 @@ module Cassandra
|
|
472
358
|
end
|
473
359
|
end
|
474
360
|
|
475
|
-
def
|
361
|
+
def refresh_peers_async_retry(error, schedule)
|
476
362
|
timeout = schedule.next
|
477
363
|
@logger.info("Failed to refresh hosts (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
478
364
|
|
479
365
|
timer = @io_reactor.schedule_timer(timeout)
|
480
366
|
timer.flat_map do
|
481
|
-
|
367
|
+
refresh_peers_async.fallback do |e|
|
482
368
|
case e
|
483
|
-
when Errors::HostError
|
484
|
-
|
369
|
+
when Errors::HostError, Errors::TimeoutError
|
370
|
+
refresh_peers_async_retry(e, schedule)
|
485
371
|
else
|
486
372
|
connection = @connection
|
487
373
|
connection && connection.close(e)
|
@@ -492,38 +378,55 @@ module Cassandra
|
|
492
378
|
end
|
493
379
|
end
|
494
380
|
|
495
|
-
def
|
381
|
+
def refresh_peers_async
|
496
382
|
connection = @connection
|
497
383
|
|
498
384
|
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
499
385
|
|
500
|
-
|
501
|
-
peers = send_select_request(connection, SELECT_PEERS)
|
386
|
+
@logger.info("Refreshing peers metadata")
|
502
387
|
|
503
|
-
|
388
|
+
send_select_request(connection, SELECT_PEERS).map do |peers|
|
504
389
|
@logger.debug("#{peers.size} peer(s) found")
|
505
390
|
|
506
391
|
ips = ::Set.new
|
507
392
|
|
508
|
-
unless local.empty?
|
509
|
-
ips << ip = IPAddr.new(connection.host)
|
510
|
-
data = local.first
|
511
|
-
@registry.host_found(ip, data)
|
512
|
-
@metadata.update(data)
|
513
|
-
end
|
514
|
-
|
515
393
|
peers.shuffle!
|
516
394
|
peers.each do |data|
|
517
|
-
ip = peer_ip(data
|
395
|
+
ip = peer_ip(data)
|
518
396
|
next unless ip
|
519
397
|
ips << ip
|
520
398
|
@registry.host_found(ip, data)
|
521
399
|
end
|
522
400
|
|
523
401
|
@registry.each_host do |host|
|
402
|
+
next if host.ip == connection.host
|
524
403
|
@registry.host_lost(host.ip) unless ips.include?(host.ip)
|
525
404
|
end
|
526
405
|
|
406
|
+
@logger.info("Refreshed peers metadata")
|
407
|
+
|
408
|
+
nil
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def refresh_metadata_async
|
413
|
+
connection = @connection
|
414
|
+
|
415
|
+
return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
|
416
|
+
|
417
|
+
@logger.info("Refreshing connected host's metadata")
|
418
|
+
|
419
|
+
send_select_request(connection, SELECT_LOCAL).map do |local|
|
420
|
+
if local.empty?
|
421
|
+
raise Errors::InternalError, "Unable to fetch connected host's metadata"
|
422
|
+
else
|
423
|
+
data = local.first
|
424
|
+
@registry.host_found(IPAddr.new(connection.host), data)
|
425
|
+
@metadata.update(data)
|
426
|
+
end
|
427
|
+
|
428
|
+
@logger.info("Refreshed connected host's metadata")
|
429
|
+
|
527
430
|
nil
|
528
431
|
end
|
529
432
|
end
|
@@ -555,16 +458,16 @@ module Cassandra
|
|
555
458
|
end
|
556
459
|
end
|
557
460
|
|
558
|
-
def refresh_host_async_maybe_retry(
|
461
|
+
def refresh_host_async_maybe_retry(address)
|
559
462
|
synchronize do
|
560
|
-
return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[
|
561
|
-
@refreshing_host[
|
463
|
+
return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[address]
|
464
|
+
@refreshing_host[address] = true
|
562
465
|
end
|
563
466
|
|
564
|
-
refresh_host_async(
|
467
|
+
refresh_host_async(address).fallback do |e|
|
565
468
|
case e
|
566
|
-
when Errors::HostError
|
567
|
-
refresh_host_async_retry(
|
469
|
+
when Errors::HostError, Errors::TimeoutError
|
470
|
+
refresh_host_async_retry(address, e, @reconnection_policy.schedule)
|
568
471
|
else
|
569
472
|
connection = @connection
|
570
473
|
connection && connection.close(e)
|
@@ -573,21 +476,21 @@ module Cassandra
|
|
573
476
|
end
|
574
477
|
end.map do
|
575
478
|
synchronize do
|
576
|
-
@refreshing_host.delete(
|
479
|
+
@refreshing_host.delete(address)
|
577
480
|
end
|
578
481
|
end
|
579
482
|
end
|
580
483
|
|
581
|
-
def refresh_host_async_retry(
|
484
|
+
def refresh_host_async_retry(address, error, schedule)
|
582
485
|
timeout = schedule.next
|
583
|
-
@logger.info("Failed to refresh host #{
|
486
|
+
@logger.info("Failed to refresh host #{address.to_s} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
584
487
|
|
585
488
|
timer = @io_reactor.schedule_timer(timeout)
|
586
489
|
timer.flat_map do
|
587
|
-
refresh_host_async(
|
490
|
+
refresh_host_async(address).fallback do |e|
|
588
491
|
case e
|
589
|
-
when Errors::HostError
|
590
|
-
refresh_host_async_retry(
|
492
|
+
when Errors::HostError, Errors::TimeoutError
|
493
|
+
refresh_host_async_retry(address, e, schedule)
|
591
494
|
else
|
592
495
|
connection = @connection
|
593
496
|
connection && connection.close(e)
|
@@ -604,19 +507,26 @@ module Cassandra
|
|
604
507
|
|
605
508
|
ip = address.to_s
|
606
509
|
|
510
|
+
@logger.info("Refreshing host metadata: #{ip}")
|
511
|
+
|
607
512
|
if ip == connection.host
|
608
513
|
request = SELECT_LOCAL
|
609
514
|
else
|
610
|
-
request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" %
|
515
|
+
request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" % ip, EMPTY_LIST, EMPTY_LIST, :one)
|
611
516
|
end
|
612
517
|
|
613
518
|
send_select_request(connection, request).map do |rows|
|
614
|
-
|
519
|
+
if rows.empty?
|
520
|
+
raise Errors::InternalError, "Unable to find host metadata: #{ip}"
|
521
|
+
else
|
522
|
+
@logger.info("Refreshed host metadata: #{ip}")
|
615
523
|
@registry.host_found(address, rows.first)
|
616
524
|
end
|
617
525
|
|
618
526
|
self
|
619
527
|
end
|
528
|
+
rescue => e
|
529
|
+
@logger.error("Refreshing host metadata failed (#{e.class.name}: #{e.message})")
|
620
530
|
end
|
621
531
|
|
622
532
|
def connect_to_first_available(plan, errors = nil)
|
@@ -671,15 +581,16 @@ Control connection failed and is unlikely to recover.
|
|
671
581
|
end
|
672
582
|
end
|
673
583
|
|
674
|
-
|
584
|
+
refresh_maybe_retry(:metadata)
|
675
585
|
end
|
676
|
-
f = f.flat_map {
|
677
|
-
f = f.flat_map {
|
586
|
+
f = f.flat_map { register_async }
|
587
|
+
f = f.flat_map { refresh_peers_async_maybe_retry }
|
588
|
+
f = f.flat_map { refresh_maybe_retry(:schema) } if @connection_options.synchronize_schema?
|
678
589
|
f = f.fallback do |error|
|
679
590
|
@logger.debug("Connection to #{host.ip} failed (#{error.class.name}: #{error.message})")
|
680
591
|
|
681
592
|
case error
|
682
|
-
when Errors::HostError
|
593
|
+
when Errors::HostError, Errors::TimeoutError
|
683
594
|
errors ||= {}
|
684
595
|
errors[host] = error
|
685
596
|
connect_to_first_available(plan, errors)
|
@@ -699,38 +610,23 @@ Control connection failed and is unlikely to recover.
|
|
699
610
|
@connector.connect(host)
|
700
611
|
end
|
701
612
|
|
702
|
-
def peer_ip(data
|
703
|
-
|
704
|
-
|
705
|
-
return nil unless peer && data['host_id'] && data['data_center'] && data['rack'] && data['tokens']
|
706
|
-
|
707
|
-
rpc_address = data['rpc_address']
|
708
|
-
|
709
|
-
if rpc_address.nil?
|
710
|
-
@logger.info("The system.peers row for '#{data['peer']}' has no rpc_address. This is likely " +
|
711
|
-
'a gossip or snitch issue. This host will be ignored.')
|
712
|
-
return nil
|
713
|
-
end
|
714
|
-
|
715
|
-
if peer == host_address || rpc_address == host_address
|
716
|
-
# Some DSE versions were inserting a line for the local node in peers (with mostly null values).
|
717
|
-
# This has been fixed, but if we detect that's the case, ignore it as it's not really a big deal.
|
718
|
-
|
719
|
-
@logger.debug("System.peers on node #{host_address} has a line for itself. This is not normal but is a " +
|
720
|
-
'known problem of some DSE versions. Ignoring the entry.')
|
721
|
-
return nil
|
722
|
-
end
|
723
|
-
|
724
|
-
ip = rpc_address
|
725
|
-
ip = peer if ip == '0.0.0.0'
|
613
|
+
def peer_ip(data)
|
614
|
+
ip = data['rpc_address']
|
615
|
+
ip = data['peer'] if ip == '0.0.0.0'
|
726
616
|
|
727
617
|
@address_resolver.resolve(ip)
|
728
618
|
end
|
729
619
|
|
730
620
|
def process_schema_changes(schema_changes)
|
731
|
-
refresh_keyspaces
|
732
|
-
refresh_tables
|
733
|
-
refresh_types
|
621
|
+
refresh_keyspaces = ::Hash.new
|
622
|
+
refresh_tables = ::Hash.new
|
623
|
+
refresh_types = ::Hash.new
|
624
|
+
|
625
|
+
# This hash is of the form <keyspace, [Change (for function changes)]>
|
626
|
+
refresh_functions = ::Hash.new
|
627
|
+
|
628
|
+
# This hash is of the form <keyspace, [Change (for aggregate changes)]>
|
629
|
+
refresh_aggregates = ::Hash.new
|
734
630
|
|
735
631
|
schema_changes.each do |change|
|
736
632
|
keyspace = change.keyspace
|
@@ -741,37 +637,91 @@ Control connection failed and is unlikely to recover.
|
|
741
637
|
when Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
742
638
|
refresh_tables.delete(keyspace)
|
743
639
|
refresh_types.delete(keyspace)
|
640
|
+
refresh_functions.delete(keyspace)
|
641
|
+
refresh_aggregates.delete(keyspace)
|
744
642
|
refresh_keyspaces[keyspace] = true
|
745
643
|
when Protocol::Constants::SCHEMA_CHANGE_TARGET_TABLE
|
746
644
|
tables = refresh_tables[keyspace] ||= ::Hash.new
|
747
|
-
tables[change.
|
645
|
+
tables[change.name] = true
|
748
646
|
when Protocol::Constants::SCHEMA_CHANGE_TARGET_UDT
|
749
647
|
types = refresh_types[keyspace] ||= ::Hash.new
|
750
|
-
types[change.
|
648
|
+
types[change.name] = true
|
649
|
+
when Protocol::Constants::SCHEMA_CHANGE_TARGET_FUNCTION
|
650
|
+
functions = refresh_functions[keyspace] ||= []
|
651
|
+
functions << change
|
652
|
+
when Protocol::Constants::SCHEMA_CHANGE_TARGET_AGGREGATE
|
653
|
+
aggregates = refresh_aggregates[keyspace] ||= []
|
654
|
+
aggregates << change
|
751
655
|
end
|
752
656
|
end
|
753
657
|
|
754
658
|
futures = ::Array.new
|
755
659
|
|
756
660
|
refresh_keyspaces.each_key do |keyspace|
|
757
|
-
futures <<
|
661
|
+
futures << refresh_maybe_retry(:keyspace, keyspace)
|
758
662
|
end
|
759
663
|
|
760
664
|
refresh_tables.each do |(keyspace, tables)|
|
761
665
|
tables.each_key do |table|
|
762
|
-
futures <<
|
666
|
+
futures << refresh_maybe_retry(:table, keyspace, table)
|
763
667
|
end
|
764
668
|
end
|
765
669
|
|
766
670
|
refresh_types.each do |(keyspace, types)|
|
767
671
|
types.each_key do |type|
|
768
|
-
futures <<
|
672
|
+
futures << refresh_maybe_retry(:type, keyspace, type)
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
refresh_functions.each do |(keyspace, function_changes)|
|
677
|
+
function_changes.each do |change|
|
678
|
+
futures << refresh_maybe_retry(:function, keyspace, change.name, change.arguments)
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
refresh_aggregates.each do |(keyspace, aggregate_changes)|
|
683
|
+
aggregate_changes.each do |change|
|
684
|
+
futures << refresh_maybe_retry(:aggregate, keyspace, change.name, change.arguments)
|
769
685
|
end
|
770
686
|
end
|
771
687
|
|
772
688
|
Ione::Future.all(*futures)
|
773
689
|
end
|
774
690
|
|
691
|
+
def refresh_maybe_retry(what, *args)
|
692
|
+
send(:"refresh_#{what}_async", *args).fallback do |e|
|
693
|
+
case e
|
694
|
+
when Errors::HostError, Errors::TimeoutError
|
695
|
+
refresh_retry(what, e, @reconnection_policy.schedule, *args)
|
696
|
+
else
|
697
|
+
connection = @connection
|
698
|
+
connection && connection.close(e)
|
699
|
+
|
700
|
+
Ione::Future.failed(e)
|
701
|
+
end
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
def refresh_retry(what, error, schedule, *args)
|
706
|
+
timeout = schedule.next
|
707
|
+
@logger.info("Failed to refresh #{what} #{args.inspect} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
|
708
|
+
|
709
|
+
timer = @io_reactor.schedule_timer(timeout)
|
710
|
+
timer.flat_map do
|
711
|
+
send(:"refresh_#{what}_async", *args).fallback do |e|
|
712
|
+
case e
|
713
|
+
when Errors::HostError, Errors::TimeoutError
|
714
|
+
refresh_retry(what, e, schedule, *args)
|
715
|
+
else
|
716
|
+
connection = @connection
|
717
|
+
connection && connection.close(e)
|
718
|
+
|
719
|
+
Ione::Future.failed(e)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
775
725
|
def handle_schema_change(change)
|
776
726
|
timer = nil
|
777
727
|
expiration_timer = nil
|
@@ -825,14 +775,17 @@ Control connection failed and is unlikely to recover.
|
|
825
775
|
end
|
826
776
|
|
827
777
|
def send_select_request(connection, request)
|
778
|
+
backtrace = caller
|
828
779
|
connection.send_request(request).map do |r|
|
829
780
|
case r
|
830
781
|
when Protocol::RowsResultResponse
|
831
782
|
r.rows
|
832
783
|
when Protocol::ErrorResponse
|
833
|
-
|
784
|
+
e = r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :one, 0)
|
785
|
+
e.set_backtrace(backtrace)
|
786
|
+
raise e
|
834
787
|
else
|
835
|
-
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
788
|
+
raise Errors::InternalError, "Unexpected response #{r.inspect}", caller
|
836
789
|
end
|
837
790
|
end
|
838
791
|
end
|