cassandra-driver 3.0.3-java → 3.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +46 -31
  3. data/lib/cassandra.rb +35 -44
  4. data/lib/cassandra/cluster.rb +40 -11
  5. data/lib/cassandra/cluster/client.rb +193 -159
  6. data/lib/cassandra/cluster/connector.rb +12 -10
  7. data/lib/cassandra/cluster/control_connection.rb +38 -10
  8. data/lib/cassandra/cluster/options.rb +8 -4
  9. data/lib/cassandra/cluster/registry.rb +1 -2
  10. data/lib/cassandra/cluster/schema/fetchers.rb +122 -26
  11. data/lib/cassandra/column_container.rb +9 -4
  12. data/lib/cassandra/custom_data.rb +24 -22
  13. data/lib/cassandra/driver.rb +30 -13
  14. data/lib/cassandra/errors.rb +12 -2
  15. data/lib/cassandra/execution/options.rb +52 -16
  16. data/lib/cassandra/execution/profile.rb +150 -0
  17. data/lib/cassandra/execution/profile_manager.rb +71 -0
  18. data/lib/cassandra/execution/trace.rb +5 -4
  19. data/lib/cassandra/executors.rb +1 -1
  20. data/lib/cassandra/index.rb +1 -1
  21. data/lib/cassandra/keyspace.rb +36 -1
  22. data/lib/cassandra/protocol.rb +5 -0
  23. data/lib/cassandra/protocol/coder.rb +2 -1
  24. data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -0
  25. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +10 -4
  26. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +14 -8
  27. data/lib/cassandra/protocol/v3.rb +2 -1
  28. data/lib/cassandra/protocol/v4.rb +58 -20
  29. data/lib/cassandra/result.rb +1 -1
  30. data/lib/cassandra/session.rb +43 -16
  31. data/lib/cassandra/statements/bound.rb +5 -1
  32. data/lib/cassandra/statements/prepared.rb +8 -3
  33. data/lib/cassandra/table.rb +72 -0
  34. data/lib/cassandra/trigger.rb +67 -0
  35. data/lib/cassandra/types.rb +12 -24
  36. data/lib/cassandra/udt.rb +3 -6
  37. data/lib/cassandra/uuid/generator.rb +6 -3
  38. data/lib/cassandra/version.rb +1 -1
  39. data/lib/cassandra_murmur3.jar +0 -0
  40. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dd12699ee5345d58839cfaf6ebc7e9f39529f835
4
- data.tar.gz: 05efbd46f2dbef7ff4669c79c88e3671629a898f
3
+ metadata.gz: ac761253a986cd88350b04de1d3ee90bf1f355c3
4
+ data.tar.gz: 6c9bbff04510173fd06518c7592d7c326534b081
5
5
  SHA512:
6
- metadata.gz: b8c4bc332b1cdd24dda360c19a564a4af64e865b04a139ac04208768949622fedc4bb83d421d1c1a7450d9bb089e14ba6c24e7b8238b562d349ba88d24980c10
7
- data.tar.gz: c99658b87ff4197aedd1c7d0f719be36720252b025797beaefd0a0e0ba718dfdcba17d20c705acd39785e1f9344b0679095aadae9f35217d4c22a561088de403
6
+ metadata.gz: ddf9b426f9f3e2934f1dc705657af049472ef68474ce1458a80d3a5e7a33b07b75fa34ab27bfb71617e2f4b111f8c774ca96e45c98b495e0cf06cc25606d3757
7
+ data.tar.gz: 526e8a7fae76a17635ecadc369b62f1a175aef694a9d0d8488262e90722de6363f8243081e0e5d18c4b6c05305932c59bbf3b369511cce1fbef91746f25ebff4
data/README.md CHANGED
@@ -1,6 +1,8 @@
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 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.3](https://github.com/datastax/ruby-driver/tree/v3.0.3).*
3
+ *If you're reading this on GitHub, please note that this is the readme for the development version and that some
4
+ features described here might not yet have been released. You can view the documentation for the latest released
5
+ version [here](http://docs.datastax.com/en/developer/ruby-driver/latest).*
4
6
 
5
7
  [![Build Status](https://travis-ci.org/datastax/ruby-driver.svg?branch=master)](https://travis-ci.org/datastax/ruby-driver)
6
8
 
@@ -8,22 +10,22 @@ A Ruby client driver for Apache Cassandra. This driver works exclusively with
8
10
  the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
9
11
 
10
12
  - Code: https://github.com/datastax/ruby-driver
11
- - Docs: http://docs.datastax.com/en/latest-ruby-driver/ruby-driver/whatsNew.html
13
+ - Docs: http://docs.datastax.com/en/developer/ruby-driver
12
14
  - Jira: https://datastax-oss.atlassian.net/browse/RUBY
13
15
  - Mailing List: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
14
16
  - IRC: #datastax-drivers on [irc.freenode.net](http://freenode.net>)
15
- - Twitter: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@stamhankar999](http://twitter.com/stamhankar999), [@al3xandru](https://twitter.com/al3xandru)
17
+ - Twitter: Follow the latest news about DataStax Drivers - [@stamhankar999](http://twitter.com/stamhankar999), [@avalanche123](http://twitter.com/avalanche123), [@al3xandru](https://twitter.com/al3xandru)
16
18
 
17
19
  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
20
 
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/)
21
+ * [Asynchronous execution](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/asynchronous_io/)
22
+ * One-off, [prepared](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/basics/prepared_statements/) and [batch statements](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/basics/batch_statements/)
23
+ * Automatic peer discovery and cluster metadata with [support for change notifications](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/state_listeners/)
24
+ * Various [load-balancing](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/load_balancing/), [retry](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/retry_policies/) and [reconnection](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/reconnection/) policies with [ability to write your own](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/load_balancing/implementing_a_policy/)
25
+ * [SSL encryption](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/security/ssl_encryption/)
26
+ * [Flexible and robust error handling](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/error_handling/)
27
+ * [Per-request execution information and tracing](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/debugging/)
28
+ * [Configurable address resolution](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/address_resolution/)
27
29
 
28
30
  [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
31
 
@@ -36,10 +38,14 @@ This driver works exclusively with the Cassandra Query Language v3 (CQL3) and Ca
36
38
  * Ruby (MRI) 2.2, 2.3
37
39
  * JRuby 1.7
38
40
 
39
- __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work. Similarly,
40
- MRI 2.0 and 2.1 are not officially supported, but they should work. 1.9.3 is deprecated
41
+ __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work. Rubinius is not supported.
42
+ MRI 2.0, 2.1, and JRuby 9k are not officially supported, but they should work. 1.9.3 is deprecated
41
43
  and is likely to break in the release following 3.0.
42
44
 
45
+ ## Feedback Requested
46
+
47
+ *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).
48
+
43
49
  ## Quick start
44
50
 
45
51
  ```ruby
@@ -51,10 +57,10 @@ cluster.each_host do |host| # automatically discovers all peers
51
57
  puts "Host #{host.ip}: id=#{host.id} datacenter=#{host.datacenter} rack=#{host.rack}"
52
58
  end
53
59
 
54
- keyspace = 'system'
60
+ keyspace = 'system_schema'
55
61
  session = cluster.connect(keyspace) # create session, optionally scoped to a keyspace, to execute queries
56
62
 
57
- future = session.execute_async('SELECT keyspace_name, table_name FROM system_schema.tables') # fully asynchronous api
63
+ future = session.execute_async('SELECT keyspace_name, table_name FROM tables') # fully asynchronous api
58
64
  future.on_success do |rows|
59
65
  rows.each do |row|
60
66
  puts "The keyspace #{row['keyspace_name']} has a table called #{row['table_name']}"
@@ -67,9 +73,9 @@ __Note__: The host you specify is just a seed node, the driver will automaticall
67
73
 
68
74
  Read more:
69
75
 
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)
76
+ * [`Cassandra.cluster` options](http://docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/#cluster-class_method)
77
+ * [`Session#execute_async` options](http://docs.datastax.com/en/developer/ruby-driver/3.0/api/cassandra/session/#execute_async-instance_method)
78
+ * [Usage documentation](http://docs.datastax.com/en/developer/ruby-driver/3.0/features)
73
79
 
74
80
  ## Installation
75
81
 
@@ -85,16 +91,29 @@ Install via Gemfile
85
91
  gem 'cassandra-driver'
86
92
  ```
87
93
 
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)
94
+ __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/features/#compression)
89
95
 
90
96
 
91
97
  ## Upgrading from cql-rb
92
98
 
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.3/examples/cql-rb-wrapper.rb) to assist you with gradual upgrade.
99
+ Some of the new features added to the driver have unfortunately led to changes in the original cql-rb API.
100
+ In the examples directory, you can find [an example of how to wrap the ruby driver to achieve almost complete
101
+ interface parity with cql-rb](https://github.com/datastax/ruby-driver/blob/v3.1.0/examples/cql-rb-wrapper.rb)
102
+ to assist you with gradual upgrade.
94
103
 
95
- ## What's new in v3.0
104
+ ## What's new in v3.1
105
+
106
+ This minor release introduces features and fixes around resiliency, schema metadata, usability, and performance. One
107
+ of the most user-impacting of these is the introduction of
108
+ [execution profiles](http://docs.datastax.com/en/developer/ruby-driver/3.1/features/basics/execution_profiles).
109
+ Execution profiles allow you to group various execution options into a 'profile' and you reference the desired
110
+ profile at execution time. Get the scoop
111
+ [here](http://docs.datastax.com/en/developer/ruby-driver/3.1/features/basics/execution_profiles).
96
112
 
97
- See the [changelog](https://github.com/datastax/ruby-driver/blob/v3.0.3/CHANGELOG.md) for details on patch versions.
113
+ See the [changelog](https://github.com/datastax/ruby-driver/blob/v3.1.0/CHANGELOG.md) for more information on all
114
+ changes in this version and past versions.
115
+
116
+ ## What's new in v3.0
98
117
 
99
118
  ### Features:
100
119
 
@@ -150,10 +169,6 @@ batch.add(query, arguments: {p1: 'val1'})
150
169
  * [[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
170
  * [[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.
152
171
 
153
- ## Feedback Requested
154
-
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).
156
-
157
172
  ## Code examples
158
173
 
159
174
  The DataStax Ruby Driver uses the awesome [Cucumber Framework](http://cukes.info/) for
@@ -164,7 +179,7 @@ examples in the `features/` directory.
164
179
  ## Running tests
165
180
 
166
181
  If you don't feel like reading through the following instructions on how to run
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.3/.travis.yml).
182
+ ruby-driver tests, feel free to [check out .travis.yml for the entire build code](https://github.com/datastax/ruby-driver/blob/v3.1.0/.travis.yml).
168
183
 
169
184
  * Check out the driver codebase and install test dependencies:
170
185
 
@@ -188,7 +203,7 @@ CASSANDRA_VERSION=2.0.17 bundle exec rake test # run both as well as integration
188
203
  ## Changelog & versioning
189
204
 
190
205
  Check out the [releases on GitHub](https://github.com/datastax/ruby-driver/releases) and
191
- [changelog](https://github.com/datastax/ruby-driver/blob/v3.0.3/CHANGELOG.md). Version
206
+ [changelog](https://github.com/datastax/ruby-driver/blob/v3.1.0/CHANGELOG.md). Version
192
207
  numbering follows the [semantic versioning](http://semver.org/) scheme.
193
208
 
194
209
  Private and experimental APIs, defined as whatever is not in the
@@ -212,7 +227,7 @@ the release.
212
227
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
213
228
  * Because the driver uses `IO#write_nonblock`, Windows is not supported.
214
229
 
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/)
230
+ Please [refer to the usage documentation for more information on common pitfalls](http://docs.datastax.com/en/developer/ruby-driver/3.0/features/)
216
231
 
217
232
  ## Contributing
218
233
 
@@ -226,7 +241,7 @@ that are common across all other DataStax drivers for Apache Cassandra.
226
241
 
227
242
  The development effort to provide an up to date, high performance, fully featured Ruby
228
243
  Driver for Apache Cassandra will continue on this project, while
229
- [cql-rb](https://github.com/iconara/cql-rb/) will be discontinued.
244
+ [cql-rb](https://github.com/iconara/cql-rb/) has been discontinued.
230
245
 
231
246
  ## Copyright
232
247
 
@@ -242,4 +257,4 @@ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
242
257
  either express or implied. See the License for the specific language governing permissions
243
258
  and limitations under the License.
244
259
 
245
- [1]: http://docs.datastax.com/en/developer/ruby-driver/3.0/supplemental/api
260
+ [1]: http://docs.datastax.com/en/developer/ruby-driver/3.0/api
@@ -56,6 +56,7 @@ module Cassandra
56
56
  CLUSTER_OPTIONS = [
57
57
  :address_resolution,
58
58
  :address_resolution_policy,
59
+ :allow_beta_protocol,
59
60
  :auth_provider,
60
61
  :client_cert,
61
62
  :client_timestamps,
@@ -68,6 +69,7 @@ module Cassandra
68
69
  :credentials,
69
70
  :custom_types,
70
71
  :datacenter,
72
+ :execution_profiles,
71
73
  :futures_factory,
72
74
  :heartbeat_interval,
73
75
  :hosts,
@@ -117,10 +119,14 @@ module Cassandra
117
119
  # found by the default Token-Aware Load Balancing Policy should be
118
120
  # shuffled. See {Cassandra::LoadBalancing::Policies::TokenAware#initialize Token-Aware Load Balancing Policy}.
119
121
  #
122
+ # @option options [Hash<String|Symbol, ExecutionProfile>] :execution_profiles (nil)
123
+ # Hash of {Cassandra::Execution::Profile}s that are available for client use (e.g.
124
+ # {Session#execute}, {Session#execute_async}, {Session#prepare}, and {Session#prepare_async}).
125
+ #
120
126
  # @option options [Numeric] :connect_timeout (10) connection timeout in
121
127
  # seconds. Setting value to `nil` will reset it to 5 seconds.
122
128
  #
123
- # @option options [Numeric] :timeout (10) request execution timeout in
129
+ # @option options [Numeric] :timeout (12) request execution timeout in
124
130
  # seconds. Setting value to `nil` will remove request timeout.
125
131
  #
126
132
  # @option options [Numeric] :heartbeat_interval (30) how often should a
@@ -191,6 +197,9 @@ module Cassandra
191
197
  # nodes. By default, this is auto-negotiated to the highest common protocol version
192
198
  # that all nodes in `:hosts` speak.
193
199
  #
200
+ # @option options [Boolean] :allow_beta_protocol (false) whether the driver should attempt to speak to nodes
201
+ # with a beta version of the newest protocol (which is still under development). USE WITH CAUTION!
202
+ #
194
203
  # @option options [Boolean, Cassandra::TimestampGenerator] :client_timestamps (false) whether the driver
195
204
  # should send timestamps for each executed statement and possibly which timestamp generator to use. Enabling this
196
205
  # setting helps mitigate Cassandra cluster clock skew because the timestamp of the client machine will be used.
@@ -315,6 +324,12 @@ module Cassandra
315
324
  CLUSTER_OPTIONS.include?(key)
316
325
  end
317
326
 
327
+ if options.key?(:execution_profiles)
328
+ [:load_balancing_policy, :retry_policy, :timeout, :consistency].each do |opt|
329
+ raise ::ArgumentError, "#{opt} is not allowed when execution profiles are used" if options.key?(opt)
330
+ end
331
+ end
332
+
318
333
  has_username = options.key?(:username)
319
334
  has_password = options.key?(:password)
320
335
  if has_username || has_password
@@ -503,15 +518,9 @@ module Cassandra
503
518
  end
504
519
  end
505
520
 
506
- if options.key?(:timeout)
507
- timeout = options[:timeout]
508
-
509
- unless timeout.nil?
510
- Util.assert_instance_of(::Numeric, timeout) do
511
- ":timeout must be a number of seconds, #{timeout.inspect} given"
512
- end
513
- Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
514
- end
521
+ if options.key?(:execution_profiles)
522
+ Util.assert_instance_of(::Hash, options[:execution_profiles],
523
+ ':execution_profiles must be a hash of <name,ExecutionProfile> entries.')
515
524
  end
516
525
 
517
526
  if options.key?(:heartbeat_interval)
@@ -562,17 +571,6 @@ module Cassandra
562
571
  end
563
572
  end
564
573
 
565
- if options.key?(:load_balancing_policy)
566
- load_balancing_policy = options[:load_balancing_policy]
567
- methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown,
568
- :distance, :plan]
569
-
570
- Util.assert_responds_to_all(methods, load_balancing_policy) do
571
- ":load_balancing_policy #{load_balancing_policy.inspect} must respond " \
572
- "to #{methods.inspect}, but doesn't"
573
- end
574
- end
575
-
576
574
  if options.key?(:reconnection_policy)
577
575
  reconnection_policy = options[:reconnection_policy]
578
576
 
@@ -582,30 +580,15 @@ module Cassandra
582
580
  end
583
581
  end
584
582
 
585
- if options.key?(:retry_policy)
586
- retry_policy = options[:retry_policy]
587
- methods = [:read_timeout, :write_timeout, :unavailable]
588
-
589
- Util.assert_responds_to_all(methods, retry_policy) do
590
- ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, " \
591
- "but doesn't"
592
- end
593
- end
583
+ # Validate options that go in an execution profile. Instantiating one
584
+ # causes validation automatically.
585
+ Cassandra::Execution::Profile.new(options)
594
586
 
595
587
  options[:listeners] = Array(options[:listeners]) if options.key?(:listeners)
596
-
597
- if options.key?(:consistency)
598
- consistency = options[:consistency]
599
-
600
- Util.assert_one_of(CONSISTENCIES, consistency) do
601
- ":consistency must be one of #{CONSISTENCIES.inspect}, " \
602
- "#{consistency.inspect} given"
603
- end
604
- end
605
-
606
588
  options[:nodelay] = !!options[:nodelay] if options.key?(:nodelay)
607
589
  options[:trace] = !!options[:trace] if options.key?(:trace)
608
590
  options[:shuffle_replicas] = !!options[:shuffle_replicas] if options.key?(:shuffle_replicas)
591
+ options[:allow_beta_protocol] = !!options[:allow_beta_protocol] if options.key?(:allow_beta_protocol)
609
592
 
610
593
  if options.key?(:page_size)
611
594
  page_size = options[:page_size]
@@ -623,12 +606,15 @@ module Cassandra
623
606
  protocol_version = options[:protocol_version]
624
607
  unless protocol_version.nil?
625
608
  Util.assert_instance_of(::Integer, protocol_version)
626
- Util.assert_one_of(1..4, protocol_version) do
627
- ":protocol_version must be a positive integer, #{protocol_version.inspect} given"
628
- end
609
+ Util.assert_one_of(1..Cassandra::Protocol::Versions::MAX_SUPPORTED_VERSION, protocol_version,
610
+ ':protocol_version must be a positive integer between 1 and ' \
611
+ "#{Cassandra::Protocol::Versions::MAX_SUPPORTED_VERSION}, #{protocol_version.inspect} given")
629
612
  end
630
613
  end
631
614
 
615
+ Util.assert(!(options[:allow_beta_protocol] && options[:protocol_version]),
616
+ 'only one of :allow_beta_protocol and :protocol_version may be specified, both given')
617
+
632
618
  if options.key?(:futures_factory)
633
619
  futures_factory = options[:futures_factory]
634
620
  methods = [:error, :value, :promise, :all]
@@ -820,9 +806,12 @@ require 'cassandra/table'
820
806
  require 'cassandra/materialized_view'
821
807
  require 'cassandra/keyspace'
822
808
  require 'cassandra/index'
809
+ require 'cassandra/trigger'
823
810
 
824
811
  require 'cassandra/execution/info'
825
812
  require 'cassandra/execution/options'
813
+ require 'cassandra/execution/profile_manager'
814
+ require 'cassandra/execution/profile'
826
815
  require 'cassandra/execution/trace'
827
816
 
828
817
  require 'cassandra/load_balancing'
@@ -845,7 +834,9 @@ module Cassandra
845
834
  # @private
846
835
  VOID_STATEMENT = Statements::Void.new
847
836
  # @private
848
- VOID_OPTIONS = Execution::Options.new(consistency: :one)
837
+ VOID_OPTIONS = Execution::Options.new(consistency: :one,
838
+ load_balancing_policy: LoadBalancing::Policies::RoundRobin.new,
839
+ retry_policy: Retry::Policies::Default.new)
849
840
  # @private
850
841
  NO_HOSTS = Errors::NoHostsAvailable.new
851
842
  end
@@ -36,9 +36,8 @@ module Cassandra
36
36
  cluster_metadata,
37
37
  execution_options,
38
38
  connection_options,
39
- load_balancing_policy,
39
+ profile_manager,
40
40
  reconnection_policy,
41
- retry_policy,
42
41
  address_resolution_policy,
43
42
  connector,
44
43
  futures_factory,
@@ -52,9 +51,8 @@ module Cassandra
52
51
  @metadata = cluster_metadata
53
52
  @execution_options = execution_options
54
53
  @connection_options = connection_options
55
- @load_balancing_policy = load_balancing_policy
54
+ @profile_manager = profile_manager
56
55
  @reconnection_policy = reconnection_policy
57
- @retry_policy = retry_policy
58
56
  @address_resolver = address_resolution_policy
59
57
  @connector = connector
60
58
  @futures = futures_factory
@@ -62,7 +60,7 @@ module Cassandra
62
60
 
63
61
  @control_connection.on_close do |_cause|
64
62
  begin
65
- @load_balancing_policy.teardown(self)
63
+ @profile_manager.teardown(self)
66
64
  rescue
67
65
  nil
68
66
  end
@@ -153,6 +151,40 @@ module Cassandra
153
151
  # @return [Boolean] true or false
154
152
  def_delegators :@schema, :keyspace, :has_keyspace?
155
153
 
154
+ # @return [Integer] Cassandra native protocol port
155
+ def port
156
+ @connection_options.port
157
+ end
158
+
159
+ # @return [Integer] the version of the native protocol used in communication with nodes
160
+ def protocol_version
161
+ @connection_options.protocol_version
162
+ end
163
+
164
+ # @param name [String] Name of profile to retrieve
165
+ # @return [Cassandra::Execution::Profile] execution profile of the given name
166
+ def execution_profile(name)
167
+ @profile_manager.profiles[name]
168
+ end
169
+
170
+ # Yield or enumerate each execution profile defined in this cluster
171
+ # @overload each_execution_profile
172
+ # @yieldparam name [String, Symbol] name of current profile
173
+ # @yieldparam profile [Cassandra::Execution::Profile] current profile
174
+ # @return [Cassandra::Cluster] self
175
+ # @overload each_execution_profile
176
+ # @return [Hash<String, Cassandra::Execution::Profile>] a hash of profiles keyed on name
177
+ def each_execution_profile(&block)
178
+ if block_given?
179
+ @profile_manager.profiles.each_pair(&block)
180
+ self
181
+ else
182
+ # Return a dup of the hash to prevent the user from adding/removing profiles from the profile-manager.
183
+ @profile_manager.profiles.dup
184
+ end
185
+ end
186
+ alias execution_profiles each_execution_profile
187
+
156
188
  # @!method refresh_schema_async
157
189
  # Trigger an asynchronous schema metadata refresh
158
190
  # @return [Cassandra::Future<nil>] a future that will be fulfilled when
@@ -201,14 +233,13 @@ module Cassandra
201
233
  @schema,
202
234
  @io_reactor,
203
235
  @connector,
204
- @load_balancing_policy,
236
+ @profile_manager,
205
237
  @reconnection_policy,
206
- @retry_policy,
207
238
  @address_resolver,
208
239
  @connection_options,
209
240
  @futures,
210
241
  @timestamp_generator)
211
- session = Session.new(client, @execution_options, @futures)
242
+ session = Session.new(client, @execution_options, @futures, @profile_manager)
212
243
  promise = @futures.promise
213
244
 
214
245
  client.connect.on_complete do |f|
@@ -282,9 +313,7 @@ module Cassandra
282
313
  "name=#{name.inspect}, " \
283
314
  "port=#{@connection_options.port}, " \
284
315
  "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}, " \
316
+ "execution_profiles=#{@profile_manager.profiles.inspect}, " \
288
317
  "hosts=#{hosts.inspect}, " \
289
318
  "keyspaces=#{keyspaces.inspect}>"
290
319
  end
@@ -29,9 +29,8 @@ module Cassandra
29
29
  cluster_schema,
30
30
  io_reactor,
31
31
  connector,
32
- load_balancing_policy,
32
+ profile_manager,
33
33
  reconnection_policy,
34
- retry_policy,
35
34
  address_resolution_policy,
36
35
  connection_options,
37
36
  futures_factory,
@@ -41,15 +40,14 @@ module Cassandra
41
40
  @schema = cluster_schema
42
41
  @reactor = io_reactor
43
42
  @connector = connector
44
- @load_balancing_policy = load_balancing_policy
43
+ @profile_manager = profile_manager
45
44
  @reconnection_policy = reconnection_policy
46
- @retry_policy = retry_policy
47
45
  @address_resolver = address_resolution_policy
48
46
  @connection_options = connection_options
49
47
  @futures = futures_factory
50
48
  @connections = ::Hash.new
51
49
  @prepared_statements = ::Hash.new
52
- @preparing_statements = ::Hash.new
50
+ @preparing_statements = ::Hash.new {|hash, host| hash[host] = {}}
53
51
  @pending_connections = ::Hash.new
54
52
  @keyspace = nil
55
53
  @state = :idle
@@ -67,7 +65,7 @@ module Cassandra
67
65
 
68
66
  @state = :connecting
69
67
  @registry.each_host do |host|
70
- distance = @load_balancing_policy.distance(host)
68
+ distance = @profile_manager.distance(host)
71
69
 
72
70
  case distance
73
71
  when :ignore
@@ -85,7 +83,6 @@ module Cassandra
85
83
 
86
84
  connecting_hosts[host] = pool_size
87
85
  @pending_connections[host] = 0
88
- @prepared_statements[host] = {}
89
86
  @preparing_statements[host] = {}
90
87
  @connections[host] = ConnectionPool.new
91
88
  end
@@ -168,7 +165,7 @@ module Cassandra
168
165
  pool_size = 0
169
166
 
170
167
  synchronize do
171
- distance = @load_balancing_policy.distance(host)
168
+ distance = @profile_manager.distance(host)
172
169
  case distance
173
170
  when :ignore
174
171
  return Ione::Future.resolved
@@ -184,7 +181,6 @@ module Cassandra
184
181
  end
185
182
 
186
183
  @pending_connections[host] ||= 0
187
- @prepared_statements[host] = {}
188
184
  @preparing_statements[host] = {}
189
185
  @connections[host] = ConnectionPool.new
190
186
  end
@@ -199,7 +195,6 @@ module Cassandra
199
195
  return Ione::Future.resolved unless @connections.key?(host)
200
196
 
201
197
  @pending_connections.delete(host) unless @pending_connections[host] > 0
202
- @prepared_statements.delete(host)
203
198
  @preparing_statements.delete(host)
204
199
  pool = @connections.delete(host)
205
200
  end
@@ -227,7 +222,9 @@ module Cassandra
227
222
  return @futures.error(
228
223
  Errors::ClientError.new(
229
224
  'Positional arguments are not supported by the current version of ' \
230
- 'Apache Cassandra'))
225
+ 'Apache Cassandra'
226
+ )
227
+ )
231
228
  end
232
229
 
233
230
  timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
@@ -248,7 +245,7 @@ module Cassandra
248
245
  promise = @futures.promise
249
246
 
250
247
  keyspace = @keyspace
251
- plan = @load_balancing_policy.plan(keyspace, statement, options)
248
+ plan = options.load_balancing_policy.plan(keyspace, statement, options)
252
249
 
253
250
  send_request_by_plan(promise,
254
251
  keyspace,
@@ -270,7 +267,7 @@ module Cassandra
270
267
 
271
268
  keyspace = @keyspace
272
269
  statement = VOID_STATEMENT
273
- plan = @load_balancing_policy.plan(keyspace, statement, options)
270
+ plan = options.load_balancing_policy.plan(keyspace, statement, options)
274
271
 
275
272
  send_request_by_plan(promise,
276
273
  keyspace,
@@ -303,7 +300,7 @@ module Cassandra
303
300
  promise = @futures.promise
304
301
 
305
302
  keyspace = @keyspace
306
- plan = @load_balancing_policy.plan(keyspace, statement, options)
303
+ plan = options.load_balancing_policy.plan(keyspace, statement, options)
307
304
 
308
305
  execute_by_plan(promise, keyspace, statement, options, request, plan, timeout)
309
306
 
@@ -315,7 +312,9 @@ module Cassandra
315
312
  return @futures.error(
316
313
  Errors::ClientError.new(
317
314
  'Batch statements are not supported by the current version of ' \
318
- 'Apache Cassandra'))
315
+ 'Apache Cassandra'
316
+ )
317
+ )
319
318
  end
320
319
 
321
320
  timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
@@ -329,7 +328,7 @@ module Cassandra
329
328
  timestamp,
330
329
  payload)
331
330
  keyspace = @keyspace
332
- plan = @load_balancing_policy.plan(keyspace, statement, options)
331
+ plan = options.load_balancing_policy.plan(keyspace, statement, options)
333
332
  promise = @futures.promise
334
333
 
335
334
  batch_by_plan(promise, keyspace, statement, options, request, plan, timeout)
@@ -366,13 +365,15 @@ module Cassandra
366
365
  'SELECT peer, rpc_address, schema_version FROM system.peers',
367
366
  EMPTY_LIST,
368
367
  EMPTY_LIST,
369
- :one)
368
+ :one
369
+ )
370
370
  SELECT_SCHEMA_LOCAL =
371
371
  Protocol::QueryRequest.new(
372
372
  "SELECT schema_version FROM system.local WHERE key='local'",
373
373
  EMPTY_LIST,
374
374
  EMPTY_LIST,
375
- :one)
375
+ :one
376
+ )
376
377
 
