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
@@ -17,21 +17,19 @@
17
17
  #++
18
18
 
19
19
  module Cassandra
20
- module Client
20
+ class Cluster
21
21
  # @private
22
- class NullLogger
23
- def close(*); end
24
- def debug(*); end
25
- def debug?; false end
26
- def error(*); end
27
- def error?; false end
28
- def fatal(*); end
29
- def fatal?; false end
30
- def info(*); end
31
- def info?; false end
32
- def unknown(*); end
33
- def warn(*); end
34
- def warn?; false end
22
+ class FailedConnection
23
+ attr_reader :error, :host
24
+
25
+ def initialize(error, host)
26
+ @error = error
27
+ @host = host
28
+ end
29
+
30
+ def connected?
31
+ false
32
+ end
35
33
  end
36
34
  end
37
35
  end
@@ -22,10 +22,11 @@ module Cassandra
22
22
  class Options
23
23
  attr_reader :credentials, :auth_provider, :compressor, :port,
24
24
  :connect_timeout, :ssl, :connections_per_local_node,
25
- :connections_per_remote_node
25
+ :connections_per_remote_node, :heartbeat_interval,
26
+ :idle_timeout
26
27
  attr_accessor :protocol_version
27
28
 
28
- def initialize(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node)
29
+ def initialize(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node, heartbeat_interval, idle_timeout)
29
30
  @protocol_version = protocol_version
30
31
  @credentials = credentials
31
32
  @auth_provider = auth_provider
@@ -33,10 +34,20 @@ module Cassandra
33
34
  @port = port
34
35
  @connect_timeout = connect_timeout
35
36
  @ssl = ssl
37
+ @heartbeat_interval = heartbeat_interval
38
+ @idle_timeout = idle_timeout
36
39
 
37
40
  @connections_per_local_node = connections_per_local_node
38
41
  @connections_per_remote_node = connections_per_remote_node
39
42
  end
43
+
44
+ def compression
45
+ @compressor && @compressor.algorithm
46
+ end
47
+
48
+ def create_authenticator(authentication_class)
49
+ @auth_provider && @auth_provider.create_authenticator(authentication_class)
50
+ end
40
51
  end
41
52
  end
42
53
  end
@@ -22,24 +22,30 @@ module Cassandra
22
22
  class Registry
23
23
  include MonitorMixin
24
24
 
25
- LISTENER_METHODS = [:host_found, :host_lost, :host_up, :host_down].freeze
26
-
27
25
  def initialize(logger)
28
26
  @logger = logger
29
27
  @hosts = ::Hash.new
30
- @listeners = ::Set.new
28
+ @listeners = ::Array.new
31
29
 
32
30
  mon_initialize
33
31
  end
34
32
 
35
33
  def add_listener(listener)
36
- synchronize { @listeners = @listeners.dup.add(listener) }
34
+ synchronize do
35
+ listeners = @listeners.dup
36
+ listeners.push(listener)
37
+ @listeners = listeners
38
+ end
37
39
 
38
40
  self
39
41
  end
40
42
 
41
43
  def remove_listener(listener)
42
- synchronize { @listeners = @listeners.dup.delete(listener) }
44
+ synchronize do
45
+ listeners = @listeners.dup
46
+ listeners.delete(listener)
47
+ @listeners = listeners
48
+ end
43
49
 
44
50
  self
45
51
  end
@@ -72,8 +78,12 @@ module Cassandra
72
78
  host.rack == data['rack'] &&
73
79
  host.datacenter == data['data_center']
74
80
 
75
- return self
81
+ return self if host.up?
82
+
83
+ host = toggle_up(host)
76
84
  else
85
+ @logger.debug("Host #{host.ip} metadata has been updated, it will be considered lost and found")
86
+
77
87
  notify_lost(host)
78
88
 
79
89
  host = create_host(address, data)
@@ -164,7 +174,7 @@ module Cassandra
164
174
  def toggle_down(host)
165
175
  host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, host.tokens, :down)
166
176
  @logger.debug("Host #{host.ip} is down")
167
- @listeners.each do |listener|
177
+ @listeners.reverse_each do |listener|
168
178
  listener.host_down(host) rescue nil
169
179
  end
