cassandra-driver 3.0.0.beta.1-java → 3.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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -39
  3. data/lib/cassandra.rb +396 -148
  4. data/lib/cassandra/address_resolution.rb +1 -1
  5. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +1 -1
  6. data/lib/cassandra/address_resolution/policies/none.rb +1 -1
  7. data/lib/cassandra/aggregate.rb +21 -7
  8. data/lib/cassandra/argument.rb +2 -2
  9. data/lib/cassandra/attr_boolean.rb +33 -0
  10. data/lib/cassandra/auth.rb +6 -5
  11. data/lib/cassandra/auth/providers.rb +1 -1
  12. data/lib/cassandra/auth/providers/password.rb +5 -13
  13. data/lib/cassandra/cassandra_logger.rb +80 -0
  14. data/lib/cassandra/cluster.rb +49 -9
  15. data/lib/cassandra/cluster/client.rb +835 -209
  16. data/lib/cassandra/cluster/connection_pool.rb +2 -2
  17. data/lib/cassandra/cluster/connector.rb +86 -27
  18. data/lib/cassandra/cluster/control_connection.rb +222 -95
  19. data/lib/cassandra/cluster/failed_connection.rb +1 -1
  20. data/lib/cassandra/cluster/metadata.rb +14 -8
  21. data/lib/cassandra/cluster/options.rb +68 -22
  22. data/lib/cassandra/cluster/registry.rb +81 -17
  23. data/lib/cassandra/cluster/schema.rb +70 -8
  24. data/lib/cassandra/cluster/schema/cql_type_parser.rb +15 -10
  25. data/lib/cassandra/cluster/schema/fetchers.rb +601 -241
  26. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +39 -38
  27. data/lib/cassandra/cluster/schema/partitioners.rb +1 -1
  28. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +6 -8
  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 +4 -23
  36. data/lib/cassandra/column_container.rb +322 -0
  37. data/lib/cassandra/compression.rb +1 -1
  38. data/lib/cassandra/compression/compressors/lz4.rb +7 -8
  39. data/lib/cassandra/compression/compressors/snappy.rb +4 -3
  40. data/lib/cassandra/driver.rb +107 -46
  41. data/lib/cassandra/errors.rb +303 -52
  42. data/lib/cassandra/execution/info.rb +16 -5
  43. data/lib/cassandra/execution/options.rb +102 -55
  44. data/lib/cassandra/execution/trace.rb +16 -9
  45. data/lib/cassandra/executors.rb +1 -1
  46. data/lib/cassandra/function.rb +19 -13
  47. data/lib/cassandra/function_collection.rb +85 -0
  48. data/lib/cassandra/future.rb +101 -49
  49. data/lib/cassandra/host.rb +25 -5
  50. data/lib/cassandra/index.rb +118 -0
  51. data/lib/cassandra/keyspace.rb +169 -33
  52. data/lib/cassandra/listener.rb +1 -1
  53. data/lib/cassandra/load_balancing.rb +2 -2
  54. data/lib/cassandra/load_balancing/policies.rb +1 -1
  55. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +39 -25
  56. data/lib/cassandra/load_balancing/policies/round_robin.rb +8 -1
  57. data/lib/cassandra/load_balancing/policies/token_aware.rb +22 -13
  58. data/lib/cassandra/load_balancing/policies/white_list.rb +18 -5
  59. data/lib/cassandra/materialized_view.rb +90 -0
  60. data/lib/cassandra/null_logger.rb +27 -6
  61. data/lib/cassandra/protocol.rb +1 -1
  62. data/lib/cassandra/protocol/coder.rb +81 -42
  63. data/lib/cassandra/protocol/cql_byte_buffer.rb +58 -44
  64. data/lib/cassandra/protocol/cql_protocol_handler.rb +57 -54
  65. data/lib/cassandra/protocol/request.rb +6 -7
  66. data/lib/cassandra/protocol/requests/auth_response_request.rb +3 -3
  67. data/lib/cassandra/protocol/requests/batch_request.rb +17 -8
  68. data/lib/cassandra/protocol/requests/credentials_request.rb +3 -3
  69. data/lib/cassandra/protocol/requests/execute_request.rb +39 -20
  70. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  71. data/lib/cassandra/protocol/requests/prepare_request.rb +5 -5
  72. data/lib/cassandra/protocol/requests/query_request.rb +28 -23
  73. data/lib/cassandra/protocol/requests/register_request.rb +2 -2
  74. data/lib/cassandra/protocol/requests/startup_request.rb +8 -8
  75. data/lib/cassandra/protocol/requests/void_query_request.rb +1 -1
  76. data/lib/cassandra/protocol/response.rb +3 -4
  77. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +12 -2
  78. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +4 -5
  79. data/lib/cassandra/protocol/responses/auth_success_response.rb +4 -5
  80. data/lib/cassandra/protocol/responses/authenticate_response.rb +4 -5
  81. data/lib/cassandra/protocol/responses/error_response.rb +104 -17
  82. data/lib/cassandra/protocol/responses/event_response.rb +3 -4
  83. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +13 -2
  84. data/lib/cassandra/protocol/responses/prepared_result_response.rb +14 -9
  85. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +14 -9
  86. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +26 -4
  87. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +22 -3
  88. data/lib/cassandra/protocol/responses/ready_response.rb +6 -7
  89. data/lib/cassandra/protocol/responses/result_response.rb +11 -10
  90. data/lib/cassandra/protocol/responses/rows_result_response.rb +8 -7
  91. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +8 -8
  92. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +19 -13
  93. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +5 -6
  94. data/lib/cassandra/protocol/responses/status_change_event_response.rb +5 -6
  95. data/lib/cassandra/protocol/responses/supported_response.rb +4 -5
  96. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +4 -5
  97. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +20 -3
  98. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +11 -2
  99. data/lib/cassandra/protocol/responses/void_result_response.rb +4 -5
  100. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +26 -4
  101. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +22 -3
  102. data/lib/cassandra/protocol/v1.rb +98 -37
  103. data/lib/cassandra/protocol/v3.rb +121 -50
  104. data/lib/cassandra/protocol/v4.rb +172 -68
  105. data/lib/cassandra/reconnection.rb +1 -1
  106. data/lib/cassandra/reconnection/policies.rb +1 -1
  107. data/lib/cassandra/reconnection/policies/constant.rb +2 -4
  108. data/lib/cassandra/reconnection/policies/exponential.rb +6 -6
  109. data/lib/cassandra/result.rb +55 -20
  110. data/lib/cassandra/retry.rb +8 -8
  111. data/lib/cassandra/retry/policies.rb +1 -1
  112. data/lib/cassandra/retry/policies/default.rb +1 -1
  113. data/lib/cassandra/retry/policies/downgrading_consistency.rb +4 -2
  114. data/lib/cassandra/retry/policies/fallthrough.rb +1 -1
  115. data/lib/cassandra/session.rb +24 -16
  116. data/lib/cassandra/statement.rb +1 -1
  117. data/lib/cassandra/statements.rb +1 -1
  118. data/lib/cassandra/statements/batch.rb +16 -10
  119. data/lib/cassandra/statements/bound.rb +10 -3
  120. data/lib/cassandra/statements/prepared.rb +62 -18
  121. data/lib/cassandra/statements/simple.rb +23 -10
  122. data/lib/cassandra/statements/void.rb +1 -1
  123. data/lib/cassandra/table.rb +53 -185
  124. data/lib/cassandra/time.rb +11 -6
  125. data/lib/cassandra/time_uuid.rb +12 -14
  126. data/lib/cassandra/timestamp_generator.rb +37 -0
  127. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  128. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  129. data/lib/cassandra/tuple.rb +4 -4
  130. data/lib/cassandra/types.rb +109 -71
  131. data/lib/cassandra/udt.rb +66 -50
  132. data/lib/cassandra/util.rb +155 -15
  133. data/lib/cassandra/uuid.rb +20 -21
  134. data/lib/cassandra/uuid/generator.rb +7 -5
  135. data/lib/cassandra/version.rb +2 -2
  136. data/lib/cassandra_murmur3.jar +0 -0
  137. data/lib/datastax/cassandra.rb +1 -1
  138. metadata +27 -16
