cassandra-driver 1.2.0 → 2.0.0

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 +8 -8
  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
@@ -19,6 +19,10 @@
19
19
  module Cassandra
20
20
  module Protocol
21
21
  class CqlByteBuffer < Ione::ByteBuffer
22
+ def inspect
23
+ "#<#{self.class.name}:0x#{self.object_id.to_s(16)} #{to_str.inspect}>"
24
+ end
25
+
22
26
  def read_unsigned_byte
23
27
  read_byte
24
28
  rescue RangeError => e
@@ -30,7 +30,6 @@ module Cassandra
30
30
  # future = protocol_handler.send_request(Cassandra::Protocol::OptionsRequest.new)
31
31
  # response = future.get
32
32
  # puts "These options are supported: #{response.options}"
33
- #
34
33
  class CqlProtocolHandler
35
34
  # @return [String] the current keyspace for the underlying connection
36
35
  attr_reader :keyspace
@@ -42,10 +41,8 @@ module Cassandra
42
41
  @connection.on_data(&method(:receive_data))
43
42
  @connection.on_closed(&method(:socket_closed))
44
43
  @promises = Array.new(128) { nil }
45
- @read_buffer = CqlByteBuffer.new
46
- @frame_encoder = FrameEncoder.new(protocol_version, @compressor)
47
- @frame_decoder = FrameDecoder.new(@compressor)
48
- @current_frame = FrameDecoder::NULL_FRAME
44
+ @frame_encoder = V1::Encoder.new(@compressor, protocol_version)
45
+ @frame_decoder = V1::Decoder.new(self, @compressor)
49
46
  @request_queue_in = []
50
47
  @request_queue_out = []
51
48
  @event_listeners = []
@@ -145,7 +142,7 @@ module Cassandra
145
142
  def send_request(request, timeout=nil, with_heartbeat = true)
146
143
  return Ione::Future.failed(Errors::IOError.new('Connection closed')) if closed?
147
144
  schedule_heartbeat if with_heartbeat
148
- promise = RequestPromise.new(request, @frame_encoder)
145
+ promise = RequestPromise.new(request)
149
146
  id = nil
150
147
  @lock.lock
151
148
  begin
@@ -157,12 +154,11 @@ module Cassandra
157
154
  end
158
155
  if id
159
156
  @connection.write do |buffer|
160
- @frame_encoder.encode_frame(request, id, buffer)
157
+ @frame_encoder.encode(buffer, request, id)
161
158
  end
162
159
  else
163
160
  @lock.lock
164
161
  begin
165
- promise.encode_frame
166
162
  @request_queue_in << promise
167
163
  ensure
168
164
  @lock.unlock
@@ -197,50 +193,6 @@ module Cassandra
197
193
  @closed_promise.future
198
194
  end
199
195
 
200
- private
201
-
202
- # @private
203
- class RequestPromise < Ione::Promise
204
- attr_reader :request, :frame
205
-
206
- def initialize(request, frame_encoder)
207
- @request = request
208
- @frame_encoder = frame_encoder
209
- @timed_out = false
210
- super()
211
- end
212
-
213
- def timed_out?
214
- @timed_out
215
- end
216
-
217
- def time_out!
218
- unless future.completed?
219
- @timed_out = true
220
- fail(Errors::TimeoutError.new('Timed out'))
221
- end
222
- end
223
-
224
- def encode_frame
225
- @frame = @frame_encoder.encode_frame(@request)
226
- end
227
- end
228
-
229
- def receive_data(data)
230
- reschedule_termination
231
- @read_buffer << data
232
- @current_frame = @frame_decoder.decode_frame(@read_buffer, @current_frame)
233
- while @current_frame.complete?
234
- id = @current_frame.stream_id
235
- if id == -1
236
- notify_event_listeners(@current_frame.body)
237
- else
238
- complete_request(id, @current_frame.body)
239
- end
240
- @current_frame = @frame_decoder.decode_frame(@read_buffer)
241
- end
242
- end
243
-
244
196
  def notify_event_listeners(event_response)
245
197
  event_listeners = nil
246
198
  @lock.lock
@@ -251,7 +203,7 @@ module Cassandra
251
203
  @lock.unlock
252
204
  end
253
205
  event_listeners.each do |listener|
