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

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +90 -38
  3. data/ext/cassandra_murmur3/cassandra_murmur3.c +1 -1
  4. data/lib/cassandra.rb +327 -130
  5. data/lib/cassandra/address_resolution.rb +1 -1
  6. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +1 -1
  7. data/lib/cassandra/address_resolution/policies/none.rb +1 -1
  8. data/lib/cassandra/aggregate.rb +21 -7
  9. data/lib/cassandra/argument.rb +2 -2
  10. data/lib/cassandra/auth.rb +4 -4
  11. data/lib/cassandra/auth/providers.rb +1 -1
  12. data/lib/cassandra/auth/providers/password.rb +9 -5
  13. data/lib/cassandra/cassandra_logger.rb +80 -0
  14. data/lib/cassandra/cluster.rb +38 -9
  15. data/lib/cassandra/cluster/client.rb +801 -205
  16. data/lib/cassandra/cluster/connection_pool.rb +2 -2
  17. data/lib/cassandra/cluster/connector.rb +74 -25
  18. data/lib/cassandra/cluster/control_connection.rb +217 -82
  19. data/lib/cassandra/cluster/failed_connection.rb +1 -1
  20. data/lib/cassandra/cluster/metadata.rb +12 -4
  21. data/lib/cassandra/cluster/options.rb +60 -11
  22. data/lib/cassandra/cluster/registry.rb +69 -16
  23. data/lib/cassandra/cluster/schema.rb +25 -7
  24. data/lib/cassandra/cluster/schema/cql_type_parser.rb +15 -10
  25. data/lib/cassandra/cluster/schema/fetchers.rb +263 -106
  26. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +41 -36
  27. data/lib/cassandra/cluster/schema/partitioners.rb +1 -1
  28. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +3 -3
  29. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +1 -1
  30. data/lib/cassandra/cluster/schema/partitioners/random.rb +1 -1
  31. data/lib/cassandra/cluster/schema/replication_strategies.rb +1 -1
  32. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +19 -18
  33. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +1 -1
  34. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +1 -1
  35. data/lib/cassandra/column.rb +3 -3
  36. data/lib/cassandra/compression.rb +1 -1
  37. data/lib/cassandra/compression/compressors/lz4.rb +4 -3
  38. data/lib/cassandra/compression/compressors/snappy.rb +4 -3
  39. data/lib/cassandra/driver.rb +103 -41
  40. data/lib/cassandra/errors.rb +265 -30
  41. data/lib/cassandra/execution/info.rb +16 -5
  42. data/lib/cassandra/execution/options.rb +99 -54
  43. data/lib/cassandra/execution/trace.rb +16 -9
  44. data/lib/cassandra/executors.rb +1 -1
  45. data/lib/cassandra/function.rb +19 -13
  46. data/lib/cassandra/function_collection.rb +85 -0
  47. data/lib/cassandra/future.rb +106 -48
  48. data/lib/cassandra/host.rb +10 -4
  49. data/lib/cassandra/keyspace.rb +90 -33
  50. data/lib/cassandra/listener.rb +1 -1
  51. data/lib/cassandra/load_balancing.rb +2 -2
  52. data/lib/cassandra/load_balancing/policies.rb +1 -1
  53. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +18 -18
  54. data/lib/cassandra/load_balancing/policies/round_robin.rb +1 -1
  55. data/lib/cassandra/load_balancing/policies/token_aware.rb +15 -13
  56. data/lib/cassandra/load_balancing/policies/white_list.rb +11 -5
  57. data/lib/cassandra/null_logger.rb +27 -6
  58. data/lib/cassandra/protocol.rb +1 -1
  59. data/lib/cassandra/protocol/coder.rb +78 -39
  60. data/lib/cassandra/protocol/cql_byte_buffer.rb +50 -33
  61. data/lib/cassandra/protocol/cql_protocol_handler.rb +44 -45
  62. data/lib/cassandra/protocol/request.rb +2 -2
  63. data/lib/cassandra/protocol/requests/auth_response_request.rb +3 -3
  64. data/lib/cassandra/protocol/requests/batch_request.rb +16 -7
  65. data/lib/cassandra/protocol/requests/credentials_request.rb +3 -3
  66. data/lib/cassandra/protocol/requests/execute_request.rb +41 -20
  67. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  68. data/lib/cassandra/protocol/requests/prepare_request.rb +5 -5
  69. data/lib/cassandra/protocol/requests/query_request.rb +27 -22
  70. data/lib/cassandra/protocol/requests/register_request.rb +2 -2
  71. data/lib/cassandra/protocol/requests/startup_request.rb +6 -4
  72. data/lib/cassandra/protocol/requests/void_query_request.rb +1 -1
  73. data/lib/cassandra/protocol/response.rb +2 -2
  74. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +12 -2
  75. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +1 -1
  76. data/lib/cassandra/protocol/responses/auth_success_response.rb +1 -1
  77. data/lib/cassandra/protocol/responses/authenticate_response.rb +1 -1
  78. data/lib/cassandra/protocol/responses/error_response.rb +101 -13
  79. data/lib/cassandra/protocol/responses/event_response.rb +1 -1
  80. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +13 -2
  81. data/lib/cassandra/protocol/responses/prepared_result_response.rb +11 -5
  82. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +14 -9
  83. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +26 -4
  84. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +22 -3
  85. data/lib/cassandra/protocol/responses/ready_response.rb +3 -3
  86. data/lib/cassandra/protocol/responses/result_response.rb +4 -2
  87. data/lib/cassandra/protocol/responses/rows_result_response.rb +5 -3
  88. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +5 -4
  89. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +16 -9
  90. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +2 -2
  91. data/lib/cassandra/protocol/responses/status_change_event_response.rb +2 -2
  92. data/lib/cassandra/protocol/responses/supported_response.rb +1 -1
  93. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +1 -1
  94. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +20 -3
  95. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +11 -2
  96. data/lib/cassandra/protocol/responses/void_result_response.rb +1 -1
  97. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +26 -4
  98. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +22 -3
  99. data/lib/cassandra/protocol/v1.rb +101 -36
  100. data/lib/cassandra/protocol/v3.rb +124 -51
  101. data/lib/cassandra/protocol/v4.rb +172 -68
  102. data/lib/cassandra/reconnection.rb +1 -1
  103. data/lib/cassandra/reconnection/policies.rb +1 -1
  104. data/lib/cassandra/reconnection/policies/constant.rb +2 -4
  105. data/lib/cassandra/reconnection/policies/exponential.rb +6 -6
  106. data/lib/cassandra/result.rb +53 -19
  107. data/lib/cassandra/retry.rb +8 -8
  108. data/lib/cassandra/retry/policies.rb +1 -1
  109. data/lib/cassandra/retry/policies/default.rb +1 -1
  110. data/lib/cassandra/retry/policies/downgrading_consistency.rb +7 -3
  111. data/lib/cassandra/retry/policies/fallthrough.rb +1 -1
  112. data/lib/cassandra/session.rb +22 -16
  113. data/lib/cassandra/statement.rb +1 -1
  114. data/lib/cassandra/statements.rb +1 -1
  115. data/lib/cassandra/statements/batch.rb +16 -10
  116. data/lib/cassandra/statements/bound.rb +10 -3
  117. data/lib/cassandra/statements/prepared.rb +59 -15
  118. data/lib/cassandra/statements/simple.rb +23 -10
  119. data/lib/cassandra/statements/void.rb +1 -1
  120. data/lib/cassandra/table.rb +79 -30
  121. data/lib/cassandra/time.rb +11 -6
  122. data/lib/cassandra/time_uuid.rb +7 -7
  123. data/lib/cassandra/tuple.rb +16 -8
  124. data/lib/cassandra/types.rb +20 -9
  125. data/lib/cassandra/udt.rb +32 -36
  126. data/lib/cassandra/util.rb +20 -13
  127. data/lib/cassandra/uuid.rb +22 -15
  128. data/lib/cassandra/uuid/generator.rb +7 -5
  129. data/lib/cassandra/version.rb +2 -2
  130. data/lib/datastax/cassandra.rb +1 -1
  131. metadata +5 -3