@@ -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.
@@ -19,6 +19,9 @@
19
19
  module Cassandra
20
20
  module Protocol
21
21
  class VoidResultResponse < ResultResponse
22
+ # @private
23
+ RESULT_TYPES[0x01] = self
24
+
22
25
  def to_s
23
26
  %(RESULT VOID)
24
27
  end
@@ -26,10 +29,6 @@ module Cassandra
26
29
  def void?
27
30
  true
28
31
  end
29
-
30
- private
31
-
32
- RESULT_TYPES[0x01] = self
33
32
  end
34
33
  end
35
34
  end
@@ -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.
@@ -21,7 +21,15 @@ module Cassandra
21
21
  class WriteFailureErrorResponse < ErrorResponse
22
22
  attr_reader :consistency, :received, :blockfor, :numfailures, :write_type
23
23
 
24
- def initialize(custom_payload, warnings, code, message, consistency, received, blockfor, numfailures, write_type)
24
+ def initialize(custom_payload,
25
+ warnings,
26
+ code,
27
+ message,
28
+ consistency,
29
+ received,
30
+ blockfor,
31
+ numfailures,
32
+ write_type)
25
33
  super(custom_payload, warnings, code, message)
26
34
 
27
35
  write_type.downcase!
@@ -34,11 +42,25 @@ module Cassandra
34
42
  end
