cassandra-driver 1.0.0.beta.3-java → 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -14
  3. data/lib/cassandra.rb +164 -78
  4. data/lib/cassandra/address_resolution.rb +36 -0
  5. data/lib/cassandra/address_resolution/policies.rb +2 -0
  6. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
  7. data/lib/cassandra/address_resolution/policies/none.rb +35 -0
  8. data/lib/cassandra/auth.rb +1 -1
  9. data/lib/cassandra/auth/providers/password.rb +1 -1
  10. data/lib/cassandra/cluster.rb +18 -5
  11. data/lib/cassandra/cluster/client.rb +175 -101
  12. data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +5 -5
  13. data/lib/cassandra/cluster/connector.rb +142 -56
  14. data/lib/cassandra/cluster/control_connection.rb +385 -134
  15. data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
  16. data/lib/cassandra/cluster/options.rb +13 -2
  17. data/lib/cassandra/cluster/registry.rb +19 -9
  18. data/lib/cassandra/column.rb +5 -0
  19. data/lib/cassandra/compression.rb +1 -1
  20. data/lib/cassandra/compression/compressors/lz4.rb +1 -1
  21. data/lib/cassandra/compression/compressors/snappy.rb +1 -1
  22. data/lib/cassandra/driver.rb +29 -21
  23. data/lib/cassandra/errors.rb +325 -35
  24. data/lib/cassandra/execution/options.rb +13 -6
  25. data/lib/cassandra/execution/trace.rb +4 -4
  26. data/lib/cassandra/future.rb +7 -3
  27. data/lib/cassandra/keyspace.rb +5 -0
  28. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +13 -4
  29. data/lib/cassandra/load_balancing/policies/token_aware.rb +2 -4
  30. data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
  31. data/lib/cassandra/null_logger.rb +35 -0
  32. data/lib/cassandra/protocol.rb +0 -16
  33. data/lib/cassandra/protocol/cql_byte_buffer.rb +18 -18
  34. data/lib/cassandra/protocol/cql_protocol_handler.rb +78 -8
  35. data/lib/cassandra/protocol/frame_decoder.rb +2 -2
  36. data/lib/cassandra/protocol/frame_encoder.rb +1 -1
  37. data/lib/cassandra/protocol/requests/query_request.rb +1 -11
  38. data/lib/cassandra/protocol/response.rb +1 -1
  39. data/lib/cassandra/protocol/responses/detailed_error_response.rb +16 -1
  40. data/lib/cassandra/protocol/responses/error_response.rb +17 -0
  41. data/lib/cassandra/protocol/responses/event_response.rb +1 -1
  42. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
  43. data/lib/cassandra/protocol/responses/result_response.rb +1 -1
  44. data/lib/cassandra/protocol/responses/rows_result_response.rb +1 -1
  45. data/lib/cassandra/protocol/type_converter.rb +4 -3
  46. data/lib/cassandra/reconnection.rb +1 -1
  47. data/lib/cassandra/result.rb +4 -6
  48. data/lib/cassandra/retry.rb +3 -5
  49. data/lib/cassandra/session.rb +14 -5
  50. data/lib/cassandra/statements/prepared.rb +5 -1
  51. data/lib/cassandra/table.rb +6 -1
  52. data/lib/cassandra/time_uuid.rb +21 -83
  53. data/lib/cassandra/util.rb +131 -1
  54. data/lib/cassandra/uuid.rb +6 -4
  55. data/lib/cassandra/uuid/generator.rb +207 -0
  56. data/lib/cassandra/version.rb +1 -1
  57. data/lib/cassandra_murmur3.jar +0 -0
  58. metadata +43 -49
  59. data/lib/cassandra/client.rb +0 -144
  60. data/lib/cassandra/client/batch.rb +0 -212
  61. data/lib/cassandra/client/client.rb +0 -591
  62. data/lib/cassandra/client/column_metadata.rb +0 -54
  63. data/lib/cassandra/client/connector.rb +0 -277
  64. data/lib/cassandra/client/execute_options_decoder.rb +0 -59
  65. data/lib/cassandra/client/peer_discovery.rb +0 -50
  66. data/lib/cassandra/client/prepared_statement.rb +0 -314
  67. data/lib/cassandra/client/query_result.rb +0 -230
  68. data/lib/cassandra/client/request_runner.rb +0 -71
  69. data/lib/cassandra/client/result_metadata.rb +0 -48
  70. data/lib/cassandra/client/void_result.rb +0 -78
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30507d23df35b3b683d9064dd63d4af9e2682ec2
4
- data.tar.gz: b135c04a1633f21c3120b2b6c9dcbd669742ed1e
3
+ metadata.gz: 8fb7875e0edf290caf3226ac04b20a6b55702ce0
4
+ data.tar.gz: 188e96a446ecaf5565f851cf76ea5f0ffa7a5229
5
5
  SHA512:
