cassandra-driver 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +8 -8
- data/lib/cassandra/cluster/client.rb +97 -74
- data/lib/cassandra/cluster/connector.rb +26 -15
- data/lib/cassandra/protocol/cql_protocol_handler.rb +1 -1
- data/lib/cassandra/protocol/type_converter.rb +7 -3
- data/lib/cassandra/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzBmYWI0MTgyNjhhMWU2MGNjMjg0NWQzM2M5ODdkZTg4MWVkZjIzMQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZmNlZTUxNGEwNDBmYTdiM2U1N2U1MDUzODRkZDM0ZjBjNTA3YzRkOA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Nzg5OGIzNzVlNzkyY2U4MWM3NjQwNTIwMDRkNWM0M2EwYjliYmM2MDg1NjA3
|
10
|
+
NjZhYmEzYjBiNTdkMWY1MWM2OWY5OTJmYmEzNWMzMzdiYjliNTM4NDE1OWM4
|
11
|
+
MDc3N2Y1YWFhMDI3MzU3NjQxODYyZGExMDU4YjM5ODYwYTkyMzE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MjVhYTZmZjEwYjFjMDY5ZTU2NzIzYmQ1ZGU3MzE3OWMxYTMzMzYwN2NjZmMx
|
14
|
+
ZGFiZGI2NTg1ZjJhMzlmYTc4MDI1MmUxNWI0ZjA5YjVmODVlYmRlOWQzYmEy
|
15
|
+
YWM5NWEwNjE0ODM4YWFiYmY1OTFjZDJlYzIyZmU4MmQ1YWRkNDY=
|
data/README.md
CHANGED
@@ -93,16 +93,12 @@ __Note__: if you want to use compression you should also install [snappy](http:/
|
|
93
93
|
|
94
94
|
Some of the new features added to the driver have unfortunately led to changes in the original cql-rb API. In the examples directory, you can find [an example of how to wrap the ruby driver to achieve almost complete interface parity with cql-rb](https://github.com/datastax/ruby-driver/blob/master/examples/cql-rb-wrapper.rb) to assist you with gradual upgrade.
|
95
95
|
|
96
|
-
## What's new in v1.
|
96
|
+
## What's new in v1.2.0
|
97
97
|
|
98
|
-
|
98
|
+
Bug Fixes:
|
99
99
|
|
100
|
-
*
|
101
|
-
*
|
102
|
-
* [`Cassandra::LoadBalancing::Policy#teardown`](http://datastax.github.io/ruby-driver/api/load_balancing/policy/#teardown-instance_method) for cleaning up resources
|
103
|
-
* [`Cassandra::Cluster#refresh_schema`](http://datastax.github.io/ruby-driver/api/cluster/#refresh_schema-instance_method) for manually refreshing schema metadata
|
104
|
-
* Host list randomization to prevent hotspots between multiple clients
|
105
|
-
* Future listeners run in a dedicated threadpool to not block the reactor
|
100
|
+
* [RUBY-83] Timestamps loses microseconds when retrieved from database
|
101
|
+
* [RUBY-85] Driver doesn't always reconnect
|
106
102
|
|
107
103
|
## Code examples
|
108
104
|
|
@@ -147,6 +143,10 @@ Prereleases will be stable, in the sense that they will have finished and proper
|
|
147
143
|
|
148
144
|
Please [refer to the usage documentation for more information on common pitfalls](http://datastax.github.io/ruby-driver/features/)
|
149
145
|
|
146
|
+
## Contributing
|
147
|
+
|
148
|
+
For contributing read [CONTRIBUTING.md](https://github.com/datastax/ruby-driver/blob/master/README.md)
|
149
|
+
|
150
150
|
## Credits
|
151
151
|
|
152
152
|
This driver is based on the original work of [Theo Hultberg](https://github.com/iconara) on [cql-rb](https://github.com/iconara/cql-rb/) and adds a series of advanced features that are common across all other DataStax drivers for Apache Cassandra.
|
@@ -36,10 +36,10 @@ module Cassandra
|
|
36
36
|
@address_resolver = address_resolution_policy
|
37
37
|
@connection_options = connection_options
|
38
38
|
@futures = futures_factory
|
39
|
-
@connecting_hosts = ::Hash.new
|
40
39
|
@connections = ::Hash.new
|
41
40
|
@prepared_statements = ::Hash.new
|
42
41
|
@preparing_statements = ::Hash.new
|
42
|
+
@pending_connections = ::Hash.new
|
43
43
|
@keyspace = nil
|
44
44
|
@state = :idle
|
45
45
|
|
@@ -47,6 +47,8 @@ module Cassandra
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def connect
|
50
|
+
connecting_hosts = ::Hash.new
|
51
|
+
|
50
52
|
synchronize do
|
51
53
|
return CLIENT_CLOSED if @state == :closed || @state == :closing
|
52
54
|
return @connected_future if @state == :connecting || @state == :connected
|
@@ -54,9 +56,24 @@ module Cassandra
|
|
54
56
|
@state = :connecting
|
55
57
|
@registry.each_host do |host|
|
56
58
|
distance = @load_balancing_policy.distance(host)
|
57
|
-
next if distance == :ignore
|
58
59
|
|
59
|
-
|
60
|
+
case distance
|
61
|
+
when :ignore
|
62
|
+
next
|
63
|
+
when :local
|
64
|
+
pool_size = @connection_options.connections_per_local_node
|
65
|
+
when :remote
|
66
|
+
pool_size = @connection_options.connections_per_remote_node
|
67
|
+
else
|
68
|
+
@logger.error("Not connecting to #{host.ip} - invalid load balancing distance. Distance must be one of #{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
|
69
|
+
next
|
70
|
+
end
|
71
|
+
|
72
|
+
connecting_hosts[host] = pool_size
|
73
|
+
@pending_connections[host] = 0
|
74
|
+
@prepared_statements[host] = {}
|
75
|
+
@preparing_statements[host] = {}
|
76
|
+
@connections[host] = ConnectionPool.new
|
60
77
|
end
|
61
78
|
end
|
62
79
|
|
@@ -65,8 +82,8 @@ module Cassandra
|
|
65
82
|
@registry.add_listener(self)
|
66
83
|
@schema.add_listener(self)
|
67
84
|
|
68
|
-
futures =
|
69
|
-
f = connect_to_host(host,
|
85
|
+
futures = connecting_hosts.map do |(host, pool_size)|
|
86
|
+
f = connect_to_host(host, pool_size)
|
70
87
|
f.recover do |error|
|
71
88
|
FailedConnection.new(error, host)
|
72
89
|
end
|
@@ -125,30 +142,40 @@ module Cassandra
|
|
125
142
|
end
|
126
143
|
|
127
144
|
def host_up(host)
|
128
|
-
|
145
|
+
pool_size = 0
|
129
146
|
|
130
147
|
synchronize do
|
131
|
-
return Ione::Future.resolved if @connecting_hosts.include?(host)
|
132
|
-
|
133
148
|
distance = @load_balancing_policy.distance(host)
|
134
|
-
|
149
|
+
case distance
|
150
|
+
when :ignore
|
151
|
+
return Ione::Future.resolved
|
152
|
+
when :local
|
153
|
+
pool_size = @connection_options.connections_per_local_node
|
154
|
+
when :remote
|
155
|
+
pool_size = @connection_options.connections_per_remote_node
|
156
|
+
else
|
157
|
+
@logger.error("Not connecting to #{host.ip} - invalid load balancing distance. Distance must be one of #{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
|
158
|
+
return Ione::Future.resolved
|
159
|
+
end
|
135
160
|
|
136
|
-
@
|
161
|
+
@pending_connections[host] ||= 0
|
162
|
+
@prepared_statements[host] = {}
|
163
|
+
@preparing_statements[host] = {}
|
164
|
+
@connections[host] = ConnectionPool.new
|
137
165
|
end
|
138
166
|
|
139
|
-
connect_to_host_maybe_retry(host,
|
167
|
+
connect_to_host_maybe_retry(host, pool_size)
|
140
168
|
end
|
141
169
|
|
142
170
|
def host_down(host)
|
143
171
|
pool = nil
|
144
172
|
|
145
173
|
synchronize do
|
146
|
-
return Ione::Future.resolved
|
174
|
+
return Ione::Future.resolved unless @connections.has_key?(host)
|
147
175
|
|
148
|
-
@
|
176
|
+
@pending_connections.delete(host) unless @pending_connections[host] > 0
|
149
177
|
@prepared_statements.delete(host)
|
150
178
|
@preparing_statements.delete(host)
|
151
|
-
|
152
179
|
pool = @connections.delete(host)
|
153
180
|
end
|
154
181
|
|
@@ -299,93 +326,89 @@ module Cassandra
|
|
299
326
|
Ione::Future.all(*futures).map(self)
|
300
327
|
end
|
301
328
|
|
302
|
-
def connect_to_host_maybe_retry(host,
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
end
|
308
|
-
|
309
|
-
f
|
329
|
+
def connect_to_host_maybe_retry(host, pool_size)
|
330
|
+
connect_to_host(host, pool_size).fallback do |e|
|
331
|
+
@logger.error("Scheduling initial connection retry to #{host.ip} (#{e.class.name}: #{e.message})")
|
332
|
+
connect_to_host_with_retry(host, pool_size, @reconnection_policy.schedule)
|
333
|
+
end.map(nil)
|
310
334
|
end
|
311
335
|
|
312
|
-
def connect_to_host_with_retry(host, schedule)
|
336
|
+
def connect_to_host_with_retry(host, pool_size, schedule)
|
313
337
|
interval = schedule.next
|
314
338
|
|
315
339
|
@logger.debug("Reconnecting to #{host.ip} in #{interval} seconds")
|
316
340
|
|
317
341
|
f = @reactor.schedule_timer(interval)
|
318
342
|
f.flat_map do
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
if @connecting_hosts.include?(host)
|
323
|
-
distance = @load_balancing_policy.distance(host)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
if distance && distance != :ignore
|
328
|
-
connect_to_host(host, distance).fallback do |e|
|
329
|
-
connect_to_host_with_retry(host, schedule)
|
330
|
-
end
|
331
|
-
else
|
332
|
-
NO_CONNECTIONS
|
343
|
+
connect_to_host(host, pool_size).fallback do |e|
|
344
|
+
@logger.error("Scheduling connection retry to #{host.ip} (#{e.class.name}: #{e.message})")
|
345
|
+
connect_to_host_with_retry(host, pool_size, schedule)
|
333
346
|
end
|
334
347
|
end
|
335
348
|
end
|
336
349
|
|
337
|
-
def connect_to_host(host,
|
338
|
-
|
339
|
-
when :ignore
|
340
|
-
return NO_CONNECTIONS
|
341
|
-
when :local
|
342
|
-
pool_size = @connection_options.connections_per_local_node
|
343
|
-
when :remote
|
344
|
-
pool_size = @connection_options.connections_per_remote_node
|
345
|
-
else
|
346
|
-
@logger.error("Invalid load balancing distance, not connecting to #{host.ip}. Distance must be one of #{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
|
347
|
-
return NO_CONNECTIONS
|
348
|
-
end
|
349
|
-
|
350
|
-
pool = nil
|
351
|
-
existing_connections = 0
|
350
|
+
def connect_to_host(host, pool_size)
|
351
|
+
size = 0
|
352
352
|
|
353
353
|
synchronize do
|
354
|
+
unless @connections.include?(host)
|
355
|
+
@logger.info("Not connecting to #{host.ip} - host is currently down")
|
356
|
+
return NO_CONNECTIONS
|
357
|
+
end
|
358
|
+
|
354
359
|
pool = @connections[host]
|
355
|
-
|
360
|
+
size = pool_size - pool.size
|
356
361
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
362
|
+
if size <= 0
|
363
|
+
@logger.info("Not connecting to #{host.ip} - host is already fully connected")
|
364
|
+
return NO_CONNECTIONS
|
365
|
+
end
|
366
|
+
|
367
|
+
size -= @pending_connections[host]
|
361
368
|
|
362
|
-
|
369
|
+
if size <= 0
|
370
|
+
@logger.info("Not connecting to #{host.ip} - host is already pending connections")
|
371
|
+
return NO_CONNECTIONS
|
372
|
+
end
|
373
|
+
|
374
|
+
@pending_connections[host] += size
|
375
|
+
end
|
376
|
+
|
377
|
+
@logger.debug("Creating #{size} connections to #{host.ip}")
|
378
|
+
f = @connector.connect_many(host, size)
|
363
379
|
|
364
380
|
f.on_value do |connections|
|
381
|
+
@logger.debug("Created #{connections.size} connections to #{host.ip}")
|
382
|
+
|
365
383
|
pool = nil
|
366
384
|
|
367
385
|
synchronize do
|
368
|
-
@
|
369
|
-
@prepared_statements[host] = {}
|
370
|
-
@preparing_statements[host] = {}
|
371
|
-
pool = @connections[host] ||= ConnectionPool.new
|
372
|
-
end
|
386
|
+
@pending_connections[host] -= size
|
373
387
|
|
374
|
-
|
388
|
+
if @connections.include?(host)
|
389
|
+
pool = @connections[host]
|
390
|
+
else
|
391
|
+
@pending_connections.delete(host) unless @pending_connections[host] > 0
|
392
|
+
end
|
393
|
+
end
|
375
394
|
|
376
|
-
|
377
|
-
|
378
|
-
distance = nil
|
395
|
+
if pool
|
396
|
+
pool.add_connections(connections)
|
379
397
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
@connecting_hosts[host] = distance unless distance == :ignore
|
384
|
-
end
|
398
|
+
connections.each do |connection|
|
399
|
+
connection.on_closed do |cause|
|
400
|
+
connect_to_host_maybe_retry(host, pool_size) if cause
|
385
401
|
end
|
386
|
-
|
387
|
-
connect_to_host_maybe_retry(host, distance).map(nil) if distance
|
388
402
|
end
|
403
|
+
else
|
404
|
+
connections.each {|c| c.close}
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
f.on_failure do |error|
|
409
|
+
synchronize do
|
410
|
+
@pending_connections[host] -= size
|
411
|
+
@pending_connections.delete(host) unless @pending_connections[host] > 0 || @connections.include?(host)
|
389
412
|
end
|
390
413
|
end
|
391
414
|
|
@@ -116,12 +116,12 @@ module Cassandra
|
|
116
116
|
UNCLAIMED_TIMEOUT = 5 # close unclaimed connections in five seconds
|
117
117
|
|
118
118
|
def do_connect(host)
|
119
|
-
|
119
|
+
@reactor.connect(host.ip.to_s, @connection_options.port, {:timeout => @connection_options.connect_timeout, :ssl => @connection_options.ssl}) do |connection|
|
120
120
|
raise Errors::ClientError, 'Not connected, reactor stopped' unless connection
|
121
121
|
Protocol::CqlProtocolHandler.new(connection, @reactor, @connection_options.protocol_version, @connection_options.compressor, @connection_options.heartbeat_interval, @connection_options.idle_timeout)
|
122
|
-
end
|
123
|
-
|
124
|
-
|
122
|
+
end.flat_map do |connection|
|
123
|
+
f = request_options(connection)
|
124
|
+
f = f.flat_map do |options|
|
125
125
|
compression = @connection_options.compression
|
126
126
|
supported_algorithms = options['COMPRESSION']
|
127
127
|
|
@@ -135,19 +135,30 @@ module Cassandra
|
|
135
135
|
|
136
136
|
startup_connection(connection, cql_version, compression)
|
137
137
|
end
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
138
|
+
f.fallback do |error|
|
139
|
+
case error
|
140
|
+
when Errors::ProtocolError
|
141
|
+
synchronize do
|
142
|
+
if @connection_options.protocol_version > 1
|
143
|
+
@logger.info("Host #{host.ip} doesn't support protocol version #{@connection_options.protocol_version}, downgrading")
|
144
|
+
@connection_options.protocol_version -= 1
|
145
|
+
do_connect(host)
|
146
|
+
else
|
147
|
+
Ione::Future.failed(error)
|
148
|
+
end
|
149
149
|
end
|
150
|
+
when Errors::TimeoutError
|
151
|
+
future = Ione::CompletableFuture.new
|
152
|
+
connection.close(error).on_complete do |f|
|
153
|
+
future.fail(error)
|
154
|
+
end
|
155
|
+
future
|
156
|
+
else
|
157
|
+
Ione::Future.failed(error)
|
150
158
|
end
|
159
|
+
end
|
160
|
+
end.fallback do |error|
|
161
|
+
case error
|
151
162
|
when Error
|
152
163
|
Ione::Future.failed(error)
|
153
164
|
else
|
@@ -188,7 +188,11 @@ module Cassandra
|
|
188
188
|
def bytes_to_timestamp(buffer, size_bytes)
|
189
189
|
return nil unless read_size(buffer, size_bytes)
|
190
190
|
timestamp = buffer.read_long
|
191
|
-
|
191
|
+
|
192
|
+
seconds = timestamp / 1_000
|
193
|
+
microsenconds = (timestamp % 1_000) * 1_000
|
194
|
+
|
195
|
+
Time.at(seconds, microsenconds)
|
192
196
|
end
|
193
197
|
|
194
198
|
def bytes_to_varchar(buffer, size_bytes)
|
@@ -339,7 +343,7 @@ module Cassandra
|
|
339
343
|
|
340
344
|
def timestamp_to_bytes(buffer, value, size_bytes)
|
341
345
|
if value
|
342
|
-
ms = (value.to_f * 1000).to_i
|
346
|
+
ms = (value.to_r.to_f * 1000).to_i
|
343
347
|
size_to_bytes(buffer, 8, size_bytes)
|
344
348
|
buffer.append_long(ms)
|
345
349
|
else
|
@@ -382,4 +386,4 @@ module Cassandra
|
|
382
386
|
end
|
383
387
|
end
|
384
388
|
end
|
385
|
-
end
|
389
|
+
end
|
data/lib/cassandra/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cassandra-driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Hultberg
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ione
|