35
43
 
36
44
  def to_error(keyspace, statement, options, hosts, consistency, retries)
37
- Errors::WriteError.new(@message, @custom_payload, @warnings, keyspace, statement, options, hosts, consistency, retries, @write_type, @consistency, @blockfor, @numfailures, @received)
45
+ Errors::WriteError.new(@message,
46
+ @custom_payload,
47
+ @warnings,
48
+ keyspace,
49
+ statement,
50
+ options,
51
+ hosts,
52
+ consistency,
53
+ retries,
54
+ @write_type,
55
+ @consistency,
56
+ @blockfor,
57
+ @numfailures,
58
+ @received)
38
59
  end
39
60
 
40
61
  def to_s
41
- "#{super} #{@write_type} #{@consistency} #{@blockfor} #{@numfailures} #{@received}"
62
+ "#{super} #{@write_type} #{@consistency} #{@blockfor} " \
63
+ "#{@numfailures} #{@received}"
42
64
  end
43
65
  end
44
66
  end
@@ -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.
@@ -21,7 +21,14 @@ module Cassandra
21
21
  class WriteTimeoutErrorResponse < ErrorResponse
22
22
  attr_reader :consistency, :received, :blockfor, :write_type
23
23
 
24
- def initialize(custom_payload, warnings, code, message, consistency, received, blockfor, write_type)
24
+ def initialize(custom_payload,
25
+ warnings,
26
+ code,
27
+ message,
28
+ consistency,
29
+ received,
30
+ blockfor,
31
+ write_type)
25
32
  super(custom_payload, warnings, code, message)
26
33
 
27
34
  write_type.downcase!
@@ -33,7 +40,19 @@ module Cassandra
33
40
  end
34
41
 
35
42
  def to_error(keyspace, statement, options, hosts, consistency, retries)
36
- Errors::WriteTimeoutError.new(@message, @custom_payload, @warnings, keyspace, statement, options, hosts, consistency, retries, @write_type, @consistency, @blockfor, @received)
43
+ Errors::WriteTimeoutError.new(@message,
44
+ @custom_payload,
45
+ @warnings,
46
+ keyspace,
47
+ statement,
48
+ options,
49
+ hosts,
50
+ consistency,
51
+ retries,
52
+ @write_type,
53
+ @consistency,
54
+ @blockfor,
55
+ @received)
37
56
  end
