cql-rb 1.0.6 → 1.1.0.pre0

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 (50) hide show
  1. data/README.md +4 -9
  2. data/lib/cql.rb +1 -0
  3. data/lib/cql/byte_buffer.rb +23 -7
  4. data/lib/cql/client.rb +11 -6
  5. data/lib/cql/client/asynchronous_client.rb +37 -83
  6. data/lib/cql/client/asynchronous_prepared_statement.rb +10 -4
  7. data/lib/cql/client/column_metadata.rb +16 -0
  8. data/lib/cql/client/request_runner.rb +46 -0
  9. data/lib/cql/future.rb +4 -5
  10. data/lib/cql/io.rb +2 -5
  11. data/lib/cql/io/connection.rb +220 -0
  12. data/lib/cql/io/io_reactor.rb +213 -185
  13. data/lib/cql/protocol.rb +1 -0
  14. data/lib/cql/protocol/cql_protocol_handler.rb +201 -0
  15. data/lib/cql/protocol/decoding.rb +6 -31
  16. data/lib/cql/protocol/encoding.rb +1 -5
  17. data/lib/cql/protocol/request.rb +4 -0
  18. data/lib/cql/protocol/responses/schema_change_result_response.rb +15 -0
  19. data/lib/cql/protocol/type_converter.rb +56 -76
  20. data/lib/cql/time_uuid.rb +104 -0
  21. data/lib/cql/uuid.rb +4 -2
  22. data/lib/cql/version.rb +1 -1
  23. data/spec/cql/client/asynchronous_client_spec.rb +47 -71
  24. data/spec/cql/client/asynchronous_prepared_statement_spec.rb +68 -0
  25. data/spec/cql/client/client_shared.rb +3 -3
  26. data/spec/cql/client/column_metadata_spec.rb +80 -0
  27. data/spec/cql/client/request_runner_spec.rb +120 -0
  28. data/spec/cql/future_spec.rb +26 -11
  29. data/spec/cql/io/connection_spec.rb +460 -0
  30. data/spec/cql/io/io_reactor_spec.rb +212 -265
  31. data/spec/cql/protocol/cql_protocol_handler_spec.rb +216 -0
  32. data/spec/cql/protocol/decoding_spec.rb +9 -28
  33. data/spec/cql/protocol/encoding_spec.rb +0 -5
  34. data/spec/cql/protocol/request_spec.rb +16 -0
  35. data/spec/cql/protocol/response_frame_spec.rb +2 -2
  36. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +70 -0
  37. data/spec/cql/time_uuid_spec.rb +136 -0
  38. data/spec/cql/uuid_spec.rb +1 -5
  39. data/spec/integration/client_spec.rb +34 -38
  40. data/spec/integration/io_spec.rb +283 -0
  41. data/spec/integration/protocol_spec.rb +53 -113
  42. data/spec/integration/regression_spec.rb +124 -0
  43. data/spec/integration/uuid_spec.rb +76 -0
  44. data/spec/spec_helper.rb +12 -9
  45. data/spec/support/fake_io_reactor.rb +52 -21
  46. data/spec/support/fake_server.rb +2 -2
  47. metadata +33 -10
  48. checksums.yaml +0 -15
  49. data/lib/cql/io/node_connection.rb +0 -209
  50. data/spec/cql/protocol/type_converter_spec.rb +0 -52
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZDk1YTJjZWRjODBkYTMyNjIyYjBhYjZkN2NjYzA5MWE1YzJkNTVjMw==
5
- data.tar.gz: !binary |-
6
- ZjI5MjQ2Mzc1MDE3MzRjYzg4MzVjMmY5YTMyM2U4ODY0ODY4ZTg0OQ==
7
- SHA512:
8
- metadata.gz: !binary |-
9
- Y2IxNTg3NGYxOWM1MzY3ZmViYTY4MjcxNDhkNDAzZjkxMmY5MTBjYjc4YzJi
10
- MDMwMjI1Y2NmZjI2OTAyNTM3ZWQ5ODk2M2YwMjNjODU5ODlkNjI5ZDUxNDk2
11
- Y2NhNWZlMjk3ZWUzNTU4YzM2Y2UyZWI5M2YyODQyMjVmODczODU=
12
- data.tar.gz: !binary |-
13
- YjJhNDIwN2M1NTg4ZjMxMWNiYjA1NGFlMjZiMDc1ODgxZDhmMDAyZTUzZDEx
14
- ZDE2OGNlZTAzN2IwNTVmNWYzNjcxYzNhNTdlNzk0Mzg3Zjk4ZDhjZjE1ZmY5
15
- MjQ4NzE3NzUyNDQ5NTc5NDE5ODQ4MmE2MGZkMjIyMjlhMjk4NWQ=
@@ -1,209 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'socket'
4
-
5
-
6
- module Cql
7
- module Io
8
- # @private
9
- class NodeConnection
10
- def initialize(*args)
11
- @host, @port, @connection_timeout = args
12
- @connected_future = Future.new
13
- @io = nil
14
- @addrinfo = nil
15
- @write_buffer = ByteBuffer.new
16
- @read_buffer = ByteBuffer.new
17
- @current_frame = Protocol::ResponseFrame.new(@read_buffer)
18
- @response_tasks = [nil] * 128
19
- @event_listeners = Hash.new { |h, k| h[k] = [] }
20
- end
21
-
22
- def open
23
- @connection_started_at = Time.now
24
- begin
25
- addrinfo = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
26
- _, port, _, ip, address_family, socket_type = addrinfo.first
27
- @sockaddr = Socket.sockaddr_in(port, ip)
28
- @io = Socket.new(address_family, socket_type, 0)
29
- @io.connect_nonblock(@sockaddr)
30
- rescue Errno::EINPROGRESS
31
- # NOTE not connected yet, this is expected
32
- rescue SystemCallError, SocketError => e
33
- fail_connection!(e)
34
- end
35
- @connected_future
36
- end
37
-
38
- def connection_id
39
- self.object_id
40
- end
41
-
42
- def to_io
43
- @io
44
- end
45
-
46
- def on_event(&listener)
47
- @event_listeners[:event] << listener
48
- end
49
-
50
- def on_close(&listener)
51
- @event_listeners[:close] << listener
52
- end
53
-
54
- def connected?
55
- @io && !connecting?
56
- end
57
-
58
- def connecting?
59
- @io && !(@connected_future.complete? || @connected_future.failed?)
60
- end
61
-
62
- def closed?
63
- @io.nil? && !connecting?
64
- end
65
-
66
- def has_capacity?
67
- !!next_stream_id && connected?
68
- end
69
-
70
- def can_write?
71
- @io && (!@write_buffer.empty? || connecting?)
72
- end
73
-
74
- def handle_read
75
- new_bytes = @io.read_nonblock(2**16)
76
- @current_frame << new_bytes
77
- while @current_frame.complete?
78
- stream_id = @current_frame.stream_id
79
- if stream_id == EVENT_STREAM_ID
80
- @event_listeners[:event].each { |listener| listener.call(@current_frame.body) }
81
- elsif @response_tasks[stream_id]
82
- @response_tasks[stream_id].complete!([@current_frame.body, connection_id])
83
- @response_tasks[stream_id] = nil
84
- else
85
- # TODO dropping the request on the floor here, but we didn't send it
86
- end
87
- @current_frame = Protocol::ResponseFrame.new(@read_buffer)
88
- end
89
- rescue => e
90
- force_close(e)
91
- end
92
-
93
- def perform_request(request, future)
94
- stream_id = next_stream_id
95
- request.encode_frame(stream_id, @write_buffer)
96
- @response_tasks[stream_id] = future
97
- rescue => e
98
- case e
99
- when CqlError
100
- error = e
101
- else
102
- error = IoError.new(e.message)
103
- error.set_backtrace(e.backtrace)
104
- end
105
- @response_tasks.delete(stream_id)
106
- future.fail!(error)
107
- end
108
-
109
- def handle_write
110
- if connecting?
111
- handle_connecting
112
- else
113
- if !@write_buffer.empty?
114
- bytes_written = @io.write_nonblock(@write_buffer.cheap_peek)
115
- @write_buffer.discard(bytes_written)
116
- end
117
- end
118
- rescue => e
119
- force_close(e)
120
- end
121
-
122
- def handle_connecting
123
- if connecting_timed_out?
124
- fail_connection!(ConnectionTimeoutError.new("Could not connect to #{@host}:#{@port} within #{@connection_timeout}s"))
125
- else
126
- @io.connect_nonblock(@sockaddr)
127
- succeed_connection!
128
- end
129
- rescue Errno::EALREADY, Errno::EINPROGRESS
130
- # NOTE still not connected
131
- rescue Errno::EISCONN
132
- succeed_connection!
133
- rescue SystemCallError, SocketError => e
134
- fail_connection!(e)
135
- end
136
-
137
- def close
138
- if @io
139
- begin
140
- @io.close
141
- rescue SystemCallError
142
- # NOTE nothing to do, it wasn't open
143
- end
144
- if connecting?
145
- succeed_connection!
146
- end
147
- @io = nil
148
- @event_listeners[:close].each { |listener| listener.call(self) }
149
- end
150
- end
151
-
152
- def to_s
153
- state = begin
154
- if connected? then 'connected'
155
- elsif connecting? then 'connecting'
156
- else 'not connected'
157
- end
158
- end
159
- %<NodeConnection(#{@host}:#{@port}, #{state})>
160
- end
161
-
162
- private
163
-
164
- EVENT_STREAM_ID = -1
165
-
166
- def connecting_timed_out?
167
- (Time.now - @connection_started_at) > @connection_timeout
168
- end
169
-
170
- def succeed_connection!
171
- @connected_future.complete!(connection_id)
172
- end
173
-
174
- def fail_connection!(e)
175
- case e
176
- when ConnectionError
177
- error = e
178
- else
179
- message = "Could not connect to #{@host}:#{@port}: #{e.message} (#{e.class.name})"
180
- error = ConnectionError.new(message)
181
- error.set_backtrace(e.backtrace)
182
- end
183
- @connected_future.fail!(error)
184
- force_close(error)
185
- end
186
-
187
- def force_close(e)
188
- case e
189
- when CqlError
190
- error = e
191
- else
192
- error = IoError.new(e.message)
193
- error.set_backtrace(e.backtrace)
194
- end
195
- @response_tasks.each do |listener|
196
- listener.fail!(error) if listener
197
- end
198
- close
199
- end
200
-
201
- def next_stream_id
202
- @response_tasks.each_with_index do |task, index|
203
- return index if task.nil?
204
- end
205
- nil
206
- end
207
- end
208
- end
209
- end
@@ -1,52 +0,0 @@
1
- # encoding: ascii-8bit
2
-
3
- require 'spec_helper'
4
-
5
-
6
- module Cql
7
- module Protocol
8
- describe TypeConverter do
9
- let :converter do
10
- described_class.new
11
- end
12
-
13
- let :buffer do
14
- ''
15
- end
16
-
17
- TYPES = [:ascii, :bigint, :blob, :boolean, :counter, :decimal, :double, :float, :inet, :int, :text, :varchar, :timestamp, :timeuuid, :uuid, :varint].freeze
18
-
19
- describe '#to_bytes' do
20
- context 'when encoding normal value' do
21
- TYPES.each do |type|
22
- it "encodes a null #{type.upcase}" do
23
- converter.to_bytes(buffer, type, nil, 4).should == "\xff\xff\xff\xff"
24
- end
25
- end
26
-
27
- it 'encodes a null LIST' do
28
- converter.to_bytes(buffer, [:list, :int], nil, 4).should == "\xff\xff\xff\xff"
29
- end
30
-
31
- it 'encodes a null MAP' do
32
- converter.to_bytes(buffer, [:map, :text, :text], nil, 4).should == "\xff\xff\xff\xff"
33
-
34
- end
35
-
36
- it 'encodes a null SET' do
37
- converter.to_bytes(buffer, [:set, :uuid], nil, 4).should == "\xff\xff\xff\xff"
38
-
39
- end
40
- end
41
-
42
- context 'when encoding collection values' do
43
- TYPES.each do |type|
44
- it "encodes a null #{type.upcase}" do
45
- converter.to_bytes(buffer, type, nil, 2).should == "\xff\xff"
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end