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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -53
  3. data/lib/cassandra.rb +22 -3
  4. data/lib/cassandra/aggregate.rb +109 -0
  5. data/lib/cassandra/argument.rb +51 -0
  6. data/lib/cassandra/auth/providers/password.rb +7 -4
  7. data/lib/cassandra/cluster.rb +14 -3
  8. data/lib/cassandra/cluster/client.rb +56 -34
  9. data/lib/cassandra/cluster/connector.rb +6 -6
  10. data/lib/cassandra/cluster/control_connection.rb +204 -251
  11. data/lib/cassandra/cluster/metadata.rb +2 -0
  12. data/lib/cassandra/cluster/schema.rb +131 -209
  13. data/lib/cassandra/cluster/schema/cql_type_parser.rb +104 -0
  14. data/lib/cassandra/cluster/schema/fetchers.rb +1174 -0
  15. data/lib/cassandra/cluster/schema/{type_parser.rb → fqcn_type_parser.rb} +7 -3
  16. data/lib/cassandra/column.rb +2 -2
  17. data/lib/cassandra/driver.rb +27 -9
  18. data/lib/cassandra/errors.rb +179 -25
  19. data/lib/cassandra/execution/info.rb +8 -1
  20. data/lib/cassandra/execution/options.rb +34 -0
  21. data/lib/cassandra/execution/trace.rb +42 -10
  22. data/lib/cassandra/function.rb +150 -0
  23. data/lib/cassandra/future.rb +66 -35
  24. data/lib/cassandra/host.rb +7 -4
  25. data/lib/cassandra/keyspace.rb +112 -13
  26. data/lib/cassandra/load_balancing.rb +1 -1
  27. data/lib/cassandra/protocol.rb +9 -3
  28. data/lib/cassandra/protocol/coder.rb +434 -155
  29. data/lib/cassandra/protocol/cql_byte_buffer.rb +43 -0
  30. data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -1
  31. data/lib/cassandra/protocol/request.rb +4 -0
  32. data/lib/cassandra/protocol/requests/auth_response_request.rb +5 -1
  33. data/lib/cassandra/protocol/requests/batch_request.rb +7 -2
  34. data/lib/cassandra/protocol/requests/credentials_request.rb +5 -1
  35. data/lib/cassandra/protocol/requests/execute_request.rb +16 -10
  36. data/lib/cassandra/protocol/requests/prepare_request.rb +12 -3
  37. data/lib/cassandra/protocol/requests/query_request.rb +20 -11
  38. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +4 -4
  39. data/lib/cassandra/protocol/responses/error_response.rb +14 -14
  40. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +41 -0
  41. data/lib/cassandra/protocol/responses/prepared_result_response.rb +12 -9
  42. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +5 -3
  43. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +43 -0
  44. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +4 -4
  45. data/lib/cassandra/protocol/responses/ready_response.rb +5 -1
  46. data/lib/cassandra/protocol/responses/result_response.rb +3 -3
  47. data/lib/cassandra/protocol/responses/rows_result_response.rb +2 -2
  48. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +25 -24
  49. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +20 -23
  50. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
  51. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +4 -4
  52. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +4 -4
  53. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +45 -0
  54. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +4 -4
  55. data/lib/cassandra/protocol/v1.rb +38 -13
  56. data/lib/cassandra/protocol/v3.rb +34 -29
  57. data/lib/cassandra/protocol/v4.rb +334 -0
  58. data/lib/cassandra/result.rb +10 -9
  59. data/lib/cassandra/retry.rb +17 -3
  60. data/lib/cassandra/retry/policies/default.rb +9 -3
  61. data/lib/cassandra/session.rb +15 -7
  62. data/lib/cassandra/statement.rb +5 -0
  63. data/lib/cassandra/statements/batch.rb +36 -12
  64. data/lib/cassandra/statements/bound.rb +2 -1
  65. data/lib/cassandra/statements/prepared.rb +106 -35
  66. data/lib/cassandra/statements/simple.rb +4 -2
  67. data/lib/cassandra/table.rb +70 -105
  68. data/lib/cassandra/time.rb +98 -0
  69. data/lib/cassandra/time_uuid.rb +1 -1
  70. data/lib/cassandra/tuple.rb +7 -0
  71. data/lib/cassandra/types.rb +472 -272
  72. data/lib/cassandra/udt.rb +10 -0
  73. data/lib/cassandra/util.rb +32 -1
  74. data/lib/cassandra/uuid.rb +6 -1
  75. data/lib/cassandra/uuid/generator.rb +7 -7
  76. data/lib/cassandra/version.rb +1 -1
  77. data/lib/cassandra_murmur3.jar +0 -0
  78. data/lib/datastax/cassandra.rb +5 -2
  79. 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
- 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)
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
- request = Protocol::PrepareRequest.new(cql, options.trace?)
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
- case e
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
- case e
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
- case e
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
- case e
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
- case e
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
- case e
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
- case error
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
- promise.fulfill(Statements::Prepared.new(cql, r.metadata, r.result_metadata, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures, @schema))
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, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector, connection_options)
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 = Protocol::QueryRequest.new('SELECT rack, data_center, host_id, release_version, tokens, partitioner FROM system.local', EMPTY_LIST, EMPTY_LIST, :one)
153
- 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)
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
- refresh_host_async_maybe_retry(address) if @registry.has_host?(address)
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
- refresh_schema_async_maybe_retry
217
+ refresh_maybe_retry(:schema)
227
218
  end
