cassandra-driver 1.2.0-java → 2.0.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/lib/cassandra.rb +5 -3
  4. data/lib/cassandra/cluster/client.rb +88 -95
  5. data/lib/cassandra/cluster/control_connection.rb +14 -13
  6. data/lib/cassandra/column.rb +1 -9
  7. data/lib/cassandra/execution/options.rb +24 -1
  8. data/lib/cassandra/executors.rb +2 -0
  9. data/lib/cassandra/load_balancing.rb +0 -2
  10. data/lib/cassandra/protocol.rb +7 -5
  11. data/lib/cassandra/protocol/coder.rb +509 -0
  12. data/lib/cassandra/protocol/cql_byte_buffer.rb +4 -0
  13. data/lib/cassandra/protocol/cql_protocol_handler.rb +38 -57
  14. data/lib/cassandra/protocol/requests/auth_response_request.rb +1 -1
  15. data/lib/cassandra/protocol/requests/batch_request.rb +35 -19
  16. data/lib/cassandra/protocol/requests/credentials_request.rb +1 -1
  17. data/lib/cassandra/protocol/requests/execute_request.rb +3 -16
  18. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  19. data/lib/cassandra/protocol/requests/prepare_request.rb +1 -1
  20. data/lib/cassandra/protocol/requests/query_request.rb +5 -61
  21. data/lib/cassandra/protocol/requests/register_request.rb +1 -1
  22. data/lib/cassandra/protocol/requests/startup_request.rb +1 -1
  23. data/lib/cassandra/protocol/response.rb +0 -9
  24. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +40 -0
  25. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +0 -4
  26. data/lib/cassandra/protocol/responses/auth_success_response.rb +1 -5
  27. data/lib/cassandra/protocol/responses/authenticate_response.rb +0 -4
  28. data/lib/cassandra/protocol/responses/error_response.rb +0 -12
  29. data/lib/cassandra/protocol/responses/event_response.rb +0 -8
  30. data/lib/cassandra/protocol/responses/prepared_result_response.rb +0 -10
  31. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
  32. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +42 -0
  33. data/lib/cassandra/protocol/responses/ready_response.rb +0 -4
  34. data/lib/cassandra/protocol/responses/result_response.rb +0 -7
  35. data/lib/cassandra/protocol/responses/rows_result_response.rb +0 -101
  36. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +0 -3
  37. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +0 -4
  38. data/lib/cassandra/protocol/responses/status_change_event_response.rb +0 -4
  39. data/lib/cassandra/protocol/responses/supported_response.rb +0 -4
  40. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +41 -0
  41. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +39 -0
  42. data/lib/cassandra/protocol/responses/void_result_response.rb +0 -4
  43. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +44 -0
  44. data/lib/cassandra/protocol/v1.rb +238 -0
  45. data/lib/cassandra/session.rb +95 -16
  46. data/lib/cassandra/statements/batch.rb +33 -6
  47. data/lib/cassandra/statements/bound.rb +3 -3
  48. data/lib/cassandra/statements/prepared.rb +38 -10
  49. data/lib/cassandra/statements/simple.rb +72 -3
  50. data/lib/cassandra/table.rb +2 -3
  51. data/lib/cassandra/util.rb +18 -0
  52. data/lib/cassandra/version.rb +1 -1
  53. metadata +8 -5
  54. data/lib/cassandra/protocol/frame_decoder.rb +0 -128
  55. data/lib/cassandra/protocol/frame_encoder.rb +0 -48
  56. data/lib/cassandra/protocol/responses/detailed_error_response.rb +0 -75
  57. data/lib/cassandra/protocol/type_converter.rb +0 -389
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module Protocol
21
+ class UnpreparedErrorResponse < ErrorResponse
22
+ attr_reader :id
23
+
24
+ def initialize(code, message, id)
25
+ super(code, message)
26
+
27
+ @id = id
28
+ end
29
+
30
+ def to_error(statement = nil)
31
+ Errors::UnpreparedError.new(@message, statement, @id)
32
+ end
33
+
34
+ def to_s
35
+ "#{super} #{@id}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -19,10 +19,6 @@
19
19
  module Cassandra
20
20
  module Protocol
