cassandra-driver 3.0.0.rc.2-java → 3.0.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -39
  3. data/lib/cassandra.rb +74 -32
  4. data/lib/cassandra/auth.rb +3 -1
  5. data/lib/cassandra/cluster.rb +14 -3
  6. data/lib/cassandra/cluster/client.rb +98 -62
  7. data/lib/cassandra/cluster/connector.rb +7 -9
  8. data/lib/cassandra/cluster/metadata.rb +1 -1
  9. data/lib/cassandra/cluster/options.rb +19 -7
  10. data/lib/cassandra/cluster/schema/cql_type_parser.rb +3 -0
  11. data/lib/cassandra/cluster/schema/fetchers.rb +1 -1
  12. data/lib/cassandra/custom_data.rb +51 -0
  13. data/lib/cassandra/driver.rb +23 -20
  14. data/lib/cassandra/execution/options.rb +1 -1
  15. data/lib/cassandra/index.rb +22 -8
  16. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +19 -1
  17. data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -0
  18. data/lib/cassandra/load_balancing/policies/token_aware.rb +7 -0
  19. data/lib/cassandra/load_balancing/policies/white_list.rb +7 -0
  20. data/lib/cassandra/protocol.rb +7 -0
  21. data/lib/cassandra/protocol/coder.rb +28 -8
  22. data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -4
  23. data/lib/cassandra/protocol/cql_protocol_handler.rb +3 -2
  24. data/lib/cassandra/protocol/requests/batch_request.rb +1 -1
  25. data/lib/cassandra/protocol/requests/execute_request.rb +1 -1
  26. data/lib/cassandra/protocol/requests/query_request.rb +1 -1
  27. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +4 -2
  28. data/lib/cassandra/protocol/v1.rb +2 -1
  29. data/lib/cassandra/protocol/v3.rb +2 -1
  30. data/lib/cassandra/protocol/v4.rb +5 -3
  31. data/lib/cassandra/result.rb +2 -2
  32. data/lib/cassandra/session.rb +10 -15
  33. data/lib/cassandra/statement.rb +5 -0
  34. data/lib/cassandra/statements/batch.rb +6 -0
  35. data/lib/cassandra/statements/bound.rb +5 -0
  36. data/lib/cassandra/statements/prepared.rb +11 -2
  37. data/lib/cassandra/statements/simple.rb +5 -0
  38. data/lib/cassandra/statements/void.rb +5 -0
  39. data/lib/cassandra/table.rb +5 -5
  40. data/lib/cassandra/timestamp_generator.rb +37 -0
  41. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  42. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  43. data/lib/cassandra/tuple.rb +2 -2
  44. data/lib/cassandra/types.rb +2 -2
  45. data/lib/cassandra/util.rb +136 -2
  46. data/lib/cassandra/version.rb +1 -1
  47. data/lib/cassandra_murmur3.jar +0 -0
  48. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 31c4aade473cf9c4faf5c905819d7e70346fb287
4
- data.tar.gz: 640e1bba76cc474ddea22ec12f61d14390bc1dc2
3
+ metadata.gz: 78dc265751584f3c23a824f4f8f8cfebd5f98d32
4
+ data.tar.gz: 303da68ffd2ec37685f54a22e7c26f0f3568b51d
5
5
  SHA512:
6
- metadata.gz: 5de161197b459eb8b5362c3594bd556fd87f25e5eb1038352e218be5ef170bdb20e2757d33e16430ba569564eed6f88fabe98dc4a1f1a84facff5c80e24310fb
7
- data.tar.gz: cf8dee7303a54788a68786b89142873056172cc28381c744af30fb55e6972af4db0297da551011d49725c297777e0dca80fd8e7d102fe957e006b5d21ccb9685
6
+ metadata.gz: 7ecd09602150990d62b56ba5b0c75e1131f54b7c598171f0ca17927dfaf2fc3a2b1bc66c2ffb7b1b61f0164daa6fcbd359c3c6d6528230b05d4e5ba34482665b
7
+ data.tar.gz: 64d64fadf8a713b97079096af4aafd966689f9b8e9e0a6e1acae8442229de407599e3d4318eed80614fb30af5fb53db4a98e340c9a8c3490b03ae07e3a363023
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. v3.0.0-rc.2](https://github.com/datastax/ruby-driver/tree/v3.0.0-rc.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 the latest version through ruby driver docs](http://docs.datastax.com/en/latest-ruby-driver/ruby-driver/whatsNew.html) or via the release tags, [e.g. v3.0.2](https://github.com/datastax/ruby-driver/tree/v3.0.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
 
@@ -8,7 +8,7 @@ A Ruby client driver for Apache Cassandra. This driver works exclusively with
8
8
  the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
9
9
 
10
10
  - Code: https://github.com/datastax/ruby-driver
11
- - Docs: http://datastax.github.io/ruby-driver/
11
+ - Docs: http://docs.datastax.com/en/latest-ruby-driver/ruby-driver/whatsNew.html
12
12
  - Jira: https://datastax-oss.atlassian.net/browse/RUBY
13
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>)
@@ -16,14 +16,14 @@ the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
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 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
- * [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/)
19
+ * [Asynchronous execution](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/asynchronous_io/)
20
+ * One-off, [prepared](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/basics/prepared_statements/) and [batch statements](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/basics/batch_statements/)
21
+ * Automatic peer discovery and cluster metadata with [support for change notifications](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/state_listeners/)
22
+ * Various [load-balancing](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/load_balancing/), [retry](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/retry_policies/) and [reconnection](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/reconnection/) policies with [ability to write your own](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/load_balancing/implementing_a_policy/)
23
+ * [SSL encryption](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/security/ssl_encryption/)
24
+ * [Flexible and robust error handling](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/error_handling/)
25
+ * [Per-request execution information and tracing](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/debugging/)
26
+ * [Configurable address resolution](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/address_resolution/)
27
27
 
28
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.
29
29
 