38
57
 
39
58
  def to_s
@@ -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.
@@ -37,7 +37,7 @@ module Cassandra
37
37
  body = @compressor.compress(body)
38
38
  end
39
39
 
40
- header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
40
+ header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
41
41
  buffer << header.pack(HEADER_FORMAT)
42
42
  buffer << body
43
43
  buffer
@@ -131,7 +131,8 @@ module Cassandra
131
131
  buffer = CqlByteBuffer.new(@compressor.decompress(buffer.read(size)))
132
132
  size = buffer.size
133
133
  else
134
- raise Errors::DecodingError, 'Compressed frame received, but no compressor configured'
134
+ raise Errors::DecodingError,
135
+ 'Compressed frame received, but no compressor configured'
135
136
  end
136
137
  end
137
138
 
@@ -145,9 +146,7 @@ module Cassandra
145
146
  extra_length = buffer.length - size
146
147
  response = decode_response(opcode, protocol_version, buffer, size, trace_id)
147
148
 
148
- if buffer.length > extra_length
149
- buffer.discard(buffer.length - extra_length)
150
- end
149
+ buffer.discard(buffer.length - extra_length) if buffer.length > extra_length
151
150
 
152
151
  if stream_id == -1
153
152
  @handler.notify_event_listeners(response)
@@ -156,8 +155,6 @@ module Cassandra
156
155
  end
157
156
  end
158
157
 
159
- private
160
-
161
158
  CODE_ERROR = 0x00
162
159
  CODE_READY = 0x02
163
160
  CODE_AUTHENTICATE = 0x03
@@ -168,22 +165,61 @@ module Cassandra
168
165
  CODE_AUTH_SUCCESS = 0x10
169
166
 
170
167
  def decode_response(opcode, protocol_version, buffer, size, trace_id)
171
- response = case opcode
172
- when CODE_READY then READY
173
- when CODE_AUTHENTICATE then AuthenticateResponse.new(buffer.read_string)
174
- when CODE_AUTH_CHALLENGE then AuthChallengeResponse.new(buffer.read_bytes)
175
- when CODE_AUTH_SUCCESS then AuthSuccessResponse.new(buffer.read_bytes)
176
- when CODE_SUPPORTED then SupportedResponse.new(buffer.read_string_multimap)
168
+ case opcode
169
+ when CODE_READY then
170
+ READY
171
+ when CODE_AUTHENTICATE then
172
+ AuthenticateResponse.new(buffer.read_string)
173
+ when CODE_AUTH_CHALLENGE then
174
+ AuthChallengeResponse.new(buffer.read_bytes)
175
+ when CODE_AUTH_SUCCESS then
176
+ AuthSuccessResponse.new(buffer.read_bytes)
177
+ when CODE_SUPPORTED then
178
+ SupportedResponse.new(buffer.read_string_multimap)
177
179
  when CODE_ERROR
178
- code = buffer.read_int
180
+ code = buffer.read_int
179
181
  message = buffer.read_string
180
182
 
181
183
  case code