170
180
  host
@@ -174,13 +184,13 @@ module Cassandra
174
184
  if host.up?
175
185
  @logger.debug("Host #{host.ip} is down and lost")
176
186
  host = Host.new(host.ip, host.id, host.rack, host.datacenter, host.release_version, host.tokens, :down)
177
- @listeners.each do |listener|
187
+ @listeners.reverse_each do |listener|
178
188
  listener.host_down(host) rescue nil
179
189
  listener.host_lost(host) rescue nil
180
190
  end
181
191
  else
182
192
  @logger.debug("Host #{host.ip} is lost")
183
- @listeners.each do |listener|
193
+ @listeners.reverse_each do |listener|
184
194
  listener.host_lost(host) rescue nil
185
195
  end
186
196
  end
@@ -78,6 +78,11 @@ module Cassandra
78
78
  cql
79
79
  end
80
80
 
81
+ # @return [String] a CLI-friendly column representation
82
+ def inspect
83
+ "#<#{self.class.name}:0x#{self.object_id.to_s(16)} @name=#{@name}>"
84
+ end
85
+
81
86
  # @return [Boolean] whether this column is equal to the other
82
87
  def eql?(other)
83
88
  other.is_a?(Column) &&
@@ -18,7 +18,7 @@
18
18
 
19
19
  module Cassandra
20
20
  module Compression
21
- # @abstract Compressors given to {Cassandra.connect} as the `:compressor`
21
+ # @abstract Compressors given to {Cassandra.cluster} as the `:compressor`
22
22
  # option don't need to be subclasses of this class, but need to implement
23
23
  # the same methods. This class exists only for documentation purposes.
24
24
  class Compressor
@@ -31,7 +31,7 @@ module Cassandra
31
31
  # [lz4-ruby](http://rubygems.org/gems/lz4-ruby) gem (v0.3.2 or later
32
32
  # required).
33
33
  # @note No need to instantiate this class manually, use `compression:
34
- # :lz4` option when calling {Cassandra.connect} and one will be created
34
+ # :lz4` option when calling {Cassandra.cluster} and one will be created
35
35
  # automatically for you.
36
36
  class Lz4 < Compressor
37
37
  # @return [String] `'lz4'`
@@ -31,7 +31,7 @@ module Cassandra
31
31
  # [snappy](http://rubygems.org/gems/snappy) gem (v0.0.10 or later for
32
32
  # JRuby support).
33
33
  # @note No need to instantiate this class manually, use `compression:
34
- # :snappy` option when calling {Cassandra.connect} and one will be
34
+ # :snappy` option when calling {Cassandra.cluster} and one will be
35
35
  # created automatically for you.
36
36
  class Snappy < Compressor
37
37
  # @return [String] `'snappy'`
@@ -24,7 +24,7 @@ module Cassandra
24
24
  define_method(:"#{name}=") { |object| @instances[name] = object }
25
25
  end
26
26
 
27
- let(:io_reactor) { Io::IoReactor.new }
27
+ let(:io_reactor) { Ione::Io::IoReactor.new }
28
28
  let(:cluster_registry) { Cluster::Registry.new(logger) }
29
29
  let(:cluster_schema) { Cluster::Schema.new(schema_type_parser) }
30
30
  let(:cluster_metadata) { Cluster::Metadata.new(
@@ -54,36 +54,42 @@ module Cassandra
54
54
  let(:ordered_partitioner) { Cluster::Schema::Partitioners::Ordered.new }
55
55
  let(:random_partitioner) { Cluster::Schema::Partitioners::Random.new }
56
56
 
57
- let(:connector) { Cluster::Connector.new(logger, io_reactor, cluster_registry, connection_options) }
57
+ let(:connector) { Cluster::Connector.new(logger, io_reactor, cluster_registry, connection_options, execution_options) }
58
58
 
59
- let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, connector) }
59
+ let(:control_connection) { Cluster::ControlConnection.new(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector) }
60
60
 
61
- let(:cluster) { Cluster.new(logger, io_reactor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, connector, futures_factory) }
61
+ let(:cluster) { Cluster.new(logger, io_reactor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory) }
62
62
 
63
63
  let(:execution_options) do