@@ -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.
@@ -28,7 +28,16 @@ module Cassandra
28
28
  end
29
29
 
30
30
  def to_error(keyspace, statement, options, hosts, consistency, retries)
31
- Errors::UnpreparedError.new(@message, @custom_payload, @warnings, keyspace, statement, options, hosts, consistency, retries, @id)
31
+ Errors::UnpreparedError.new(@message,
32
+ @custom_payload,
33
+ @warnings,
34
+ keyspace,
35
+ statement,
36
+ options,
37
+ hosts,
38
+ consistency,
39
+ retries,
40
+ @id)
32
41
  end
33
42
 
34
43
  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.
@@ -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)
@@ -168,22 +167,61 @@ module Cassandra
168
167
  CODE_AUTH_SUCCESS = 0x10
169
168
 
170
169
  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)
170
+ case opcode
171
+ when CODE_READY then
172
+ READY
173
+ when CODE_AUTHENTICATE then
174
+ AuthenticateResponse.new(buffer.read_string)
175
+ when CODE_AUTH_CHALLENGE then
176
+ AuthChallengeResponse.new(buffer.read_bytes)
177
+ when CODE_AUTH_SUCCESS then
178
+ AuthSuccessResponse.new(buffer.read_bytes)
179
+ when CODE_SUPPORTED then
180
+ SupportedResponse.new(buffer.read_string_multimap)
177
181
  when CODE_ERROR