182
- when 0x1000 then UnavailableErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int)
183
- when 0x1100 then WriteTimeoutErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, buffer.read_string)
184
- when 0x1200 then ReadTimeoutErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, (buffer.read_byte != 0))
185
- when 0x2400 then AlreadyExistsErrorResponse.new(nil, nil, code, message, buffer.read_string, buffer.read_string)
186
- when 0x2500 then UnpreparedErrorResponse.new(nil, nil, code, message, buffer.read_short_bytes)
184
+ when 0x1000 then
185
+ UnavailableErrorResponse.new(nil,
186
+ nil,
187
+ code,
188
+ message,
189
+ buffer.read_consistency,
190
+ buffer.read_int,
191
+ buffer.read_int)
192
+ when 0x1100 then
193
+ WriteTimeoutErrorResponse.new(nil,
194
+ nil,
195
+ code,
196
+ message,
197
+ buffer.read_consistency,
198
+ buffer.read_int,
199
+ buffer.read_int,
200
+ buffer.read_string)
201
+ when 0x1200 then
202
+ ReadTimeoutErrorResponse.new(nil,
203
+ nil,
204
+ code,
205
+ message,
206
+ buffer.read_consistency,
207
+ buffer.read_int,
208
+ buffer.read_int,
209
+ (buffer.read_byte != 0))
210
+ when 0x2400 then
211
+ AlreadyExistsErrorResponse.new(nil,
212
+ nil,
213
+ code,
214
+ message,
215
+ buffer.read_string,
216
+ buffer.read_string)
217
+ when 0x2500 then
218
+ UnpreparedErrorResponse.new(nil,
219
+ nil,
220
+ code,
221
+ message,
222
+ buffer.read_short_bytes)
187
223
  else
188
224
  ErrorResponse.new(nil, nil, code, message)
189
225
  end
@@ -197,50 +233,75 @@ module Cassandra
197
233
  column_specs, paging_state = Coder.read_metadata_v1(buffer)
198
234
 
199
235
  if column_specs.nil?
200
- consumed_bytes = original_buffer_length - buffer.length
201
- remaining_bytes = CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
202
- RawRowsResultResponse.new(nil, nil, protocol_version, remaining_bytes, paging_state, trace_id)
236
+ consumed_bytes = original_buffer_length - buffer.length
237
+ remaining_bytes =
238
+ CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
239
+ RawRowsResultResponse.new(nil,
240
+ nil,
241
+ protocol_version,
242
+ remaining_bytes,
243
+ paging_state,
244
+ trace_id)
203
245
  else
204
- RowsResultResponse.new(nil, nil, Coder.read_values_v1(buffer, column_specs), column_specs, paging_state, trace_id)
246
+ RowsResultResponse.new(nil,
247
+ nil,
248
+ Coder.read_values_v1(buffer, column_specs),
249
+ column_specs,
250
+ paging_state,
251
+ trace_id)
205
252
  end
206
253
  when 0x0003 # SetKeyspace
207
254
  SetKeyspaceResultResponse.new(nil, nil, buffer.read_string, trace_id)
208
255
  when 0x0004 # Prepared
209
- id = buffer.read_short_bytes
256
+ id = buffer.read_short_bytes
210
257
  params_metadata = Coder.read_metadata_v1(buffer).first
211
258
  result_metadata = nil
212
259
  result_metadata = Coder.read_metadata_v1(buffer).first if protocol_version > 1
213
260
 
214
- PreparedResultResponse.new(nil, nil, id, params_metadata, result_metadata, nil, trace_id)
261
+ PreparedResultResponse.new(nil,
262
+ nil,
263
+ id,
264
+ params_metadata,
265
+ result_metadata,
266
+ nil,
267
+ trace_id)
215
268
  when 0x0005 # SchemaChange
216
- change = buffer.read_string
217
- keyspace = buffer.read_string
218
- name = buffer.read_string
269
+ change = buffer.read_string
270
+ keyspace = buffer.read_string
271
+ name = buffer.read_string
219
272
  arguments = EMPTY_LIST
220
- target = nil
273
+ target = nil
221
274
 
222
275
  if name.empty?
223
- name = nil
276
+ name = nil
224
277
  target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
225
278
  else
226
279
  target = Constants::SCHEMA_CHANGE_TARGET_TABLE
227
280
  end
228
281
 
229
- SchemaChangeResultResponse.new(nil, nil, change, keyspace, name, target, arguments, nil)
282
+ SchemaChangeResultResponse.new(nil,
283
+ nil,
284
+ change,
285
+ keyspace,
286
+ name,
287
+ target,
288
+ arguments,
289
+ nil)
230
290
  else