377
378
  def connected(f)
378
379
  if f.resolved?
@@ -472,7 +473,7 @@ module Cassandra
472
473
  @pending_connections[host] += size
473
474
  end
474
475
 
475
- @logger.debug("Creating #{size} connections to #{host.ip}")
476
+ @logger.debug("Creating #{size} request connections to #{host.ip}")
476
477
  futures = size.times.map do
477
478
  @connector.connect(host).recover do |e|
478
479
  FailedConnection.new(e, host)
@@ -491,7 +492,7 @@ module Cassandra
491
492
  end
492
493
  end
493
494
 
494
- @logger.debug("Created #{connections.size} connections to #{host.ip}")
495
+ @logger.debug("Created #{connections.size} request connections to #{host.ip}")
495
496
 
496
497
  pool = nil
497
498
 
@@ -510,6 +511,12 @@ module Cassandra
510
511
 
511
512
  connections.each do |connection|
512
513
  connection.on_closed do |cause|
514
+ if cause
515
+ @logger.info('Request connection closed ' \
516
+ "(#{cause.class.name}: #{cause.message})")
517
+ else
518
+ @logger.info('Request connection closed')
519
+ end
513
520
  connect_to_host_maybe_retry(host, pool_size) if cause
514
521
  end
515
522
  end