@@ -31,8 +31,8 @@ This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [
31
31
 
32
32
  This driver works exclusively with the Cassandra Query Language v3 (CQL3) and Cassandra's native protocol. The current version works with:
33
33
 
34
- * Apache Cassandra versions 1.2, 2.0, 2.1, and 3.x
35
- * DataStax Enterprise 4.0, 4.5, 4.6, 4.7, and 4.8
34
+ * Apache Cassandra versions 1.2, 2.0, 2.1, 2.2, and 3.x
35
+ * DataStax Enterprise 4.0 and above.
36
36
  * Ruby (MRI) 2.2, 2.3
37
37
  * JRuby 1.7
38
38
 
@@ -67,9 +67,9 @@ __Note__: The host you specify is just a seed node, the driver will automaticall
67
67
 
68
68
  Read more:
69
69
 
70
- * [`Cassandra.cluster` options](http://datastax.github.io/ruby-driver/api/#cluster-class_method)
71
- * [`Session#execute_async` options](http://datastax.github.io/ruby-driver/api/session/#execute_async-instance_method)
72
- * [Usage documentation](http://datastax.github.io/ruby-driver/features)
70
+ * [`Cassandra.cluster` options](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/api/cassandra/#cluster-class_method)
71
+ * [`Session#execute_async` options](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/api/cassandra/session/#execute_async-instance_method)
72
+ * [Usage documentation](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features)
73
73
 
74
74
  ## Installation
75
75
 
@@ -85,39 +85,46 @@ Install via Gemfile
85
85
  gem 'cassandra-driver'
86
86
  ```
87
87
 
88
- __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)
88
+ __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://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/#compression)
89
89
 
90
90
 
91
91
  ## Upgrading from cql-rb
92
92
 
93
- 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.
93
+ 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/v3.0.2/examples/cql-rb-wrapper.rb) to assist you with gradual upgrade.
94
94
 
95
- ## What's new in v3.0.0
95
+ ## What's new in v3.0
96
+
97
+ See the [changelog](https://github.com/datastax/ruby-driver/blob/v3.0.2/CHANGELOG.md) for details on patch versions.
96
98
 
97
99
  ### Features:
98
100
 
99
- * Apache Cassandra native protocol v4
100
- * Add support for smallint, tinyint, date (Cassandra::Date) and time (Cassandra::Time) data types.
101
+ * Add support for Apache Cassandra native protocol v4
102
+ * Add support for smallint, tinyint, date (`Cassandra::Date`) and time (`Cassandra::Time`) data types.
101
103
  * Include schema metadata for User Defined Functions and User Defined Aggregates.
104
+ * Augment the `Cassandra::Table` object to expose many more attributes: `id`, `options`, `keyspace`, `partition_key`, `clustering_columns`, and `clustering_order`. This makes it significantly easier to write administration scripts that report various attributes of your schema, which may help to highlight areas for improvement.
102
105
  * Include client ip addresses in request traces, only on Cassandra 3.x.
103
- * Add new retry policy decision Cassandra::Retry::Policy#try_next_host.
104
- * Support specifying statement idempotence with the new :idempotent option when executing.
105
- * Support sending custom payloads when preparing or executing statements using the new :payload option.
106
- * Expose custom payloads received with responses on server exceptions and Cassandra::Execution::Info instances.
107
- * Expose server warnings on server exceptions and Cassandra::Execution::Info instances.
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
- * 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.
106
+ * Add new retry policy decision `Cassandra::Retry::Policy#try_next_host`.
107
+ * Support specifying statement idempotence with the new `idempotent` option when executing.
108
+ * Support sending custom payloads when preparing or executing statements using the new `payload` option.
109
+ * Expose custom payloads received with responses on server exceptions and `Cassandra::Execution::Info` instances.
110
+ * Expose server warnings on server exceptions and `Cassandra::Execution::Info` instances.
111
+ * Add `connections_per_local_node`, `connections_per_remote_node`, `requests_per_connection` cluster configuration options to tune parallel query execution and resource usage.
112
+ * Add `Cassandra::Logger` class to make it easy for users to enable debug logging in the client.
113
+ * Add `protocol_version` configuration option to allow the user to force the protocol version to use for communication with nodes.
111
114
  * Add support for materialized views and indexes in the schema metadata.
115
+ * Support the `ReadError`, `WriteError`, and `FunctionCallError` Cassandra error responses introduced in Cassandra 2.2.
116
+ * Add support for unset variables in bound statements.
117
+ * Support DSE security (`DseAuthenticator`, configured for LDAP).
118
+ * Add a timeout option to `Cassandra::Future#get`.
112
119
 
113
- ### Breaking Changes:
120
+ ### Breaking Changes from 2.x:
114
121
 
115
- * Cassandra::Future#join is now an alias to Cassandra::Future#get and will raise an error if the future is resolved with one.
122
+ * `Cassandra::Future#join` is now an alias to Cassandra::Future#get and will raise an error if the future is resolved with one.
116
123
  * Default consistency level is now LOCAL_ONE.
117
124
  * Enable tcp no-delay by default.
118
125
  * Unavailable errors are retried on the next host in the load balancing plan by default.
119
- * Statement execution no longer retried on timeouts, unless :idempotent => true has been specified when executing.
120
- * Cassandra::Statements::Batch#add signature has changed in how one specifies query parameters. Specify the query parameters array as the value of the arguments key:
126
+ * Statement execution no longer retried on timeouts, unless the statement is marked as idempotent in the call to `Cassandra::Session#execute*` or when creating a `Cassandra::Statement` object.
127
+ * `Cassandra::Statements::Batch#add` and `Cassandra::Session#execute*` signatures have changed in how one specifies query parameters. Specify the query parameters array as the value of the arguments key:
121
128
 
122
129
  ```ruby
123
130
  batch.add(query, ['val1', 'val2'])
@@ -128,6 +135,10 @@ batch.add(query, {p1: 'val1'})
128
135
  # becomes
129
136
  batch.add(query, arguments: {p1: 'val1'})
130
137
  ```
138
+ * The Datacenter-aware load balancing policy (`Cassandra::LoadBalancing::Policies::DCAwareRoundRobin`) defaults to using
139
+ nodes in the local DC only. In prior releases, the policy would fall back to remote nodes after exhausting local nodes.
140
+ Specify a positive value (or nil for unlimited) for `max_remote_hosts_to_use` when initializing the policy to allow remote node use.
141
+ * Unspecified variables in statements previously resulted in an exception. Now they are essentially ignored or treated as null.
131
142
 
132
143
  ### Bug Fixes:
133
144
 
@@ -135,12 +146,13 @@ batch.add(query, arguments: {p1: 'val1'})
135
146
  * [[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.
136
147
  * [[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.
137
148
  * [[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.
149
+ * [[RUBY-155](https://datastax-oss.atlassian.net/browse/RUBY-155)] Request timeout timer should not include request queuing time.
150
+ * [[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.
151
+ * [[RUBY-214](https://datastax-oss.atlassian.net/browse/RUBY-214)] Ensure client timestamps have microsecond precision in JRuby. Previously, some row updates would get lost in high transaction environments.
139
152
 
140
153
  ## Feedback Requested
141
154
 
142
- *Help us focus our efforts!* [Provide your input](http://goo.gl/forms/pCs8PTpHLf)
143
- on the Ruby Driver Platform and Runtime Survey (we kept it short).
155
+ *Help us focus our efforts!* [Provide your input](http://goo.gl/forms/pCs8PTpHLf) on the Ruby Driver Platform and Runtime Survey (we kept it short).
144
156
 
145
157
  ## Code examples
146
158
 
@@ -152,7 +164,7 @@ examples in the `features/` directory.
152
164
  ## Running tests
153
165
 
154
166
  If you don't feel like reading through the following instructions on how to run
155
- 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).
167
+ ruby-driver tests, feel free to [check out .travis.yml for the entire build code](https://github.com/datastax/ruby-driver/blob/v3.0.2/.travis.yml).
156
168
 
157
169
  * Check out the driver codebase and install test dependencies:
158
170
 
@@ -176,7 +188,7 @@ CASSANDRA_VERSION=2.0.17 bundle exec rake test # run both as well as integration
176
188
  ## Changelog & versioning
177
189
 
178
190
  Check out the [releases on GitHub](https://github.com/datastax/ruby-driver/releases) and
179
- [changelog](https://github.com/datastax/ruby-driver/blob/master/CHANGELOG.md). Version
191
+ [changelog](https://github.com/datastax/ruby-driver/blob/v3.0.2/CHANGELOG.md). Version
180
192
  numbering follows the [semantic versioning](http://semver.org/) scheme.
181
193
 
182
194
  Private and experimental APIs, defined as whatever is not in the
@@ -200,7 +212,7 @@ the release.
200
212
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
201
213
  * Because the driver uses `IO#write_nonblock`, Windows is not supported.
202
214
 
203
- Please [refer to the usage documentation for more information on common pitfalls](http://datastax.github.io/ruby-driver/features/)
215
+ Please [refer to the usage documentation for more information on common pitfalls](http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/features/)
204
216
 
205
217
  ## Contributing
206
218
 
@@ -230,4 +242,4 @@ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
230
242
  either express or implied. See the License for the specific language governing permissions
231
243
  and limitations under the License.
232
244
 
233
- [1]: http://datastax.github.io/ruby-driver/api
245
+ [1]: http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/api
@@ -66,6 +66,7 @@ module Cassandra
66
66
  :connections_per_remote_node,
67
67
  :consistency,
68
68
  :credentials,
69
+ :custom_types,
69
70
  :datacenter,
70
71
  :futures_factory,
71
72
  :heartbeat_interval,
@@ -187,14 +188,17 @@ module Cassandra
187
188
  # v2 or earlier protocol.
188
189
  #
189
190
  # @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
+ # nodes. By default, this is auto-negotiated to the highest common protocol version
191
192
  # that all nodes in `:hosts` speak.
192
193
  #
193
- # @option options [Boolean] :client_timestamps (false) whether the driver
194
- # should send timestamps for each executed statement. Enabling this setting
195
- # allows mitigating Cassandra cluster clock skew because the timestamp of
196
- # the client machine will be used. This does not help mitigate application
197
- # cluster clock skew.
194
+ # @option options [Boolean, Cassandra::TimestampGenerator] :client_timestamps (false) whether the driver
195
+ # should send timestamps for each executed statement and possibly which timestamp generator to use. Enabling this
196
+ # setting helps mitigate Cassandra cluster clock skew because the timestamp of the client machine will be used.
197
+ # This does not help mitigate application cluster clock skew. Also accepts an initialized
198
+ # {Cassandra::TimestampGenerator}, `:simple` (indicating an instance of {Cassandra::TimestampGenerator::Simple}),
199
+ # or `:monotonic` (indicating an instance of {Cassandra::TimestampGenerator::TickingOnDuplicate}). If set to true,
200
+ # it defaults to {Cassandra::TimestampGenerator::Simple} for all Ruby flavors except JRuby. On JRuby, it defaults to
201
+ # {Cassandra::TimestampGenerator::TickingOnDuplicate}.
198
202
  #
199
203
  # @option options [Boolean] :synchronize_schema (true) whether the driver
200
204
  # should automatically keep schema metadata synchronized. When enabled, the
@@ -290,28 +294,7 @@ module Cassandra
290
294
  # @return [Cassandra::Future<Cassandra::Cluster>] a future resolving to the
291
295
  # cluster instance.
292
296
  def self.cluster_async(options = {})
293
- options = validate_and_massage_options(options)
294
- hosts = []
295
-
296
- Array(options.fetch(:hosts, '127.0.0.1')).each do |host|
297
- case host
298
- when ::IPAddr
299
- hosts << host
300
- when ::String # ip address or hostname
301
- Resolv.each_address(host) do |ip|
302
- hosts << ::IPAddr.new(ip)
303
- end
304
- else
305
- raise ::ArgumentError, ":hosts must be String or IPAddr, #{host.inspect} given"
306
- end
307
- end
308
-
309
- if hosts.empty?
310
- raise ::ArgumentError,
311
- ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
312
- end
313
-
314
- hosts.shuffle!
297
+ options, hosts = validate_and_massage_options(options)
315
298
  rescue => e
316
299
  futures = options.fetch(:futures_factory) { return Future::Error.new(e) }
317
300
  futures.error(e)
@@ -661,14 +644,14 @@ module Cassandra
661
644
 
662
645
  case address_resolution
663
646
  when :none
664
- # do nothing
647
+ # do nothing
665
648
  when :ec2_multi_region
666
649
  options[:address_resolution_policy] =
667
650
  AddressResolution::Policies::EC2MultiRegion.new
668
651
  else
669
652
  raise ::ArgumentError,
670
653
  ':address_resolution must be either :none or :ec2_multi_region, ' \
671
- "#{address_resolution.inspect} given"
654
+ "#{address_resolution.inspect} given"
672
655
  end
673
656
  end
674
657
 
@@ -682,7 +665,35 @@ module Cassandra
682
665
  end
683
666
 
684
667
  options[:synchronize_schema] = !!options[:synchronize_schema] if options.key?(:synchronize_schema)
685
- options[:client_timestamps] = !!options[:client_timestamps] if options.key?(:client_timestamps)
668
+
669
+ if options.key?(:client_timestamps)
670
+ timestamp_generator = case options[:client_timestamps]
671
+ when true
672
+ if RUBY_ENGINE == 'jruby'
673
+ Cassandra::TimestampGenerator::TickingOnDuplicate.new
674
+ else
675
+ Cassandra::TimestampGenerator::Simple.new
676
+ end
677
+ when false
678
+ nil
679
+ when :simple
680
+ Cassandra::TimestampGenerator::Simple.new
681
+ when :monotonic
682
+ Cassandra::TimestampGenerator::TickingOnDuplicate.new
683
+ else
684
+ # The value must be a generator instance.
685
+ options[:client_timestamps]
686
+ end
687
+
688
+ if timestamp_generator
689
+ Util.assert_responds_to(:next, timestamp_generator) do
690
+ ":client_timestamps #{options[:client_timestamps].inspect} must be a boolean, :simple, :monotonic, or " \
691
+ 'an object that responds to :next'
692
+ end
693
+ end
694
+ options.delete(:client_timestamps)
695
+ options[:timestamp_generator] = timestamp_generator
696
+ end
686
697
 
687
698
  if options.key?(:connections_per_local_node)
688
699
  connections_per_node = options[:connections_per_local_node]
@@ -726,7 +737,31 @@ module Cassandra
726
737
  end
727
738
  end
728
739
  end
729
- options
740
+
741
+ # Get host addresses.
742
+ hosts = []
743
+
744
+ Array(options.fetch(:hosts, '127.0.0.1')).each do |host|
745
+ case host
746
+ when ::IPAddr
747
+ hosts << host
748
+ when ::String # ip address or hostname
749
+ Resolv.each_address(host) do |ip|
750
+ hosts << ::IPAddr.new(ip)
751
+ end
752
+ else
753
+ raise ::ArgumentError, ":hosts must be String or IPAddr, #{host.inspect} given"
754
+ end
755
+ end
756
+
757
+ if hosts.empty?
758
+ raise ::ArgumentError,
759
+ ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
760
+ end
761
+
762
+ hosts.shuffle!
763
+
764
+ [options, hosts]
730
765
  end
731
766
 
732
767
  # @private
@@ -767,6 +802,7 @@ require 'cassandra/null_logger'
767
802
  require 'cassandra/executors'
768
803
  require 'cassandra/future'
769
804
  require 'cassandra/cluster'
805
+ require 'cassandra/custom_data'
770
806
  require 'cassandra/driver'
771
807
  require 'cassandra/host'
772
808
  require 'cassandra/session'
@@ -793,12 +829,18 @@ require 'cassandra/load_balancing'
793
829
  require 'cassandra/reconnection'
794
830
  require 'cassandra/retry'
795
831
  require 'cassandra/address_resolution'
832
+ require 'cassandra/timestamp_generator'
796
833
 
797
834
  require 'cassandra/util'
798
835
 
799
836
  # murmur3 hash extension
800
837
  require 'cassandra_murmur3'
801
838
 
839
+ # SortedSet has a race condition where it does some class/global initialization when the first instance is created.
840
+ # If this is done in a multi-threaded environment, bad things can happen. So force the initialization here,
841
+ # when loading the C* module.
842
+ ::SortedSet.new
843
+
802
844
  module Cassandra
803
845
  # @private
804
846
  VOID_STATEMENT = Statements::Void.new
@@ -34,7 +34,7 @@ module Cassandra
34
34
  #
35
35
  # @see Cassandra::Auth::Providers
36
36
  class Provider
37
- # @!method create_authenticator(authentication_class, protocol_version)
37
+ # @!method create_authenticator(authentication_class, host)
38
38
  #
39
39
  # Create a new authenticator object. This method will be called once per
40
40
  # connection that requires authentication. The auth provider can create
@@ -45,6 +45,8 @@ module Cassandra
45
45
  #
46
46
  # @param authentication_class [String] the authentication class used by
47
47
  # the server.
48
+ # @param host [Cassandra::Host] the node to whom we're authenticating.
49
+ #
48
50
  # @return [Cassandra::Auth::Authenticator, nil] an object with an
49
51
  # interface matching {Cassandra::Auth::Authenticator} or `nil` if the
50
52
  # authentication class is not supported.
@@ -41,7 +41,8 @@ module Cassandra
41
41
  retry_policy,
42
42
  address_resolution_policy,
43
43
  connector,
44
- futures_factory)
44
+ futures_factory,
45
+ timestamp_generator)
45
46
  @logger = logger
46
47
  @io_reactor = io_reactor
47
48
  @executor = executor
@@ -57,6 +58,7 @@ module Cassandra
57
58
  @address_resolver = address_resolution_policy
58
59
  @connector = connector
59
60
  @futures = futures_factory
61
+ @timestamp_generator = timestamp_generator
60
62
 
61
63
  @control_connection.on_close do |_cause|
62
64
  begin
@@ -204,7 +206,8 @@ module Cassandra
204
206
  @retry_policy,
205
207
  @address_resolver,
206
208
  @connection_options,
207
- @futures)
209
+ @futures,
210
+ @timestamp_generator)
208
211
  session = Session.new(client, @execution_options, @futures)
209
212
  promise = @futures.promise
210
213
 
@@ -275,7 +278,15 @@ module Cassandra
275
278
 
276
279
  # @private
277
280
  def inspect
278
- "#<#{self.class.name}:0x#{object_id.to_s(16)}>"
281
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} " \
282
+ "name=#{name.inspect}, " \
283
+ "port=#{@connection_options.port}, " \
284
+ "protocol_version=#{@connection_options.protocol_version}, " \
285
+ "load_balancing_policy=#{@load_balancing_policy.inspect}, " \
286
+ "consistency=#{@execution_options.consistency.inspect}, " \
287
+ "timeout=#{@execution_options.timeout.inspect}, " \
288
+ "hosts=#{hosts.inspect}, " \
289
+ "keyspaces=#{keyspaces.inspect}>"
279
290
  end
280
291
  end
281
292
  end
@@ -34,7 +34,8 @@ module Cassandra
34
34
  retry_policy,
35
35
  address_resolution_policy,
36
36
  connection_options,
37
- futures_factory)
37
+ futures_factory,
38
+ timestamp_generator)
38
39
  @logger = logger
39
40
  @registry = cluster_registry
40
41
  @schema = cluster_schema
@@ -52,6 +53,7 @@ module Cassandra
52
53
  @pending_connections = ::Hash.new
53
54
  @keyspace = nil
54
55
  @state = :idle
56
+ @timestamp_generator = timestamp_generator
55
57
 
56
58
  mon_initialize
57
59
  end
@@ -228,11 +230,7 @@ module Cassandra
228
230
  'Apache Cassandra'))
229
231
  end
230
232
 
231
- timestamp = nil
232
- if @connection_options.client_timestamps? &&
233
- @connection_options.protocol_version > 2
234
- timestamp = ::Time.now
235
- end
233
+ timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
236
234
  payload = nil
237
235
  payload = options.payload if @connection_options.protocol_version >= 4
238
236
  request = Protocol::QueryRequest.new(statement.cql,
@@ -286,11 +284,7 @@ module Cassandra
286
284
  end
287
285
 
288
286
  def execute(statement, options)
289
- timestamp = nil
290
- if @connection_options.client_timestamps? &&
291
- @connection_options.protocol_version > 2
292
- timestamp = ::Time.now
293
- end
287
+ timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
294
288
  payload = nil
295
289
  payload = options.payload if @connection_options.protocol_version >= 4
296
290
  timeout = options.timeout
@@ -324,11 +318,7 @@ module Cassandra
324
318
  'Apache Cassandra'))
325
319
  end
326
320
 
327
- timestamp = nil
328
- if @connection_options.client_timestamps? &&
329
- @connection_options.protocol_version > 2
330
- timestamp = ::Time.now
331
- end
321
+ timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
332
322
  payload = nil
333
323
  payload = options.payload if @connection_options.protocol_version >= 4
334
324
  timeout = options.timeout
@@ -644,7 +634,15 @@ module Cassandra
644
634
  errors,
645
635
  hosts)
646
636
  cql = statement.cql
647
- id = synchronize { @prepared_statements[host][cql] }
637
+ id = nil
638
+ host_is_up = true
639
+ synchronize do
640
+ if @prepared_statements[host].nil?
641
+ host_is_up = false
642
+ else
643
+ id = @prepared_statements[host][cql]
644
+ end
645
+ end
648
646
 
649
647
  if id
650
648
  request.id = id
@@ -659,6 +657,19 @@ module Cassandra
659
657
  timeout,
660
658
  errors,
661
659
  hosts)
660
+ elsif !host_is_up
661
+ # We've hit a race condition where the plan says we can query this host, but the host has gone
662
+ # down in the mean time. Just execute the plan again on the next host.
663
+ @logger.debug("#{host} is down; executing plan on next host")
664
+ execute_by_plan(promise,
665
+ keyspace,
666
+ statement,
667
+ options,
668
+ request,
669
+ plan,
670
+ timeout,
671
+ errors,
672
+ hosts)
662
673
  else
663
674
  prepare = prepare_statement(host, connection, cql, timeout)
664
675
  prepare.on_complete do |_|
@@ -816,10 +827,29 @@ module Cassandra
816
827
  cql = statement.cql
817
828
 
818
829
  if statement.is_a?(Statements::Bound)
819
- id = synchronize { @prepared_statements[host][cql] }
830
+ host_is_up = true
831
+ id = nil
832
+ synchronize do
833
+ if @prepared_statements[host].nil?
834
+ host_is_up = false
835
+ else
836
+ id = @prepared_statements[host][cql]
837
+ end
838
+ end
820
839
 
821
840
  if id
822
841
  request.add_prepared(id, statement.params, statement.params_types)
842
+ elsif !host_is_up
843
+ @logger.debug("#{host} is down; executing on next host in plan")
844
+ return batch_by_plan(promise,
845
+ keyspace,
846
+ batch_statement,
847
+ options,
848
+ request,
849
+ plan,
850
+ timeout,
851
+ errors,
852
+ hosts)
823
853
  else
824
854
  unprepared[cql] << statement
825
855
  end
@@ -1156,17 +1186,17 @@ module Cassandra
1156
1186
  end
1157
1187
  when Protocol::SetKeyspaceResultResponse
1158
1188
  @keyspace = r.keyspace
1159
- promise.fulfill(Results::Void.new(r.custom_payload,
1160
- r.warnings,
1161
- r.trace_id,
1162
- keyspace,
1163
- statement,
1164
- options,
1165
- hosts,
1166
- request.consistency,
1167
- retries,
1168
- self,
1169
- @futures))
1189
+ promise.fulfill(Cassandra::Results::Void.new(r.custom_payload,
1190
+ r.warnings,
1191
+ r.trace_id,
1192
+ keyspace,
1193
+ statement,
1194
+ options,
1195
+ hosts,
1196
+ request.consistency,
1197
+ retries,
1198
+ self,
1199
+ @futures))
1170
1200
  when Protocol::PreparedResultResponse
1171
1201
  cql = request.cql
1172
1202
  synchronize do
@@ -1328,7 +1358,7 @@ module Cassandra
1328
1358
  promise.fulfill(
1329
1359
  Results::Void.new(r.custom_payload,
1330
1360
  r.warnings,
1331
- r.trace_id,
1361
+ nil,
1332
1362
  keyspace,
1333
1363
  statement,
1334
1364
  options,
@@ -1360,38 +1390,44 @@ module Cassandra
1360
1390
  end
1361
1391
  else
1362
1392
  response_future.on_failure do |ex|
1363
- errors[host] = ex
1364
- case request
1365
- when Protocol::QueryRequest, Protocol::PrepareRequest
1366
- send_request_by_plan(promise,
1367
- keyspace,
1368
- statement,
1369
- options,
1370
- request,
1371
- plan,
1372
- timeout,
1373
- errors,
1374
- hosts)
1375
- when Protocol::ExecuteRequest
1376
- execute_by_plan(promise,
1377
- keyspace,
1378
- statement,
1379
- options,
1380
- request,
1381
- plan,
1382
- timeout,
1383
- errors,
1384
- hosts)
1385
- when Protocol::BatchRequest
1386
- batch_by_plan(promise,
1387
- keyspace,
1388
- statement,
1389
- options,
1390
- request,
1391
- plan,
1392
- timeout,
1393
- errors,
1394
- hosts)
1393
+ if ex.is_a?(Errors::HostError) ||
1394
+ (ex.is_a?(Errors::TimeoutError) && statement.idempotent?)
1395
+
1396
+ errors[host] = ex
1397
+ case request
1398
+ when Protocol::QueryRequest, Protocol::PrepareRequest
1399
+ send_request_by_plan(promise,
1400
+ keyspace,
1401
+ statement,
1402
+ options,
1403
+ request,
1404
+ plan,
1405
+ timeout,
1406
+ errors,
1407
+ hosts)
1408
+ when Protocol::ExecuteRequest
1409
+ execute_by_plan(promise,
1410
+ keyspace,
1411
+ statement,
1412
+ options,
1413
+ request,
1414
+ plan,
1415
+ timeout,
1416
+ errors,
1417
+ hosts)
1418
+ when Protocol::BatchRequest
1419
+ batch_by_plan(promise,
1420
+ keyspace,
1421
+ statement,
1422
+ options,
1423
+ request,
1424
+ plan,
1425
+ timeout,
1426
+ errors,
1427
+ hosts)
1428
+ else
1429
+ promise.break(ex)
1430
+ end
1395
1431
  else
1396
1432
  promise.break(ex)
1397
1433
  end