231
- raise Errors::DecodingError, "Unsupported result type: #{result_type.inspect}"
291
+ raise Errors::DecodingError,
292
+ "Unsupported result type: #{result_type.inspect}"
232
293
  end
233
294
  when CODE_EVENT
234
295
  event_type = buffer.read_string
235
296
  case event_type
236
297
  when 'SCHEMA_CHANGE'
237
- change = buffer.read_string
238
- keyspace = buffer.read_string
239
- name = buffer.read_string
298
+ change = buffer.read_string
299
+ keyspace = buffer.read_string
300
+ name = buffer.read_string
240
301
  arguments = EMPTY_LIST
241
302
 
242
303
  if name.empty?
243
- name = nil
304
+ name = nil
244
305
  target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
245
306
  else
246
307
  target = Constants::SCHEMA_CHANGE_TARGET_TABLE
@@ -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.
@@ -37,7 +37,7 @@ module Cassandra
37
37
  body = @compressor.compress(body)
38
38
  end
39
39
 
40
- header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
40
+ header = [@protocol_version, flags, stream_id, request.opcode, body.bytesize]
41
41
  buffer << header.pack(HEADER_FORMAT)
42
42
  buffer << body
43
43
 
@@ -81,7 +81,9 @@ module Cassandra
81
81
  stream_id = (frame_header >> 8) & 0xff
82
82
  stream_id = (stream_id & 0x7f) - (stream_id & 0x80)
83
83
 
84
- @handler.complete_request(stream_id, ErrorResponse.new(nil, nil, 0x000A, "Invalid or unsupported protocol version"))
84
+ error_response = ErrorResponse.new(nil, nil, 0x000A,
85
+ 'Invalid or unsupported protocol version')
86
+ @handler.complete_request(stream_id, error_response)
85
87
 
86
88
  return
87
89
  end
@@ -150,7 +152,7 @@ module Cassandra
150
152
  nil
151
153
  end
152
154
 
153
- def actual_decode(buffer, fields, size, code)
155
+ def actual_decode(buffer, fields, frame_length, code)
154
156
  protocol_version = (fields >> 24) & 0x7f
155
157
  compression = (fields >> 16) & 0x01
156
158
  tracing = (fields >> 16) & 0x02
@@ -158,28 +160,40 @@ module Cassandra
158
160
  stream_id = (stream_id & 0x7fff) - (stream_id & 0x8000)
159
161
  opcode = code & 0xff
160
162
 
163
+ # If we're dealing with a compressed body, read the whole body, decompress,
164
+ # and treat the uncompressed body as if that's what we got in the first place.
165
+ # This means we must reset frame_length to that uncompressed size.
161
166
  if compression == 1
162
167
  if @compressor
163
- buffer = CqlByteBuffer.new(@compressor.decompress(buffer.read(size)))
164
- size = buffer.size
168
+ buffer = CqlByteBuffer.new(
169
+ @compressor.decompress(buffer.read(frame_length)))
170
+ frame_length = buffer.size
165
171
  else
166
- raise Errors::DecodingError, 'Compressed frame received, but no compressor configured'
172
+ raise Errors::DecodingError,
173
+ 'Compressed frame received, but no compressor configured'
167
174
  end
168
175
  end
169
176
 
170
- if tracing == 2
171
- trace_id = buffer.read_uuid
172
- size -= 16
173
- else
174
- trace_id = nil
175
- end
177
+ # We want to read one full frame; but after we read/parse chunks of the body
178
+ # there may be more cruft left in the frame that we don't care about. So,
179
+ # we save off the current size of the buffer, do all our reads for the
180
+ # frame, get the final remaining size, and based on that discard possible
181
+ # remaining bytes in the frame. In particular, we account for the possibility
182
+ # that the buffer contains some/all of a subsequent frame as well, and we
183
+ # don't want to mess with that.
176
184
 
