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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +90 -38
  3. data/ext/cassandra_murmur3/cassandra_murmur3.c +1 -1
  4. data/lib/cassandra.rb +327 -130
  5. data/lib/cassandra/address_resolution.rb +1 -1
  6. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +1 -1
  7. data/lib/cassandra/address_resolution/policies/none.rb +1 -1
  8. data/lib/cassandra/aggregate.rb +21 -7
  9. data/lib/cassandra/argument.rb +2 -2
  10. data/lib/cassandra/auth.rb +4 -4
  11. data/lib/cassandra/auth/providers.rb +1 -1
  12. data/lib/cassandra/auth/providers/password.rb +9 -5
  13. data/lib/cassandra/cassandra_logger.rb +80 -0
  14. data/lib/cassandra/cluster.rb +38 -9
  15. data/lib/cassandra/cluster/client.rb +801 -205
  16. data/lib/cassandra/cluster/connection_pool.rb +2 -2
  17. data/lib/cassandra/cluster/connector.rb +74 -25
  18. data/lib/cassandra/cluster/control_connection.rb +217 -82
  19. data/lib/cassandra/cluster/failed_connection.rb +1 -1
  20. data/lib/cassandra/cluster/metadata.rb +12 -4
  21. data/lib/cassandra/cluster/options.rb +60 -11
  22. data/lib/cassandra/cluster/registry.rb +69 -16
  23. data/lib/cassandra/cluster/schema.rb +25 -7
  24. data/lib/cassandra/cluster/schema/cql_type_parser.rb +15 -10
  25. data/lib/cassandra/cluster/schema/fetchers.rb +263 -106
  26. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +41 -36
  27. data/lib/cassandra/cluster/schema/partitioners.rb +1 -1
  28. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +3 -3
  29. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +1 -1
  30. data/lib/cassandra/cluster/schema/partitioners/random.rb +1 -1
  31. data/lib/cassandra/cluster/schema/replication_strategies.rb +1 -1
  32. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +19 -18
  33. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +1 -1
  34. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +1 -1
  35. data/lib/cassandra/column.rb +3 -3
  36. data/lib/cassandra/compression.rb +1 -1
  37. data/lib/cassandra/compression/compressors/lz4.rb +4 -3
  38. data/lib/cassandra/compression/compressors/snappy.rb +4 -3
  39. data/lib/cassandra/driver.rb +103 -41
  40. data/lib/cassandra/errors.rb +265 -30
  41. data/lib/cassandra/execution/info.rb +16 -5
  42. data/lib/cassandra/execution/options.rb +99 -54
  43. data/lib/cassandra/execution/trace.rb +16 -9
  44. data/lib/cassandra/executors.rb +1 -1
  45. data/lib/cassandra/function.rb +19 -13
  46. data/lib/cassandra/function_collection.rb +85 -0
  47. data/lib/cassandra/future.rb +106 -48
  48. data/lib/cassandra/host.rb +10 -4
  49. data/lib/cassandra/keyspace.rb +90 -33
  50. data/lib/cassandra/listener.rb +1 -1
  51. data/lib/cassandra/load_balancing.rb +2 -2
  52. data/lib/cassandra/load_balancing/policies.rb +1 -1
  53. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +18 -18
  54. data/lib/cassandra/load_balancing/policies/round_robin.rb +1 -1
  55. data/lib/cassandra/load_balancing/policies/token_aware.rb +15 -13
  56. data/lib/cassandra/load_balancing/policies/white_list.rb +11 -5
  57. data/lib/cassandra/null_logger.rb +27 -6
  58. data/lib/cassandra/protocol.rb +1 -1
  59. data/lib/cassandra/protocol/coder.rb +78 -39
  60. data/lib/cassandra/protocol/cql_byte_buffer.rb +50 -33
  61. data/lib/cassandra/protocol/cql_protocol_handler.rb +44 -45
  62. data/lib/cassandra/protocol/request.rb +2 -2
  63. data/lib/cassandra/protocol/requests/auth_response_request.rb +3 -3
  64. data/lib/cassandra/protocol/requests/batch_request.rb +16 -7
  65. data/lib/cassandra/protocol/requests/credentials_request.rb +3 -3
  66. data/lib/cassandra/protocol/requests/execute_request.rb +41 -20
  67. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  68. data/lib/cassandra/protocol/requests/prepare_request.rb +5 -5
  69. data/lib/cassandra/protocol/requests/query_request.rb +27 -22
  70. data/lib/cassandra/protocol/requests/register_request.rb +2 -2
  71. data/lib/cassandra/protocol/requests/startup_request.rb +6 -4
  72. data/lib/cassandra/protocol/requests/void_query_request.rb +1 -1
  73. data/lib/cassandra/protocol/response.rb +2 -2
  74. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +12 -2
  75. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +1 -1
  76. data/lib/cassandra/protocol/responses/auth_success_response.rb +1 -1
  77. data/lib/cassandra/protocol/responses/authenticate_response.rb +1 -1
  78. data/lib/cassandra/protocol/responses/error_response.rb +101 -13
  79. data/lib/cassandra/protocol/responses/event_response.rb +1 -1
  80. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +13 -2
  81. data/lib/cassandra/protocol/responses/prepared_result_response.rb +11 -5
  82. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +14 -9
  83. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +26 -4
  84. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +22 -3
  85. data/lib/cassandra/protocol/responses/ready_response.rb +3 -3
  86. data/lib/cassandra/protocol/responses/result_response.rb +4 -2
  87. data/lib/cassandra/protocol/responses/rows_result_response.rb +5 -3
  88. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +5 -4
  89. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +16 -9
  90. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
  91. data/lib/cassandra/protocol/responses/status_change_event_response.rb +2 -2
  92. data/lib/cassandra/protocol/responses/supported_response.rb +1 -1
  93. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +1 -1
  94. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +20 -3
  95. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +11 -2
  96. data/lib/cassandra/protocol/responses/void_result_response.rb +1 -1
  97. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +26 -4
  98. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +22 -3
  99. data/lib/cassandra/protocol/v1.rb +101 -36
  100. data/lib/cassandra/protocol/v3.rb +124 -51
  101. data/lib/cassandra/protocol/v4.rb +172 -68
  102. data/lib/cassandra/reconnection.rb +1 -1
  103. data/lib/cassandra/reconnection/policies.rb +1 -1
  104. data/lib/cassandra/reconnection/policies/constant.rb +2 -4
  105. data/lib/cassandra/reconnection/policies/exponential.rb +6 -6
  106. data/lib/cassandra/result.rb +53 -19
  107. data/lib/cassandra/retry.rb +8 -8
  108. data/lib/cassandra/retry/policies.rb +1 -1
  109. data/lib/cassandra/retry/policies/default.rb +1 -1
  110. data/lib/cassandra/retry/policies/downgrading_consistency.rb +7 -3
  111. data/lib/cassandra/retry/policies/fallthrough.rb +1 -1
  112. data/lib/cassandra/session.rb +22 -16
  113. data/lib/cassandra/statement.rb +1 -1
  114. data/lib/cassandra/statements.rb +1 -1
  115. data/lib/cassandra/statements/batch.rb +16 -10
  116. data/lib/cassandra/statements/bound.rb +10 -3
  117. data/lib/cassandra/statements/prepared.rb +59 -15
  118. data/lib/cassandra/statements/simple.rb +23 -10
  119. data/lib/cassandra/statements/void.rb +1 -1
  120. data/lib/cassandra/table.rb +79 -30
  121. data/lib/cassandra/time.rb +11 -6
  122. data/lib/cassandra/time_uuid.rb +7 -7
  123. data/lib/cassandra/tuple.rb +16 -8
  124. data/lib/cassandra/types.rb +20 -9
  125. data/lib/cassandra/udt.rb +32 -36
  126. data/lib/cassandra/util.rb +20 -13
  127. data/lib/cassandra/uuid.rb +22 -15
  128. data/lib/cassandra/uuid/generator.rb +7 -5
  129. data/lib/cassandra/version.rb +2 -2
  130. data/lib/datastax/cassandra.rb +1 -1
  131. metadata +5 -3
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OWVmNzk2M2MxNGJlNmE1OTVmZDMyOGJmN2U4ODc3MzI5MDNjZDA5MQ==
4
+ YTFhMzk5ZGFjZWJhYTQzZDFhYjA5ZGM3Mzk0YjY1MWMwODdjMDUyNA==
5
5
  data.tar.gz: !binary |-