@@ -533,13 +540,16 @@ module Cassandra
533
540
  plan,
534
541
  timeout,
535
542
  errors = nil,
536
- hosts = [])
543
+ hosts = [],
544
+ retries = -1)
537
545
  unless plan.has_next?
538
546
  promise.break(Errors::NoHostsAvailable.new(errors))
539
547
  return
540
548
  end
541
549
 
542
550
  hosts << host = plan.next
551
+ retries += 1
552
+
543
553
  pool = nil
544
554
  synchronize { pool = @connections[host] }
545
555
 
@@ -554,7 +564,8 @@ module Cassandra
554
564
  plan,
555
565
  timeout,
556
566
  errors,
557
- hosts)
567
+ hosts,
568
+ retries)
558
569
  end
559
570
 
560
571
  connection = pool.random_connection
@@ -573,7 +584,8 @@ module Cassandra
573
584
  plan,
574
585
  timeout,
575
586
  errors,
576
- hosts)
587
+ hosts,
588
+ retries)
577
589
  else
578
590
  s.on_failure do |e|
579
591
  if e.is_a?(Errors::HostError) ||
@@ -588,7 +600,8 @@ module Cassandra
588
600
  plan,
589
601
  timeout,
590
602
  errors,
591
- hosts)
603
+ hosts,
604
+ retries)
592
605
  else
