cassandra-driver 1.1.1-java → 1.2.0-java

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 984d90b0ce4b175a04a676dca086bc1ea986326c
4
- data.tar.gz: 78893f940c6799e77ee062edc206dfb7b6747801
3
+ metadata.gz: c4d3013280c22a0d22b0bf77340c1c27c3fc0bbc
4
+ data.tar.gz: 19450149da8ffdd4eeeb53962ddc3640dc25a1d5
5
5
  SHA512:
6
- metadata.gz: e9cbe330d6fab7ab4aed5c48345a04f25adb329ba40220d7eaf5e714fb3f4f8695063b6534f487b4f88f5dd6014976152360215a732e1209046a68bc72745344
7
- data.tar.gz: 09e4ee074e44063aa14f4766aed0874560368c1c4cca7a353e5db37dda3876baf0b4d73b1a9380ae1705e6dd1905aae7ce198ce138f4f436e66b9a48f5e32c01
6
+ metadata.gz: ca9a5a0b9801ba7bfa4ac53cbcd697c45a5dfdc4febb1da959ae4a7b476d2883c0206233d53fa0dc3ab2e0e17c0417776c3302199a4f46dd55887a15ba470476
7
+ data.tar.gz: 55149c4d71b6b7c2cb544d4267b30438d6d261c20a6ecb4d14327620ff5bed9d9bb4b5111da4d2c1adac59fc4b4cd25b73c3a7edc0d21f7d1460a5fc32bac9f8
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.1.1
96
+ ## What's new in v1.2.0
97
97
 
98
- Current release introduces the following new features:
98
+ Bug Fixes:
99
99
 
100
- * Ability to disable automatic schema synchronization
101
- * Schema change event storm protection using a sliding delay
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
- @connecting_hosts[host] = distance
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 = @connecting_hosts.map do |(host, distance)|
69
- f = connect_to_host(host, distance)
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
- distance = nil
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
- return Ione::Future.resolved if distance == :ignore
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
- @connecting_hosts[host] = distance
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, distance).map(nil)
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 if !@connections.has_key?(host) && !@connecting_hosts.include?(host)
174
+ return Ione::Future.resolved unless @connections.has_key?(host)
147
175
 
148
- @connecting_hosts.delete(host)
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, distance)
303
- f = connect_to_host(host, distance)
304
-
305
- f.on_failure do |e|
306
- connect_to_host_with_retry(host, @reconnection_policy.schedule)
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
- distance = nil
320
-
321
- synchronize do
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, distance)
338
- case distance
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
- end
360
+ size = pool_size - pool.size
356
361
 
357
- existing_connections = pool.size if pool
358
- pool = nil
359
- missing_connections = (pool_size - existing_connections)
360
- return Ione::Future.resolved if missing_connections <= 0
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
- f = @connector.connect_many(host, missing_connections)
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
- @connecting_hosts.delete(host)
369
- @prepared_statements[host] = {}
370
- @preparing_statements[host] = {}
371
- pool = @connections[host] ||= ConnectionPool.new
372
- end
386
+ @pending_connections[host] -= size
373
387
 
374
- pool.add_connections(connections)
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
- connections.each do |connection|
377
- connection.on_closed do
378
- distance = nil
395
+ if pool
396
+ pool.add_connections(connections)
379
397
 
380
- synchronize do
381
- if !(@state == :closed || @state == :closing) && !@connecting_hosts.include?(host) && @connections.include?(host)
382
- distance = @load_balancing_policy.distance(host)
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
- f = @reactor.connect(host.ip.to_s, @connection_options.port, {:timeout => @connection_options.connect_timeout, :ssl => @connection_options.ssl}) do |connection|
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
- f = f.flat_map do |connection|
124
- request_options(connection).flat_map do |options|
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
- end
139
- f.fallback do |error|
140
- case error
141
- when Errors::ProtocolError
142
- synchronize do
143
- if @connection_options.protocol_version > 1
144
- @logger.info("Host #{host.ip} doesn't support protocol version #{@connection_options.protocol_version}, downgrading")
145
- @connection_options.protocol_version -= 1
146
- do_connect(host)
147
- else
148
- Ione::Future.failed(error)
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
@@ -337,7 +337,7 @@ module Cassandra
337
337
  @request_queue_out.clear
338
338
  end
339
339
  promises_to_fail.each do |promise|
340
- promise.fail(request_failure_cause)
340
+ promise.fail(request_failure_cause) unless promise.timed_out?
341
341
  end
342
342
  if cause
343
343
  @closed_promise.fail(cause)
@@ -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
- Time.at(timestamp/1000.0)
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
@@ -17,5 +17,5 @@
17
17
  #++
18
18
 
19
19
  module Cassandra
20
- VERSION = '1.1.1'.freeze
20
+ VERSION = '1.2.0'.freeze
21
21
  end
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.1.1
4
+ version: 1.2.0
5
5
  platform: java
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: 2014-12-15 00:00:00.000000000 Z
12
+ date: 2015-01-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ione