6
- metadata.gz: 83d9554f95da481f110427cade444772b7ee73cce03808dd220d92115110a3b7b50bab5880f34f65dab8201b0e03779a9b8583b0cbc67ab66bea83d559f61ca4
7
- data.tar.gz: c77a60ed7222a1a10a4e1c87b7c0e002b607ba4b09bfcd0208251ec50ac7bb38a8b431ea125090194a5b29df656d9dd048afd7e181f2e2dd54a5722253e4f742
6
+ metadata.gz: b4c5895f4a5e774cf62b2caf9e199538467124ffcf522a42e2118f77fa09b9490c4f0db0a66922e1dee168e5cc2afddbe71830033ad3c30a2f8fa6f14b4dca84
7
+ data.tar.gz: 04f3589e992f19720ddcf877499b485a2a819338889e6fba94acba2f66fd7102558dfa519eff76c28ed51497e5cb3bd6c25819e6c3ba3347823579ee59c5c4b2
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Datastax Ruby Driver for Apache Cassandra
2
2
 
3
+ *If you're reading this on GitHub, please note that this is the readme for the development version and that some features described here might not yet have been released. You can [find the documentation for latest version through ruby driver docs](http://datastax.github.io/ruby-driver/) or via the release tags, [e.g. v1.0.0-beta.3](https://github.com/datastax/ruby-driver/tree/v1.0.0-beta.3).*
4
+
3
5
  [![Build Status](https://travis-ci.org/datastax/ruby-driver.svg?branch=master)](https://travis-ci.org/datastax/ruby-driver)
4
6
 
5
7
  A Ruby client driver for Apache Cassandra. This driver works exclusively with
@@ -7,10 +9,10 @@ the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
7
9
 
8
10
  - Code: https://github.com/datastax/ruby-driver
9
11
  - Docs: http://datastax.github.io/ruby-driver/
10
- - JIRA: https://datastax-oss.atlassian.net/browse/RUBY
11
- - MAILING LIST: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
12
+ - Jira: https://datastax-oss.atlassian.net/browse/RUBY
13
+ - Mailing List: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
12
14
  - IRC: #datastax-drivers on [irc.freenode.net](http://freenode.net>)
13
- - TWITTER: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
15
+ - Twitter: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
14
16
 
15
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:
16
18
 
@@ -18,15 +20,17 @@ This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [
18
20
  * one-off, [prepared](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/) and [batch statements](http://datastax.github.io/ruby-driver/features/basics/batch_statements/)
19
21
  * automatic peer discovery and cluster metadata
20
22
  * various [load-balancing](http://datastax.github.io/ruby-driver/features/load_balancing/), [retry](http://datastax.github.io/ruby-driver/features/retry_policies/) and reconnection policies, [with ability to write your own](http://datastax.github.io/ruby-driver/features/load_balancing/implementing_a_policy/)
23
+ * [SSL encryption](http://datastax.github.io/ruby-driver/features/security/ssl_encryption/)
21
24
 
22
25
  ## Compability
23
26
 
24
27
  This driver works exclusively with the Cassandra Query Language v3 (CQL3) and Cassandra's native protocol. The current version works with:
25
28
 
26
- * Cassandra versions 1.2 and 2.0
27
- * Ruby 1.9.3 and 2.0
29
+ * Apache Cassandra versions 1.2 and 2.0
30
+ * DataStax Enterprise 3.1, 3.2, 4.0 and 4.5
31
+ * Ruby (MRI) 1.9.3, 2.0 and 2.1
28
32
  * JRuby 1.7
29
- * Rubinius 2.1
33
+ * Rubinius 2.2
30
34
 
31
35
  __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work.
32
36
 
@@ -35,7 +39,7 @@ __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work.
35
39
  ```ruby
36
40
  require 'cassandra'
37
41
 
38
- cluster = Cassandra.connect # connects to localhost by default
42
+ cluster = Cassandra.cluster # connects to localhost by default
39
43
 
40
44
  cluster.each_host do |host| # automatically discovers all peers
41
45
  puts "Host #{host.ip}: id=#{host.id} datacenter=#{host.datacenter} rack=#{host.rack}"
@@ -57,7 +61,7 @@ The host you specify is just a seed node, the driver will automatically discover
57
61
 
58
62
  Read more:
59
63
 
60
- * [`Cassandra.connect` options](http://datastax.github.io/ruby-driver/api/#connect-class_method)
64
+ * [`Cassandra.cluster` options](http://datastax.github.io/ruby-driver/api/#cluster-class_method)
61
65
  * [`Session#execute_async` options](http://datastax.github.io/ruby-driver/api/session/#execute_async-instance_method)
62
66
  * [Usage documentation](http://datastax.github.io/ruby-driver/features)
63
67
 
@@ -72,7 +76,7 @@ gem install cassandra-driver --pre
72
76
  Install via Gemfile
73
77
 
74
78
  ```ruby
75
- gem 'cassandra-driver', '~> 1.0.0.beta'
79
+ gem 'cassandra-driver', '~> 1.0.0.rc'
76
80
  ```
77
81
 
78
82
  Note: if you want to use compression you should also install [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby). [Read more about compression.](http://datastax.github.io/ruby-driver/features/#compression)
@@ -82,13 +86,45 @@ Note: if you want to use compression you should also install [snappy](http://rub
82
86
 
83
87
  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.
84
88
 
85
- ## What's new in v1.0.0.beta.2
89
+ ## What's new in v1.0.0
86
90
 
87
91
  Current release introduces the following new features:
88
92
 
89
- * [Token-aware load balancing policy](http://datastax.github.io/ruby-driver/features/load_balancing/token_aware/)
93
+ * [Asynchronous execution](http://datastax.github.io/ruby-driver/features/asynchronous_io/)
94
+ * One-off, [prepared](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/) and [batch statements](http://datastax.github.io/ruby-driver/features/basics/batch_statements/)
95
+ * Automatic peer discovery and cluster metadata with [support for change notifications](http://datastax.github.io/ruby-driver/features/state_listeners/)
96
+ * Various [load-balancing](http://datastax.github.io/ruby-driver/features/load_balancing/), [retry](http://datastax.github.io/ruby-driver/features/retry_policies/) and reconnection policies, [with ability to write your own](http://datastax.github.io/ruby-driver/features/load_balancing/implementing_a_policy/)
90
97
  * [SSL encryption](http://datastax.github.io/ruby-driver/features/security/ssl_encryption/)
91
- * Domain names
98
+ * [Flexible and robust error handling](http://datastax.github.io/ruby-driver/features/error_handling/)
99
+ * [Per-request execution information and tracing](http://datastax.github.io/ruby-driver/features/debugging/)
100
+ * [Configurable address resolution](http://datastax.github.io/ruby-driver/features/address_resolution/)
101
+
102
+ ## Code examples
103
+
104
+ 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.
105
+
106
+ ## Running tests
107
+
108
+ 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).
109
+
110
+ * Check out the driver codebase and install test dependencies:
111
+
112
+ ```bash
113
+ git clone https://github.com/datastax/ruby-driver.git
114
+ cd ruby-driver
115
+ bundle install --without docs
116
+ ```
117
+
118
+ * [Install ccm](http://www.datastax.com/dev/blog/ccm-a-development-tool-for-creating-local-cassandra-clusters)
119
+
120
+ * Run tests:
121
+
122
+ ```bash
123
+ bundle exec cucumber # runs end-to-end tests (or bundle exec rake cucumber)
124
+ bundle exec rspec # runs unit tests (or bundle exec rake rspec)
125
+ bundle exec rake integration # run integration tests
126
+ bundle exec rake test # run both as well as integration tests
127
+ ```
92
128
 
93
129
  ## Changelog & versioning
94
130
 
@@ -102,13 +138,15 @@ Prereleases will be stable, in the sense that they will have finished and proper
102
138
 
103
139
  * 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.
104
140
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
141
+ * Because the driver uses `IO#write_nonblock`, Windows is not supported.
105
142
 
143
+ Please [refer to the usage documentation for more information on common pitfalls](http://datastax.github.io/ruby-driver/features/)
106
144
 
107
145
  ## Credits
108
146
 
109
147
  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.
110
148
 
111
- 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.
149
+ 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.
112
150
 
113
151
 
114
152
  ## Copyright
@@ -122,4 +160,3 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
122
160
  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.
123
161
 
124
162
  [1]: http://datastax.github.io/ruby-driver/api
125
-
@@ -30,9 +30,13 @@ require 'digest'
30
30
  require 'stringio'
31
31
  require 'resolv'
32
32
  require 'openssl'
33
+ require 'securerandom'
34
+ require 'time'
33
35
 
34
36
  module Cassandra
35
37
  # A list of all supported request consistencies
38
+ # @see http://www.datastax.com/documentation/cassandra/2.0/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 2.0
39
+ # @see http://www.datastax.com/documentation/cassandra/1.2/cassandra/dml/dml_config_consistency_c.html Consistency levels in Apache Cassandra 1.2
36
40
  # @see Cassandra::Session#execute_async
37
41
  CONSISTENCIES = [ :any, :one, :two, :three, :quorum, :all, :local_quorum,
38
42
  :each_quorum, :serial, :local_serial, :local_one ].freeze
@@ -41,6 +45,12 @@ module Cassandra
41
45
  # @see Cassandra::Session#execute_async
42
46
  SERIAL_CONSISTENCIES = [:serial, :local_serial].freeze
43
47
 
48
+ # A list of all possible write types that a
49
+ # {Cassandra::Errors::WriteTimeoutError} can have.
50
+ #
51
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L591-L603 Description of possible types of writes in Apache Cassandra native protocol spec v1
52
+ WRITE_TYPES = [:simple, :batch, :unlogged_batch, :counter, :batch_log].freeze
53
+
44
54
  # Creates a {Cassandra::Cluster} instance
45
55
  #
46
56
  # @option options [Array<String, IPAddr>] :hosts (['127.0.0.1']) a list of
@@ -50,8 +60,28 @@ module Cassandra
50
60
  #
51
61
  # @option options [Integer] :port (9042) cassandra native protocol port.
52
62
  #
63
+ # @option options [String] :datacenter (nil) name of current datacenter.
64
+ # First datacenter found will be assumed current by default. Note that you
65
+ # can skip this option if you specify only hosts from the local datacenter
66
+ # in `:hosts` option.
67
+ #
53
68
  # @option options [Numeric] :connect_timeout (10) connection timeout in
54
- # seconds.
69
+ # seconds. Setting value to `nil` will reset it to 5 seconds.
70
+ #
71
+ # @option options [Numeric] :timeout (10) request execution timeout in
72
+ # seconds. Setting value to `nil` will remove request timeout.
73
+ #
74
+ # @option options [Numeric] :heartbeat_interval (30) how often should a
75
+ # heartbeat be sent to determine if a connection is alive. Several things to
76
+ # note about this option. Only one heartbeat request will ever be
77
+ # outstanding on a given connection. Each heatbeat will be sent in at least
78
+ # `:heartbeat_interval` seconds after the last request has been sent on a
79
+ # given connection. Setting value to `nil` will remove connection timeout.
80
+ #
81
+ # @option options [Numeric] :idle_timeout (60) period of inactivity after
82
+ # which a connection is considered dead. Note that this value should be at
83
+ # least a few times larger than `:heartbeat_interval`. Setting value to
84
+ # `nil` will remove automatic connection termination.
55
85
  #
56
86
  # @option options [String] :username (none) username to use for
57
87
  # authentication to cassandra. Note that you must also specify `:password`.
@@ -83,12 +113,15 @@ module Cassandra
83
113
  # work, you must install 'snappy' or 'lz4-ruby' gems.
84
114
  #
85
115
  # @option options [Cassandra::LoadBalancing::Policy] :load_balancing_policy
86
- # default: {Cassandra::LoadBalancing::Policies::RoundRobin}.
116
+ # default: token aware data center aware round robin.
117
+ #
118
+ # @option options [Symbol] :address_resolution (:none) a pre-configured
119
+ # address resolver to use. Must be one of `:none` or
120
+ # `:ec2_multi_region`.
87
121
  #
88
122
  # @option options [Cassandra::Reconnection::Policy] :reconnection_policy
89
123
  # default: {Cassandra::Reconnection::Policies::Exponential}. Note that the
90
- # default policy is configured with
91
- # `Reconnection::Policies::Exponential.new(0.5, 30, 2)`.
124
+ # default policy is configured with `(0.5, 30, 2)`.
92
125
  #
93
126
  # @option options [Cassandra::Retry::Policy] :retry_policy default:
94
127
  # {Cassandra::Retry::Policies::Default}.
@@ -101,50 +134,69 @@ module Cassandra
101
134
  # initial listeners. A list of initial cluster state listeners. Note that a
102
135
  # `:load_balancing` policy is automatically registered with the cluster.
103
136
  #
104
- # @option options [Symbol] :consistency (:quorum) default consistency to use
105
- # for all requests. Must be one of {Cassandra::CONSISTENCIES}.
137
+ # @option options [Symbol] :consistency (:one) default consistency to use for
138
+ # all requests. Must be one of {Cassandra::CONSISTENCIES}.
106
139
  #
107
140
  # @option options [Boolean] :trace (false) whether or not to trace all
108
141
  # requests by default.
109
142
  #
110
- # @option options [Integer] :page_size (nil) default page size for all select
111
- # queries.
143
+ # @option options [Integer] :page_size (10000) default page size for all
144
+ # select queries. Set this value to `nil` to disable paging.
112
145
  #
113
146
  # @option options [Hash{String => String}] :credentials (none) a hash of credentials - to be used with [credentials authentication in cassandra 1.2](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L238-L250). Note that if you specified `:username` and `:password` options, those credentials are configured automatically.
114
147
  #
115
148
  # @option options [Cassandra::Auth::Provider] :auth_provider (none) a custom auth provider to be used with [SASL authentication in cassandra 2.0](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v2.spec#L257-L273). Note that if you have specified `:username` and `:password`, then a {Cassandra::Auth::Providers::Password} will be used automatically.
116
149
  #
117
- # @option options [Cassandra::Compressor] :compressor (none) a custom
118
- # compressor. Note that if you have specified `:compression`, an
150
+ # @option options [Cassandra::Compression::Compressor] :compressor (none) a
151
+ # custom compressor. Note that if you have specified `:compression`, an
119
152
  # appropriate compressor will be provided automatically.
120
153
  #
154
+ # @option options [Cassandra::AddressResolution::Policy]
155
+ # :address_resolution_policy default:
156
+ # {Cassandra::AddressResolution::Policies::None} a custom address resolution
157
+ # policy. Note that if you have specified `:address_resolution`, an
158
+ # appropriate address resolution policy will be provided automatically.
159
+ #
121
160
  # @option options [Object<#all, #error, #value, #promise>] :futures_factory
122
- # (none) a custom futures factory to assist with integration into existing
123
- # futures library. Note that promises returned by this object must conform
124
- # to {Cassandra::Promise} api, which is not yet public. Things may change,
125
- # use at your own risk.
161
+ # default: {Cassandra::Future} a futures factory to assist with integration
162
+ # into existing futures library. Note that promises returned by this object
163
+ # must conform to {Cassandra::Promise} api, which is not yet public. Things
164
+ # may change, use at your own risk.
126
165
  #
127
166
  # @example Connecting to localhost
128
- # cluster = Cassandra.connect
167
+ # cluster = Cassandra.cluster
129
168
  #
130
169
  # @example Configuring {Cassandra::Cluster}
131
- # cluster = Cassandra.connect(
170
+ # cluster = Cassandra.cluster(
132
171
  # username: username,
133
172
  # password: password,
134
173
  # hosts: ['10.0.1.1', '10.0.1.2', '10.0.1.3']
135
174
  # )
136
175
  #
137
176
  # @return [Cassandra::Cluster] a cluster instance
138
- def self.connect(options = {})
139
- options.select! do |key, value|
177
+ def self.cluster(options = {})
178
+ cluster_async(options).get
179
+ end
180
+
181
+ # Creates a {Cassandra::Cluster} instance
182
+ #
183
+ # @see Cassandra.cluster
184
+ #
185
+ # @return [Cassandra::Future<Cassandra::Cluster>] a future resolving to the
186
+ # cluster instance.
187
+ def self.cluster_async(options = {})
188
+ options = options.select do |key, value|
140
189
  [ :credentials, :auth_provider, :compression, :hosts, :logger, :port,
141
190
  :load_balancing_policy, :reconnection_policy, :retry_policy, :listeners,
142
191
  :consistency, :trace, :page_size, :compressor, :username, :password,
143
192
  :ssl, :server_cert, :client_cert, :private_key, :passphrase,
144
- :connect_timeout, :futures_factory
193
+ :connect_timeout, :futures_factory, :datacenter, :address_resolution,
194
+ :address_resolution_policy, :idle_timeout, :heartbeat_interval, :timeout
145
195
  ].include?(key)
146
196
  end
147
197
 
198
+ futures = options.fetch(:futures_factory, Future)
199
+
148
200
  has_username = options.has_key?(:username)
149
201
  has_password = options.has_key?(:password)
150
202
  if has_username || has_password
@@ -156,11 +208,13 @@ module Cassandra
156
208
  raise ::ArgumentError, "both :username and :password options must be specified, but only :password given"
157
209
  end
158
210
 
159
- username = String(options.delete(:username))
160
- password = String(options.delete(:password))
211
+ username = options.delete(:username)
212
+ password = options.delete(:password)
161
213
 
162
- raise ::ArgumentError, ":username cannot be empty" if username.empty?
163
- raise ::ArgumentError, ":password cannot be empty" if password.empty?
214
+ Util.assert_instance_of(::String, username) { ":username must be a String, #{username.inspect} given" }
215
+ Util.assert_instance_of(::String, password) { ":password must be a String, #{password.inspect} given" }
216
+ Util.assert_not_empty(username) { ":username cannot be empty" }
217
+ Util.assert_not_empty(password) { ":password cannot be empty" }
164
218
 
165
219
  options[:credentials] = {:username => username, :password => password}
166
220
  options[:auth_provider] = Auth::Providers::Password.new(username, password)
@@ -169,17 +223,13 @@ module Cassandra
169
223
  if options.has_key?(:credentials)
170
224
  credentials = options[:credentials]
171
225
 
172
- unless credentials.is_a?(Hash)
173
- raise ::ArgumentError, ":credentials must be a hash, #{credentials.inspect} given"
174
- end
226
+ Util.assert_instance_of(::Hash, credentials) { ":credentials must be a hash, #{credentials.inspect} given" }
175
227
  end
176
228
 
177
229
  if options.has_key?(:auth_provider)
178
230
  auth_provider = options[:auth_provider]
179
231
 
180
- unless auth_provider.respond_to?(:create_authenticator)
181
- raise ::ArgumentError, ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't"
182
- end
232
+ Util.assert_responds_to(:create_authenticator, auth_provider) { ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't" }
183
233
  end
184
234
 
185
235
  has_client_cert = options.has_key?(:client_cert)
@@ -197,13 +247,8 @@ module Cassandra
197
247
  client_cert = ::File.expand_path(options[:client_cert])
198
248
  private_key = ::File.expand_path(options[:private_key])
199
249
 
200
- unless ::File.exists?(client_cert)
201
- raise ::ArgumentError, ":client_cert #{client_cert.inspect} doesn't exist"
202
- end
203
-
204
- unless ::File.exists?(private_key)
205
- raise ::ArgumentError, ":private_key #{private_key.inspect} doesn't exist"
206
- end
250
+ Util.assert_file_exists(client_cert) { ":client_cert #{client_cert.inspect} doesn't exist" }
251
+ Util.assert_file_exists(private_key) { ":private_key #{private_key.inspect} doesn't exist" }
207
252
  end
208
253
 
209
254
  has_server_cert = options.has_key?(:server_cert)
@@ -211,9 +256,7 @@ module Cassandra
211
256
  if has_server_cert
212
257
  server_cert = ::File.expand_path(options[:server_cert])
213
258
 
214
- unless ::File.exists?(server_cert)
215
- raise ::ArgumentError, ":server_cert #{server_cert.inspect} doesn't exist"
216
- end
259
+ Util.assert_file_exists(server_cert) { ":server_cert #{server_cert.inspect} doesn't exist" }
217
260
  end
218
261
 
219
262
  if has_client_cert || has_server_cert
@@ -240,9 +283,7 @@ module Cassandra
240
283
  if options.has_key?(:ssl)
241
284
  ssl = options[:ssl]
242
285
 
243
- unless ssl.is_a?(::TrueClass) || ssl.is_a?(::FalseClass) || ssl.is_a?(::OpenSSL::SSL::SSLContext)
244
- raise ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given"
245
- end
286
+ 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" }
246
287
  end
247
288
 
248
289
  if options.has_key?(:compression)
@@ -264,33 +305,59 @@ module Cassandra
264
305
  compressor = options[:compressor]
265
306
  methods = [:algorithm, :compress?, :compress, :decompress]
266
307
 
267
- unless methods.all? {|method| compressor.respond_to?(method)}
268
- raise ::ArgumentError, ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't"
269
- end
308
+ Util.assert_responds_to_all(methods, compressor) { ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't" }
270
309
  end
271
310
 
272
311
  if options.has_key?(:logger)
273
312
  logger = options[:logger]
274
313
  methods = [:debug, :info, :warn, :error, :fatal]
275
314
 
276
- unless methods.all? {|method| logger.respond_to?(method)}
277
- raise ::ArgumentError, ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't"
278
- end
315
+ Util.assert_responds_to_all(methods, logger) { ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't" }
279
316
  end
280
317
 
281
318
  if options.has_key?(:port)
282
319
  port = options[:port] = Integer(options[:port])
283
320
 
284
- if port < 0 || port > 65536
285
- raise ::ArgumentError, ":port must be a valid ip port, #{port.given}"
286
- end
321
+ Util.assert_one_of(0..65536, port) { ":port must be a valid ip port, #{port} given" }
322
+ end
323
+
324
+ if options.has_key?(:datacenter)
325
+ options[:datacenter] = String(options[:datacenter])
287
326
  end
288
327
 
289
328
  if options.has_key?(:connect_timeout)
290
- timeout = options[:connect_timeout] = Integer(options[:connect_timeout])
329
+ timeout = options[:connect_timeout]
330
+
331
+ unless timeout.nil?
332
+ Util.assert_instance_of(::Numeric, timeout) { ":connect_timeout must be a number of seconds, #{timeout} given" }
333
+ Util.assert(timeout > 0) { ":connect_timeout must be greater than 0, #{timeout} given" }
334
+ end
335
+ end
336
+
337
+ if options.has_key?(:timeout)
338
+ timeout = options[:timeout]
339
+
340
+ unless timeout.nil?
341
+ Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
342
+ Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
343
+ end
344
+ end
345
+
346
+ if options.has_key?(:heartbeat_interval)
347
+ timeout = options[:heartbeat_interval]
291
348
 
292
- if timeout < 0
293
- raise ::ArgumentError, ":connect_timeout must be a positive value, #{timeout.given}"
349
+ unless timeout.nil?
350
+ Util.assert_instance_of(::Numeric, timeout) { ":heartbeat_interval must be a number of seconds, #{timeout} given" }
351
+ Util.assert(timeout > 0) { ":heartbeat_interval must be greater than 0, #{timeout} given" }
352
+ end
353
+ end
354
+
355
+ if options.has_key?(:idle_timeout)
356
+ timeout = options[:idle_timeout]
357
+
358
+ unless timeout.nil?
359
+ Util.assert_instance_of(::Numeric, timeout) { ":idle_timeout must be a number of seconds, #{timeout} given" }
360
+ Util.assert(timeout > 0) { ":idle_timeout must be greater than 0, #{timeout} given" }
294
361
  end
295
362
  end
296
363
 
@@ -298,42 +365,32 @@ module Cassandra
298
365
  load_balancing_policy = options[:load_balancing_policy]
299
366
  methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :distance, :plan]
300
367
 
301
- unless methods.all? {|method| load_balancing_policy.respond_to?(method)}
302
- raise ::ArgumentError, ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't"
303
- end
368
+ Util.assert_responds_to_all(methods, load_balancing_policy) { ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
304
369
  end
305
370
 
306
371
  if options.has_key?(:reconnection_policy)
307
372
  reconnection_policy = options[:reconnection_policy]
308
373
 
309
- unless reconnection_policy.respond_to?(:schedule)
310
- raise ::ArgumentError, ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't"
311
- end
374
+ Util.assert_responds_to(:schedule, reconnection_policy) { ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't" }
312
375
  end
313
376
 
314
377
  if options.has_key?(:retry_policy)
315
378
  retry_policy = options[:retry_policy]
316
379
  methods = [:read_timeout, :write_timeout, :unavailable]
317
380
 
318
- unless methods.all? {|method| retry_policy.respond_to?(method)}
319
- raise ::ArgumentError, ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't"
320
- end
381
+ Util.assert_responds_to_all(methods, retry_policy) { ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
321
382
  end
322
383
 
323
384
  if options.has_key?(:listeners)
324
385
  listeners = options[:listeners]
325
386
 
326
- unless listeners.respond_to?(:each)
327
- raise ::ArgumentError, ":listeners must be an Enumerable, #{listeners.inspect} given"
328
- end
387
+ Util.assert_instance_of(::Enumerable, listeners) { ":listeners must be an Enumerable, #{listeners.inspect} given" }
329
388
  end
330
389
 
331
390
  if options.has_key?(:consistency)
332
391
  consistency = options[:consistency]
333
392
 
334
- unless CONSISTENCIES.include?(consistency)
335
- raise ::ArgumentError, ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given"
336
- end
393
+ Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
337
394
  end
338
395
 
339
396
  if options.has_key?(:trace)
@@ -341,10 +398,11 @@ module Cassandra
341
398
  end
342
399
 
343
400
  if options.has_key?(:page_size)
344
- page_size = options[:page_size] = Integer(options[:page_size])
401
+ page_size = options[:page_size]
345
402
 
346
- if page_size <= 0
347
- raise ::ArgumentError, ":page_size must be a positive integer, #{page_size.inspect} given"
403
+ unless page_size.nil?
404
+ page_size = options[:page_size] = Integer(page_size)
405
+ Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
348
406
  end
349
407
  end
350
408
 
@@ -352,11 +410,28 @@ module Cassandra
352
410
  futures_factory = options[:futures_factory]
353
411
  methods = [:error, :value, :promise, :all]
354
412
 
355
- unless methods.all? {|method| futures_factory.respond_to?(method)}
356
- raise ::ArgumentError, ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't"
413
+ Util.assert_responds_to_all(methods, futures_factory) { ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't" }
414
+ end
415
+
416
+ if options.has_key?(:address_resolution)
417
+ address_resolution = options.delete(:address_resolution)
418
+
419
+ case address_resolution
420
+ when :none
421
+ # do nothing
422
+ when :ec2_multi_region
423
+ options[:address_resolution_policy] = AddressResolution::Policies::EC2MultiRegion.new
424
+ else
425
+ raise ::ArgumentError, ":address_resolution must be either :none or :ec2_multi_region, #{address_resolution.inspect} given"
357
426
  end
358
427
  end
359
428
 
429
+ if options.has_key?(:address_resolution_policy)
430
+ address_resolver = options[:address_resolution_policy]
431
+
432
+ Util.assert_responds_to(:resolve, address_resolver) { ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't" }
433
+ end
434
+
360
435
  hosts = []
361
436
 
362
437
  Array(options.fetch(:hosts, '127.0.0.1')).each do |host|
@@ -375,8 +450,20 @@ module Cassandra
375
450
  if hosts.empty?
376
451
  raise ::ArgumentError, ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
377
452
  end
453
+ rescue => e
454
+ futures.error(e)
455
+ else
456
+ promise = futures.promise
457
+
458
+ Driver.new(options).connect(hosts).on_complete do |f|
459
+ if f.resolved?
460
+ promise.fulfill(f.value)
461
+ else
462
+ f.on_failure {|e| promise.break(e)}
463
+ end
464
+ end
378
465
 
379
- Driver.new(options).connect(hosts).value
466
+ promise.future
380
467
  end
381
468
  end
382
469
 
@@ -386,7 +473,7 @@ require 'cassandra/time_uuid'
386
473
  require 'cassandra/compression'
387
474
  require 'cassandra/protocol'
388
475
  require 'cassandra/auth'
389
- require 'cassandra/client'
476
+ require 'cassandra/null_logger'
390
477
 
391
478
  require 'cassandra/future'
392
479
  require 'cassandra/cluster'
@@ -408,6 +495,7 @@ require 'cassandra/execution/trace'
408
495
  require 'cassandra/load_balancing'
409
496
  require 'cassandra/reconnection'
410
497
  require 'cassandra/retry'
498
+ require 'cassandra/address_resolution'
411
499
 
412
500
  require 'cassandra/util'
413
501
 
@@ -415,8 +503,6 @@ require 'cassandra/util'
415
503
  require 'cassandra_murmur3'
416
504
 
417
505
  module Cassandra
418
- # @private
419
- Io = Ione::Io
420
506
  # @private
421
507
  VOID_STATEMENT = Statements::Void.new
422
508
  # @private