593
606
  promise.break(e)
594
607
  end
@@ -606,7 +619,8 @@ module Cassandra
606
619
  plan,
607
620
  timeout,
608
621
  errors,
609
- hosts)
622
+ hosts,
623
+ retries)
610
624
  end
611
625
  rescue => e
612
626
  errors ||= {}
@@ -619,7 +633,8 @@ module Cassandra
619
633
  plan,
620
634
  timeout,
621
635
  errors,
622
- hosts)
636
+ hosts,
637
+ retries)
623
638
  end
624
639
 
625
640
  def prepare_and_send_request_by_plan(host,
@@ -632,17 +647,16 @@ module Cassandra
632
647
  plan,
633
648
  timeout,
634
649
  errors,
635
- hosts)
650
+ hosts,
651
+ retries)
636
652
  cql = statement.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
653
+
654
+ # Get the prepared statement id for this statement from our cache if possible. We are optimistic
655
+ # that the statement has previously been prepared on all hosts, so the id will be valid. However, if
656
+ # we're in the midst of preparing the statement on the given host, we know that executing with the id
657
+ # will fail. So, act like we don't have the prepared-statement id in that case.
658
+
659
+ id = synchronize { @preparing_statements[host][cql] ? nil : @prepared_statements[cql] }
646
660
 