254
- listener.call(@current_frame.body) rescue nil
206
+ listener.call(event_response)
255
207
  end
256
208
  end
257
209
 
@@ -276,6 +228,35 @@ module Cassandra
276
228
  end
277
229
  end
278
230
 
231
+ private
232
+
233
+ # @private
234
+ class RequestPromise < Ione::Promise
235
+ attr_reader :request
236
+
237
+ def initialize(request)
238
+ @request = request
239
+ @timed_out = false
240
+ super()
241
+ end
242
+
243
+ def timed_out?
244
+ @timed_out
245
+ end
246
+
247
+ def time_out!
248
+ unless future.completed?
249
+ @timed_out = true
250
+ fail(Errors::TimeoutError.new('Timed out'))
251
+ end
252
+ end
253
+ end
254
+
255
+ def receive_data(data)
256
+ reschedule_termination
257
+ @frame_decoder << data
258
+ end
259
+
279
260
  def flush_request_queue
280
261
  @lock.lock
281
262
  begin
@@ -288,7 +269,7 @@ module Cassandra
288
269
  end
289
270
  while true
290
271
  id = nil
291
- frame = nil
272
+ promise = nil
292
273
  @lock.lock
293
274
  begin
294
275
  if @request_queue_out.any? && (id = next_stream_id)
@@ -296,7 +277,6 @@ module Cassandra
296
277
  if promise.timed_out?
297
278
  next
298
279
  else
299
- frame = promise.frame
300
280
  @promises[id] = promise
301
281
  end
302
282
  end
@@ -304,8 +284,9 @@ module Cassandra
304
284
  @lock.unlock
305
285
  end
306
286
  if id
307
- @frame_encoder.change_stream_id(id, frame)
308
- @connection.write(frame)
287
+ @connection.write do |buffer|
288
+ @frame_encoder.encode(buffer, promise.request, id)
289
+ end
309
290
  else
310
291
  break
311
292
  end
@@ -26,7 +26,7 @@ module Cassandra
26
26
  @token = token
27
27
  end
28
28
 
29
- def write(protocol_version, buffer)
29
+ def write(buffer, protocol_version, encoder)
30
30
  buffer.append_bytes(@token)
31
31
  end
32
32
 
@@ -23,38 +23,43 @@ module Cassandra
23
23
  UNLOGGED_TYPE = 1
24
24
  COUNTER_TYPE = 2
25
25
 
26
- attr_reader :type, :part_count
26
+ attr_reader :type
27
27
  attr_accessor :consistency, :retries
28
28
 
29
29
  def initialize(type, consistency, trace=false)
30
30
  super(0x0D, trace)
31
- @type = type
32
- @part_count = 0
33
- @encoded_queries = CqlByteBuffer.new
31
+ @type = type
32
+ @parts = []
34
33
  @consistency = consistency
35
34
  end
36
35
 
37
- def add_query(cql, values=nil, type_hints=nil)
38
- @encoded_queries.append(QUERY_KIND)
39
- @encoded_queries.append_long_string(cql)
40
- QueryRequest.encode_values(@encoded_queries, values, type_hints)
41
- @part_count += 1
36
+ def add_query(cql, values, types)
37
+ @parts << [:simple, cql, values, types]
42
38
  nil
43
39
  end
44
40
 
45
- def add_prepared(id, metadata, values)
46
- @encoded_queries.append(PREPARED_KIND)
47
- @encoded_queries.append_short_bytes(id)
48
- ExecuteRequest.encode_values(@encoded_queries, metadata, values)
49
- @part_count += 1
41
+ def add_prepared(id, values, types)
42
+ @parts << [:prepared, id, values, types]
50
43
  nil
51
44
  end
52
45
 
53
- def write(protocol_version, buffer)
46
+ def write(buffer, protocol_version, encoder)
54
47
  buffer.append(@type.chr)
55
- buffer.append_short(@part_count)
56
- buffer.append(@encoded_queries)
48
+ buffer.append_short(@parts.size)
49
+
50
+ @parts.each do |(statement_kind, *arguments)|
51
+ __send__(:"write_#{statement_kind}", buffer, protocol_version, encoder, *arguments)
52
+ end
53
+
57
54
  buffer.append_consistency(@consistency)