64
64
  Execution::Options.new({
65
65
  :consistency => consistency,
66
66
  :trace => trace,
67
- :page_size => page_size
67
+ :page_size => page_size,
68
+ :timeout => timeout
68
69
  })
69
70
  end
70
71
 
71
- let(:connection_options) { Cluster::Options.new(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node) }
72
-
73
- let(:port) { 9042 }
74
- let(:protocol_version) { 2 }
75
- let(:connect_timeout) { 10 }
76
- let(:ssl) { false }
77
- let(:logger) { Client::NullLogger.new }
78
- let(:compressor) { nil }
79
- let(:credentials) { nil }
80
- let(:auth_provider) { nil }
81
- let(:load_balancing_policy) { LoadBalancing::Policies::RoundRobin.new }
82
- let(:reconnection_policy) { Reconnection::Policies::Exponential.new(0.5, 30, 2) }
83
- let(:retry_policy) { Retry::Policies::Default.new }
84
- let(:consistency) { :quorum }
85
- let(:trace) { false }
86
- let(:page_size) { nil }
72
+ let(:connection_options) { Cluster::Options.new(protocol_version, credentials, auth_provider, compressor, port, connect_timeout, ssl, connections_per_local_node, connections_per_remote_node, heartbeat_interval, idle_timeout) }
73
+
74
+ let(:port) { 9042 }
75
+ let(:protocol_version) { 2 }
76
+ let(:connect_timeout) { 10 }
77
+ let(:ssl) { false }
78
+ let(:logger) { NullLogger.new }
79
+ let(:compressor) { nil }
80
+ let(:credentials) { nil }
81
+ let(:auth_provider) { nil }
82
+ let(:datacenter) { nil }
83
+ let(:load_balancing_policy) { LoadBalancing::Policies::TokenAware.new(LoadBalancing::Policies::DCAwareRoundRobin.new(datacenter, 0)) }
84
+ let(:reconnection_policy) { Reconnection::Policies::Exponential.new(0.5, 30, 2) }
85
+ let(:retry_policy) { Retry::Policies::Default.new }
86
+ let(:address_resolution_policy) { AddressResolution::Policies::None.new }
87
+ let(:consistency) { :one }
88
+ let(:trace) { false }
89
+ let(:page_size) { 10000 }
90
+ let(:heartbeat_interval) { 30 }
91
+ let(:idle_timeout) { 60 }
92
+ let(:timeout) { 10 }
87
93
 
88
94
  let(:connections_per_local_node) { 2 }
89
95
  let(:connections_per_remote_node) { 1 }
@@ -103,8 +109,10 @@ module Cassandra
103
109
  cluster.register(listener)
104
110
  end
105
111
 
112
+ logger.debug('Populating policies and listeners with initial endpoints')
106
113
  addresses.each {|address| cluster_registry.host_found(address)}
107
114
 
115
+ logger.info('Establishing control connection')
108
116
  control_connection.connect_async.map(cluster)
109
117
  end
110
118
  end
@@ -17,63 +17,353 @@
17
17
  #++
18
18
 
19
19
  module Cassandra
20
- # Base class for all Errors raised by the driver
20
+ # Included in all Errors raised by the driver to allow rescuing from any
21
+ # driver-specific error.
22
+ # @example Catching all driver errors
23
+ # begin
24
+ # cluster = Cassandra.cluster
25
+ # session = cluster.connect
26
+ # rescue Cassandra::Error => e
27
+ # puts "#{e.class.name}: #{e.message}"
28
+ # end
21
29
  # @see Cassandra::Errors
22
- class Error < StandardError
30
+ module Error
23
31
  end
24
32
 
25
33
  module Errors