647
661
  if id
648
662
  request.id = id
@@ -656,20 +670,8 @@ module Cassandra
656
670
  plan,
657
671
  timeout,
658
672
  errors,
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)
673
+ hosts,
674
+ retries)
673
675
  else
674
676
  prepare = prepare_statement(host, connection, cql, timeout)
675
677
  prepare.on_complete do |_|
@@ -685,7 +687,8 @@ module Cassandra
685
687
  plan,
686
688
  timeout,
687
689
  errors,
688
- hosts)
690
+ hosts,
691
+ retries)
689
692
  else
690
693
  prepare.on_failure do |e|
691
694
  if e.is_a?(Errors::HostError) ||
@@ -700,7 +703,8 @@ module Cassandra
700
703
  plan,
701
704
  timeout,
702
705
  errors,
703
- hosts)
706
+ hosts,
707
+ retries)
704
708
  else
705
709
  promise.break(e)
706
710
  end
@@ -720,13 +724,15 @@ module Cassandra
720
724
  plan,
721
725
  timeout,
722
726
  errors = nil,
723
- hosts = [])
727
+ hosts = [],
728
+ retries = -1)
724
729
  unless plan.has_next?
725
730
  promise.break(Errors::NoHostsAvailable.new(errors))
726
731
  return
727
732
  end
728
733
 
729
734
  hosts << host = plan.next
735
+ retries += 1
730
736
  pool = nil
731
737
  synchronize { pool = @connections[host] }
732
738
 
@@ -741,7 +747,8 @@ module Cassandra
741
747
  plan,
742
748
  timeout,
743
749
  errors,
744
- hosts)
750
+ hosts,
751
+ retries)
745
752
  end
746
753
 
747
754
  connection = pool.random_connection
@@ -760,7 +767,8 @@ module Cassandra
760
767
  plan,
761
768
  timeout,
762
769
  errors,
763
- hosts)
770
+ hosts,
771
+ retries)
764
772
  else
765
773
  s.on_failure do |e|
766
774
  if e.is_a?(Errors::HostError) ||
@@ -775,7 +783,8 @@ module Cassandra
775
783
  plan,
776
784
  timeout,
777
785
  errors,
778
- hosts)
786
+ hosts,
787
+ retries)
779
788
  else
780
789
  promise.break(e)
781
790
  end
@@ -793,7 +802,8 @@ module Cassandra
793
802
  plan,
794
803
  timeout,
795
804
  errors,
796
- hosts)
805
+ hosts,
806
+ retries)
797
807
  end
798
808
  rescue => e
799
809
  errors ||= {}
@@ -806,7 +816,8 @@ module Cassandra
806
816
  plan,
807
817
  timeout,
808
818
  errors,
809
- hosts)
819
+ hosts,
820
+ retries)
810
821
  end
811
822
 
812
823
  def batch_and_send_request_by_plan(host,
@@ -819,7 +830,8 @@ module Cassandra
819
830
  plan,
820
831
  timeout,
821
832
  errors,
822
- hosts)
833
+ hosts,
834
+ retries)
823
835
  request.clear
824
836
  unprepared = Hash.new {|hash, cql| hash[cql] = []}
825
837
 
@@ -827,29 +839,15 @@ module Cassandra
827
839
  cql = statement.cql
828
840
 
829
841
  if statement.is_a?(Statements::Bound)
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
842
+ # Get the prepared statement id for this statement from our cache if possible. We are optimistic
843
+ # that the statement has previously been prepared on all hosts, so the id will be valid. However, if
844
+ # we're in the midst of preparing the statement on the given host, we know that executing with the id
845
+ # will fail. So, act like we don't have the prepared-statement id in that case.
846
+
847
+ id = synchronize { @preparing_statements[host][cql] ? nil : @prepared_statements[cql] }
839
848
 
840
849
  if id
841
850
  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)
853
851
  else
854
852
  unprepared[cql] << statement
855
853
  end
@@ -869,7 +867,8 @@ module Cassandra
869
867
  plan,
870
868
  timeout,
871
869
  errors,
872
- hosts)
870
+ hosts,
871
+ retries)
873
872
  else
874
873
  to_prepare = unprepared.to_a
875
874
  futures = to_prepare.map do |cql, _|
@@ -897,7 +896,8 @@ module Cassandra
897
896
  plan,
898
897
  timeout,
899
898
  errors,
900
- hosts)
899
+ hosts,
900
+ retries)
901
901
  else
902
902
  f.on_failure do |e|
903
903
  if e.is_a?(Errors::HostError) ||
@@ -912,7 +912,8 @@ module Cassandra
912
912
  plan,
913
913
  timeout,
914
914
  errors,
915
- hosts)
915
+ hosts,
916
+ retries)
916
917
  else
917
918
  promise.break(e)
918
919
  end
@@ -930,13 +931,15 @@ module Cassandra
930
931
  plan,
931
932
  timeout,
932
933
  errors = nil,
933
- hosts = [])
934
+ hosts = [],
935
+ retries = -1)
934
936
  unless plan.has_next?
935
937
  promise.break(Errors::NoHostsAvailable.new(errors))
936
938
  return
937
939
  end
938
940
 
939
941
  hosts << host = plan.next
942
+ retries += 1
940
943
  pool = nil
941
944
  synchronize { pool = @connections[host] }
942
945
 
@@ -951,7 +954,8 @@ module Cassandra
951
954
  plan,
952
955
  timeout,
953
956
  errors,
954
- hosts)
957
+ hosts,
958
+ retries)
955
959
  end
956
960
 
957
961
  connection = pool.random_connection
@@ -970,7 +974,8 @@ module Cassandra
970
974
  plan,
971
975
  timeout,
972
976
  errors,
