cassandra-driver 3.0.0.rc.1 → 3.0.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +6 -1
  3. data/lib/cassandra.rb +74 -55
  4. data/lib/cassandra/attr_boolean.rb +33 -0
  5. data/lib/cassandra/auth.rb +2 -1
  6. data/lib/cassandra/auth/providers/password.rb +4 -16
  7. data/lib/cassandra/cluster/connector.rb +14 -4
  8. data/lib/cassandra/cluster/control_connection.rb +59 -67
  9. data/lib/cassandra/cluster/metadata.rb +1 -3
  10. data/lib/cassandra/cluster/options.rb +9 -10
  11. data/lib/cassandra/cluster/registry.rb +16 -5
  12. data/lib/cassandra/cluster/schema.rb +45 -1
  13. data/lib/cassandra/cluster/schema/fetchers.rb +475 -272
  14. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +2 -6
  15. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +5 -7
  16. data/lib/cassandra/column.rb +1 -20
  17. data/lib/cassandra/column_container.rb +322 -0
  18. data/lib/cassandra/compression/compressors/lz4.rb +3 -5
  19. data/lib/cassandra/driver.rb +1 -1
  20. data/lib/cassandra/errors.rb +38 -22
  21. data/lib/cassandra/execution/options.rb +4 -2
  22. data/lib/cassandra/future.rb +3 -9
  23. data/lib/cassandra/host.rb +16 -2
  24. data/lib/cassandra/index.rb +104 -0
  25. data/lib/cassandra/keyspace.rb +88 -9
  26. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +6 -10
  27. data/lib/cassandra/materialized_view.rb +90 -0
  28. data/lib/cassandra/protocol/coder.rb +3 -3
  29. data/lib/cassandra/protocol/cql_byte_buffer.rb +12 -11
  30. data/lib/cassandra/protocol/cql_protocol_handler.rb +12 -8
  31. data/lib/cassandra/protocol/request.rb +4 -5
  32. data/lib/cassandra/protocol/requests/execute_request.rb +3 -5
  33. data/lib/cassandra/protocol/requests/query_request.rb +1 -1
  34. data/lib/cassandra/protocol/requests/startup_request.rb +6 -8
  35. data/lib/cassandra/protocol/response.rb +1 -2
  36. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +3 -4
  37. data/lib/cassandra/protocol/responses/auth_success_response.rb +3 -4
  38. data/lib/cassandra/protocol/responses/authenticate_response.rb +3 -4
  39. data/lib/cassandra/protocol/responses/error_response.rb +3 -4
  40. data/lib/cassandra/protocol/responses/event_response.rb +2 -3
  41. data/lib/cassandra/protocol/responses/prepared_result_response.rb +3 -4
  42. data/lib/cassandra/protocol/responses/ready_response.rb +3 -4
  43. data/lib/cassandra/protocol/responses/result_response.rb +7 -8
  44. data/lib/cassandra/protocol/responses/rows_result_response.rb +3 -4
  45. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +3 -4
  46. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +3 -4
  47. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +3 -4
  48. data/lib/cassandra/protocol/responses/status_change_event_response.rb +3 -4
  49. data/lib/cassandra/protocol/responses/supported_response.rb +3 -4
  50. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +3 -4
  51. data/lib/cassandra/protocol/responses/void_result_response.rb +3 -4
  52. data/lib/cassandra/protocol/v1.rb +1 -5
  53. data/lib/cassandra/protocol/v3.rb +1 -3
  54. data/lib/cassandra/result.rb +2 -1
  55. data/lib/cassandra/retry/policies/downgrading_consistency.rb +1 -3
  56. data/lib/cassandra/statements/prepared.rb +3 -3
  57. data/lib/cassandra/table.rb +39 -220
  58. data/lib/cassandra/time_uuid.rb +5 -7
  59. data/lib/cassandra/tuple.rb +4 -12
  60. data/lib/cassandra/types.rb +92 -65
  61. data/lib/cassandra/udt.rb +34 -14
  62. data/lib/cassandra/uuid.rb +10 -18
  63. data/lib/cassandra/version.rb +1 -1
  64. metadata +8 -2
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YTFhMzk5ZGFjZWJhYTQzZDFhYjA5ZGM3Mzk0YjY1MWMwODdjMDUyNA==
4
+ ZTBiZDQ4YTM2MDliN2U0N2VlNmJjY2RiYjQyOWVlOWI4MzlhNjNkZg==
5
5
  data.tar.gz: !binary |-
