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

Sign up to get free protection for your applications and to get access to all the features.
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'