973
- hosts)
977
+ hosts,
978
+ retries)
974
979
  else
975
980
  s.on_failure do |e|
976
981
  if e.is_a?(Errors::HostError) ||
@@ -985,7 +990,8 @@ module Cassandra
985
990
  plan,
986
991
  timeout,
987
992
  errors,
988
- hosts)
993
+ hosts,
994
+ retries)
989
995
  else
990
996
  promise.break(e)
991
997
  end
@@ -1003,7 +1009,8 @@ module Cassandra
1003
1009
  plan,
1004
1010
  timeout,
1005
1011
  errors,
1006
- hosts)
1012
+ hosts,
1013
+ retries)
1007
1014
  end
1008
1015
  rescue => e
1009
1016
  errors ||= {}
@@ -1016,7 +1023,8 @@ module Cassandra
1016
1023
  plan,
1017
1024
  timeout,
1018
1025
  errors,
1019
- hosts)
1026
+ hosts,
1027
+ retries)
1020
1028
  end
1021
1029
 
1022
1030
  def do_send_request_by_plan(host,
@@ -1030,7 +1038,7 @@ module Cassandra
1030
1038
  timeout,
1031
1039
  errors,
1032
1040
  hosts,
1033
- retries = 0)
1041
+ retries)
1034
1042
  request.retries = retries
1035
1043
 
1036
1044
  f = connection.send_request(request, timeout)
@@ -1075,37 +1083,43 @@ module Cassandra
1075
1083
 
1076
1084
  case r
1077
1085
  when Protocol::UnavailableErrorResponse
1078
- decision = @retry_policy.unavailable(statement,
1079
- r.consistency,
1080
- r.required,
1081
- r.alive,
1082
- retries)
1086
+ decision = options.retry_policy.unavailable(statement,
1087
+ r.consistency,
1088
+ r.required,
1089
+ r.alive,
1090
+ retries)
1083
1091
  when Protocol::WriteTimeoutErrorResponse
1084
- decision = @retry_policy.write_timeout(statement,
1085
- r.consistency,
1086
- r.write_type,
1087
- r.blockfor,
1088
- r.received,
1089
- retries)
1092
+ decision = options.retry_policy.write_timeout(statement,
1093
+ r.consistency,
1094
+ r.write_type,
1095
+ r.blockfor,
1096
+ r.received,
1097
+ retries)
1090
1098
  when Protocol::ReadTimeoutErrorResponse
1091
- decision = @retry_policy.read_timeout(statement,
1092
- r.consistency,
1093
- r.blockfor,
1094
- r.received,
1095
- r.data_present,
1096
- retries)
1099
+ decision = options.retry_policy.read_timeout(statement,
1100
+ r.consistency,
1101
+ r.blockfor,
1102
+ r.received,
1103
+ r.data_present,
1104
+ retries)
1097
1105
  when Protocol::UnpreparedErrorResponse
1098
- cql = statement.cql
1099
-
1100
- synchronize do
1101
- @preparing_statements[host].delete(cql)
1102
- @prepared_statements[host].delete(cql)
1106
+ cql = nil
1107
+ if statement.is_a?(Cassandra::Statements::Batch)
1108
+ # Find the prepared statement with the prepared-statement-id reported by the node.
1109
+ unprepared_child = statement.statements.select do |s|
1110
+ (s.is_a?(Cassandra::Statements::Prepared) || s.is_a?(Cassandra::Statements::Bound)) && s.id == r.id
1111
+ end.first
1112
+ cql = unprepared_child ? unprepared_child.cql : nil
1113
+ else
1114
+ # This is a normal statement, so we have everything we need.
1115
+ cql = statement.cql
1116
+ synchronize { @preparing_statements[host].delete(cql) }
1103
1117
  end
1104
1118
 
1105
1119
  prepare = prepare_statement(host, connection, cql, timeout)
1106
1120
  prepare.on_complete do |_|
1107
1121
  if prepare.resolved?
1108
- request.id = prepare.value
1122
+ request.id = prepare.value unless request.is_a?(Cassandra::Protocol::BatchRequest)
1109
1123
  do_send_request_by_plan(host,
1110
1124
  connection,
1111
1125
  promise,
@@ -1116,7 +1130,8 @@ module Cassandra
1116
1130
  plan,
1117
1131
  timeout,
1118
1132
  errors,
1119
- hosts)
1133
+ hosts,
1134
+ retries)
1120
1135
  else
1121
1136
  prepare.on_failure do |e|
1122
1137
  if e.is_a?(Errors::HostError) ||
@@ -1130,7 +1145,8 @@ module Cassandra
1130
1145
  plan,
1131
1146
  timeout,
1132
1147
  errors,
1133
- hosts)
1148
+ hosts,
1149
+ retries)
1134
1150
  else
1135
1151
  promise.break(e)
1136
1152
  end
@@ -1159,7 +1175,8 @@ module Cassandra
1159
1175
  plan,
1160
1176
  timeout,
1161
1177
  errors,
1162
- hosts)
1178
+ hosts,
1179
+ retries)
1163
1180
  when Protocol::ExecuteRequest
1164
1181
  execute_by_plan(promise,
1165
1182
  keyspace,
@@ -1169,7 +1186,8 @@ module Cassandra
1169
1186
  plan,
1170
1187
  timeout,
1171
1188
  errors,
1172
- hosts)
1189
+ hosts,
1190
+ retries)
1173
1191
  when Protocol::BatchRequest
1174
1192
  batch_by_plan(promise,
1175
1193
  keyspace,
@@ -1179,7 +1197,8 @@ module Cassandra
1179
1197
  plan,
1180
1198
  timeout,
1181
1199
  errors,
1182
- hosts)
1200
+ hosts,
1201
+ retries)
1183
1202
  end
1184
1203
  else
1185
1204
  promise.break(error)
@@ -1200,7 +1219,7 @@ module Cassandra
1200
1219
  when Protocol::PreparedResultResponse
1201
1220
  cql = request.cql
1202
1221
  synchronize do
1203
- @prepared_statements[host][cql] = r.id
1222
+ @prepared_statements[cql] = r.id
1204
1223
  @preparing_statements[host].delete(cql)
1205
1224
  end
1206
1225
 
@@ -1209,7 +1228,8 @@ module Cassandra
1209
1228
  pk_idx ||= @schema.get_pk_idx(metadata)
1210
1229
 
1211
1230
  promise.fulfill(
1212
- Statements::Prepared.new(r.custom_payload,
1231
+ Statements::Prepared.new(r.id,
1232
+ r.custom_payload,
1213
1233
  r.warnings,
1214
1234
  cql,
1215
1235
  metadata,
@@ -1223,7 +1243,8 @@ module Cassandra
1223
1243
  request.consistency,
1224
1244
  retries,
1225
1245
  self,
1226
- @connection_options))
1246
+ @connection_options)
1247
+ )
1227
1248
  when Protocol::RawRowsResultResponse