21
21
  class VoidResultResponse < ResultResponse
22
- def self.decode(protocol_version, buffer, length, trace_id=nil)
23
- new(trace_id)
24
- end
25
-
26
22
  def to_s
27
23
  %(RESULT VOID)
28
24
  end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module Protocol
21
+ class WriteTimeoutErrorResponse < ErrorResponse
22
+ attr_reader :consistency, :received, :blockfor, :write_type
23
+
24
+ def initialize(code, message, consistency, received, blockfor, write_type)
25
+ super(code, message)
26
+
27
+ write_type.downcase!
28
+
29
+ @consistency = consistency
30
+ @received = received
31
+ @blockfor = blockfor
32
+ @write_type = write_type.to_sym
33
+ end
34
+
35
+ def to_error(statement = nil)
36
+ Errors::WriteTimeoutError.new(@message, statement, @write_type, @consistency, @blockfor, @received)
37
+ end
38
+
39
+ def to_s
40
+ "#{super} #{@write_type} #{@consistency} #{@blockfor} #{@received}"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,238 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module Protocol
21
+ module V1
22
+ class Encoder
23
+ HEADER_FORMAT = 'c4N'.freeze
24
+
25
+ def initialize(compressor = nil, protocol_version = 1)
26
+ @compressor = compressor
27
+ @protocol_version = protocol_version
28
+ end
29
+
30
+ def encode(buffer, request, stream_id)
31
+ flags = request.trace? ? 2 : 0
32
+ body = request.write(CqlByteBuffer.new, @protocol_version, self)
33
+
34
+ if @compressor && request.compressable? && @compressor.compress?(body)
35
+ flags |= 1
36
+ body = @compressor.compress(body)
37
+ end
38
+
39
+ header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
40
+ buffer << header.pack(HEADER_FORMAT)
41
+ buffer << body
42
+ buffer
43
+ end
44
+
45
+ def write_parameters(buffer, params, types)
46
+ Coder.write_values_v1(buffer, params, types)
47
+ end
48
+ end
49
+
50
+ class Decoder
51
+ def initialize(handler, compressor = nil)
52
+ @handler = handler
53
+ @compressor = compressor
54
+ @state = :header
55
+ @header = nil
56
+ @length = nil
57
+ @buffer = CqlByteBuffer.new
58
+ end
59
+
60
+ def <<(data)
61
+ @buffer << data
62
+
63
+ __send__(:"decode_#{@state}", @buffer)
64
+ end
65
+
66
+ private
67
+
68
+ READY = ReadyResponse.new
69
+
70
+ def decode_header(buffer)
71
+ loop do
72
+ buffer_length = buffer.length
73
+
74
+ return if buffer_length < 8
75
+
76
+ frame_header = buffer.read_int
77
+ frame_length = buffer.read_int
78
+
79
+ if (buffer_length - 8) < frame_length
80
+ @header = frame_header
81
+ @length = frame_length
82
+ @state = :body
83
+
84
+ return
85
+ end
86
+
87
+ actual_decode(buffer, frame_header, frame_length)
88
+ end
89
+
90
+ nil
91
+ end
92
+
93
+ def decode_body(buffer)
94
+ frame_header = @header
95
+ frame_length = @length
96
+
97
+ loop do
98
+ buffer_length = buffer.length
99
+
100
+ return if buffer_length < frame_length
101
+
102
+ actual_decode(buffer, frame_header, frame_length)
103
+
104
+ if (buffer_length - frame_length) < 8
105
+ @header = nil
106
+ @length = nil
107
+ @state = :header
108
+
109
+ return
110
+ end
111
+
112
+ frame_header = buffer.read_int
113
+ frame_length = buffer.read_int
114
+ end
115
+
116
+ @header = frame_header
117
+ @length = frame_length
118
+
119
+ nil
120
+ end
121
+
122
+ def actual_decode(buffer, fields, size)
123
+ protocol_version = (fields >> 24) & 0x7f
124
+ compression = (fields >> 16) & 0x01
125
+ tracing = (fields >> 16) & 0x02
126
+ stream_id = (fields >> 8) & 0xff
127
+ stream_id = (stream_id & 0x7f) - (stream_id & 0x80)
128
+ opcode = fields & 0xff
129
+
130
+ if compression == 1
131
+ if @compressor
132
+ buffer = CqlByteBuffer.new(@compressor.decompress(buffer.read(size)))
133
+ size = buffer.size
134
+ else
135
+ raise Errors::DecodingError, 'Compressed frame received, but no compressor configured'
136
+ end
137
+ end
138
+
139
+ if tracing == 2
140
+ trace_id = buffer.read_uuid
141
+ size -= 16
142
+ else
143
+ trace_id = nil
144
+ end
145
+
146
+ extra_length = buffer.length - size
147
+ response = decode_response(opcode, protocol_version, buffer, size, trace_id)
148
+
149
+ if buffer.length > extra_length
150
+ buffer.discard(buffer.length - extra_length)
151
+ end
152
+
153
+ if stream_id == -1
154
+ @handler.notify_event_listeners(response)
155
+ else
156
+ @handler.complete_request(stream_id, response)
157
+ end
158
+ end
159
+
160
+ CODE_ERROR = 0x00
161
+ CODE_READY = 0x02
162
+ CODE_AUTHENTICATE = 0x03
163
+ CODE_SUPPORTED = 0x06
164
+ CODE_RESULT = 0x08
165
+ CODE_EVENT = 0x0c
166
+ CODE_AUTH_CHALLENGE = 0x0e
167
+ CODE_AUTH_SUCCESS = 0x10
168
+
169
+ def decode_response(opcode, protocol_version, buffer, size, trace_id)
170
+ response = case opcode
171
+ when CODE_READY then READY
172
+ when CODE_AUTHENTICATE then AuthenticateResponse.new(buffer.read_string)
173
+ when CODE_AUTH_CHALLENGE then AuthChallengeResponse.new(buffer.read_bytes)
174
+ when CODE_AUTH_SUCCESS then AuthSuccessResponse.new(buffer.read_bytes)
175
+ when CODE_SUPPORTED then SupportedResponse.new(buffer.read_string_multimap)
176
+ when CODE_ERROR
177
+ code = buffer.read_int
178
+ message = buffer.read_string
179
+
180
+ case code
181
+ when 0x1000 then UnavailableErrorResponse.new(code, message, buffer.read_consistency, buffer.read_int, buffer.read_int)
182
+ when 0x1100 then WriteTimeoutErrorResponse.new(code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, buffer.read_string)
183
+ when 0x1200 then ReadTimeoutErrorResponse.new(code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, (buffer.read_byte != 0))
184
+ when 0x2400 then AlreadyExistsErrorResponse.new(code, message, buffer.read_string, buffer.read_string)
185
+ when 0x2500 then UnpreparedErrorResponse.new(code, message, buffer.read_short_bytes)
186
+ else
187
+ ErrorResponse.new(code, message)
188
+ end
189
+ when CODE_RESULT
190
+ result_type = buffer.read_int
191
+ case result_type
192
+ when 0x0001 # Void
193
+ VoidResultResponse.new(trace_id)
194
+ when 0x0002 # Rows
195
+ original_buffer_length = buffer.length
196
+ column_specs, paging_state = Coder.read_metadata_v1(buffer)
197
+
198
+ if column_specs.nil?
199
+ consumed_bytes = original_buffer_length - buffer.length
200
+ remaining_bytes = CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
201
+ RawRowsResultResponse.new(protocol_version, remaining_bytes, paging_state, trace_id)
202
+ else
203
+ RowsResultResponse.new(Coder.read_values_v1(buffer, column_specs), column_specs, paging_state, trace_id)
204
+ end
205
+ when 0x0003 # SetKeyspace
206
+ SetKeyspaceResultResponse.new(buffer.read_string, trace_id)
207
+ when 0x0004 # Prepared
208
+ id = buffer.read_short_bytes
209
+ params_metadata = Coder.read_metadata_v1(buffer).first
210
+ result_metadata = nil
211
+ result_metadata = Coder.read_metadata_v1(buffer).first if protocol_version > 1
212
+
213
+ PreparedResultResponse.new(id, params_metadata, result_metadata, trace_id)
214
+ when 0x0005 # SchemaChange
215
+ SchemaChangeResultResponse.new(buffer.read_string, buffer.read_string, buffer.read_string, trace_id)
216
+ else
217
+ raise Errors::DecodingError, "Unsupported result type: #{result_type.inspect}"
218
+ end
219
+ when CODE_EVENT
220
+ event_type = buffer.read_string
221
+ case event_type
222
+ when 'SCHEMA_CHANGE'
223
+ SchemaChangeEventResponse.new(buffer.read_string, buffer.read_string, buffer.read_string)
224
+ when 'STATUS_CHANGE'
225
+ StatusChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
226
+ when 'TOPOLOGY_CHANGE'
227
+ TopologyChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
228
+ else
229
+ raise Errors::DecodingError, "Unsupported event type: #{event_type.inspect}"
230
+ end
231
+ else
232
+ raise Errors::DecodingError, "Unsupported response opcode: #{opcode.inspect}"
233
+ end
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
@@ -33,14 +33,14 @@ module Cassandra
33
33
  @futures = futures_factory
