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.
- data/README.md +4 -9
- data/lib/cql.rb +1 -0
- data/lib/cql/byte_buffer.rb +23 -7
- data/lib/cql/client.rb +11 -6
- data/lib/cql/client/asynchronous_client.rb +37 -83
- data/lib/cql/client/asynchronous_prepared_statement.rb +10 -4
- data/lib/cql/client/column_metadata.rb +16 -0
- data/lib/cql/client/request_runner.rb +46 -0
- data/lib/cql/future.rb +4 -5
- data/lib/cql/io.rb +2 -5
- data/lib/cql/io/connection.rb +220 -0
- data/lib/cql/io/io_reactor.rb +213 -185
- data/lib/cql/protocol.rb +1 -0
- data/lib/cql/protocol/cql_protocol_handler.rb +201 -0
- data/lib/cql/protocol/decoding.rb +6 -31
- data/lib/cql/protocol/encoding.rb +1 -5
- data/lib/cql/protocol/request.rb +4 -0
- data/lib/cql/protocol/responses/schema_change_result_response.rb +15 -0
- data/lib/cql/protocol/type_converter.rb +56 -76
- data/lib/cql/time_uuid.rb +104 -0
- data/lib/cql/uuid.rb +4 -2
- data/lib/cql/version.rb +1 -1
- data/spec/cql/client/asynchronous_client_spec.rb +47 -71
- data/spec/cql/client/asynchronous_prepared_statement_spec.rb +68 -0
- data/spec/cql/client/client_shared.rb +3 -3
- data/spec/cql/client/column_metadata_spec.rb +80 -0
- data/spec/cql/client/request_runner_spec.rb +120 -0
- data/spec/cql/future_spec.rb +26 -11
- data/spec/cql/io/connection_spec.rb +460 -0
- data/spec/cql/io/io_reactor_spec.rb +212 -265
- data/spec/cql/protocol/cql_protocol_handler_spec.rb +216 -0
- data/spec/cql/protocol/decoding_spec.rb +9 -28
- data/spec/cql/protocol/encoding_spec.rb +0 -5
- data/spec/cql/protocol/request_spec.rb +16 -0
- data/spec/cql/protocol/response_frame_spec.rb +2 -2
- data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +70 -0
- data/spec/cql/time_uuid_spec.rb +136 -0
- data/spec/cql/uuid_spec.rb +1 -5
- data/spec/integration/client_spec.rb +34 -38
- data/spec/integration/io_spec.rb +283 -0
- data/spec/integration/protocol_spec.rb +53 -113
- data/spec/integration/regression_spec.rb +124 -0
- data/spec/integration/uuid_spec.rb +76 -0
- data/spec/spec_helper.rb +12 -9
- data/spec/support/fake_io_reactor.rb +52 -21
- data/spec/support/fake_server.rb +2 -2
- metadata +33 -10
- checksums.yaml +0 -15
- data/lib/cql/io/node_connection.rb +0 -209
- 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
|