26
- # @!parse class IoError < StandardError; end
27
- # @private
28
- IoError = Ione::IoError
29
-
30
- # This error type represents errors sent by the server, the `code` attribute
31
- # can be used to find the exact type, and `cql` contains the request's CQL,
32
- # if any. `message` contains the human readable error message sent by the
33
- # server.
34
- class QueryError < Error
35
- # @return [Integer] error code
36
- attr_reader :code
37
- # @return [String] original CQL used
38
- attr_reader :cql
39
- # @return [Hash{Symbol => String, Integer}] various error details
40
- attr_reader :details
34
+ # Mixed into any host-specific errors. Requests resulting in these errors
35
+ # are attempted on other hosts. Once all hosts failed with this type of
36
+ # error, a {Cassandra::Errors::NoHostsAvailable} error is raised with
37
+ # details of failures.
38
+ #
39
+ # @see Errors::NoHostsAvailable
40
+ module HostError
41
+ end
42
+
43
+ # Raised when something unexpected happened. This indicates a server-side
44
+ # bug.
45
+ #
46
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L554-L555 Description of Server Error in Apache Cassandra native protocol spec v1
47
+ class ServerError < ::StandardError
48
+ include Error, HostError
49
+ end
50
+
51
+ # Mixed into all internal driver errors.
52
+ class InternalError < ::RuntimeError
53
+ include Error, HostError
54
+ end
55
+
56
+ # Raised when data decoding fails.
57
+ class DecodingError < ::RuntimeError
58
+ include Error, HostError
59
+ end
60
+
61
+ # Raised when data encoding fails.
62
+ class EncodingError < ::RuntimeError
63
+ include Error, HostError
64
+ end
65
+
66
+ # Raised when a connection level error occured.
67
+ class IOError < ::IOError
68
+ include Error, HostError
69
+ end
70
+
71
+ # Raised when a timeout has occured.
72
+ class TimeoutError < ::Timeout::Error
73
+ include Error, HostError
74
+ end
75
+
76
+ # Mixed into all request execution errors.
77
+ module ExecutionError
78
+ include Error
79
+
80
+ # @return [Cassandra::Statement] statement that triggered the error.
81
+ attr_reader :statement
41
82
 
42
83
  # @private
43
- def initialize(code, message, cql=nil, details=nil)
84
+ def initialize(message, statement)
44
85
  super(message)
45
- @code = code
46
- @cql = cql
47
- @details = details
86
+
87
+ @statement = statement
48
88
  end
49
89
  end
50
90
 
51
- # This error is thrown when not hosts could be reached during connection or query execution.
52
- class NoHostsAvailable < Error
53
- # @return [Hash{Cassandra::Host => Exception}] a map of hosts to underlying exceptions
54
- attr_reader :errors
91
+ # Raised when coordinator determines that a request cannot be executed
92
+ # because there are not enough replicas. In this scenario, the request is
93
+ # not sent to the nodes at all.
94
+ #
95
+ # @note This error can be handled by a {Cassandra::Retry::Policy} to
96
+ # determine the desired outcome.
97
+ #
98
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L562-L572 Description of Unavailable Error in Apache Cassandra native protocol spec v1
99
+ class UnavailableError < ::StandardError
100
+ include ExecutionError
101
+ # Consistency level that triggered the error.
102
+ #
103
+ # @return [Symbol] the original consistency level for the request, one of
104
+ # {Cassandra::CONSISTENCIES}
105
+ attr_reader :consistency
106
+
107
+ # @return [Integer] the number of replicas required to achieve requested
108
+ # consistency level
109
+ attr_reader :required
110
+
111
+ # @return [Integer] the number of replicas available for the request
112
+ attr_reader :alive
55
113
 
56
114
  # @private
57
- def initialize(errors = {})
58
- super("no hosts available, check #errors property for details")
115
+ def initialize(message, statement, consistency, required, alive)
116
+ super(message, statement)
59
117
 
60
- @errors = errors
118
+ @consistency = consistency
119
+ @required = required
120
+ @alive = alive
61
121
  end
62
122
  end
63
123
 