6
- NjJmOGJmYmQ4ZWYwMDRkNGNiNWJlNDg2ODhlOGFiOTBhOTRlYWJiOQ==
6
+ NGE5OTQ1YjYyNjA1ZTVhNDI4OGQzNmJiMmFlMzJlNzRlMzNiMTkyMw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmRmNzJlMTQ5NzMxOTRiNTY3YzEzNzJmZjNkZjA0ZDZiNTg2YTNlOTEzZTM4
10
- ZTgyNDY0ZWFmNDA4ZDc4ZjJhOTkxZjA4MTBiNWJhZTU0N2YwMWNhYzQ5M2Y2
11
- NjE4MzEzYWE5NzFhMzI3Mzc0NDIxNzg0Mzc3NjAzNzVlYTg2NWM=
9
+ MWZiZmZiOWNkMzFkMDM3NzE3ZTQxMzUzZWM5NjU1MjA1ODI2ODFkNDkxNzI4
10
+ YjlmNmJhZGE2OTEyNWY1ZmIyOWQwNjhlNTQyNjdiN2U2Njk3ZDYyMzNhYTg4
11
+ NmZjYjY5YmZiMDRlNTA2Njg4ZTQ2YTJlZWQ3YjVhY2MwNGE0NjA=
12
12
  data.tar.gz: !binary |-