228
219
  when 'REMOVED_NODE'
229
220
  @registry.host_lost(event.address)
230
- refresh_schema_async_maybe_retry
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
- keyspaces = send_select_request(connection, SELECT_KEYSPACES)
247
- tables = send_select_request(connection, SELECT_TABLES)
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 refresh_schema_async_retry(error, schedule)
266
- timeout = schedule.next
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
- timer = @io_reactor.schedule_timer(timeout)
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
- Ione::Future.failed(e)
280
- end
281
- end
282
- end
283
- end
249
+ @logger.info("Refreshing keyspace \"#{keyspace_name}\"")
284
250
 
285
- def refresh_keyspace_async_maybe_retry(keyspace)
286
- refresh_keyspace_async(keyspace).fallback do |e|
287
- case e
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
- connection = @connection
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
- def refresh_keyspace_async_retry(keyspace, error, schedule)
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 refresh_keyspace_async(keyspace)
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
- keyspaces = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_keyspaces WHERE keyspace_name = '%s'" % keyspace, EMPTY_LIST, EMPTY_LIST, :one))
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
- if keyspaces.empty?
338
- @schema.delete_keyspace(keyspace)
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.update_keyspace(host, keyspaces.first, tables, columns, types)
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
- Ione::Future.failed(e)
374
- end
375
- end
276
+ @logger.info("Refreshed table \"#{keyspace_name}.#{table_name}\"")
376
277
  end
377
278
  end
378
279
 
379
- def refresh_table_async(keyspace, table)
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
- params = [keyspace, table]
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
- Ione::Future.all(tables, columns).map do |(tables, columns)|
389
- host = @registry.host(connection.host)
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.update_table(host, keyspace, tables.first, columns)
291
+ @schema.delete_type(keyspace_name, type_name)
395
292
  end
396
- end
397
- end
398
293
 
399
- def refresh_type_async_maybe_retry(keyspace, type)
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 refresh_type_async_retry(keyspace, type, error, schedule)
414
- timeout = schedule.next
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
- timer = @io_reactor.schedule_timer(timeout)
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
- Ione::Future.failed(e)
428
- end
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 refresh_type_async(keyspace, type)
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
- params = [keyspace, type]
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
- if types.empty?
445
- @schema.delete_type(keyspace, type)
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.update_type(host, keyspace, types.first)
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 refresh_hosts_async_maybe_retry
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
- refresh_hosts_async.fallback do |e|
344
+ refresh_peers_async.fallback do |e|
459
345
  case e
460
- when Errors::HostError
461
- refresh_hosts_async_retry(e, @reconnection_policy.schedule)
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 refresh_hosts_async_retry(error, schedule)
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
- refresh_hosts_async.fallback do |e|
367
+ refresh_peers_async.fallback do |e|
482
368
  case e
483
- when Errors::HostError
484
- refresh_hosts_async_retry(e, schedule)
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 refresh_hosts_async
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
- local = send_select_request(connection, SELECT_LOCAL)
501
- peers = send_select_request(connection, SELECT_PEERS)
386
+ @logger.info("Refreshing peers metadata")
502
387
 
503
- Ione::Future.all(local, peers).map do |(local, peers)|
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, connection.host)
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(host)
461
+ def refresh_host_async_maybe_retry(address)
559
462
  synchronize do
560
- return Ione::Future.resolved if @refreshing_hosts || @refreshing_host[host]
561
- @refreshing_host[host] = true
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(host).fallback do |e|
467
+ refresh_host_async(address).fallback do |e|
565
468
  case e
566
- when Errors::HostError
567
- refresh_host_async_retry(host, e, @reconnection_policy.schedule)
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(host)
479
+ @refreshing_host.delete(address)
577
480
  end
578
481
  end
579
482
  end
580
483
 
581
- def refresh_host_async_retry(host, error, schedule)
484
+ def refresh_host_async_retry(address, error, schedule)
582
485
  timeout = schedule.next
583
- @logger.info("Failed to refresh host #{host.ip.to_s} (#{error.class.name}: #{error.message}), retrying in #{timeout}")
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(host).fallback do |e|
490
+ refresh_host_async(address).fallback do |e|
588
491
  case e
589
- when Errors::HostError
590
- refresh_host_async_retry(host, e, schedule)
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'" % address, EMPTY_LIST, EMPTY_LIST, :one)
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
- unless rows.empty?
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
- register_async
584
+ refresh_maybe_retry(:metadata)
675
585
  end
676
- f = f.flat_map { refresh_hosts_async_maybe_retry }
677
- f = f.flat_map { refresh_schema_async_maybe_retry } if @connection_options.synchronize_schema?
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, host_address)
703
- peer = data['peer']
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 = ::Hash.new
732
- refresh_tables = ::Hash.new
733
- refresh_types = ::Hash.new
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.table] = true
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.type] = true
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 << refresh_keyspace_async_maybe_retry(keyspace)
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 << refresh_table_async_maybe_retry(keyspace, table)
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 << refresh_type_async_maybe_retry(keyspace, type)
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
- raise r.to_error(VOID_STATEMENT)
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