34
34
  end
35
35
 
36
+ # @!method execute_async(statement, options = nil)
36
37
  # Executes a given statement and returns a future result
37
- # @!method execute_async(statement, *args, options = {})
38
38
  #
39
39
  # @param statement [String, Cassandra::Statements::Simple,
40
40
  # Cassandra::Statements::Bound, Cassandra::Statements::Prepared]
41
41
  # statement to execute
42
- # @param args [*Object] arguments to paramterized query or prepared
43
- # statement
42
+ #
43
+ # @param options [nil, Hash] a customizable set of options
44
44
  #
45
45
  # @option options [Symbol] :consistency consistency level for the request.
46
46
  # Must be one of {Cassandra::CONSISTENCIES}
@@ -56,35 +56,66 @@ module Cassandra
56
56
  # @option options [String] :paging_state (nil) this option is used for
57
57
  # stateless paging, where result paging is resumed some time after the
58
58
  # initial request.
59
+ # @option options [Array] :arguments (nil) positional arguments for the
60
+ # statement.
61
+ #
62
+ # @overload execute_async(statement, *args, options = nil)
63
+ # Executes a statement using the deprecated splat-style way of passing
64
+ # positional arguments/
65
+ #
66
+ # @deprecated This style will soon be removed, use the `:arguments`
67
+ # option to provide positional arguments instead.
68
+ #
69
+ # @param statement [String, Cassandra::Statements::Simple,
70
+ # Cassandra::Statements::Bound, Cassandra::Statements::Prepared]
71
+ # statement to execute
72
+ #
73
+ # @param args [*Object] **this style of positional arguments is
74
+ # deprecated, please use the `:arguments` options instead** -
75
+ # positional arguments to paramterized query or prepared statement.
76
+ #
77
+ # @param options [nil, Hash] a customizable set of options
78
+ #
79
+ # @note Last argument will be treated as `options` if it is a {Hash}.
80
+ # Therefore, make sure to pass empty `options` when executing a
81
+ # statement with the last parameter required to be a map datatype.
59
82
  #