64
- # Client error represents bad driver state or configuration
124
+ # Raised when the request cannot be processed because the coordinator node
125
+ # is overloaded
126
+ #
127
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L573-L574 Description of Overloaded Error in Apache Cassandra native protocol spec v1
128
+ class OverloadedError < ::StandardError
129
+ include ExecutionError, HostError
130
+ end
131
+
132
+ # Raise when the request was a read request but the coordinator node is
133
+ # bootstrapping
134
+ #
135
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L575-L576 Description of Is Bootstrapping Error in Apache Cassandra native protocol spec v1
136
+ class IsBootstrappingError < ::StandardError
137
+ include ExecutionError, HostError
138
+ end
139
+
140
+ # Raised when truncation failed.
141
+ #
142
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L577 Description of Truncate Error in Apache Cassandra native protocol spec v1
143
+ class TruncateError < ::StandardError
144
+ include ExecutionError
145
+ end
146
+
147
+ # Raised when a write request timed out.
148
+ #
149
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L578-L603 Description of Write Timeout Error in Apache Cassandra native protocol spec v1
150
+ class WriteTimeoutError < ::StandardError
151
+ include ExecutionError
152
+
153
+ # @return [Symbol] the type of write request that timed out, one of
154
+ # {Cassandra::WRITE_TYPES}
155
+ attr_reader :type
156
+ # @return [Symbol] the original consistency level for the request, one of
157
+ # {Cassandra::CONSISTENCIES}
158
+ attr_reader :consistency
159
+ # @return [Integer] the number of acks required to achieve requested
160
+ # consistency level
161
+ attr_reader :required
162
+ # @return [Integer] the number of acks received by the time the query
163
+ # timed out
164
+ attr_reader :received
165
+
166
+ # @private
167
+ def initialize(message, statement, type, consistency, required, received)
168
+ super(message, statement)
169
+
170
+ @type = type
171
+ @consistency = consistency
172
+ @required = required
173
+ @received = received
174
+ end
175
+ end
176
+
177
+ # Raised when a read request timed out.
178
+ #
179
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L604-L622 Description of Read Timeout Error in Apache Cassandra native protocol spec v1
180
+ class ReadTimeoutError < ::StandardError
181
+ include ExecutionError
182
+
183
+ # @return [Boolean] whether actual data (as opposed to data checksum) was
184
+ # present in the received responses.
185
+ attr_reader :retrieved
186
+ # @return [Symbol] the original consistency level for the request, one of
187
+ # {Cassandra::CONSISTENCIES}
188
+ attr_reader :consistency
189
+ # @return [Integer] the number of responses required to achieve requested
190
+ # consistency level
191
+ attr_reader :required
192
+ # @return [Integer] the number of responses received by the time the
193
+ # query timed out
194
+ attr_reader :received
195
+
196
+ # @private
197
+ def initialize(message, statement, retrieved, consistency, required, received)
198
+ super(message, statement)
199
+
200
+ @retrieved = retrieved
201
+ @consistency = consistency
202
+ @required = required
203
+ @received = received
204
+ end
205
+
206
+ def retrieved?
207
+ @retrieved
208
+ end
209
+ end
210
+
211
+ # Client error represents bad driver state or mis-configuration
212
+ class ClientError < ::StandardError
213
+ include Error
214
+ end
215
+
216
+ # Raised when some client message triggered a protocol violation (for
217
+ # instance a QUERY message is sent before a STARTUP one has been sent)
65
218
  #
66
- # @see Cassandra::Errors::AuthenticationError
67
- class ClientError < Error
219
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L556-L558 Description of Protocol Error in Apache Cassandra native protocol spec v1
220
+ class ProtocolError < ClientError
68
221
  end
69
222
 
70
223
  # Raised when cannot authenticate to Cassandra
224
+ #
225
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L559-L561 Description of Bad Credentials Error in Apache Cassandra native protocol spec v1
71
226
  class AuthenticationError < ClientError
72
227
  end
73
228
 
