cassandra-driver 1.0.0.rc.1-java → 1.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -18
  3. data/lib/cassandra.rb +132 -93
  4. data/lib/cassandra/auth.rb +3 -3
  5. data/lib/cassandra/cluster.rb +65 -39
  6. data/lib/cassandra/cluster/client.rb +67 -28
  7. data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
  8. data/lib/cassandra/cluster/connector.rb +101 -30
  9. data/lib/cassandra/cluster/control_connection.rb +160 -96
  10. data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
  11. data/lib/cassandra/cluster/options.rb +26 -11
  12. data/lib/cassandra/cluster/schema.rb +22 -1
  13. data/lib/cassandra/column.rb +5 -0
  14. data/lib/cassandra/driver.rb +46 -12
  15. data/lib/cassandra/errors.rb +5 -5
  16. data/lib/cassandra/execution/options.rb +42 -8
  17. data/lib/cassandra/execution/trace.rb +4 -4
  18. data/lib/cassandra/executors.rb +111 -0
  19. data/lib/cassandra/future.rb +88 -64
  20. data/lib/cassandra/keyspace.rb +12 -0
  21. data/lib/cassandra/load_balancing.rb +10 -0
  22. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
  23. data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
  24. data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
  25. data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
  26. data/lib/cassandra/null_logger.rb +35 -0
  27. data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
  28. data/lib/cassandra/protocol/requests/query_request.rb +1 -11
  29. data/lib/cassandra/result.rb +34 -9
  30. data/lib/cassandra/session.rb +6 -0
  31. data/lib/cassandra/statements/prepared.rb +5 -1
  32. data/lib/cassandra/table.rb +5 -0
  33. data/lib/cassandra/util.rb +130 -0
  34. data/lib/cassandra/version.rb +1 -1
  35. metadata +40 -50
  36. data/lib/cassandra/client.rb +0 -144
  37. data/lib/cassandra/client/batch.rb +0 -212
  38. data/lib/cassandra/client/client.rb +0 -591
  39. data/lib/cassandra/client/column_metadata.rb +0 -54
  40. data/lib/cassandra/client/connector.rb +0 -273
  41. data/lib/cassandra/client/execute_options_decoder.rb +0 -59
  42. data/lib/cassandra/client/peer_discovery.rb +0 -50
  43. data/lib/cassandra/client/prepared_statement.rb +0 -314
  44. data/lib/cassandra/client/query_result.rb +0 -230
  45. data/lib/cassandra/client/request_runner.rb +0 -70
  46. data/lib/cassandra/client/result_metadata.rb +0 -48
  47. data/lib/cassandra/client/void_result.rb +0 -78
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 325bb43b4250cf8631082f0427667fd07a0de7fd
4
- data.tar.gz: 5868c433339ac05cef2b683873418f2caeb3151d
3
+ metadata.gz: ba36bd754db916c52e42130906733192c16ec6fa
4
+ data.tar.gz: dd30b1f020b3647d686e901638305b93c6286412
5
5
  SHA512:
6
- metadata.gz: e029b8d4e24cc483b0a0b3c5258dd2d41fd9ff502d9a729ac9930d8dd830149625987563f10153e5b0941d55b99609dd1356ee57761b1b5f07f4537dd02ded91
7
- data.tar.gz: 54989da93f758c4c9f1d3130e5c9396ace3d48919286ee418d7e183cf7453bf27b2278bb2f0e7fe839b637c5496d00e8dfc56143ef6606314879aaef6f60aec2
6
+ metadata.gz: e4e143ed5e11f1d2f88fefee54acd0ac3a92ffd2d8f650cf34b2c090041ee1f8e359c3b9c2b93dafd2e6ec8582a691d351e1c8371c4bc376e630273f3e1c0e0e
7
+ data.tar.gz: bca986745e23c0efc77e24cf2f816e94db79479079dfa2c115476f6d9c14b9c69ad17468f112ea6b65dc4f803f62da14048d25f16ec1eb4f1a073b8e4efb71c7
data/README.md CHANGED
@@ -9,27 +9,35 @@ the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
9
9
 
10
10
  - Code: https://github.com/datastax/ruby-driver
11
11
  - Docs: http://datastax.github.io/ruby-driver/