6
- NGE5OTQ1YjYyNjA1ZTVhNDI4OGQzNmJiMmFlMzJlNzRlMzNiMTkyMw==
6
+ OGY1MDNjN2Y5ZmFjYmY2YWY0ZWI0ZGNjZjViMTA1ZDdkYzQyOTg0Yg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MWZiZmZiOWNkMzFkMDM3NzE3ZTQxMzUzZWM5NjU1MjA1ODI2ODFkNDkxNzI4
10
- YjlmNmJhZGE2OTEyNWY1ZmIyOWQwNjhlNTQyNjdiN2U2Njk3ZDYyMzNhYTg4
11
- NmZjYjY5YmZiMDRlNTA2Njg4ZTQ2YTJlZWQ3YjVhY2MwNGE0NjA=
9
+ MTIzOTk1Nzk0NDI2NWNkZWNiZmUyMmIzZjk4YjQ2YmRjZDkwODc4YjUxY2Fj
10
+ N2FmYjRlOGZiMjBlNTAzY2RmOGM4OGNlZmZkZWVjN2RjNDU1ZjY4MjYxODE3
11
+ YWU1MTZiNWMyMjViOTVhODExODlkNmQwMzc1ODZlMjkwYWU0NDQ=
12
12
  data.tar.gz: !binary |-
13
- NDJiNzQ1ZTgzN2VkOTBmYWZjOGFmN2QwMDc4OWU3YmQxMjdlYmFjZGQ0OTM5
14
- NDlmYmQxMDE1YjczZmNmZjg4MGRjNDY1ODRhZjNlYzBkODE2YTQ5YmM0Njlm
15
- N2IyYjhkM2JhZmUwMjUyM2I4ODhlM2VmY2Q5YmNkZTUzZmM1ZGE=
13
+ ZDI1ZDVmMWQyNzJiMGRiYzc5NTgxYjE4ZGEwNjVmZWM0Nzc0Yzk4MGJjODcx
14
+ YjEzYjNlNTZhOTU1YWY2M2JlZGUxZDA1YWU3NjRlMGE4ZmM4ODUyMTgyNmVj
15
+ NjU3NWUzYzFiMDNmOGJlZDg1ODJiYzJkMDQ3OGZhNjU3MWZlMTY=
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Datastax Ruby Driver for Apache Cassandra
2
2
 
3
- *If you're reading this on GitHub, please note that this is the readme for the development version and that some features described here might not yet have been released. You can [find the documentation for latest version through ruby driver docs](http://datastax.github.io/ruby-driver/) or via the release tags, [e.g. v1.0.0-beta.3](https://github.com/datastax/ruby-driver/tree/v1.0.0-beta.3).*
3
+ *If you're reading this on GitHub, please note that this is the readme for the development version and that some features described here might not yet have been released. You can [find the documentation for latest version through ruby driver docs](http://datastax.github.io/ruby-driver/) or via the release tags, [e.g. v3.0.0-rc.2](https://github.com/datastax/ruby-driver/tree/v3.0.0-rc.2).*
4
4
 