60
83
  # @see Cassandra.cluster Options that can be specified on the cluster-level
61
84
  # and their default values.
62
85
  #
63
- # @note Last argument will be treated as `options` if it is a {Hash}.
64
- # Therefore, make sure to pass empty `options` when executing a statement
65
- # with the last parameter required to be a map datatype.
66
- #
67
- # @note Positional arguments are only supported on Apache Cassandra 2.0 and
68
- # above.
86
+ # @note Positional arguments for simple statements are only supported on
87
+ # starting with Apache Cassandra 2.0 and above.
69
88
  #
70
89
  # @return [Cassandra::Future<Cassandra::Result>]
71
90
  #
72
91
  # @see Cassandra::Session#execute A list of errors this future can be
73
92
  # resolved with
74
93
  def execute_async(statement, *args)
75
- if args.last.is_a?(::Hash)
76
- options = @options.override(args.pop)
94
+ options = nil
95
+ options = args.pop if args.last.is_a?(::Hash)
96
+
97
+ unless args.empty?
98
+ ::Kernel.warn "[WARNING] Splat style (*args) positional arguments " \
99
+ "are deprecated, use the :arguments option instead, " \
100
+ "called from #{caller.first}"
101
+
102
+ options ||= {}
103
+ options[:arguments] = args
104
+ end
105
+
106
+ if options
107
+ options = @options.override(options)
77
108
  else