55
+
56
+ if protocol_version > 2
57
+ flags = 0
58
+
59
+ buffer.append(flags.chr)
60
+ end
61
+
62
+ buffer
58
63
  end
59
64
 
60
65
  def to_s
@@ -63,14 +68,25 @@ module Cassandra
63
68
  when UNLOGGED_TYPE then 'UNLOGGED'
64
69
  when COUNTER_TYPE then 'COUNTER'
65
70
  end
66
- %(BATCH #{type_str} #{@part_count} #{@consistency.to_s.upcase})
71
+ %(BATCH #{type_str} #{@parts.size} #{@consistency.to_s.upcase})
67
72
  end
68
73
 
69
74
  private
70
75
 
71
- TYPE_CONVERTER = TypeConverter.new
72
76
  QUERY_KIND = "\x00".freeze
73
77
  PREPARED_KIND = "\x01".freeze
78
+
79
+ def write_simple(buffer, protocol_version, encoder, cql, values, types)
80
+ buffer.append(QUERY_KIND)
81
+ buffer.append_long_string(cql)
82
+ encoder.write_parameters(buffer, values, types)
83
+ end
84
+
85
+ def write_prepared(buffer, protocol_version, encoder, id, values, types)
86
+ buffer.append(PREPARED_KIND)
87
+ buffer.append_short_bytes(id)
88
+ encoder.write_parameters(buffer, values, types)
89
+ end
74
90
  end
75
91
  end
76
92
  end
@@ -26,7 +26,7 @@ module Cassandra
26
26
  @credentials = credentials.dup.freeze
27
27
  end
28
28
 
29
- def write(protocol_version, buffer)
29
+ def write(buffer, protocol_version, encoder)
30
30
  buffer.append_string_map(@credentials)
31
31
  end
32
32
 
@@ -36,10 +36,9 @@ module Cassandra
36
36
  @serial_consistency = serial_consistency
37
37
  @page_size = page_size
38
38
  @paging_state = paging_state
39
- @encoded_values = self.class.encode_values(CqlByteBuffer.new, @metadata, @values)
40
39
  end
41
40
 
42
- def write(protocol_version, buffer)
41
+ def write(buffer, protocol_version, encoder)
43
42
  buffer.append_short_bytes(@id)
44
43
  if protocol_version > 1
45
44
  buffer.append_consistency(@consistency)
@@ -51,13 +50,13 @@ module Cassandra
51
50
  flags |= 0x10 if @serial_consistency
52
51
  buffer.append(flags.chr)
53
52
  if @values.size > 0
54
- buffer.append(@encoded_values)
53
+ encoder.write_parameters(buffer, @values, @metadata)
55
54
  end
56
55
  buffer.append_int(@page_size) if @page_size
57
56
  buffer.append_bytes(@paging_state) if @paging_state
58
57
  buffer.append_consistency(@serial_consistency) if @serial_consistency
59
58
  else
60
- buffer.append(@encoded_values)
59
+ encoder.write_parameters(buffer, @values, @metadata)
61
60
  buffer.append_consistency(@consistency)
62
61
  end
63
62
  buffer
@@ -86,18 +85,6 @@ module Cassandra
86
85
  h
87
86
  end
88
87
  end
89
-
90
- def self.encode_values(buffer, metadata, values)
91
- buffer.append_short(metadata.size)
92
- metadata.each_with_index do |(_, _, _, type), index|
93
- TYPE_CONVERTER.to_bytes(buffer, type, values[index])
94
- end
95
- buffer
96
- end
97
-
98
- private
99
-
100
- TYPE_CONVERTER = TypeConverter.new
101
88
  end
102
89
  end
103
90
  end
@@ -27,7 +27,7 @@ module Cassandra
27
27
  false
28
28
  end
29
29
 
30
- def write(protocol_version, buffer)
30
+ def write(buffer, protocol_version, encoder)
31
31
  buffer
32
32
  end
33
33
 
@@ -29,7 +29,7 @@ module Cassandra
29
29
  @consistency = :one
30
30
  end
31
31
 
32
- def write(protocol_version, buffer)
32
+ def write(buffer, protocol_version, encoder)
33
33
  buffer.append_long_string(@cql)
34
34
  end
35
35
 
@@ -22,23 +22,18 @@ module Cassandra
22
22
  attr_reader :cql, :values, :type_hints, :serial_consistency, :page_size, :paging_state
23
23
  attr_accessor :consistency, :retries
24
24
 
25
- def initialize(cql, values, type_hints, consistency, serial_consistency=nil, page_size=nil, paging_state=nil, trace=false)
26
- raise ArgumentError, %(No CQL given!) unless cql
27
- raise ArgumentError, %(No such consistency: #{consistency.inspect}) if consistency.nil? || !CONSISTENCIES.include?(consistency)
28
- raise ArgumentError, %(No such consistency: #{serial_consistency.inspect}) unless serial_consistency.nil? || CONSISTENCIES.include?(serial_consistency)
29
- raise ArgumentError, %(Bound values and type hints must have the same number of elements (got #{values.size} values and #{type_hints.size} hints)) if values && type_hints && values.size != type_hints.size
30
- raise ArgumentError, %(Paging state given but no page size) if paging_state && !page_size
25
+ def initialize(cql, values, type_hints, consistency, serial_consistency = nil, page_size = nil, paging_state = nil, trace = false)
31
26
  super(7, trace)
32
27
  @cql = cql
33
- @values = values || EMPTY_LIST
34
- @type_hints = type_hints || EMPTY_LIST
28
+ @values = values
29
+ @type_hints = type_hints
35
30
  @consistency = consistency
36
31
  @serial_consistency = serial_consistency
37
32
  @page_size = page_size
38
33
  @paging_state = paging_state
39
34
  end
40
35
 
41
- def write(protocol_version, buffer)
36
+ def write(buffer, protocol_version, encoder)
42
37
  buffer.append_long_string(@cql)
43
38
  buffer.append_consistency(@consistency)
44
39
  if protocol_version > 1
@@ -49,7 +44,7 @@ module Cassandra
49
44
  if @values && @values.size > 0
50
45
  flags |= 0x01
51
46
  buffer.append(flags.chr)
52
- self.class.encode_values(buffer, @values, @type_hints)
47
+ encoder.write_parameters(buffer, @values, @type_hints)
53
48
  else
54
49
  buffer.append(flags.chr)
55
50
  end
@@ -87,57 +82,6 @@ module Cassandra
87
82
  h = 0xffffffffffffffff & (0x100000001b3 * (h ^ @paging_state.hash))
88
83
  h
89
84
  end
90
-
91
- def self.encode_values(buffer, values, hints)
92
- if values && values.size > 0
93
- buffer.append_short(values.size)
94
- values.each_with_index do |value, index|
95
- type = (hints && hints[index]) || guess_type(value)
96
- raise EncodingError, "Could not guess a suitable type for #{value.inspect}" unless type
97
- TYPE_CONVERTER.to_bytes(buffer, type, value)
98
- end
99
- buffer
100
- else
101
- buffer.append_short(0)
102
- end
103
- end
104
-
105
- private
106
-
107
- def self.guess_type(value)
108
- type = TYPE_GUESSES[value.class]
109
- if type == :map
110
- pair = value.first
111
- [type, guess_type(pair[0]), guess_type(pair[1])]
112
- elsif type == :list
113
- [type, guess_type(value.first)]
114
- elsif type == :set
115
- [type, guess_type(value.first)]
116
- else
117
- type
118
- end
119
- end
120
-
121
- TYPE_GUESSES = {
122
- String => :varchar,
123
- Fixnum => :bigint,
124
- Float => :double,
125
- Bignum => :varint,
126
- BigDecimal => :decimal,
127
- TrueClass => :boolean,
128
- FalseClass => :boolean,
129
- NilClass => :bigint,
130
- Uuid => :uuid,
131
- TimeUuid => :uuid,
132
- IPAddr => :inet,
133
- Time => :timestamp,
134
- Hash => :map,
135
- Array => :list,
136
- Set => :set,
137
- }.freeze
138
- TYPE_CONVERTER = TypeConverter.new
139
- EMPTY_LIST = [].freeze
140
- NO_FLAGS = "\x00".freeze
141
85
  end
142
86
  end
143
87
  end
@@ -26,7 +26,7 @@ module Cassandra
26
26
  @events = events
27
27
  end
28
28
 
29
- def write(protocol_version, buffer)
29
+ def write(buffer, protocol_version, encoder)
30
30
  buffer.append_string_list(@events)
31
31
  end
32
32