5
5
  [![Build Status](https://travis-ci.org/datastax/ruby-driver.svg?branch=master)](https://travis-ci.org/datastax/ruby-driver)
6
6
 
@@ -107,6 +107,8 @@ Some of the new features added to the driver have unfortunately led to changes i
107
107
  * Expose server warnings on server exceptions and Cassandra::Execution::Info instances.
108
108
  * Add connections_per_local_node, connections_per_remote_node, requests_per_connection cluster configuration options to tune parallel query execution and resource usage.
109
109
  * Add Cassandra::Logger class to make it easy for users to enable debug logging in the client.
110
+ * Add protocol_version configuration option to allow the user to force the protocol version to use for communication with nodes.
111
+ * Add support for materialized views and indexes in the schema metadata.
110
112
 
111
113
  ### Breaking Changes:
112
114
 
@@ -133,6 +135,7 @@ batch.add(query, arguments: {p1: 'val1'})
133
135
  * [[RUBY-143](https://datastax-oss.atlassian.net/browse/RUBY-143)] Retry querying system table for metadata of new hosts when prior attempts fail, ultimately enabling use of new hosts.
134
136
  * [[RUBY-150](https://datastax-oss.atlassian.net/browse/RUBY-150)] Fixed a protocol decoding error that occurred when multiple messages are available in a stream.
135
137
  * [[RUBY-151](https://datastax-oss.atlassian.net/browse/RUBY-151)] Decode incomplete UDTs properly.
138
+ * [[RUBY-161](https://datastax-oss.atlassian.net/browse/RUBY-161)] Protocol version negotiation in mixed version clusters should not fall back to v1 unless it is truly warranted.
136
139
 
137
140
  ## Feedback Requested
138
141
 
@@ -191,6 +194,8 @@ the release.
191
194
 
192
195
  ## Known bugs & limitations
193
196
 
197
+ * Specifying a `protocol_version` option of 1 or 2 in cluster options will fail with a
198
+ `NoHostsAvailable` error rather than a `ProtocolError` against Cassandra node versions 3.0-3.4.
194
199
  * JRuby 1.6 is not officially supported, although 1.6.8 should work.
195
200
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
196
201
  * Because the driver uses `IO#write_nonblock`, Windows is not supported.
@@ -34,8 +34,10 @@ require 'date'
34
34
 
35
35
  module Cassandra
36
36
  # A list of all supported request consistencies
37
- # @see http://www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 2.0
38
- # @see http://www.datastax.com/documentation/cassandra/1.2/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 1.2
37
+ # @see http://www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_config_consistency_c.html Consistency
38
+ # levels in Apache Cassandra 2.0
39
+ # @see http://www.datastax.com/documentation/cassandra/1.2/cassandra/dml/dml_config_consistency_c.html Consistency
40
+ # levels in Apache Cassandra 1.2
39
41
  # @see Cassandra::Session#execute_async
40
42
  CONSISTENCIES = [:any, :one, :two, :three, :quorum, :all, :local_quorum,
41
43
  :each_quorum, :serial, :local_serial, :local_one].freeze
@@ -47,9 +49,52 @@ module Cassandra
47
49
  # A list of all possible write types that a
48
50
  # {Cassandra::Errors::WriteTimeoutError} can have.
49
51
  #
50
- # @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L872-L887 Description of possible types of writes in Apache Cassandra native protocol spec v1
52
+ # @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L872-L887 Description of
53
+ # possible types of writes in Apache Cassandra native protocol spec v1
51
54
  WRITE_TYPES = [:simple, :batch, :unlogged_batch, :counter, :batch_log].freeze
52
55
 
56
+ CLUSTER_OPTIONS = [
57
+ :address_resolution,
58
+ :address_resolution_policy,
59
+ :auth_provider,
60
+ :client_cert,
61
+ :client_timestamps,
62
+ :compression,
63
+ :compressor,
64
+ :connect_timeout,
65
+ :connections_per_local_node,
66
+ :connections_per_remote_node,
67
+ :consistency,
68
+ :credentials,
69
+ :datacenter,
70
+ :futures_factory,
71
+ :heartbeat_interval,
72
+ :hosts,
73
+ :idle_timeout,
74
+ :listeners,
75
+ :load_balancing_policy,
76
+ :logger,
77
+ :nodelay,
78
+ :reconnection_policy,
79
+ :retry_policy,
80
+ :page_size,
81
+ :passphrase,
82
+ :password,
83
+ :port,
84
+ :private_key,
85
+ :protocol_version,
86
+ :requests_per_connection,
87
+ :schema_refresh_delay,
88
+ :schema_refresh_timeout,
89
+ :server_cert,
90
+ :shuffle_replicas,
91
+ :ssl,
92
+ :synchronize_schema,
93
+ :timeout,
94
+ :trace,
95
+ :username
96
+ ].freeze
97
+
53
98
  # Creates a {Cassandra::Cluster Cluster instance}.
54
99
  #
55
100
  # @option options [Array<String, IPAddr>] :hosts (['127.0.0.1']) a list of
@@ -141,6 +186,10 @@ module Cassandra
141
186
  # for nodes that use the v3 or later protocol, and `128` for nodes that use the
142
187
  # v2 or earlier protocol.
143
188
  #
189
+ # @option options [Integer] :protocol_version (nil) Version of protocol to speak to
190
+ # nodes. By default, this is auto-negotiated to the lowest common protocol version
191
+ # that all nodes in `:hosts` speak.
192
+ #
144
193
  # @option options [Boolean] :client_timestamps (false) whether the driver
145
194
  # should send timestamps for each executed statement. Enabling this setting
146
195
  # allows mitigating Cassandra cluster clock skew because the timestamp of
@@ -274,49 +323,13 @@ module Cassandra
274
323
  # @private
275
324
  SSL_CLASSES = [::TrueClass, ::FalseClass, ::OpenSSL::SSL::SSLContext].freeze
276
325
 
326
+ # rubocop:disable Metrics/AbcSize
327
+ # rubocop:disable Metrics/CyclomaticComplexity
328
+ # rubocop:disable Metrics/PerceivedComplexity
277
329
  # @private
278
330
  def self.validate_and_massage_options(options)
279
331
  options = options.select do |key, _|
280
- [
281
- :address_resolution,
282
- :address_resolution_policy,
283
- :auth_provider,
284
- :client_cert,
285
- :client_timestamps,
286
- :compression,
287
- :compressor,
288
- :connect_timeout,
289
- :connections_per_local_node,
290
- :connections_per_remote_node,
291
- :consistency,
292
- :credentials,
293
- :datacenter,
294
- :futures_factory,
295
- :heartbeat_interval,
296
- :hosts,
297
- :idle_timeout,
298
- :listeners,
299
- :load_balancing_policy,
300
- :logger,
301
- :nodelay,
302
- :reconnection_policy,
303
- :retry_policy,
304
- :page_size,
305
- :passphrase,
306
- :password,
307
- :port,
308
- :private_key,
309
- :requests_per_connection,
310
- :schema_refresh_delay,
311
- :schema_refresh_timeout,
312
- :server_cert,
313
- :shuffle_replicas,
314
- :ssl,
315
- :synchronize_schema,
316
- :timeout,
317
- :trace,
318
- :username
319
- ].include?(key)
332
+ CLUSTER_OPTIONS.include?(key)
320
333
  end
321
334
 
322
335
  has_username = options.key?(:username)
@@ -608,12 +621,8 @@ module Cassandra
608
621
  end
609
622
 
610
623
  options[:nodelay] = !!options[:nodelay] if options.key?(:nodelay)
611
-
612
624
  options[:trace] = !!options[:trace] if options.key?(:trace)
613
-
614
- if options.key?(:shuffle_replicas)
615
- options[:shuffle_replicas] = !!options[:shuffle_replicas]
616
- end
625
+ options[:shuffle_replicas] = !!options[:shuffle_replicas] if options.key?(:shuffle_replicas)
617
626
 
618
627
  if options.key?(:page_size)
619
628
  page_size = options[:page_size]
@@ -627,6 +636,16 @@ module Cassandra
627
636
  end
628
637
  end
629
638
 
639
+ if options.key?(:protocol_version)
640
+ protocol_version = options[:protocol_version]
641
+ unless protocol_version.nil?
642
+ Util.assert_instance_of(::Integer, protocol_version)
643
+ Util.assert_one_of(1..4, protocol_version) do
644
+ ":protocol_version must be a positive integer, #{protocol_version.inspect} given"
645
+ end
646
+ end
647
+ end
648
+
630
649
  if options.key?(:futures_factory)
631
650
  futures_factory = options[:futures_factory]
632
651
  methods = [:error, :value, :promise, :all]
@@ -662,13 +681,8 @@ module Cassandra
662
681
  end
663
682
  end
664
683
 
665
- if options.key?(:synchronize_schema)
666
- options[:synchronize_schema] = !!options[:synchronize_schema]
667
- end
668
-
669
- if options.key?(:client_timestamps)
670
- options[:client_timestamps] = !!options[:client_timestamps]
671
- end
684
+ options[:synchronize_schema] = !!options[:synchronize_schema] if options.key?(:synchronize_schema)
685
+ options[:client_timestamps] = !!options[:client_timestamps] if options.key?(:client_timestamps)
672
686
 
673
687
  if options.key?(:connections_per_local_node)
674
688
  connections_per_node = options[:connections_per_local_node]
@@ -733,6 +747,8 @@ module Cassandra
733
747
  DATE_OFFSET = (::Time.utc(1970, 1, 1).to_date.jd - 2**31)
734
748
  end
735
749
 
750
+ require 'cassandra/attr_boolean'
751
+ require 'cassandra/version'
736
752
  require 'cassandra/uuid'
737
753
  require 'cassandra/time_uuid'
738
754
  require 'cassandra/tuple'
@@ -763,8 +779,11 @@ require 'cassandra/argument'
763
779
  require 'cassandra/function'
764
780
  require 'cassandra/function_collection'
765
781
  require 'cassandra/column'
782
+ require 'cassandra/column_container'
766
783
  require 'cassandra/table'
784
+ require 'cassandra/materialized_view'
767
785
  require 'cassandra/keyspace'
786
+ require 'cassandra/index'
768
787
 
769
788
  require 'cassandra/execution/info'
770
789
  require 'cassandra/execution/options'
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2016 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ # This file monkey-patches Module to have an attr_boolean method to make it easy
20
+ # for classes to define boolean instance variables with "foo?" reader methods.
21
+ # Inspired by http://stackoverflow.com/questions/4013591/attr-reader-with-question-mark-in-a-name
22
+ module Cassandra
23
+ module AttrBoolean
24
+ def attr_boolean(*names)
25
+ names.each do |name|
26
+ define_method(:"#{name}?") do
27
+ res = instance_variable_get(:"@#{name}")
28
+ !res.nil? && res != false
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -59,7 +59,8 @@ module Cassandra
59
59
  # subclasses of this class, but need to implement the same methods. This
60
60
  # class exists only for documentation purposes.
61
61
  #
62
- # @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L257-L273 Cassandra native protocol v2 SASL authentication
62
+ # @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L257-L273 Cassandra
63
+ # native protocol v2 SASL authentication
63
64
  # @see Cassandra::Auth::Provider#create_authenticator
64
65
  class Authenticator
65
66
  # @!method initial_response
@@ -53,24 +53,12 @@ module Cassandra
53
53
  @password = password
54
54
  end
55
55
 
56
- # Returns a Password Authenticator only if
57
- # `org.apache.cassandra.auth.PasswordAuthenticator` is given.
58
- # @param authentication_class [String] must equal to
59
- # `org.apache.cassandra.auth.PasswordAuthenticator`
60
- # @return [Cassandra::Auth::Authenticator] when `authentication_class ==
61
- # "org.apache.cassandra.auth.PasswordAuthenticator"`
62
- # @return [nil] for all other values of `authentication_class`
56
+ # Returns a Password Authenticator
57
+ # @param authentication_class [String] ignored
58
+ # @return [Cassandra::Auth::Authenticator]
63
59
  def create_authenticator(authentication_class)
64
- if authentication_class == PASSWORD_AUTHENTICATOR_FQCN
65
- Authenticator.new(@username, @password)
66
- end
60
+ Authenticator.new(@username, @password)
67
61
  end
68
-
69
- private
70
-
71
- # @private
72
- PASSWORD_AUTHENTICATOR_FQCN =
73
- 'org.apache.cassandra.auth.PasswordAuthenticator'.freeze
74
62
  end
75
63
  end
76
64
  end
@@ -136,6 +136,7 @@ module Cassandra
136
136
  @connection_options.idle_timeout,
137
137
  @connection_options.requests_per_connection)
138
138
  end.flat_map do |connection|
139
+ # connection is a CqlProtocolHandler
139
140
  f = request_options(connection)
140
141
  f = f.flat_map do |options|
141
142
  compression = @connection_options.compression
@@ -159,10 +160,19 @@ module Cassandra
159
160
  case error
160
161
  when Errors::ProtocolError
161
162
  synchronize do
162
- if @connection_options.protocol_version > 1
163
+ current_version = connection.protocol_version
164
+ if current_version > 1 && @connection_options.protocol_negotiable?
163
165
  @logger.info("Host #{host.ip} doesn't support protocol version " \
164
- "#{@connection_options.protocol_version}, downgrading")
165
- @connection_options.protocol_version -= 1
166
+ "#{current_version}, downgrading")
167
+
168
+ # This is tricky. We want to try with the next lower protocol version.
169
+ # However, the connection_options used for all connections may have
170
+ # already been updated due to other node connection failures. So,
171
+ # it may already have a lower protocol-version than our current-1. We
172
+ # don't want to accidentally raise it, so we update it to the min
173
+ # of itself and current-1.
174
+ @connection_options.protocol_version =
175
+ [@connection_options.protocol_version, current_version - 1].min
166
176
  do_connect(host)
167
177
  else
168
178
  Ione::Future.failed(error)
@@ -170,7 +180,7 @@ module Cassandra
170
180
  end
171
181
  when Errors::TimeoutError
172
182
  future = Ione::CompletableFuture.new
173
- connection.close(error).on_complete do |_f|
183
+ connection.close(error).on_complete do |_|
174
184
  future.fail(error)
175
185
  end
176
186
  future
@@ -147,20 +147,20 @@ module Cassandra
147
147
  private
148
148
 
149
149
  SELECT_LOCAL = Protocol::QueryRequest.new(
150
- 'SELECT rack, data_center, host_id, release_version, tokens, partitioner ' \
150
+ 'SELECT * ' \
151
151
  'FROM system.local',
152
152
  EMPTY_LIST,
153
153
  EMPTY_LIST,
154
154
  :one)
155
155
  SELECT_PEERS = Protocol::QueryRequest.new(
156
- 'SELECT peer, rack, data_center, host_id, rpc_address, release_version, tokens ' \
156
+ 'SELECT * ' \
157
157
  'FROM system.peers',
158
158
  EMPTY_LIST,
159
159
  EMPTY_LIST,
160
160
  :one)
161
161
 
162
162
  SELECT_PEER_QUERY =
163
- 'SELECT rack, data_center, host_id, rpc_address, release_version, tokens ' \
163
+ 'SELECT * ' \
164
164
  'FROM system.peers ' \
165
165
  "WHERE peer = '%s'".freeze
166
166
 
@@ -191,18 +191,14 @@ module Cassandra
191
191
  def register_async
192
192
  connection = @connection
193
193
 
194
- if connection.nil?
195
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
196
- end
194
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
197
195
 
198
196
  request = Protocol::RegisterRequest.new(
199
197
  Protocol::TopologyChangeEventResponse::TYPE,
200
198
  Protocol::StatusChangeEventResponse::TYPE
201
199
  )
202
200
 
203
- if @connection_options.synchronize_schema?
204
- request.events << Protocol::SchemaChangeEventResponse::TYPE
205
- end
201
+ request.events << Protocol::SchemaChangeEventResponse::TYPE if @connection_options.synchronize_schema?
206
202
 
207
203
  f = connection.send_request(request)
208
204
  f = f.map do |r|
@@ -257,9 +253,7 @@ module Cassandra
257
253
 
258
254
  @logger.info('Refreshing schema')
259
255
 
260
- if connection.nil?
261
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
262
- end
256
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
263
257
 
264
258
  @schema_fetcher.fetch(connection).map do |keyspaces|
265
259
  @schema.replace(keyspaces)
@@ -271,9 +265,7 @@ module Cassandra
271
265
  def refresh_keyspace_async(keyspace_name)
272
266
  connection = @connection
273
267
 
274
- if connection.nil?
275
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
276
- end
268
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
277
269
 
278
270
  @logger.info("Refreshing keyspace \"#{keyspace_name}\"")
279
271
 
@@ -284,16 +276,14 @@ module Cassandra
284
276
  @schema.delete_keyspace(keyspace_name)
285
277
  end
286
278
 
287
- @logger.info("Refreshed keyspace \"#{keyspace_name}\"")
279
+ @logger.info("Completed refreshing keyspace \"#{keyspace_name}\"")
288
280
  end
289
281
  end
290
282
 
291
283
  def refresh_table_async(keyspace_name, table_name)
292
284
  connection = @connection
293
285
 
294
- if connection.nil?
295
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
296
- end
286
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
297
287
 
298
288
  @logger.info("Refreshing table \"#{keyspace_name}.#{table_name}\"")
299
289
 
@@ -304,16 +294,32 @@ module Cassandra
304
294
  @schema.delete_table(keyspace_name, table_name)
305
295
  end
306
296
 
307
- @logger.info("Refreshed table \"#{keyspace_name}.#{table_name}\"")
297
+ @logger.info("Completed refreshing table \"#{keyspace_name}.#{table_name}\"")
308
298
  end
309
299
  end
310
300
 
311
- def refresh_type_async(keyspace_name, type_name)
301
+ def refresh_materialized_view_async(keyspace_name, view_name)
312
302
  connection = @connection
313
303
 
314
- if connection.nil?
315
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
304
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
305
+
306
+ @logger.info("Refreshing materialized view \"#{keyspace_name}.#{view_name}\"")
307
+
308
+ @schema_fetcher.fetch_materialized_view(connection, keyspace_name, view_name).map do |view|
309
+ if view
310
+ @schema.replace_materialized_view(view)
311
+ else
312
+ @schema.delete_materialized_view(keyspace_name, view_name)
313
+ end
314
+
315
+ @logger.info("Completed refreshing materialized view \"#{keyspace_name}.#{view_name}\"")
316
316
  end
317
+ end
318
+
319
+ def refresh_type_async(keyspace_name, type_name)
320
+ connection = @connection
321
+
322
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
317
323
 
318
324
  @logger.info("Refreshing user-defined type \"#{keyspace_name}.#{type_name}\"")
319
325
 
@@ -324,16 +330,14 @@ module Cassandra
324
330
  @schema.delete_type(keyspace_name, type_name)
325
331
  end
326
332
 
327
- @logger.info("Refreshed user-defined type \"#{keyspace_name}.#{type_name}\"")
333
+ @logger.info("Completed refreshing user-defined type \"#{keyspace_name}.#{type_name}\"")
328
334
  end
329
335
  end
330
336
 
331
337
  def refresh_function_async(keyspace_name, function_name, function_args)
332
338
  connection = @connection
333
339
 
334
- if connection.nil?
335
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
336
- end
340
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
337
341
 
338
342
  @logger.info('Refreshing user-defined function ' \
339
343
  "\"#{keyspace_name}.#{function_name}\"")
@@ -351,7 +355,7 @@ module Cassandra
351
355
  @schema.delete_function(keyspace_name, function_name, parsed_function_args)
352
356
  end
353
357
 
354
- @logger.info('Refreshed user-defined function ' \
358
+ @logger.info('Completed refreshing user-defined function ' \
355
359
  "\"#{keyspace_name}.#{function_name}(#{function_args.join(',')})\"")
356
360
  end
357
361
  end
@@ -359,9 +363,7 @@ module Cassandra
359
363
  def refresh_aggregate_async(keyspace_name, aggregate_name, aggregate_args)
360
364
  connection = @connection
361
365
 
362
- if connection.nil?
363
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
364
- end
366
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
365
367
 
366
368
  @logger.info('Refreshing user-defined aggregate ' \
367
369
  "\"#{keyspace_name}.#{aggregate_name}\"")
@@ -380,7 +382,7 @@ module Cassandra
380
382
  @schema.delete_aggregate(keyspace_name, aggregate_name, parsed_aggregate_args)
381
383
  end
382
384
 
383
- @logger.info('Refreshed user-defined aggregate ' \
385
+ @logger.info('Completed refreshing user-defined aggregate ' \
384
386
  "\"#{keyspace_name}.#{aggregate_name}(#{aggregate_args.join(',')})\"")
385
387
  end
386
388
  end
@@ -432,9 +434,7 @@ module Cassandra
432
434
  def refresh_peers_async
433
435
  connection = @connection
434
436
 
435
- if connection.nil?
436
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
437
- end
437
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
438
438
 
439
439
  @logger.info('Refreshing peers metadata')
440
440
 
@@ -456,7 +456,7 @@ module Cassandra
456
456
  @registry.host_lost(host.ip) unless ips.include?(host.ip)
457
457
  end
458
458
 
459
- @logger.info('Refreshed peers metadata')
459
+ @logger.info('Completed refreshing peers metadata')
460
460
 
461
461
  nil
462
462
  end
@@ -465,22 +465,18 @@ module Cassandra
465
465
  def refresh_metadata_async
466
466
  connection = @connection
467
467
 
468
- if connection.nil?
469
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
470
- end
468
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
471
469
 
472
470
  @logger.info("Refreshing connected host's metadata")
473
471
 
474
472
  send_select_request(connection, SELECT_LOCAL).map do |local|
475
- if local.empty?
476
- raise Errors::InternalError, "Unable to fetch connected host's metadata"
477
- else
478
- data = local.first
479
- @registry.host_found(IPAddr.new(connection.host), data)
480
- @metadata.update(data)
481
- end
473
+ raise Errors::InternalError, "Unable to fetch connected host's metadata" if local.empty?
474
+
475
+ data = local.first
476
+ @registry.host_found(IPAddr.new(connection.host), data)
477
+ @metadata.update(data)
482
478
 
483
- @logger.info("Refreshed connected host's metadata")
479
+ @logger.info("Completed refreshing connected host's metadata")
484
480
 
485
481
  nil
486
482
  end
@@ -559,9 +555,7 @@ module Cassandra
559
555
 
560
556
  def refresh_host_async(address)
561
557
  connection = @connection
562
- if connection.nil?
563
- return Ione::Future.failed(Errors::ClientError.new('Not connected'))
564
- end
558
+ return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
565
559
 
566
560
  ip = address.to_s
567
561
 
@@ -577,12 +571,10 @@ module Cassandra
577
571
  end
578
572
 
579
573
  send_select_request(connection, request).map do |rows|
580
- if rows.empty?
581
- raise Errors::InternalError, "Unable to find host metadata: #{ip}"
582
- else
583
- @logger.info("Refreshed host metadata: #{ip}")
584
- @registry.host_found(address, rows.first)
585
- end
574
+ raise Errors::InternalError, "Unable to find host metadata: #{ip}" if rows.empty?
575
+
576
+ @logger.info("Completed refreshing host metadata: #{ip}")
577
+ @registry.host_found(address, rows.first)
586
578
 
587
579
  self
588
580
  end
@@ -647,9 +639,7 @@ Control connection failed and is unlikely to recover.
647
639
  end
648
640
  f = f.flat_map { register_async }
649
641
  f = f.flat_map { refresh_peers_async_maybe_retry }
650
- if @connection_options.synchronize_schema?
651
- f = f.flat_map { refresh_maybe_retry(:schema) }
652
- end
642
+ f = f.flat_map { refresh_maybe_retry(:schema) } if @connection_options.synchronize_schema?
653
643
  f = f.fallback do |error|
654
644
  @logger.debug("Connection to #{host.ip} failed " \
655
645
  "(#{error.class.name}: #{error.message})")
@@ -683,8 +673,8 @@ Control connection failed and is unlikely to recover.
683
673
  end
684
674
 
685
675
  def process_schema_changes(schema_changes)
686
- refresh_keyspaces = ::Hash.new
687
- refresh_tables = ::Hash.new
676
+ refresh_keyspaces = ::Hash.new
677
+ refresh_tables_and_views = ::Hash.new
688
678
  refresh_types = ::Hash.new
689
679
 
690
680
  # This hash is of the form <keyspace, [Change (for function changes)]>
@@ -700,14 +690,15 @@ Control connection failed and is unlikely to recover.
700
690
 
701
691
  case change.target
702
692
  when Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
703
- refresh_tables.delete(keyspace)
693
+ refresh_tables_and_views.delete(keyspace)
704
694
  refresh_types.delete(keyspace)
705
695
  refresh_functions.delete(keyspace)
706
696
  refresh_aggregates.delete(keyspace)
707
697
  refresh_keyspaces[keyspace] = true
708
698
  when Protocol::Constants::SCHEMA_CHANGE_TARGET_TABLE
709
- tables = refresh_tables[keyspace] ||= ::Hash.new
710
- tables[change.name] = true
699
+ # We can't distinguish between table and view change events, so refresh both.
700
+ tables_and_views = refresh_tables_and_views[keyspace] ||= ::Hash.new
701
+ tables_and_views[change.name] = true
711
702
  when Protocol::Constants::SCHEMA_CHANGE_TARGET_UDT
712
703
  types = refresh_types[keyspace] ||= ::Hash.new
713
704
  types[change.name] = true
@@ -726,9 +717,10 @@ Control connection failed and is unlikely to recover.
726
717
  futures << refresh_maybe_retry(:keyspace, keyspace)
727
718
  end
728
719
 
729
- refresh_tables.each do |(keyspace, tables)|
730
- tables.each_key do |table|
731
- futures << refresh_maybe_retry(:table, keyspace, table)
720
+ refresh_tables_and_views.each do |(keyspace, tables_and_views)|
721
+ tables_and_views.each_key do |table_or_view|
722
+ futures << refresh_maybe_retry(:table, keyspace, table_or_view)
723
+ futures << refresh_maybe_retry(:materialized_view, keyspace, table_or_view)
732
724
  end
733
725
  end
734
726