12
- - JIRA: https://datastax-oss.atlassian.net/browse/RUBY
13
- - MAILING LIST: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
12
+ - Jira: https://datastax-oss.atlassian.net/browse/RUBY
13
+ - Mailing List: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
14
14
  - IRC: #datastax-drivers on [irc.freenode.net](http://freenode.net>)
15
- - TWITTER: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
15
+ - Twitter: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
16
16
 
17
17
  This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [Theo Hultberg](https://github.com/iconara) and we added support for:
18
18
 
19
- * [asynchronous execution](http://datastax.github.io/ruby-driver/features/asynchronous_io/)
20
- * one-off, [prepared](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/) and [batch statements](http://datastax.github.io/ruby-driver/features/basics/batch_statements/)
21
- * automatic peer discovery and cluster metadata
22
- * various [load-balancing](http://datastax.github.io/ruby-driver/features/load_balancing/), [retry](http://datastax.github.io/ruby-driver/features/retry_policies/) and reconnection policies, [with ability to write your own](http://datastax.github.io/ruby-driver/features/load_balancing/implementing_a_policy/)
19
+ * [Asynchronous execution](http://datastax.github.io/ruby-driver/features/asynchronous_io/)
20
+ * One-off, [prepared](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/) and [batch statements](http://datastax.github.io/ruby-driver/features/basics/batch_statements/)
21
+ * Automatic peer discovery and cluster metadata with [support for change notifications](http://datastax.github.io/ruby-driver/features/state_listeners/)
22
+ * Various [load-balancing](http://datastax.github.io/ruby-driver/features/load_balancing/), [retry](http://datastax.github.io/ruby-driver/features/retry_policies/) and [reconnection](http://datastax.github.io/ruby-driver/features/reconnection/) policies with [ability to write your own](http://datastax.github.io/ruby-driver/features/load_balancing/implementing_a_policy/)
23
23
  * [SSL encryption](http://datastax.github.io/ruby-driver/features/security/ssl_encryption/)
24
+ * [Flexible and robust error handling](http://datastax.github.io/ruby-driver/features/error_handling/)
25
+ * [Per-request execution information and tracing](http://datastax.github.io/ruby-driver/features/debugging/)
26
+ * [Configurable address resolution](http://datastax.github.io/ruby-driver/features/address_resolution/)
27
+
28
+ [Check out the slides from Ruby Driver Explained](https://speakerdeck.com/avalanche123/ruby-driver-explained) for a detailed overview of the Ruby Driver architecture.
24
29
 
25
30
  ## Compability
26
31
 
27
32
  This driver works exclusively with the Cassandra Query Language v3 (CQL3) and Cassandra's native protocol. The current version works with:
28
33
 
29
- * Cassandra versions 1.2 and 2.0
30
- * Ruby 1.9.3 and 2.0
34
+ * Apache Cassandra versions 1.2, 2.0 and partially 2.1
35
+ * DataStax Enterprise 3.1, 3.2, 4.0 and 4.5
36
+ * Ruby (MRI) 1.9.3, 2.0 and 2.1
31
37
  * JRuby 1.7
32
- * Rubinius 2.1
38
+ * Rubinius 2.2
39
+
40
+ __Note__: Apache Cassandra 2.1 support is limited to the Cassandra 2.0 API, e.g. no user-defined types.
33
41
 
34
42
  __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work.
35
43
 
@@ -56,7 +64,7 @@ end
56
64
  future.join
57
65
  ```
58
66
 
59
- The host you specify is just a seed node, the driver will automatically discover all peers in the cluster.
67
+ __Note__: The host you specify is just a seed node, the driver will automatically discover all peers in the cluster.
60
68
 
61
69
  Read more:
62
70
 
@@ -69,29 +77,59 @@ Read more:
69
77
  Install via rubygems
70
78
 
71
79
  ```bash
72
- gem install cassandra-driver --pre
80
+ gem install cassandra-driver
73
81
  ```
74
82
 
75
83
  Install via Gemfile
76
84
 
77
85
  ```ruby
78
- gem 'cassandra-driver', '~> 1.0.0.beta'
86
+ gem 'cassandra-driver', '~> 1.0.0'
79
87
  ```
80
88
 
81
- Note: if you want to use compression you should also install [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby). [Read more about compression.](http://datastax.github.io/ruby-driver/features/#compression)
89
+ __Note__: if you want to use compression you should also install [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby). [Read more about compression.](http://datastax.github.io/ruby-driver/features/#compression)
82
90
 
83
91
 
84
92
  ## Upgrading from cql-rb
85
93
 
86
94
  Some of the new features added to the driver have unfortunately led to changes in the original cql-rb API. In the examples directory, you can find [an example of how to wrap the ruby driver to achieve almost complete interface parity with cql-rb](https://github.com/datastax/ruby-driver/blob/master/examples/cql-rb-wrapper.rb) to assist you with gradual upgrade.
87
95
 
88
- ## What's new in v1.0.0.beta.3
96
+ ## What's new in v1.1.0
89
97
 
90
98
  Current release introduces the following new features:
91
99
 
92
- * [Token-aware load balancing policy](http://datastax.github.io/ruby-driver/features/load_balancing/token_aware/)
93
- * [SSL encryption](http://datastax.github.io/ruby-driver/features/security/ssl_encryption/)
94
- * Domain names
100
+ * Ability to disable automatic schema synchronization
101
+ * Schema change event storm protection using a sliding delay
102
+ * [`Cassandra::LoadBalancing::Policy#teardown`](http://datastax.github.io/ruby-driver/api/load_balancing/policy/#teardown-instance_method) for cleaning up resources
103
+ * [`Cassandra::Cluster#refresh_schema`](http://datastax.github.io/ruby-driver/api/cluster/#refresh_schema-instance_method) for manually refreshing schema metadata
104
+ * Host list randomization to prevent hotspots between multiple clients
105
+ * Future listeners run in a dedicated threadpool to not block the reactor
106
+
107
+ ## Code examples
108
+
109
+ The DataStax Ruby Driver uses the awesome [Cucumber Framework](http://cukes.info/) for both end-to-end, or acceptance, testing and constructing documentation. All of the features supported by the driver have appropriate acceptance tests with easy-to-copy code examples in the `features/` directory.
110
+
111
+ ## Running tests
112
+
113
+ If you don't feel like reading through the following instructions on how to run ruby-driver tests, feel free to [check out .travis.yml for the entire build code](https://github.com/datastax/ruby-driver/blob/master/.travis.yml).
114
+
115
+ * Check out the driver codebase and install test dependencies:
116
+
117
+ ```bash
118
+ git clone https://github.com/datastax/ruby-driver.git
119
+ cd ruby-driver
120
+ bundle install --without docs
121
+ ```
122
+
123
+ * [Install ccm](http://www.datastax.com/dev/blog/ccm-a-development-tool-for-creating-local-cassandra-clusters)
124
+
125
+ * Run tests:
126
+
127
+ ```bash
128
+ bundle exec cucumber # runs end-to-end tests (or bundle exec rake cucumber)
129
+ bundle exec rspec # runs unit tests (or bundle exec rake rspec)
130
+ bundle exec rake integration # run integration tests
131
+ bundle exec rake test # run both as well as integration tests
132
+ ```
95
133
 
96
134
  ## Changelog & versioning
97
135
 
@@ -105,7 +143,9 @@ Prereleases will be stable, in the sense that they will have finished and proper
105
143
 
106
144
  * JRuby 1.6 is not officially supported, although 1.6.8 should work, if you're stuck in JRuby 1.6.8 try and see if it works for you.
107
145
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
146
+ * Because the driver uses `IO#write_nonblock`, Windows is not supported.
108
147
 
148
+ Please [refer to the usage documentation for more information on common pitfalls](http://datastax.github.io/ruby-driver/features/)
109
149
 
110
150
  ## Credits
111
151
 
@@ -25,7 +25,6 @@ require 'ipaddr'
25
25
  require 'set'
26
26
  require 'bigdecimal'
27
27
  require 'forwardable'
28
- require 'timeout'
29
28
  require 'digest'
30
29
  require 'stringio'
31
30
  require 'resolv'
@@ -51,7 +50,7 @@ module Cassandra
51
50
  # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L591-L603 Description of possible types of writes in Apache Cassandra native protocol spec v1
52
51
  WRITE_TYPES = [:simple, :batch, :unlogged_batch, :counter, :batch_log].freeze
53
52
 
54
- # Creates a {Cassandra::Cluster} instance
53
+ # Creates a {Cassandra::Cluster Cluster instance}.
55
54
  #
56
55
  # @option options [Array<String, IPAddr>] :hosts (['127.0.0.1']) a list of
57
56
  # initial addresses. Note that the entire list of cluster members will be
@@ -65,22 +64,27 @@ module Cassandra
65
64
  # can skip this option if you specify only hosts from the local datacenter
66
65
  # in `:hosts` option.
67
66
  #
67
+ # @option options [Boolean] :shuffle_replicas (true) whether replicas list
68
+ # found by the default Token-Aware Load Balancing Policy should be
69
+ # shuffled. See {Cassandra::LoadBalancing::Policies::TokenAware#initialize Token-Aware Load Balancing Policy}.
70
+ #
68
71
  # @option options [Numeric] :connect_timeout (10) connection timeout in
69
- # seconds.
72
+ # seconds. Setting value to `nil` will reset it to 5 seconds.
70
73
  #
71
74
  # @option options [Numeric] :timeout (10) request execution timeout in
72
- # seconds.
75
+ # seconds. Setting value to `nil` will remove request timeout.
73
76
  #
74
77
  # @option options [Numeric] :heartbeat_interval (30) how often should a
75
78
  # heartbeat be sent to determine if a connection is alive. Several things to
76
79
  # note about this option. Only one heartbeat request will ever be
77
80
  # outstanding on a given connection. Each heatbeat will be sent in at least
78
81
  # `:heartbeat_interval` seconds after the last request has been sent on a
79
- # given connection.
82
+ # given connection. Setting value to `nil` will remove connection timeout.
80
83
  #
81
84
  # @option options [Numeric] :idle_timeout (60) period of inactivity after
82
85
  # which a connection is considered dead. Note that this value should be at
83
- # least a few times larger than `:heartbeat_interval`.
86
+ # least a few times larger than `:heartbeat_interval`. Setting value to
87
+ # `nil` will remove automatic connection termination.
84
88
  #
85
89
  # @option options [String] :username (none) username to use for
86
90
  # authentication to cassandra. Note that you must also specify `:password`.
@@ -118,12 +122,33 @@ module Cassandra
118
122
  # address resolver to use. Must be one of `:none` or
119
123
  # `:ec2_multi_region`.
120
124
  #
125
+ # @option options [Boolean] :synchronize_schema (true) whether the driver
126
+ # should automatically keep schema metadata synchronized. When enabled, the
127
+ # driver updates schema metadata after receiving schema change
128
+ # notifications from Cassandra. Setting this setting to `false` disables
129
+ # automatic schema updates. Schema metadata is used by the driver to
130
+ # determine cluster partitioners as well as to find partition keys and
131
+ # replicas of prepared statements, this information makes token aware load
132
+ # balancing possible. One can still {Cassandra::Cluster#refresh_schema refresh schema manually}.
133
+ #
134
+ # @option options [Numeric] :schema_refresh_delay (1) the driver will wait
135
+ # for `:schema_refresh_delay` before fetching metadata after receiving a
136
+ # schema change event. This timer is restarted every time a new schema
137
+ # change event is received. Finally, when the timer expires or a maximum
138
+ # wait time of `:schema_refresh_timeout` has been reached, a schema refresh
139
+ # attempt will be made and the timeout is reset.
140
+ #
141
+ # @option options [Numeric] :schema_refresh_timeout (10) the maximum delay
142
+ # before automatically refreshing schema. Such delay can occur whenever
143
+ # multiple schema change events are continuously arriving within
144
+ # `:schema_refresh_delay` interval.
145
+ #
121
146
  # @option options [Cassandra::Reconnection::Policy] :reconnection_policy
122
- # default: {Cassandra::Reconnection::Policies::Exponential}. Note that the
123
- # default policy is configured with `(0.5, 30, 2)`.
147
+ # default: {Cassandra::Reconnection::Policies::Exponential Exponential}.
148
+ # Note that the default policy is configured with `(0.5, 30, 2)`.
124
149
  #
125
150
  # @option options [Cassandra::Retry::Policy] :retry_policy default:
126
- # {Cassandra::Retry::Policies::Default}.
151
+ # {Cassandra::Retry::Policies::Default Default Retry Policy}.
127
152
  #
128
153
  # @option options [Logger] :logger (none) logger. a {Logger} instance from the
129
154
  # standard library or any object responding to standard log methods
@@ -139,28 +164,28 @@ module Cassandra
139
164
  # @option options [Boolean] :trace (false) whether or not to trace all
140
165
  # requests by default.
141
166
  #
142
- # @option options [Integer] :page_size (nil) default page size for all select
143
- # queries.
167
+ # @option options [Integer] :page_size (10000) default page size for all
168
+ # select queries. Set this value to `nil` to disable paging.
144
169
  #
145
170
  # @option options [Hash{String => String}] :credentials (none) a hash of credentials - to be used with [credentials authentication in cassandra 1.2](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L238-L250). Note that if you specified `:username` and `:password` options, those credentials are configured automatically.
146
171
  #
147
- # @option options [Cassandra::Auth::Provider] :auth_provider (none) a custom auth provider to be used with [SASL authentication in cassandra 2.0](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v2.spec#L257-L273). Note that if you have specified `:username` and `:password`, then a {Cassandra::Auth::Providers::Password} will be used automatically.
172
+ # @option options [Cassandra::Auth::Provider] :auth_provider (none) a custom auth provider to be used with [SASL authentication in cassandra 2.0](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v2.spec#L257-L273). Note that if you have specified `:username` and `:password`, then a {Cassandra::Auth::Providers::Password Password Provider} will be used automatically.
148
173
  #
149
- # @option options [Cassandra::Compressor] :compressor (none) a custom
150
- # compressor. Note that if you have specified `:compression`, an
174
+ # @option options [Cassandra::Compression::Compressor] :compressor (none) a
175
+ # custom compressor. Note that if you have specified `:compression`, an
151
176
  # appropriate compressor will be provided automatically.
152
177
  #
153
178
  # @option options [Cassandra::AddressResolution::Policy]
154
179
  # :address_resolution_policy default:
155
- # {Cassandra::AddressResolution::Policies::None} a custom address resolution
180
+ # {Cassandra::AddressResolution::Policies::None No Resolution Policy} a custom address resolution
156
181
  # policy. Note that if you have specified `:address_resolution`, an
157
182
  # appropriate address resolution policy will be provided automatically.
158
183
  #
159
184
  # @option options [Object<#all, #error, #value, #promise>] :futures_factory
160
- # (none) a custom futures factory to assist with integration into existing
161
- # futures library. Note that promises returned by this object must conform
162
- # to {Cassandra::Promise} api, which is not yet public. Things may change,
163
- # use at your own risk.
185
+ # default: {Cassandra::Future} a futures factory to assist with integration
186
+ # into existing futures library. Note that promises returned by this object
187
+ # must conform to {Cassandra::Promise} api, which is not yet public. Things
188
+ # may change, use at your own risk.
164
189
  #
165
190
  # @example Connecting to localhost
166
191
  # cluster = Cassandra.cluster
@@ -174,13 +199,25 @@ module Cassandra
174
199
  #
175
200
  # @return [Cassandra::Cluster] a cluster instance
176
201
  def self.cluster(options = {})
202
+ cluster_async(options).get
203
+ end
204
+
205
+ # Creates a {Cassandra::Cluster Cluster instance}.
206
+ #
207
+ # @see Cassandra.cluster
208
+ #
209
+ # @return [Cassandra::Future<Cassandra::Cluster>] a future resolving to the
210
+ # cluster instance.
211
+ def self.cluster_async(options = {})
177
212
  options = options.select do |key, value|
178
213
  [ :credentials, :auth_provider, :compression, :hosts, :logger, :port,
179
214
  :load_balancing_policy, :reconnection_policy, :retry_policy, :listeners,
180
215
  :consistency, :trace, :page_size, :compressor, :username, :password,
181
216
  :ssl, :server_cert, :client_cert, :private_key, :passphrase,
182
217
  :connect_timeout, :futures_factory, :datacenter, :address_resolution,
183
- :address_resolution_policy, :idle_timeout, :heartbeat_interval, :timeout
218
+ :address_resolution_policy, :idle_timeout, :heartbeat_interval, :timeout,
219
+ :synchronize_schema, :schema_refresh_delay, :schema_refresh_timeout,
220
+ :shuffle_replicas
184
221
  ].include?(key)
185
222
  end
186
223
 
@@ -195,11 +232,13 @@ module Cassandra
195
232
  raise ::ArgumentError, "both :username and :password options must be specified, but only :password given"
196
233
  end
197
234
 
198
- username = String(options.delete(:username))
199
- password = String(options.delete(:password))
235
+ username = options.delete(:username)
236
+ password = options.delete(:password)
200
237
 
201
- raise ::ArgumentError, ":username cannot be empty" if username.empty?
202
- raise ::ArgumentError, ":password cannot be empty" if password.empty?
238
+ Util.assert_instance_of(::String, username) { ":username must be a String, #{username.inspect} given" }
239
+ Util.assert_instance_of(::String, password) { ":password must be a String, #{password.inspect} given" }
240
+ Util.assert_not_empty(username) { ":username cannot be empty" }
241
+ Util.assert_not_empty(password) { ":password cannot be empty" }
203
242
 
204
243
  options[:credentials] = {:username => username, :password => password}
205
244
  options[:auth_provider] = Auth::Providers::Password.new(username, password)
@@ -208,17 +247,13 @@ module Cassandra
208
247
  if options.has_key?(:credentials)
209
248
  credentials = options[:credentials]
210
249
 
211
- unless credentials.is_a?(Hash)
212
- raise ::ArgumentError, ":credentials must be a hash, #{credentials.inspect} given"
213
- end
250
+ Util.assert_instance_of(::Hash, credentials) { ":credentials must be a hash, #{credentials.inspect} given" }
214
251
  end
215
252
 
216
253
  if options.has_key?(:auth_provider)
217
254
  auth_provider = options[:auth_provider]
218
255
 
219
- unless auth_provider.respond_to?(:create_authenticator)
220
- raise ::ArgumentError, ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't"
221
- end
256
+ Util.assert_responds_to(:create_authenticator, auth_provider) { ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't" }
222
257
  end
223
258
 
224
259
  has_client_cert = options.has_key?(:client_cert)
@@ -236,13 +271,8 @@ module Cassandra
236
271
  client_cert = ::File.expand_path(options[:client_cert])
237
272
  private_key = ::File.expand_path(options[:private_key])
238
273
 
239
- unless ::File.exists?(client_cert)
240
- raise ::ArgumentError, ":client_cert #{client_cert.inspect} doesn't exist"
241
- end
242
-
243
- unless ::File.exists?(private_key)
244
- raise ::ArgumentError, ":private_key #{private_key.inspect} doesn't exist"
245
- end
274
+ Util.assert_file_exists(client_cert) { ":client_cert #{client_cert.inspect} doesn't exist" }
275
+ Util.assert_file_exists(private_key) { ":private_key #{private_key.inspect} doesn't exist" }
246
276
  end
247
277
 
248
278
  has_server_cert = options.has_key?(:server_cert)
@@ -250,9 +280,7 @@ module Cassandra
250
280
  if has_server_cert
251
281
  server_cert = ::File.expand_path(options[:server_cert])
252
282
 
253
- unless ::File.exists?(server_cert)
254
- raise ::ArgumentError, ":server_cert #{server_cert.inspect} doesn't exist"
255
- end
283
+ Util.assert_file_exists(server_cert) { ":server_cert #{server_cert.inspect} doesn't exist" }
256
284
  end
257
285
 
258
286
  if has_client_cert || has_server_cert
@@ -279,9 +307,7 @@ module Cassandra
279
307
  if options.has_key?(:ssl)
280
308
  ssl = options[:ssl]
281
309
 
282
- unless ssl.is_a?(::TrueClass) || ssl.is_a?(::FalseClass) || ssl.is_a?(::OpenSSL::SSL::SSLContext)
283
- raise ::ArgumentError, ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given"
284
- end
310
+ Util.assert_instance_of_one_of([::TrueClass, ::FalseClass, ::OpenSSL::SSL::SSLContext], ssl) { ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given" }
285
311
  end
286
312
 
287
313
  if options.has_key?(:compression)
@@ -303,26 +329,20 @@ module Cassandra
303
329
  compressor = options[:compressor]
304
330
  methods = [:algorithm, :compress?, :compress, :decompress]
305
331
 
306
- unless methods.all? {|method| compressor.respond_to?(method)}
307
- raise ::ArgumentError, ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't"
308
- end
332
+ Util.assert_responds_to_all(methods, compressor) { ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't" }
309
333
  end
310
334
 
311
335
  if options.has_key?(:logger)
312
336
  logger = options[:logger]
313
337
  methods = [:debug, :info, :warn, :error, :fatal]
314
338
 
315
- unless methods.all? {|method| logger.respond_to?(method)}
316
- raise ::ArgumentError, ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't"
317
- end
339
+ Util.assert_responds_to_all(methods, logger) { ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't" }
318
340
  end
319
341
 
320
342
  if options.has_key?(:port)
321
343
  port = options[:port] = Integer(options[:port])
322
344
 
323
- if port < 0 || port > 65536
324
- raise ::ArgumentError, ":port must be a valid ip port, #{port.given}"
325
- end
345
+ Util.assert_one_of(0..65536, port) { ":port must be a valid ip port, #{port} given" }
326
346
  end
327
347
 
328
348
  if options.has_key?(:datacenter)
@@ -330,88 +350,99 @@ module Cassandra
330
350
  end
331
351
 
332
352
  if options.has_key?(:connect_timeout)
333
- timeout = options[:connect_timeout] = Integer(options[:connect_timeout])
353
+ timeout = options[:connect_timeout]
334
354
 
335
- if timeout < 0
336
- raise ::ArgumentError, ":connect_timeout must be a positive value, #{timeout.given}"
355
+ unless timeout.nil?
356
+ Util.assert_instance_of(::Numeric, timeout) { ":connect_timeout must be a number of seconds, #{timeout} given" }
357
+ Util.assert(timeout > 0) { ":connect_timeout must be greater than 0, #{timeout} given" }
337
358
  end
338
359
  end
339
360
 
340
361
  if options.has_key?(:timeout)
341
- timeout = options[:timeout] = Integer(options[:timeout])
362
+ timeout = options[:timeout]
342
363
 
343
- if timeout < 0
344
- raise ::ArgumentError, ":timeout must be a positive value, #{timeout.given}"
364
+ unless timeout.nil?
365
+ Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
366
+ Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
345
367
  end
346
368
  end
347
369
 
348
370
  if options.has_key?(:heartbeat_interval)
349
- timeout = options[:heartbeat_interval] = Integer(options[:heartbeat_interval])
371
+ timeout = options[:heartbeat_interval]
350
372
 
351
- if timeout < 0
352
- raise ::ArgumentError, ":heartbeat_interval must be a positive value, #{timeout.given}"
373
+ unless timeout.nil?
374
+ Util.assert_instance_of(::Numeric, timeout) { ":heartbeat_interval must be a number of seconds, #{timeout} given" }
375
+ Util.assert(timeout > 0) { ":heartbeat_interval must be greater than 0, #{timeout} given" }
353
376
  end
354
377
  end
355
378
 
356
379
  if options.has_key?(:idle_timeout)
357
- timeout = options[:idle_timeout] = Integer(options[:idle_timeout])
380
+ timeout = options[:idle_timeout]
358
381
 
359
- if timeout < 0
360
- raise ::ArgumentError, ":idle_timeout must be a positive value, #{timeout.given}"
382
+ unless timeout.nil?
383
+ Util.assert_instance_of(::Numeric, timeout) { ":idle_timeout must be a number of seconds, #{timeout} given" }
384
+ Util.assert(timeout > 0) { ":idle_timeout must be greater than 0, #{timeout} given" }
361
385
  end
362
386
  end
363
387
 
388
+ if options.has_key?(:schema_refresh_delay)
389
+ timeout = options[:schema_refresh_delay]
390
+
391
+ Util.assert_instance_of(::Numeric, timeout) { ":schema_refresh_delay must be a number of seconds, #{timeout} given" }
392
+ Util.assert(timeout > 0) { ":schema_refresh_delay must be greater than 0, #{timeout} given" }
393
+ end
394
+
395
+ if options.has_key?(:schema_refresh_timeout)
396
+ timeout = options[:schema_refresh_timeout]
397
+
398
+ Util.assert_instance_of(::Numeric, timeout) { ":schema_refresh_timeout must be a number of seconds, #{timeout} given" }
399
+ Util.assert(timeout > 0) { ":schema_refresh_timeout must be greater than 0, #{timeout} given" }
400
+ end
401
+
364
402
  if options.has_key?(:load_balancing_policy)
365
403
  load_balancing_policy = options[:load_balancing_policy]
366
- methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :distance, :plan]
404
+ methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown, :distance, :plan]
367
405
 
368
- unless methods.all? {|method| load_balancing_policy.respond_to?(method)}
369
- raise ::ArgumentError, ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't"
370
- end
406
+ Util.assert_responds_to_all(methods, load_balancing_policy) { ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
371
407
  end
372
408
 
373
409
  if options.has_key?(:reconnection_policy)
374
410
  reconnection_policy = options[:reconnection_policy]
375
411
 
376
- unless reconnection_policy.respond_to?(:schedule)
377
- raise ::ArgumentError, ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't"
378
- end
412
+ Util.assert_responds_to(:schedule, reconnection_policy) { ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't" }
379
413
  end
380
414
 
381
415
  if options.has_key?(:retry_policy)
382
416
  retry_policy = options[:retry_policy]
383
417
  methods = [:read_timeout, :write_timeout, :unavailable]
384
418
 
385
- unless methods.all? {|method| retry_policy.respond_to?(method)}
386
- raise ::ArgumentError, ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't"
387
- end
419
+ Util.assert_responds_to_all(methods, retry_policy) { ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
388
420
  end
389
421
 
390
422
  if options.has_key?(:listeners)
391
- listeners = options[:listeners]
392
-
393
- unless listeners.respond_to?(:each)
394
- raise ::ArgumentError, ":listeners must be an Enumerable, #{listeners.inspect} given"
395
- end
423
+ options[:listeners] = Array(options[:listeners])
396
424
  end
397
425
 
398
426
  if options.has_key?(:consistency)
399
427
  consistency = options[:consistency]
400
428
 
401
- unless CONSISTENCIES.include?(consistency)
402
- raise ::ArgumentError, ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given"
403
- end
429
+ Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
404
430
  end
405
431
 
406
432
  if options.has_key?(:trace)
407
433
  options[:trace] = !!options[:trace]
408
434
  end
409
435
 
436
+ if options.has_key?(:shuffle_replicas)
437
+ options[:shuffle_replicas] = !!options[:shuffle_replicas]
438
+ end
439
+
410
440
  if options.has_key?(:page_size)
411
- page_size = options[:page_size] = Integer(options[:page_size])
441
+ page_size = options[:page_size]
412
442
 
413
- if page_size <= 0
414
- raise ::ArgumentError, ":page_size must be a positive integer, #{page_size.inspect} given"
443
+ unless page_size.nil?
444
+ page_size = options[:page_size] = Integer(page_size)
445
+ Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
415
446
  end
416
447
  end
417
448
 
@@ -419,9 +450,7 @@ module Cassandra
419
450
  futures_factory = options[:futures_factory]
420
451
  methods = [:error, :value, :promise, :all]
421
452
 
422
- unless methods.all? {|method| futures_factory.respond_to?(method)}
423
- raise ::ArgumentError, ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't"
424
- end
453
+ Util.assert_responds_to_all(methods, futures_factory) { ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't" }
425
454
  end
426
455
 
427
456
  if options.has_key?(:address_resolution)
@@ -429,6 +458,7 @@ module Cassandra
429
458
 
430
459
  case address_resolution
431
460
  when :none
461
+ # do nothing
432
462
  when :ec2_multi_region
433
463
  options[:address_resolution_policy] = AddressResolution::Policies::EC2MultiRegion.new
434
464
  else
@@ -439,9 +469,11 @@ module Cassandra
439
469
  if options.has_key?(:address_resolution_policy)
440
470
  address_resolver = options[:address_resolution_policy]
441
471
 
442
- unless address_resolver.respond_to?(:resolve)
443
- raise ::ArgumentError, ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't"
444
- end
472
+ Util.assert_responds_to(:resolve, address_resolver) { ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't" }
473
+ end
474
+
475
+ if options.has_key?(:synchronize_schema)
476
+ options[:synchronize_schema] = !!options[:synchronize_schema]
445
477
  end
446
478
 
447
479
  hosts = []
@@ -463,7 +495,13 @@ module Cassandra
463
495
  raise ::ArgumentError, ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
464
496
  end
465
497
 
466
- Driver.new(options).connect(hosts).value
498
+ hosts.shuffle!
499
+ rescue => e
500
+ futures = options.fetch(:futures_factory) { Driver.new.futures_factory }
501
+ futures.error(e)
502
+ else
503
+ driver = Driver.new(options)
504
+ driver.connect(hosts)
467
505
  end
468
506
  end
469
507
 
@@ -473,8 +511,9 @@ require 'cassandra/time_uuid'
473
511
  require 'cassandra/compression'
474
512
  require 'cassandra/protocol'
475
513
  require 'cassandra/auth'
476
- require 'cassandra/client'
514
+ require 'cassandra/null_logger'
477
515
 
516
+ require 'cassandra/executors'
478
517
  require 'cassandra/future'
479
518
  require 'cassandra/cluster'
480
519
  require 'cassandra/driver'