cassandra-driver 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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