177
- extra_length = buffer.length - size
178
- response = decode_response(opcode, protocol_version, buffer, size, trace_id)
185
+ buffer_starting_length = buffer.length
179
186
 
180
- if buffer.length > extra_length
181
- buffer.discard(buffer.length - extra_length)
182
- end
187
+ trace_id = (buffer.read_uuid if tracing == 2)
188
+
189
+ remaining_frame_length = frame_length -
190
+ (buffer_starting_length - buffer.length)
191
+ response = decode_response(opcode, protocol_version, buffer,
192
+ remaining_frame_length, trace_id)
193
+
194
+ # Calculate and discard remaining cruft in the frame.
195
+ extra_length = frame_length - (buffer_starting_length - buffer.length)
196
+ buffer.discard(extra_length) if extra_length > 0
183
197
 
184
198
  if stream_id == -1
185
199
  @handler.notify_event_listeners(response)
@@ -191,15 +205,49 @@ module Cassandra
191
205
  def decode_response(opcode, protocol_version, buffer, size, trace_id)
192
206
  case opcode
193
207
  when 0x00 # ERROR
194
- code = buffer.read_int
208
+ code = buffer.read_int
195
209
  message = buffer.read_string
196
210
 
197
211
  case code
198
- when 0x1000 then UnavailableErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int)
199
- when 0x1100 then WriteTimeoutErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, buffer.read_string)
200
- when 0x1200 then ReadTimeoutErrorResponse.new(nil, nil, code, message, buffer.read_consistency, buffer.read_int, buffer.read_int, (buffer.read_byte != 0))
201
- when 0x2400 then AlreadyExistsErrorResponse.new(nil, nil, code, message, buffer.read_string, buffer.read_string)
202
- when 0x2500 then UnpreparedErrorResponse.new(nil, nil, code, message, buffer.read_short_bytes)
212
+ when 0x1000
213
+ UnavailableErrorResponse.new(nil,
214
+ nil,
215
+ code,
216
+ message,
217
+ buffer.read_consistency,
218
+ buffer.read_int,
219
+ buffer.read_int)
220
+ when 0x1100
221
+ WriteTimeoutErrorResponse.new(nil,
222
+ nil,
223
+ code,
224
+ message,
225
+ buffer.read_consistency,
226
+ buffer.read_int,
227
+ buffer.read_int,
228
+ buffer.read_string)
229
+ when 0x1200
230
+ ReadTimeoutErrorResponse.new(nil,
231
+ nil,
232
+ code,
233
+ message,
234
+ buffer.read_consistency,
235
+ buffer.read_int,
236
+ buffer.read_int,
237
+ (buffer.read_byte != 0))
238
+ when 0x2400
239
+ AlreadyExistsErrorResponse.new(nil,
240
+ nil,
241
+ code,
242
+ message,
243
+ buffer.read_string,
244
+ buffer.read_string)
245
+ when 0x2500
246
+ UnpreparedErrorResponse.new(nil,
247
+ nil,
248
+ code,
249
+ message,
250
+ buffer.read_short_bytes)
203
251
  else
204
252
  ErrorResponse.new(nil, nil, code, message)
205
253
  end
@@ -219,49 +267,70 @@ module Cassandra
219
267
  column_specs, paging_state = Coder.read_metadata_v3(buffer)
220
268
 
221
269
  if column_specs.nil?
222
- consumed_bytes = original_buffer_length - buffer.length
223
- remaining_bytes = CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
224
- RawRowsResultResponse.new(nil, nil, protocol_version, remaining_bytes, paging_state, trace_id)
270
+ consumed_bytes = original_buffer_length - buffer.length
271
+ remaining_bytes =
272
+ CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
273
+ RawRowsResultResponse.new(nil,
274
+ nil,
275
+ protocol_version,
276
+ remaining_bytes,
277
+ paging_state,
278
+ trace_id)
225
279
  else