1228
1249
  r.materialize(statement.result_metadata)
1229
1250
  promise.fulfill(
@@ -1239,7 +1260,8 @@ module Cassandra
1239
1260
  request.consistency,
1240
1261
  retries,
1241
1262
  self,
1242
- @futures))
1263
+ @futures)
1264
+ )
1243
1265
  when Protocol::RowsResultResponse
1244
1266
  promise.fulfill(
1245
1267
  Results::Paged.new(r.custom_payload,
@@ -1254,7 +1276,8 @@ module Cassandra
1254
1276
  request.consistency,
1255
1277
  retries,
1256
1278
  self,
1257
- @futures))
1279
+ @futures)
1280
+ )
1258
1281
  when Protocol::SchemaChangeResultResponse
1259
1282
  if r.change == 'DROPPED' &&
1260
1283
  r.target == Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
@@ -1267,7 +1290,8 @@ module Cassandra
1267
1290
  unless f.resolved?
1268
1291
  f.on_failure do |e|
1269
1292
  @logger.error(
1270
- "Schema agreement failure (#{e.class.name}: #{e.message})")
1293
+ "Schema agreement failure (#{e.class.name}: #{e.message})"
1294
+ )
1271
1295
  end
1272
1296
  end
1273
1297
  promise.fulfill(
@@ -1281,7 +1305,8 @@ module Cassandra
1281
1305
  request.consistency,
1282
1306
  retries,
1283
1307
  self,
1284
- @futures))
1308
+ @futures)
1309
+ )
1285
1310
  end
1286
1311
  else
1287
1312
  promise.fulfill(Results::Void.new(r.custom_payload,
@@ -1330,7 +1355,8 @@ module Cassandra
1330
1355
  plan,
1331
1356
  timeout,
1332
1357
  errors,
1333
- hosts)
1358
+ hosts,
1359
+ retries)
1334
1360
  when Protocol::ExecuteRequest
1335
1361
  execute_by_plan(promise,
1336
1362
  keyspace,
@@ -1340,7 +1366,8 @@ module Cassandra
1340
1366
  plan,
1341
1367
  timeout,
1342
1368
  errors,
1343
- hosts)
1369
+ hosts,
1370
+ retries)
1344
1371
  when Protocol::BatchRequest
1345
1372
  batch_by_plan(promise,
1346
1373
  keyspace,
@@ -1350,7 +1377,8 @@ module Cassandra
1350
1377
  plan,
1351
1378
  timeout,
1352
1379
  errors,
1353
- hosts)
1380
+ hosts,
1381
+ retries)
1354
1382
  else
1355
1383
  promise.break(e)
1356
1384
  end
@@ -1366,7 +1394,8 @@ module Cassandra
1366
1394
  request.consistency,
1367
1395
  retries,
1368
1396
  self,
1369
- @futures))
1397
+ @futures)
1398
+ )
1370
1399
  when Retry::Decisions::Reraise
1371
1400
  promise.break(
1372
1401
  r.to_error(keyspace,
@@ -1374,7 +1403,8 @@ module Cassandra
1374
1403
  options,
1375
1404
  hosts,
1376
1405
  request.consistency,
1377
- retries))
1406
+ retries)
1407
+ )
1378
1408
  else
1379
1409
  promise.break(
1380
1410
  r.to_error(keyspace,
@@ -1382,7 +1412,8 @@ module Cassandra
1382
1412
  options,
1383
1413
  hosts,
1384
1414
  request.consistency,
1385
- retries))
1415
+ retries)
1416
+ )
1386
1417
  end
1387
1418
  end
1388
1419
  rescue => e
@@ -1391,32 +1422,23 @@ module Cassandra
1391
1422
  else
1392
1423
  response_future.on_failure do |ex|
1393
1424
  if ex.is_a?(Errors::HostError) ||
1394
- (ex.is_a?(Errors::TimeoutError) && statement.idempotent?)
1425
+ (ex.is_a?(Errors::TimeoutError) && statement.idempotent?)
1395
1426
 
1396
1427
  errors[host] = ex
1397
1428
  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,
1429
+ when Protocol::QueryRequest, Protocol::PrepareRequest
1430
+ send_request_by_plan(promise,
1431
+ keyspace,
1432
+ statement,
1433
+ options,
1434
+ request,
1435
+ plan,
1436
+ timeout,
1437
+ errors,
1438
+ hosts,
1439
+ retries)
1440
+ when Protocol::ExecuteRequest
1441
+ execute_by_plan(promise,
1420
1442
  keyspace,
1421
1443
  statement,
1422
1444
  options,
@@ -1424,9 +1446,21 @@ module Cassandra
1424
1446
  plan,
1425
1447
  timeout,
1426
1448
  errors,
1427
- hosts)
1428
- else
1429
- promise.break(ex)
1449
+ hosts,
1450
+ retries)
1451
+ when Protocol::BatchRequest
1452
+ batch_by_plan(promise,
1453
+ keyspace,
1454
+ statement,
1455
+ options,
1456
+ request,
1457
+ plan,
1458
+ timeout,
1459
+ errors,
1460
+ hosts,
1461
+ retries)
1462
+ else
1463
+ promise.break(ex)
1430
1464
  end
1431
1465
  else
1432
1466
  promise.break(ex)
@@ -1445,7 +1479,7 @@ module Cassandra
1445
1479
  unless local.empty?
1446
1480
  host = @registry.host(connection.host)
1447
1481
 
1448
- if host && @load_balancing_policy.distance(host) != :ignore
1482
+ if host && @profile_manager.distance(host) != :ignore
1449
1483
  versions << version = local.first['schema_version']
1450
1484
  @logger.debug("Host #{host.ip} schema version is #{version}")
1451
1485
  end
@@ -1453,7 +1487,7 @@ module Cassandra
1453
1487
 
1454
1488
  peers.each do |row|
1455
1489
  host = @registry.host(peer_ip(row))
1456
- next unless host && @load_balancing_policy.distance(host) != :ignore
1490
+ next unless host && @profile_manager.distance(host) != :ignore
1457
1491
 
1458
1492
  versions << version = row['schema_version']
1459
1493
  @logger.debug("Host #{host.ip} schema version is #{version}")
@@ -1533,7 +1567,7 @@ module Cassandra
1533
1567
  when Protocol::PreparedResultResponse
1534
1568
  id = r.id
1535
1569
  synchronize do
1536
- @prepared_statements[host][cql] = id
1570
+ @prepared_statements[cql] = id
1537
1571
  @preparing_statements[host].delete(cql)
1538
1572
  end
1539
1573
  id