178
- code = buffer.read_int
182
+ code = buffer.read_int
179
183
  message = buffer.read_string
180
184
 
181
185
  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)
186
+ when 0x1000 then
187
+ UnavailableErrorResponse.new(nil,
188
+ nil,
189
+ code,
190
+ message,
191
+ buffer.read_consistency,
192
+ buffer.read_int,
193
+ buffer.read_int)
194
+ when 0x1100 then
195
+ WriteTimeoutErrorResponse.new(nil,
196
+ nil,
197
+ code,
198
+ message,
199
+ buffer.read_consistency,
200
+ buffer.read_int,
201
+ buffer.read_int,
202
+ buffer.read_string)
203
+ when 0x1200 then
204
+ ReadTimeoutErrorResponse.new(nil,
205
+ nil,
206
+ code,
207
+ message,
208
+ buffer.read_consistency,
209
+ buffer.read_int,
210
+ buffer.read_int,
211
+ (buffer.read_byte != 0))
212
+ when 0x2400 then
213
+ AlreadyExistsErrorResponse.new(nil,
214
+ nil,
215
+ code,
216
+ message,
217
+ buffer.read_string,
218
+ buffer.read_string)
219
+ when 0x2500 then
220
+ UnpreparedErrorResponse.new(nil,
221
+ nil,
222
+ code,
223
+ message,
224
+ buffer.read_short_bytes)
187
225
  else
188
226
  ErrorResponse.new(nil, nil, code, message)
189
227
  end
@@ -197,50 +235,77 @@ module Cassandra
197
235
  column_specs, paging_state = Coder.read_metadata_v1(buffer)
198
236
 
199
237
  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)
238
+ consumed_bytes = original_buffer_length - buffer.length
239
+ remaining_bytes =
240
+ CqlByteBuffer.new(buffer.read(size - consumed_bytes - 4))
241
+ RawRowsResultResponse.new(nil,
242
+ nil,
243
+ protocol_version,
244
+ remaining_bytes,
245
+ paging_state,
246
+ trace_id)
203
247
  else
204
- RowsResultResponse.new(nil, nil, Coder.read_values_v1(buffer, column_specs), column_specs, paging_state, trace_id)
248
+ RowsResultResponse.new(nil,
249
+ nil,
250
+ Coder.read_values_v1(buffer, column_specs),
251
+ column_specs,
252
+ paging_state,
253
+ trace_id)
205
254
  end
206
255
  when 0x0003 # SetKeyspace
207
256
  SetKeyspaceResultResponse.new(nil, nil, buffer.read_string, trace_id)
208
257
  when 0x0004 # Prepared
209
- id = buffer.read_short_bytes
258
+ id = buffer.read_short_bytes
210
259
  params_metadata = Coder.read_metadata_v1(buffer).first
211
260
  result_metadata = nil
212
- result_metadata = Coder.read_metadata_v1(buffer).first if protocol_version > 1
261
+ if protocol_version > 1
262
+ result_metadata = Coder.read_metadata_v1(buffer).first
263
+ end
213
264
 
214
- PreparedResultResponse.new(nil, nil, id, params_metadata, result_metadata, nil, trace_id)
265
+ PreparedResultResponse.new(nil,
266
+ nil,
267
+ id,
268
+ params_metadata,
269
+ result_metadata,
270
+ nil,
271
+ trace_id)
215
272
  when 0x0005 # SchemaChange
216
- change = buffer.read_string
217
- keyspace = buffer.read_string
218
- name = buffer.read_string
273
+ change = buffer.read_string
274
+ keyspace = buffer.read_string
275
+ name = buffer.read_string
219
276
  arguments = EMPTY_LIST
220
- target = nil
277
+ target = nil
221
278
 
222
279
  if name.empty?