13
- ODA0MDRkMTBiMDhlYzViYzI1MWE1MjMxMThlMzIyZWRmZTg1MTEwNzU3NWNj
14
- MWYyMWVhYzZmZjFhOThhYzQ4Y2UxNzMwNDQzY2I3NTM0YmQxZDY4YTJkNzg2
15
- MTQzZmVkN2M1ZGQ3NTk1ODIyZTBjNjI0MWQ5ZGY0NThiODU0Y2Y=
13
+ NDJiNzQ1ZTgzN2VkOTBmYWZjOGFmN2QwMDc4OWU3YmQxMjdlYmFjZGQ0OTM5
14
+ NDlmYmQxMDE1YjczZmNmZjg4MGRjNDY1ODRhZjNlYzBkODE2YTQ5YmM0Njlm
15
+ N2IyYjhkM2JhZmUwMjUyM2I4ODhlM2VmY2Q5YmNkZTUzZmM1ZGE=
data/README.md CHANGED
@@ -12,7 +12,7 @@ the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
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>)
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), [@stamhankar999](http://twitter.com/stamhankar999), [@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
 
@@ -27,17 +27,18 @@ This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [
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
 
30
- ## Compability
30
+ ## Compatibility
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 and 2.1
35
- * DataStax Enterprise 3.1, 3.2, 4.0 and 4.5
36
- * Ruby (MRI) 1.9.3, 2.0, 2.1 and 2.2
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
36
+ * Ruby (MRI) 2.2, 2.3
37
37
  * JRuby 1.7
38
- * Rubinius 2.2
39
38
 
40
- __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work.
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
+ and is likely to break in the release following 3.0.
41
42
 
42
43
  ## Quick start
43
44
 
@@ -53,10 +54,10 @@ end
53
54
  keyspace = 'system'
54
55
  session = cluster.connect(keyspace) # create session, optionally scoped to a keyspace, to execute queries
55
56
 
56
- future = session.execute_async('SELECT keyspace_name, columnfamily_name FROM schema_columnfamilies') # fully asynchronous api
57
+ future = session.execute_async('SELECT keyspace_name, table_name FROM system_schema.tables') # fully asynchronous api
57
58
  future.on_success do |rows|
58
59
  rows.each do |row|
59
- puts "The keyspace #{row['keyspace_name']} has a table called #{row['columnfamily_name']}"
60
+ puts "The keyspace #{row['keyspace_name']} has a table called #{row['table_name']}"
60
61
  end
61
62
  end
62
63
  future.join
@@ -91,31 +92,64 @@ __Note__: if you want to use compression you should also install [snappy](http:/
91
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
94
 
94
- ## What's new in v2.1.3
95
-
96
- Features:
95
+ ## What's new in v3.0.0
96
+
97
+ ### Features:
98
+
99
+ * Apache Cassandra native protocol v4
100
+ * Add support for smallint, tinyint, date (Cassandra::Date) and time (Cassandra::Time) data types.
101
+ * Include schema metadata for User Defined Functions and User Defined Aggregates.
102
+ * 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
+
111
+ ### Breaking Changes:
112
+
113
+ * Cassandra::Future#join is now an alias to Cassandra::Future#get and will raise an error if the future is resolved with one.
114
+ * Default consistency level is now LOCAL_ONE.
115
+ * Enable tcp no-delay by default.
116
+ * Unavailable errors are retried on the next host in the load balancing plan by default.
117
+ * Statement execution no longer retried on timeouts, unless :idempotent => true has been specified when executing.
118
+ * 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:
119
+
120
+ ```ruby
121
+ batch.add(query, ['val1', 'val2'])
122
+ # becomes
123
+ batch.add(query, arguments: ['val1', 'val2'])
97
124
 
98
- * Apache Cassandra native protocol v3
99
- * [User-defined types](http://datastax.github.io/ruby-driver/features/basics/user_defined_types/) and [tuples](http://datastax.github.io/ruby-driver/features/basics/datatypes/#using-tuples)
100
- * [Schema metadata includes user-defined types](http://datastax.github.io/ruby-driver/api/keyspace/#type-instance_method)
101
- * [Named arguments](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/#an-insert-statement-is-prepared-with-named-parameters)
102
- * [Public types api for type definition and introspection](http://datastax.github.io/ruby-driver/api/types/)
125
+ batch.add(query, {p1: 'val1'})
126
+ # becomes
127
+ batch.add(query, arguments: {p1: 'val1'})
128
+ ```
103
129
 
104
- Breaking Changes:
130
+ ### Bug Fixes:
105
131
 
106
- * Splat style positional arguments support, deprecated in 2.0.0, has been dropped
132
+ * [[RUBY-120](https://datastax-oss.atlassian.net/browse/RUBY-120)] Tuples and UDTs can be used in sets and hash keys.
133
+ * [[RUBY-143](https://datastax-oss.atlassian.net/browse/RUBY-143)] Retry querying system table for metadata of new hosts when prior attempts fail, ultimately enabling use of new hosts.
134
+ * [[RUBY-150](https://datastax-oss.atlassian.net/browse/RUBY-150)] Fixed a protocol decoding error that occurred when multiple messages are available in a stream.
135
+ * [[RUBY-151](https://datastax-oss.atlassian.net/browse/RUBY-151)] Decode incomplete UDTs properly.
107
136
 
108
- Bug Fixes:
137
+ ## Feedback Requested
109
138
 
110
- * [[RUBY-93](https://datastax-oss.atlassian.net/browse/RUBY-93)] Reconnection can overflow the stack
139
+ *Help us focus our efforts!* [Provide your input](http://goo.gl/forms/pCs8PTpHLf)
140
+ on the Ruby Driver Platform and Runtime Survey (we kept it short).
111
141
 
112
142
  ## Code examples
113
143
 
114
- 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.
144
+ The DataStax Ruby Driver uses the awesome [Cucumber Framework](http://cukes.info/) for
145
+ both end-to-end, or acceptance, testing and constructing documentation. All of the
146
+ features supported by the driver have appropriate acceptance tests with easy-to-copy code
147
+ examples in the `features/` directory.
115
148
 
116
149
  ## Running tests
117
150
 
118
- 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).
151
+ If you don't feel like reading through the following instructions on how to run
152
+ 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).
119
153
 
120
154
  * Check out the driver codebase and install test dependencies:
121
155
 
@@ -127,26 +161,37 @@ bundle install --without docs
127
161
 
128
162
  * [Install ccm](http://www.datastax.com/dev/blog/ccm-a-development-tool-for-creating-local-cassandra-clusters)
129
163
 
130
- * Run tests:
164
+ * Run tests against different versions of Cassandra:
131
165
 
132
166
  ```bash
133
- bundle exec cucumber # runs end-to-end tests (or bundle exec rake cucumber)
134
- bundle exec rspec # runs unit tests (or bundle exec rake rspec)
135
- bundle exec rake integration # run integration tests
136
- bundle exec rake test # run both as well as integration tests
167
+ CASSANDRA_VERSION=3.1.1 bundle exec cucumber # runs end-to-end tests (or bundle exec rake cucumber)
168
+ CASSANDRA_VERSION=3.0.0 bundle exec rspec # runs unit tests (or bundle exec rake rspec)
169
+ CASSANDRA_VERSION=2.1.12 bundle exec rake integration # run integration tests
170
+ CASSANDRA_VERSION=2.0.17 bundle exec rake test # run both as well as integration tests
137
171
  ```
138
172
 
139
173
  ## Changelog & versioning
140
174
 
141
- Check out the [releases on GitHub](https://github.com/datastax/ruby-driver/releases) and [changelog](https://github.com/datastax/ruby-driver/blob/master/CHANGELOG.md). Version numbering follows the [semantic versioning](http://semver.org/) scheme.
175
+ Check out the [releases on GitHub](https://github.com/datastax/ruby-driver/releases) and
176
+ [changelog](https://github.com/datastax/ruby-driver/blob/master/CHANGELOG.md). Version
177
+ numbering follows the [semantic versioning](http://semver.org/) scheme.
142
178
 
143
- Private and experimental APIs, defined as whatever is not in the [public API documentation][1], i.e. classes and methods marked as `@private`, will change without warning. If you've been recommended to try an experimental API by the maintainers, please let them know if you depend on that API. Experimental APIs will eventually become public, and knowing how they are used helps in determining their maturity.
179
+ Private and experimental APIs, defined as whatever is not in the
180
+ [public API documentation][1], i.e. classes and methods marked as `@private`, will change
181
+ without warning. If you've been recommended to try an experimental API by the maintainers,
182
+ please let them know if you depend on that API. Experimental APIs will eventually become
183
+ public, and knowing how they are used helps in determining their maturity.
144
184
 
145
- Prereleases will be stable, in the sense that they will have finished and properly tested features only, but may introduce APIs that will change before the final release. Please use the prereleases and report bugs, but don't deploy them to production without consulting the maintainers, or doing extensive testing yourself. If you do deploy to production please let the maintainers know as this helps determining the maturity of the release.
185
+ Prereleases will be stable, in the sense that they will have finished and properly tested
186
+ features only, but may introduce APIs that will change before the final release. Please
187
+ use the prereleases and report bugs, but don't deploy them to production without
188
+ consulting the maintainers, or doing extensive testing yourself. If you do deploy to
189
+ production please let the maintainers know as this helps in determining the maturity of
190
+ the release.
146
191
 
147
192
  ## Known bugs & limitations
148
193
 
149
- * 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.
194
+ * JRuby 1.6 is not officially supported, although 1.6.8 should work.
150
195
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
151
196
  * Because the driver uses `IO#write_nonblock`, Windows is not supported.
152
197
 
@@ -158,19 +203,26 @@ For contributing read [CONTRIBUTING.md](https://github.com/datastax/ruby-driver/
158
203
 
159
204
  ## Credits
160
205
 
161
- This driver is based on the original work of [Theo Hultberg](https://github.com/iconara) on [cql-rb](https://github.com/iconara/cql-rb/) and adds a series of advanced features that are common across all other DataStax drivers for Apache Cassandra.
162
-
163
- The development effort to provide an up to date, high performance, fully featured Ruby Driver for Apache Cassandra will continue on this project, while [cql-rb](https://github.com/iconara/cql-rb/) will be discontinued.
206
+ This driver is based on the original work of [Theo Hultberg](https://github.com/iconara)
207
+ on [cql-rb](https://github.com/iconara/cql-rb/) and adds a series of advanced features
208
+ that are common across all other DataStax drivers for Apache Cassandra.
164
209
 
210
+ The development effort to provide an up to date, high performance, fully featured Ruby
211
+ Driver for Apache Cassandra will continue on this project, while
212
+ [cql-rb](https://github.com/iconara/cql-rb/) will be discontinued.
165
213
 
166
214
  ## Copyright
167
215
 
168
- Copyright 2013-2015 DataStax, Inc.
216
+ Copyright 2013-2016 DataStax, Inc.
169
217
 
170
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
218
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
219
+ except in compliance with the License. You may obtain a copy of the License at
171
220
 
172
221
  [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
173
222
 
174
- Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
223
+ Unless required by applicable law or agreed to in writing, software distributed under the
224
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
225
+ either express or implied. See the License for the specific language governing permissions
226
+ and limitations under the License.
175
227
 
176
228
  [1]: http://datastax.github.io/ruby-driver/api
@@ -1,4 +1,4 @@
1
- // Copyright 2013-2015 DataStax, Inc.
1
+ // Copyright 2013-2016 DataStax, Inc.
2
2
  //
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
data/lib/cassandra.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
4
+ # Copyright 2013-2016 DataStax, Inc.
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
16
16
  # limitations under the License.
17
17
  #++
18
18
 
19
-
20
19
  require 'ione'
21
20
  require 'json'
22
21
 
@@ -38,8 +37,8 @@ module Cassandra
38
37
  # @see http://www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 2.0
39
38
  # @see http://www.datastax.com/documentation/cassandra/1.2/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 1.2
40
39
  # @see Cassandra::Session#execute_async
41
- CONSISTENCIES = [ :any, :one, :two, :three, :quorum, :all, :local_quorum,
42
- :each_quorum, :serial, :local_serial, :local_one ].freeze
40
+ CONSISTENCIES = [:any, :one, :two, :three, :quorum, :all, :local_quorum,
41
+ :each_quorum, :serial, :local_serial, :local_one].freeze
43
42
 
44
43
  # A list of all supported serial consistencies
45
44
  # @see Cassandra::Session#execute_async
@@ -126,6 +125,22 @@ module Cassandra
126
125
  # address resolver to use. Must be one of `:none` or
127
126
  # `:ec2_multi_region`.
128
127
  #
128
+ # @option options [Integer] :connections_per_local_node (nil) Number of connections to
129
+ # open to each local node; the value of this option directly correlates to the number
130
+ # of requests the client can make to the local node concurrently. When `nil`, the
131
+ # setting is `1` for nodes that use the v3 or later protocol, and `2` for nodes that
132
+ # use the v2 or earlier protocol.
133
+ #
134
+ # @option options [Integer] :connections_per_remote_node (1) Number of connections to
135
+ # open to each remote node; the value of this option directly correlates to the
136
+ # number of requests the client can make to the remote node concurrently.
137
+ #
138
+ # @option options [Integer] :requests_per_connection (nil) Number of outstanding
139
+ # requests to support on one connection. Depending on the types of requests, some may
140
+ # get processed in parallel in the Cassandra node. When `nil`, the setting is `1024`
141
+ # for nodes that use the v3 or later protocol, and `128` for nodes that use the
142
+ # v2 or earlier protocol.
143
+ #
129
144
  # @option options [Boolean] :client_timestamps (false) whether the driver
130
145
  # should send timestamps for each executed statement. Enabling this setting
131
146
  # allows mitigating Cassandra cluster clock skew because the timestamp of
@@ -139,7 +154,8 @@ module Cassandra
139
154
  # automatic schema updates. Schema metadata is used by the driver to
140
155
  # determine cluster partitioners as well as to find partition keys and
141
156
  # replicas of prepared statements, this information makes token aware load
142
- # balancing possible. One can still {Cassandra::Cluster#refresh_schema refresh schema manually}.
157
+ # balancing possible. One can still
158
+ # {Cassandra::Cluster#refresh_schema refresh schema manually}.
143
159
  #
144
160
  # @option options [Numeric] :schema_refresh_delay (1) the driver will wait
145
161
  # for `:schema_refresh_delay` before fetching metadata after receiving a
@@ -177,9 +193,15 @@ module Cassandra
177
193
  # @option options [Integer] :page_size (10000) default page size for all
178
194
  # select queries. Set this value to `nil` to disable paging.
179
195
  #
180
- # @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/cassandra-2.0.16/doc/native_protocol_v1.spec#L238-L250). Note that if you specified `:username` and `:password` options, those credentials are configured automatically.
196
+ # @option options [Hash{String => String}] :credentials (none) a hash of credentials -
197
+ # to be used with [credentials authentication in cassandra 1.2](https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v1.spec#L238-L250).
198
+ # Note that if you specified `:username` and `:password` options, those credentials
199
+ # are configured automatically.
181
200
  #
182
- # @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/cassandra-2.0.16/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.
201
+ # @option options [Cassandra::Auth::Provider] :auth_provider (none) a custom auth
202
+ # provider to be used with [SASL authentication in cassandra 2.0](https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L257-L273).
203
+ # Note that if you have specified `:username` and `:password`, then a
204
+ # {Cassandra::Auth::Providers::Password Password Provider} will be used automatically.
183
205
  #
184
206
  # @option options [Cassandra::Compression::Compressor] :compressor (none) a
185
207
  # custom compressor. Note that if you have specified `:compression`, an
@@ -187,8 +209,8 @@ module Cassandra
187
209
  #
188
210
  # @option options [Cassandra::AddressResolution::Policy]
189
211
  # :address_resolution_policy default:
190
- # {Cassandra::AddressResolution::Policies::None No Resolution Policy} a custom address resolution
191
- # policy. Note that if you have specified `:address_resolution`, an
212
+ # {Cassandra::AddressResolution::Policies::None No Resolution Policy} a custom address
213
+ # resolution policy. Note that if you have specified `:address_resolution`, an
192
214
  # appropriate address resolution policy will be provided automatically.
193
215
  #
194
216
  # @option options [Object<#all, #error, #value, #promise>] :futures_factory
@@ -219,78 +241,176 @@ module Cassandra
219
241
  # @return [Cassandra::Future<Cassandra::Cluster>] a future resolving to the
220
242
  # cluster instance.
221
243
  def self.cluster_async(options = {})
222
- options = options.select do |key, value|
223
- [ :credentials, :auth_provider, :compression, :hosts, :logger, :port,
224
- :load_balancing_policy, :reconnection_policy, :retry_policy, :listeners,
225
- :consistency, :trace, :page_size, :compressor, :username, :password,
226
- :ssl, :server_cert, :client_cert, :private_key, :passphrase,
227
- :connect_timeout, :futures_factory, :datacenter, :address_resolution,
228
- :address_resolution_policy, :idle_timeout, :heartbeat_interval, :timeout,
229
- :synchronize_schema, :schema_refresh_delay, :schema_refresh_timeout,
230
- :shuffle_replicas, :client_timestamps
244
+ options = validate_and_massage_options(options)
245
+ hosts = []
246
+
247
+ Array(options.fetch(:hosts, '127.0.0.1')).each do |host|
248
+ case host
249
+ when ::IPAddr
250
+ hosts << host
251
+ when ::String # ip address or hostname
252
+ Resolv.each_address(host) do |ip|
253
+ hosts << ::IPAddr.new(ip)
254
+ end
255
+ else
256
+ raise ::ArgumentError, ":hosts must be String or IPAddr, #{host.inspect} given"
257
+ end
258
+ end
259
+
260
+ if hosts.empty?
261
+ raise ::ArgumentError,
262
+ ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
263
+ end
264
+
265
+ hosts.shuffle!
266
+ rescue => e
267
+ futures = options.fetch(:futures_factory) { return Future::Error.new(e) }
268
+ futures.error(e)
269
+ else
270
+ driver = Driver.new(options)
271
+ driver.connect(hosts)
272
+ end
273
+
274
+ # @private
275
+ SSL_CLASSES = [::TrueClass, ::FalseClass, ::OpenSSL::SSL::SSLContext].freeze
276
+
277
+ # @private
278
+ def self.validate_and_massage_options(options)
279
+ options = options.select do |key, _|
280
+ [
281
+ :address_resolution,
282
+ :address_resolution_policy,
283
+ :auth_provider,
284
+ :client_cert,
285
+ :client_timestamps,
286
+ :compression,
287
+ :compressor,
288
+ :connect_timeout,
289
+ :connections_per_local_node,
290
+ :connections_per_remote_node,
291
+ :consistency,
292
+ :credentials,
293
+ :datacenter,
294
+ :futures_factory,
295
+ :heartbeat_interval,
296
+ :hosts,
297
+ :idle_timeout,
298
+ :listeners,
299
+ :load_balancing_policy,
300
+ :logger,
301
+ :nodelay,
302
+ :reconnection_policy,
303
+ :retry_policy,
304
+ :page_size,
305
+ :passphrase,
306
+ :password,
307
+ :port,
308
+ :private_key,
309
+ :requests_per_connection,
310
+ :schema_refresh_delay,
311
+ :schema_refresh_timeout,
312
+ :server_cert,
313
+ :shuffle_replicas,
314
+ :ssl,
315
+ :synchronize_schema,
316
+ :timeout,
317
+ :trace,
318
+ :username
231
319
  ].include?(key)
232
320
  end
233
321
 
234
- has_username = options.has_key?(:username)
235
- has_password = options.has_key?(:password)
322
+ has_username = options.key?(:username)
323
+ has_password = options.key?(:password)
236
324
  if has_username || has_password
237
325
  if has_username && !has_password
238
- raise ::ArgumentError, "both :username and :password options must be specified, but only :username given"
326
+ raise ::ArgumentError,
327
+ 'both :username and :password options must be specified, ' \
328
+ 'but only :username given'
239
329
  end
240
330
 
241
331
  if !has_username && has_password
242
- raise ::ArgumentError, "both :username and :password options must be specified, but only :password given"
332
+ raise ::ArgumentError,
333
+ 'both :username and :password options must be specified, ' \
334
+ 'but only :password given'
243
335
  end
244
336
 
245
337
  username = options.delete(:username)
246
338
  password = options.delete(:password)
247
339
 
248
- Util.assert_instance_of(::String, username) { ":username must be a String, #{username.inspect} given" }
249
- Util.assert_instance_of(::String, password) { ":password must be a String, #{password.inspect} given" }
250
- Util.assert_not_empty(username) { ":username cannot be empty" }
251
- Util.assert_not_empty(password) { ":password cannot be empty" }
340
+ Util.assert_instance_of(::String, username) do
341
+ ":username must be a String, #{username.inspect} given"
342
+ end
343
+ Util.assert_instance_of(::String, password) do
344
+ ":password must be a String, #{password.inspect} given"
345
+ end
346
+ Util.assert_not_empty(username) { ':username cannot be empty' }
347
+ Util.assert_not_empty(password) { ':password cannot be empty' }
252
348
 
253
- options[:credentials] = {:username => username, :password => password}
349
+ options[:credentials] = {username: username, password: password}
254
350
  options[:auth_provider] = Auth::Providers::Password.new(username, password)
255
351
  end
256
352
 
257
- if options.has_key?(:credentials)
353
+ if options.key?(:credentials)
258
354
  credentials = options[:credentials]
259
355
 
260
- Util.assert_instance_of(::Hash, credentials) { ":credentials must be a hash, #{credentials.inspect} given" }
356
+ Util.assert_instance_of(::Hash, credentials) do
357
+ ":credentials must be a hash, #{credentials.inspect} given"
358
+ end
261
359
  end
262
360
 
263
- if options.has_key?(:auth_provider)
361
+ if options.key?(:auth_provider)
264
362
  auth_provider = options[:auth_provider]
265
363
 
266
- Util.assert_responds_to(:create_authenticator, auth_provider) { ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't" }
364
+ Util.assert_responds_to(:create_authenticator, auth_provider) do
365
+ ":auth_provider #{auth_provider.inspect} must respond to " \
366
+ ":create_authenticator, but doesn't"
367
+ end
267
368
  end
268
369
 
269
- has_client_cert = options.has_key?(:client_cert)
270
- has_private_key = options.has_key?(:private_key)
370
+ has_client_cert = options.key?(:client_cert)
371
+ has_private_key = options.key?(:private_key)
271
372
 
272
373
  if has_client_cert || has_private_key
273
374
  if has_client_cert && !has_private_key
274
- raise ::ArgumentError, "both :client_cert and :private_key options must be specified, but only :client_cert given"
375
+ raise ::ArgumentError,
376
+ 'both :client_cert and :private_key options must be specified, ' \
377
+ 'but only :client_cert given'
275
378
  end
276
379
 
277
380
  if !has_client_cert && has_private_key
278
- raise ::ArgumentError, "both :client_cert and :private_key options must be specified, but only :private_key given"
381
+ raise ::ArgumentError,
382
+ 'both :client_cert and :private_key options must be specified, ' \
383
+ 'but only :private_key given'
279
384
  end
280
385
 
386
+ Util.assert_instance_of(::String, options[:client_cert]) do
387
+ ":client_cert must be a string, #{options[:client_cert].inspect} given"
388
+ end
389
+ Util.assert_instance_of(::String, options[:private_key]) do
390
+ ":client_cert must be a string, #{options[:private_key].inspect} given"
391
+ end
281
392
  client_cert = ::File.expand_path(options[:client_cert])
282
393
  private_key = ::File.expand_path(options[:private_key])
283
394
 
284
- Util.assert_file_exists(client_cert) { ":client_cert #{client_cert.inspect} doesn't exist" }
285
- Util.assert_file_exists(private_key) { ":private_key #{private_key.inspect} doesn't exist" }
395
+ Util.assert_file_exists(client_cert) do
396
+ ":client_cert #{client_cert.inspect} doesn't exist"
397
+ end
398
+ Util.assert_file_exists(private_key) do
399
+ ":private_key #{private_key.inspect} doesn't exist"
400
+ end
286
401
  end
287
402
 
288
- has_server_cert = options.has_key?(:server_cert)
403
+ has_server_cert = options.key?(:server_cert)
289
404
 
290
405
  if has_server_cert
406
+ Util.assert_instance_of(::String, options[:server_cert]) do
407
+ ":server_cert must be a string, #{options[:server_cert].inspect} given"
408
+ end
291
409
  server_cert = ::File.expand_path(options[:server_cert])
292
410
 
293
- Util.assert_file_exists(server_cert) { ":server_cert #{server_cert.inspect} doesn't exist" }
411
+ Util.assert_file_exists(server_cert) do
412
+ ":server_cert #{server_cert.inspect} doesn't exist"
413
+ end
294
414
  end
295
415
 
296
416
  if has_client_cert || has_server_cert
@@ -304,23 +424,26 @@ module Cassandra
304
424
  if has_client_cert
305
425
  context.cert = ::OpenSSL::X509::Certificate.new(File.read(client_cert))
306
426
 
307
- if options.has_key?(:passphrase)
308
- context.key = ::OpenSSL::PKey::RSA.new(File.read(private_key), options[:passphrase])
309
- else
310
- context.key = ::OpenSSL::PKey::RSA.new(File.read(private_key))
311
- end
427
+ context.key = if options.key?(:passphrase)
428
+ ::OpenSSL::PKey::RSA.new(File.read(private_key),
429
+ options[:passphrase])
430
+ else
431
+ ::OpenSSL::PKey::RSA.new(File.read(private_key))
432
+ end
312
433
  end
313
434
 
314
435
  options[:ssl] = context
315
436
  end
316
437
 
317
- if options.has_key?(:ssl)
438
+ if options.key?(:ssl)
318
439
  ssl = options[:ssl]
319
440
 
320
- 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" }
441
+ Util.assert_instance_of_one_of(SSL_CLASSES, ssl) do
442
+ ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given"
443
+ end
321
444
  end
322
445
 
323
- if options.has_key?(:compression)
446
+ if options.key?(:compression)
324
447
  compression = options.delete(:compression)
325
448
 
326
449
  case compression
@@ -329,195 +452,267 @@ module Cassandra
329
452
  when :lz4
330
453
  options[:compressor] = Compression::Compressors::Lz4.new
331
454
  else
332
- raise ::ArgumentError, ":compression must be either :snappy or :lz4, #{compression.inspect} given"
455
+ raise ::ArgumentError,
456
+ ":compression must be either :snappy or :lz4, #{compression.inspect} given"
333
457
  end
334
458
  end
335
459
 
336
- if options.has_key?(:compressor)
460
+ if options.key?(:compressor)
337
461
  compressor = options[:compressor]
338
462
  methods = [:algorithm, :compress?, :compress, :decompress]
339
463
 
340
- Util.assert_responds_to_all(methods, compressor) { ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't" }
464
+ Util.assert_responds_to_all(methods, compressor) do
465
+ ":compressor #{compressor.inspect} must respond to #{methods.inspect}, " \
466
+ "but doesn't"
467
+ end
341
468
  end
342
469
 
343
- if options.has_key?(:logger)
344
- logger = options[:logger]
345
- methods = [:debug, :info, :warn, :error, :fatal]
470
+ if options.key?(:logger)
471
+ if options[:logger].nil?
472
+ # Delete the key because we want to fallback to the default logger in Driver.
473
+ options.delete(:logger)
474
+ else
475
+ # Validate
476
+ logger = options[:logger]
477
+ methods = [:debug, :info, :warn, :error, :fatal]
346
478
 
347
- Util.assert_responds_to_all(methods, logger) { ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't" }
479
+ Util.assert_responds_to_all(methods, logger) do
480
+ ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't"
481
+ end
482
+ end
348
483
  end
349
484
 
350
- if options.has_key?(:port)
351
- port = options[:port] = Integer(options[:port])
352
-
353
- Util.assert_one_of(0..65536, port) { ":port must be a valid ip port, #{port} given" }
485
+ if options.key?(:port)
486
+ unless options[:port].nil?
487
+ port = options[:port]
488
+ Util.assert_instance_of(::Integer, port)
489
+ Util.assert_one_of(1...2**16, port) do
490
+ ":port must be a valid ip port, #{port} given"
491
+ end
492
+ end
354
493
  end
355
494
 
356
- if options.has_key?(:datacenter)
357
- options[:datacenter] = String(options[:datacenter])
358
- end
495
+ options[:datacenter] = String(options[:datacenter]) if options.key?(:datacenter)
359
496
 
360
- if options.has_key?(:connect_timeout)
497
+ if options.key?(:connect_timeout)
361
498
  timeout = options[:connect_timeout]
362
499
 
363
500
  unless timeout.nil?
364
- Util.assert_instance_of(::Numeric, timeout) { ":connect_timeout must be a number of seconds, #{timeout} given" }
365
- Util.assert(timeout > 0) { ":connect_timeout must be greater than 0, #{timeout} given" }
501
+ Util.assert_instance_of(::Numeric, timeout) do
502
+ ":connect_timeout must be a number of seconds, #{timeout.inspect} given"
503
+ end
504
+ Util.assert(timeout > 0) do
505
+ ":connect_timeout must be greater than 0, #{timeout} given"
506
+ end
366
507
  end
367
508
  end
368
509
 
369
- if options.has_key?(:timeout)
510
+ if options.key?(:timeout)
370
511
  timeout = options[:timeout]
371
512
 
372
513
  unless timeout.nil?
373
- Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
514
+ Util.assert_instance_of(::Numeric, timeout) do
515
+ ":timeout must be a number of seconds, #{timeout.inspect} given"
516
+ end
374
517
  Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
375
518
  end
376
519
  end
377
520
 
378
- if options.has_key?(:heartbeat_interval)
521
+ if options.key?(:heartbeat_interval)
379
522
  timeout = options[:heartbeat_interval]
380
523
 
381
524
  unless timeout.nil?
382
- Util.assert_instance_of(::Numeric, timeout) { ":heartbeat_interval must be a number of seconds, #{timeout} given" }
383
- Util.assert(timeout > 0) { ":heartbeat_interval must be greater than 0, #{timeout} given" }
525
+ Util.assert_instance_of(::Numeric, timeout) do
526
+ ":heartbeat_interval must be a number of seconds, #{timeout.inspect} given"
527
+ end
528
+ Util.assert(timeout > 0) do
529
+ ":heartbeat_interval must be greater than 0, #{timeout} given"
530
+ end
384
531
  end
385
532
  end
386
533
 
387
- if options.has_key?(:idle_timeout)
534
+ if options.key?(:idle_timeout)
388
535
  timeout = options[:idle_timeout]
389
536
 
390
537
  unless timeout.nil?
391
- Util.assert_instance_of(::Numeric, timeout) { ":idle_timeout must be a number of seconds, #{timeout} given" }
392
- Util.assert(timeout > 0) { ":idle_timeout must be greater than 0, #{timeout} given" }
538
+ Util.assert_instance_of(::Numeric, timeout) do
539
+ ":idle_timeout must be a number of seconds, #{timeout.inspect} given"
540
+ end
541
+ Util.assert(timeout > 0) do
542
+ ":idle_timeout must be greater than 0, #{timeout} given"
543
+ end
393
544
  end
394
545
  end
395
546
 
396
- if options.has_key?(:schema_refresh_delay)
547
+ if options.key?(:schema_refresh_delay)
397
548
  timeout = options[:schema_refresh_delay]
398
549
 
399
- Util.assert_instance_of(::Numeric, timeout) { ":schema_refresh_delay must be a number of seconds, #{timeout} given" }
400
- Util.assert(timeout > 0) { ":schema_refresh_delay must be greater than 0, #{timeout} given" }
550
+ Util.assert_instance_of(::Numeric, timeout) do
551
+ ":schema_refresh_delay must be a number of seconds, #{timeout.inspect} given"
552
+ end
553
+ Util.assert(timeout > 0) do
554
+ ":schema_refresh_delay must be greater than 0, #{timeout} given"
555
+ end
401
556
  end
402
557
 
403
- if options.has_key?(:schema_refresh_timeout)
558
+ if options.key?(:schema_refresh_timeout)
404
559
  timeout = options[:schema_refresh_timeout]
405
560
 
406
- Util.assert_instance_of(::Numeric, timeout) { ":schema_refresh_timeout must be a number of seconds, #{timeout} given" }
407
- Util.assert(timeout > 0) { ":schema_refresh_timeout must be greater than 0, #{timeout} given" }
561
+ Util.assert_instance_of(::Numeric, timeout) do
562
+ ":schema_refresh_timeout must be a number of seconds, #{timeout.inspect} given"
563
+ end
564
+ Util.assert(timeout > 0) do
565
+ ":schema_refresh_timeout must be greater than 0, #{timeout} given"
566
+ end
408
567
  end
409
568
 
410
- if options.has_key?(:load_balancing_policy)
569
+ if options.key?(:load_balancing_policy)
411
570
  load_balancing_policy = options[:load_balancing_policy]
412
- methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown, :distance, :plan]
571
+ methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown,
572
+ :distance, :plan]
413
573
 
414
- Util.assert_responds_to_all(methods, load_balancing_policy) { ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
574
+ Util.assert_responds_to_all(methods, load_balancing_policy) do
575
+ ":load_balancing_policy #{load_balancing_policy.inspect} must respond " \
576
+ "to #{methods.inspect}, but doesn't"
577
+ end
415
578
  end
416
579
 
417
- if options.has_key?(:reconnection_policy)
580
+ if options.key?(:reconnection_policy)
418
581
  reconnection_policy = options[:reconnection_policy]
419
582
 
420
- Util.assert_responds_to(:schedule, reconnection_policy) { ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't" }
583
+ Util.assert_responds_to(:schedule, reconnection_policy) do
584
+ ":reconnection_policy #{reconnection_policy.inspect} must respond to " \
585
+ ":schedule, but doesn't"
586
+ end
421
587
  end
422
588
 
423
- if options.has_key?(:retry_policy)
589
+ if options.key?(:retry_policy)
424
590
  retry_policy = options[:retry_policy]
425
591
  methods = [:read_timeout, :write_timeout, :unavailable]
426
592
 
427
- Util.assert_responds_to_all(methods, retry_policy) { ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
593
+ Util.assert_responds_to_all(methods, retry_policy) do
594
+ ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, " \
595
+ "but doesn't"
596
+ end
428
597
  end
429
598
 
430
- if options.has_key?(:listeners)
431
- options[:listeners] = Array(options[:listeners])
432
- end
599
+ options[:listeners] = Array(options[:listeners]) if options.key?(:listeners)
433
600
 
434
- if options.has_key?(:consistency)
601
+ if options.key?(:consistency)
435
602
  consistency = options[:consistency]
436
603
 
437
- Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
604
+ Util.assert_one_of(CONSISTENCIES, consistency) do
605
+ ":consistency must be one of #{CONSISTENCIES.inspect}, " \
606
+ "#{consistency.inspect} given"
607
+ end
438
608
  end
439
609
 
440
- if options.has_key?(:nodelay)
441
- options[:nodelay] = !!options[:nodelay]
442
- end
610
+ options[:nodelay] = !!options[:nodelay] if options.key?(:nodelay)
443
611
 
444
- if options.has_key?(:trace)
445
- options[:trace] = !!options[:trace]
446
- end
612
+ options[:trace] = !!options[:trace] if options.key?(:trace)
447
613
 
448
- if options.has_key?(:shuffle_replicas)
614
+ if options.key?(:shuffle_replicas)
449
615
  options[:shuffle_replicas] = !!options[:shuffle_replicas]
450
616
  end
451
617
 
452
- if options.has_key?(:page_size)
618
+ if options.key?(:page_size)
453
619
  page_size = options[:page_size]
454
620
 
455
621
  unless page_size.nil?
456
- page_size = options[:page_size] = Integer(page_size)
457
- Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
622
+ page_size = options[:page_size]
623
+ Util.assert_instance_of(::Integer, page_size)
624
+ Util.assert_one_of(1...2**32, page_size) do
625
+ ":page_size must be a positive integer, #{page_size.inspect} given"
626
+ end
458
627
  end
459
628
  end
460
629
 
461
- if options.has_key?(:futures_factory)
630
+ if options.key?(:futures_factory)
462
631
  futures_factory = options[:futures_factory]
463
632
  methods = [:error, :value, :promise, :all]
464
633
 
465
- Util.assert_responds_to_all(methods, futures_factory) { ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't" }
634
+ Util.assert_responds_to_all(methods, futures_factory) do
635
+ ":futures_factory #{futures_factory.inspect} must respond to " \
636
+ "#{methods.inspect}, but doesn't"
637
+ end
466
638
  end
467
639
 
468
- if options.has_key?(:address_resolution)
640
+ if options.key?(:address_resolution)
469
641
  address_resolution = options.delete(:address_resolution)
470
642
 
471
643
  case address_resolution
472
644
  when :none
473
645
  # do nothing
474
646
  when :ec2_multi_region
475
- options[:address_resolution_policy] = AddressResolution::Policies::EC2MultiRegion.new
647
+ options[:address_resolution_policy] =
648
+ AddressResolution::Policies::EC2MultiRegion.new
476
649
  else
477
- raise ::ArgumentError, ":address_resolution must be either :none or :ec2_multi_region, #{address_resolution.inspect} given"
650
+ raise ::ArgumentError,
651
+ ':address_resolution must be either :none or :ec2_multi_region, ' \
652
+ "#{address_resolution.inspect} given"
478
653
  end
479
654
  end
480
655
 
481
- if options.has_key?(:address_resolution_policy)
656
+ if options.key?(:address_resolution_policy)
482
657
  address_resolver = options[:address_resolution_policy]
483
658
 
484
- Util.assert_responds_to(:resolve, address_resolver) { ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't" }
659
+ Util.assert_responds_to(:resolve, address_resolver) do
660
+ ':address_resolution_policy must respond to :resolve, ' \
661
+ "#{address_resolver.inspect} but doesn't"
662
+ end
485
663
  end
486
664
 
487
- if options.has_key?(:synchronize_schema)
665
+ if options.key?(:synchronize_schema)
488
666
  options[:synchronize_schema] = !!options[:synchronize_schema]
489
667
  end
490
668
 
491
- if options.has_key?(:client_timestamps)
669
+ if options.key?(:client_timestamps)
492
670
  options[:client_timestamps] = !!options[:client_timestamps]
493
671
  end
494
672
 
495
- hosts = []
673
+ if options.key?(:connections_per_local_node)
674
+ connections_per_node = options[:connections_per_local_node]
496
675
 
497
- Array(options.fetch(:hosts, '127.0.0.1')).each do |host|
498
- case host
499
- when ::IPAddr
500
- hosts << host
501
- when ::String # ip address or hostname
502
- Resolv.each_address(host) do |ip|
503
- hosts << ::IPAddr.new(ip)
676
+ unless connections_per_node.nil?
677
+ connections_per_node = options[:connections_per_local_node]
678
+ Util.assert_instance_of(::Integer, connections_per_node)
679
+ Util.assert_one_of(1...2**16, connections_per_node) do
680
+ ':connections_per_local_node must be a positive integer between ' \
681
+ "1 and 65535, #{connections_per_node.inspect} given"
504
682
  end
505
- else
506
- raise ::ArgumentError, ":hosts must be String or IPAddr, #{host.inspect} given"
507
683
  end
508
684
  end
509
685
 
510
- if hosts.empty?
511
- raise ::ArgumentError, ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
686
+ if options.key?(:connections_per_remote_node)
687
+ connections_per_node = options[:connections_per_remote_node]
688
+
689
+ unless connections_per_node.nil?
690
+ connections_per_node = options[:connections_per_remote_node]
691
+ Util.assert_instance_of(::Integer, connections_per_node)
692
+ Util.assert_one_of(1...2**16, connections_per_node) do
693
+ ':connections_per_remote_node must be a positive integer between ' \
694
+ "1 and 65535, #{connections_per_node.inspect} given"
695
+ end
696
+ end
512
697
  end
513
698
 
514
- hosts.shuffle!
515
- rescue => e
516
- futures = options.fetch(:futures_factory) { return Future::Error.new(e) }
517
- futures.error(e)
518
- else
519
- driver = Driver.new(options)
520
- driver.connect(hosts)
699
+ if options.key?(:requests_per_connection)
700
+ requests_per_connection = options[:requests_per_connection]
701
+
702
+ unless requests_per_connection.nil?
703
+ requests_per_connection = options[:requests_per_connection]
704
+ Util.assert_instance_of(::Integer, requests_per_connection)
705
+
706
+ # v3 protocol says that max stream-id is 32767 (2^15-1). This setting might be
707
+ # used to talk to a v2 (or less) node, but then we'll adjust it down.
708
+
709
+ Util.assert_one_of(1...2**15, requests_per_connection) do
710
+ ':requests_per_connection must be a positive integer, ' \
711
+ "#{requests_per_connection.inspect} given"
712
+ end
713
+ end
714
+ end
715
+ options
521
716
  end
522
717
 
523
718
  # @private
@@ -535,7 +730,7 @@ module Cassandra
535
730
  # => 1970-1-1
536
731
  # ::Date.jd(DATE_OFFSET + 2 ** 32, ::Date::GREGORIAN)
537
732
  # => 5881580-07-12
538
- DATE_OFFSET = (::Time.utc(1970, 1, 1).to_date.jd - 2 ** 31)
733
+ DATE_OFFSET = (::Time.utc(1970, 1, 1).to_date.jd - 2**31)
539
734
  end
540
735
 
541
736
  require 'cassandra/uuid'
@@ -550,6 +745,7 @@ require 'cassandra/errors'
550
745
  require 'cassandra/compression'
551
746
  require 'cassandra/protocol'
552
747
  require 'cassandra/auth'
748
+ require 'cassandra/cassandra_logger'
553
749
  require 'cassandra/null_logger'
554
750
 
555
751
  require 'cassandra/executors'
@@ -565,6 +761,7 @@ require 'cassandra/statements'
565
761
  require 'cassandra/aggregate'
566
762
  require 'cassandra/argument'
567
763
  require 'cassandra/function'
764
+ require 'cassandra/function_collection'
568
765
  require 'cassandra/column'
569
766
  require 'cassandra/table'
570
767
  require 'cassandra/keyspace'
@@ -587,7 +784,7 @@ module Cassandra
587
784
  # @private
588
785
  VOID_STATEMENT = Statements::Void.new
589
786
  # @private
590
- VOID_OPTIONS = Execution::Options.new({:consistency => :one})
787
+ VOID_OPTIONS = Execution::Options.new(consistency: :one)
591
788
  # @private
592
789
  NO_HOSTS = Errors::NoHostsAvailable.new
593
790
  end