78
109
  options = @options
79
110
  end
80
111
 
81
112
  case statement
82
113
  when ::String
83
- @client.query(Statements::Simple.new(statement, *args), options)
114
+ @client.query(Statements::Simple.new(statement, options.arguments), options)
84
115
  when Statements::Simple
85
116
  @client.query(statement, options)
86
117
  when Statements::Prepared
87
- @client.execute(statement.bind(*args), options)
118
+ @client.execute(statement.bind(options.arguments), options)
88
119
  when Statements::Bound
89
120
  @client.execute(statement, options)
90
121
  when Statements::Batch
@@ -92,10 +123,40 @@ module Cassandra
92
123
  else
93
124
  @futures.error(::ArgumentError.new("unsupported statement #{statement.inspect}"))
94
125
  end
126
+ rescue => e
127
+ @futures.error(e)
95
128
  end
96
129
 
130
+ # @!method execute(statement, options = nil)
97
131
  # A blocking wrapper around {Cassandra::Session#execute_async}
98
- # @!method execute(statement, *args, options = {})
132
+ #
133
+ # @param statement [String, Cassandra::Statements::Simple,
134
+ # Cassandra::Statements::Bound, Cassandra::Statements::Prepared]
135
+ # statement to execute
136
+ #
137
+ # @param options [nil, Hash] a customizable set of options
138
+ #
139
+ # @overload execute(statement, *args, options = nil)
140
+ # Executes a statement using the deprecated splat-style way of passing
141
+ # positional arguments/
142
+ #
143
+ # @deprecated This style will soon be removed, use the `:arguments`
144
+ # option to provide positional arguments instead.
145
+ #
146
+ # @param statement [String, Cassandra::Statements::Simple,
147
+ # Cassandra::Statements::Bound, Cassandra::Statements::Prepared]
148
+ # statement to execute
149
+ #
150
+ # @param args [*Object] **this style of positional arguments is
151
+ # deprecated, please use the `:arguments` options instead** -
152
+ # positional arguments to paramterized query or prepared statement.
153
+ #
154
+ # @param options [nil, Hash] a customizable set of options
155
+ #
156
+ # @note Last argument will be treated as `options` if it is a {Hash}.
157
+ # Therefore, make sure to pass empty `options` when executing a
158
+ # statement with the last parameter required to be a map datatype.
159
+ #
99
160
  # @see Cassandra::Session#execute_async
100
161
  # @see Cassandra::Future#get
101
162
  #
@@ -105,8 +166,24 @@ module Cassandra
105
166
  # @raise [Cassandra::Errors::ValidationError] if Cassandra fails to validate
106
167
  # @raise [Cassandra::Errors::TimeoutError] if request has not completed
107
168
  # within the `:timeout` given
108
- def execute(*args)
109
- execute_async(*args).get
169
+ def execute(statement, *args)
170
+ options = nil
171
+ options = args.pop if args.last.is_a?(::Hash)
172
+
173
+ unless args.empty?
174
+ ::Kernel.warn "[WARNING] Splat style (*args) positional arguments " \
175
+ "are deprecated, use the :arguments option instead, " \
176
+ "called from #{caller.first}"
177
+
178
+ options ||= {}
179
+ options[:arguments] = args
180
+ end
181
+
182
+ if options
183
+ execute_async(statement, options).get
184
+ else
185
+ execute_async(statement).get
186
+ end
110
187
  end
111
188
 
112
189
  # Prepares a given statement and returns a future prepared statement
@@ -135,6 +212,8 @@ module Cassandra
135
212
  else
136
213
  @futures.error(::ArgumentError.new("unsupported statement #{statement.inspect}"))
137
214
  end
215
+ rescue => e
216
+ @futures.error(e)
138
217
  end
139
218
 
140
219
  # A blocking wrapper around {Cassandra::Session#prepare_async}