226
- RowsResultResponse.new(nil, nil, Coder.read_values_v3(buffer, column_specs), column_specs, paging_state, trace_id)
280
+ RowsResultResponse.new(nil,
281
+ nil,
282
+ Coder.read_values_v3(buffer, column_specs),
283
+ column_specs,
284
+ paging_state,
285
+ trace_id)
227
286
  end
228
287
  when 0x0003 # SetKeyspace
229
288
  SetKeyspaceResultResponse.new(nil, nil, buffer.read_string, trace_id)
230
289
  when 0x0004 # Prepared
231
- id = buffer.read_short_bytes
290
+ id = buffer.read_short_bytes
232
291
  params_metadata = Coder.read_metadata_v3(buffer).first
233
292
  result_metadata = nil
234
293
  result_metadata = Coder.read_metadata_v3(buffer).first if protocol_version > 1
235
294
 
236
- PreparedResultResponse.new(nil, nil, id, params_metadata, result_metadata, nil, trace_id)
295
+ PreparedResultResponse.new(nil,
296
+ nil,
297
+ id,
298
+ params_metadata,
299
+ result_metadata,
300
+ nil,
301
+ trace_id)
237
302
  when 0x0005 # SchemaChange
238
- change = buffer.read_string
239
- target = buffer.read_string
240
- keyspace = buffer.read_string
303
+ change = buffer.read_string
304
+ target = buffer.read_string
305
+ keyspace = buffer.read_string
241
306
  arguments = EMPTY_LIST
242
- name = nil
243
-
244
- if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
245
- name = buffer.read_string
246
- end
247
-
248
- SchemaChangeResultResponse.new(nil, nil, change, keyspace, name, target, arguments, nil)
307
+ name = nil
308
+
309
+ name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
310
+
311
+ SchemaChangeResultResponse.new(nil,
312
+ nil,
313
+ change,
314
+ keyspace,
315
+ name,
316
+ target,
317
+ arguments,
318
+ nil)
249
319
  else
250
- raise Errors::DecodingError, "Unsupported result type: #{result_type.inspect}"
320
+ raise Errors::DecodingError,
321
+ "Unsupported result type: #{result_type.inspect}"
251
322
  end
252
323
  when 0x0C # EVENT
253
324
  event_type = buffer.read_string
254
325
  case event_type
255
326
  when 'SCHEMA_CHANGE'
256
- change = buffer.read_string
257
- target = buffer.read_string
258
- keyspace = buffer.read_string
259
- name = nil
327
+ change = buffer.read_string
328
+ target = buffer.read_string
329
+ keyspace = buffer.read_string
330
+ name = nil
260
331
  arguments = EMPTY_LIST
261
332
 
262
- if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
263
- name = buffer.read_string
264
- end
333
+ name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
265
334
 
266
335
  SchemaChangeEventResponse.new(change, keyspace, name, target, arguments)
267
336
  when 'STATUS_CHANGE'
@@ -269,14 +338,16 @@ module Cassandra
269
338
  when 'TOPOLOGY_CHANGE'
270
339
  TopologyChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
271
340
  else
272
- raise Errors::DecodingError, "Unsupported event type: #{event_type.inspect}"
341
+ raise Errors::DecodingError,
342
+ "Unsupported event type: #{event_type.inspect}"
273
343
  end
274
344
  when 0x0E # AUTH_CHALLENGE
275
345
  AuthChallengeResponse.new(buffer.read_bytes)
276
346
  when 0x10 # AUTH_SUCCESS
277
347
  AuthSuccessResponse.new(buffer.read_bytes)
278
348
  else
279
- raise Errors::DecodingError, "Unsupported response opcode: #{opcode.inspect}"
349
+ raise Errors::DecodingError,
350
+ "Unsupported response opcode: #{opcode.inspect}"
280
351
  end
281
352
  end
282
353
  end