223
- name = nil
280
+ name = nil
224
281
  target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
225
282
  else
226
283
  target = Constants::SCHEMA_CHANGE_TARGET_TABLE
227
284
  end
228
285
 
229
- SchemaChangeResultResponse.new(nil, nil, change, keyspace, name, target, arguments, nil)
286
+ SchemaChangeResultResponse.new(nil,
287
+ nil,
288
+ change,
289
+ keyspace,
290
+ name,
291
+ target,
292
+ arguments,
293
+ nil)
230
294
  else
231
- raise Errors::DecodingError, "Unsupported result type: #{result_type.inspect}"
295
+ raise Errors::DecodingError,
296
+ "Unsupported result type: #{result_type.inspect}"
232
297
  end
233
298
  when CODE_EVENT
234
299
  event_type = buffer.read_string
235
300
  case event_type
236
301
  when 'SCHEMA_CHANGE'
237
- change = buffer.read_string
238
- keyspace = buffer.read_string
239
- name = buffer.read_string
302
+ change = buffer.read_string
303
+ keyspace = buffer.read_string
304
+ name = buffer.read_string
240
305
  arguments = EMPTY_LIST
241
306
 
242
307
  if name.empty?
243
- name = nil
308
+ name = nil
244
309
  target = Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
245
310
  else
246
311
  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,72 @@ 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
- result_metadata = Coder.read_metadata_v3(buffer).first if protocol_version > 1
293
+ if protocol_version > 1
294
+ result_metadata = Coder.read_metadata_v3(buffer).first
295
+ end
235
296
 
236
- PreparedResultResponse.new(nil, nil, id, params_metadata, result_metadata, nil, trace_id)
297
+ PreparedResultResponse.new(nil,
298
+ nil,
299
+ id,
300
+ params_metadata,
301
+ result_metadata,
302
+ nil,
303
+ trace_id)
237
304
  when 0x0005 # SchemaChange
238
- change = buffer.read_string
239
- target = buffer.read_string
240
- keyspace = buffer.read_string
305
+ change = buffer.read_string
306
+ target = buffer.read_string
307
+ keyspace = buffer.read_string
241
308
  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)
309
+ name = nil
310
+
311
+ name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
312
+
313
+ SchemaChangeResultResponse.new(nil,
314
+ nil,
315
+ change,
316
+ keyspace,
317
+ name,
318
+ target,
319
+ arguments,
320
+ nil)
249
321
  else
250
- raise Errors::DecodingError, "Unsupported result type: #{result_type.inspect}"
322
+ raise Errors::DecodingError,
323
+ "Unsupported result type: #{result_type.inspect}"
251
324
  end
252
325
  when 0x0C # EVENT
253
326
  event_type = buffer.read_string
254
327
  case event_type
255
328
  when 'SCHEMA_CHANGE'
256
- change = buffer.read_string
257
- target = buffer.read_string
258
- keyspace = buffer.read_string
259
- name = nil
329
+ change = buffer.read_string
330
+ target = buffer.read_string
331
+ keyspace = buffer.read_string
332
+ name = nil
260
333
  arguments = EMPTY_LIST
261
334
 
262
- if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
263
- name = buffer.read_string
264
- end
335
+ name = buffer.read_string if target == Constants::SCHEMA_CHANGE_TARGET_TABLE
265
336
 
266
337
  SchemaChangeEventResponse.new(change, keyspace, name, target, arguments)
267
338
  when 'STATUS_CHANGE'
@@ -269,14 +340,16 @@ module Cassandra
269
340
  when 'TOPOLOGY_CHANGE'
270
341
  TopologyChangeEventResponse.new(buffer.read_string, *buffer.read_inet)
271
342
  else
272
- raise Errors::DecodingError, "Unsupported event type: #{event_type.inspect}"
343
+ raise Errors::DecodingError,
344
+ "Unsupported event type: #{event_type.inspect}"
273
345
  end
274
346
  when 0x0E # AUTH_CHALLENGE
275
347
  AuthChallengeResponse.new(buffer.read_bytes)
276
348
  when 0x10 # AUTH_SUCCESS
277
349
  AuthSuccessResponse.new(buffer.read_bytes)
278
350
  else
279
- raise Errors::DecodingError, "Unsupported response opcode: #{opcode.inspect}"
351
+ raise Errors::DecodingError,
352
+ "Unsupported response opcode: #{opcode.inspect}"
280
353
  end
281
354
  end
282
355
  end