74
- # @private
75
- NotConnectedError = Class.new(Error)
76
- # @private
77
- NotPreparedError = Class.new(Error)
229
+ # Mixed into all request validation errors.
230
+ module ValidationError
231
+ include Error
232
+
233
+ # @return [Cassandra::Statement] statement that triggered the error.
234
+ attr_reader :statement
235
+
236
+ # @private
237
+ def initialize(message, statement)
238
+ super(message)
239
+
240
+ @statement = statement
241
+ end
242
+ end
243
+
244
+ # Raised when a prepared statement tries to be executed and the provided
245
+ # prepared statement ID is not known by this host
246
+ #
247
+ # @note Seeing this error can be considered a Ruby Driver bug as it should
248
+ # handle automatic re-preparing internally.
249
+ #
250
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L638-L641 Description of Unprepared Error in Apache Cassandra native protocol spec v1
251
+ class UnpreparedError < ::StandardError
252
+ include ValidationError
253
+ # @return [String] prepared statement id that triggered the error
254
+ attr_reader :id
255
+
256
+ # @private
257
+ def initialize(message, statement, id)
258
+ super(message, statement)
259
+
260
+ @id = id
261
+ end
262
+ end
263
+
264
+ # Raised when the submitted query has a syntax error.
265
+ #
266
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L623 Description of Syntax Error in Apache Cassandra native protocol spec v1
267
+ class SyntaxError < ::StandardError
268
+ include ValidationError
269
+ end
270
+
271
+ # Raised when the logged user doesn't have the right to perform the query.
272
+ #
273
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L624-L625 Description of Unauthorized Error in Apache Cassandra native protocol spec v1
274
+ class UnauthorizedError < ::StandardError
275
+ include ValidationError
276
+ end
277
+
278
+ # Raised when the query is syntactically correct but invalid.
279
+ #
280
+ # @example Creating a table without selecting a keyspace
281
+ # begin
282
+ # session.execute("CREATE TABLE users (user_id INT PRIMARY KEY)")
283
+ # rescue Cassandra::Errors::InvalidError
284
+ # end
285
+ #
286
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L626 Description of Invalid Error in Apache Cassandra native protocol spec v1
287
+ class InvalidError < ::StandardError
288
+ include ValidationError
289
+ end
290
+
291
+ # Raised when the query is invalid because of some configuration issue.
292
+ #
293
+ # @example Dropping non-existent keyspace
294
+ # begin
295
+ # client.execute("DROP KEYSPACE unknown_keyspace")
296
+ # rescue Cassandra::Errors::ConfigurationError
297
+ # end
298
+ #
299
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L627 Description of Config Error in Apache Cassandra native protocol spec v1
300
+ class ConfigurationError < ::StandardError
301
+ include ValidationError
302
+ end
303
+
304
+ # Raised when the query attempted to create a keyspace or a table that was
305
+ # already existing.
306
+ #
307
+ # @example Creating a table twice
308
+ # session.execute("USE my_keyspace")
309
+ # session.execute("CREATE TABLE users (user_id INT PRIMARY KEY)")
310
+ # begin
311
+ # session.execute("CREATE TABLE users (user_id INT PRIMARY KEY)")
312
+ # rescue Cassandra::Errors::AlreadyExistsError => e
313
+ # p ['already exists', e.keyspace, e.table]
314
+ # end
315
+ #
316
+ # @see https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L628-L637 Description of Already Exists Error in Apache Cassandra native protocol spec v1
317
+ class AlreadyExistsError < ConfigurationError
318
+ # @return [String] keyspace
319
+ attr_reader :keyspace
320
+
321
+ # @return [String, nil] table or `nil`
322
+ attr_reader :table
323
+
324
+ # @private
325
+ def initialize(message, statement, keyspace, table)
326
+ super(message, statement)
327
+
328
+ @keyspace = keyspace
329
+ @table = table
330
+ end
331
+ end
332
+
333
+ # This error is thrown when all attempted hosts raised a
334
+ # {Cassandra::Errors::HostError} during connection or query execution.
335
+ #
336
+ # @see Cassandra::Cluster#connect
337
+ # @see Cassandra::Session#execute
338
+ class NoHostsAvailable < ::StandardError
339
+ include Error
340
+
341
+ # @return [Hash{Cassandra::Host => Cassandra::Errors::HostError}] a map
342
+ # of hosts to underlying exceptions
343
+ attr_reader :errors
344
+
345
+ # @private
346
+ def initialize(errors = nil)
347
+ if errors
348
+ first = true
349
+ message = "All attempted hosts failed"
350
+ details = errors.each do |(host, error)|
351
+ if first
352
+ first = false
353
+ message << ': '
354
+ else
355
+ message << ', '
356
+ end
357
+ message << "#{host.ip} (#{error.class.name}: #{error.message})"
358
+ end
359
+ else
360
+ message = "All hosts down"
361
+ end
362
+
363
+ super(message)
364
+
365
+ @errors = errors || {}
366
+ end
367
+ end
78
368
  end
79
369
  end