cassandra-driver 1.0.0.rc.1-java → 1.1.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +58 -18
  3. data/lib/cassandra.rb +132 -93
  4. data/lib/cassandra/auth.rb +3 -3
  5. data/lib/cassandra/cluster.rb +65 -39
  6. data/lib/cassandra/cluster/client.rb +67 -28
  7. data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
  8. data/lib/cassandra/cluster/connector.rb +101 -30
  9. data/lib/cassandra/cluster/control_connection.rb +160 -96
  10. data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
  11. data/lib/cassandra/cluster/options.rb +26 -11
  12. data/lib/cassandra/cluster/schema.rb +22 -1
  13. data/lib/cassandra/column.rb +5 -0
  14. data/lib/cassandra/driver.rb +46 -12
  15. data/lib/cassandra/errors.rb +5 -5
  16. data/lib/cassandra/execution/options.rb +42 -8
  17. data/lib/cassandra/execution/trace.rb +4 -4
  18. data/lib/cassandra/executors.rb +111 -0
  19. data/lib/cassandra/future.rb +88 -64
  20. data/lib/cassandra/keyspace.rb +12 -0
  21. data/lib/cassandra/load_balancing.rb +10 -0
  22. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
  23. data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
  24. data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
  25. data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
  26. data/lib/cassandra/null_logger.rb +35 -0
  27. data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
  28. data/lib/cassandra/protocol/requests/query_request.rb +1 -11
  29. data/lib/cassandra/result.rb +34 -9
  30. data/lib/cassandra/session.rb +6 -0
  31. data/lib/cassandra/statements/prepared.rb +5 -1
  32. data/lib/cassandra/table.rb +5 -0
  33. data/lib/cassandra/util.rb +130 -0
  34. data/lib/cassandra/version.rb +1 -1
  35. metadata +40 -50
  36. data/lib/cassandra/client.rb +0 -144
  37. data/lib/cassandra/client/batch.rb +0 -212
  38. data/lib/cassandra/client/client.rb +0 -591
  39. data/lib/cassandra/client/column_metadata.rb +0 -54
  40. data/lib/cassandra/client/connector.rb +0 -273
  41. data/lib/cassandra/client/execute_options_decoder.rb +0 -59
  42. data/lib/cassandra/client/peer_discovery.rb +0 -50
  43. data/lib/cassandra/client/prepared_statement.rb +0 -314
  44. data/lib/cassandra/client/query_result.rb +0 -230
  45. data/lib/cassandra/client/request_runner.rb +0 -70
  46. data/lib/cassandra/client/result_metadata.rb +0 -48
  47. data/lib/cassandra/client/void_result.rb +0 -78
@@ -22,7 +22,7 @@ module Cassandra
22
22
  class ControlConnection
23
23
  include MonitorMixin
24
24
 
25
- def initialize(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector)
25
+ def initialize(logger, io_reactor, cluster_registry, cluster_schema, cluster_metadata, load_balancing_policy, reconnection_policy, address_resolution_policy, connector, connection_options)
26
26
  @logger = logger
27
27
  @io_reactor = io_reactor
28
28
  @registry = cluster_registry
@@ -32,17 +32,24 @@ module Cassandra
32
32
  @reconnection_policy = reconnection_policy
33
33
  @address_resolver = address_resolution_policy
34
34
  @connector = connector
35
- @refreshing_statuses = Hash.new(false)
35
+ @connection_options = connection_options
36
+ @refreshing_statuses = ::Hash.new(false)
36
37
  @status = :closed
37
- @refreshing_schema = false
38
- @refreshing_keyspaces = Hash.new(false)
39
- @refreshing_tables = Hash.new
40
38
  @refreshing_hosts = false
41
- @refreshing_host = Hash.new(false)
39
+ @refreshing_host = ::Hash.new(false)
40
+ @closed_promise = Ione::Promise.new
41
+ @schema_changes = ::Array.new
42
+ @schema_refresh_timer = nil
43
+ @schema_refresh_window = nil
42
44
 
43
45
  mon_initialize
44
46
  end
45
47
 
48
+ def on_close(&block)
49
+ @closed_promise.future.on_value(&block)
50
+ @closed_promise.future.on_failure(&block)
51
+ end
52
+
46
53
  def connect_async
47
54
  synchronize do
48
55
  return Ione::Future.resolved if @status == :connecting || @status == :connected
@@ -110,10 +117,33 @@ module Cassandra
110
117
 
111
118
  def close_async
112
119
  synchronize do
113
- return Ione::Future.resolved if @status == :closing || @status == :closed
120
+ return @closed_promise.future if @status == :closing || @status == :closed
114
121
  @status = :closing
115
122
  end
116
- @io_reactor.stop
123
+ f = @io_reactor.stop
124
+
125
+ f.on_value(&method(:connection_closed))
126
+ f.on_failure(&method(:connection_closed))
127
+
128
+ @closed_promise.future
129
+ end
130
+
131
+ def connection_closed(cause)
132
+ @closed_promise.fulfill
133
+ end
134
+
135
+ def refresh_schema_async_maybe_retry
136
+ refresh_schema_async.fallback do |e|
137
+ case e
138
+ when Errors::HostError
139
+ refresh_schema_async_retry(e, @reconnection_policy.schedule)
140
+ else
141
+ connection = @connection
142
+ connection && connection.close(e)
143
+
144
+ Ione::Future.failed(e)
145
+ end
146
+ end
117
147
  end
118
148
 
119
149
  def inspect
@@ -127,11 +157,6 @@ module Cassandra
127
157
  SELECT_KEYSPACES = Protocol::QueryRequest.new('SELECT * FROM system.schema_keyspaces', nil, nil, :one)
128
158
  SELECT_TABLES = Protocol::QueryRequest.new('SELECT * FROM system.schema_columnfamilies', nil, nil, :one)
129
159
  SELECT_COLUMNS = Protocol::QueryRequest.new('SELECT * FROM system.schema_columns', nil, nil, :one)
130
- REGISTER = Protocol::RegisterRequest.new(
131
- Protocol::TopologyChangeEventResponse::TYPE,
132
- Protocol::StatusChangeEventResponse::TYPE,
133
- Protocol::SchemaChangeEventResponse::TYPE
134
- )
135
160
 
136
161
  def reconnect_async(schedule)
137
162
  timeout = schedule.next
@@ -163,7 +188,14 @@ module Cassandra
163
188
 
164
189
  return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
165
190
 
166
- f = connection.send_request(REGISTER)
191
+ request = Protocol::RegisterRequest.new(
192
+ Protocol::TopologyChangeEventResponse::TYPE,
193
+ Protocol::StatusChangeEventResponse::TYPE
194
+ )
195
+
196
+ request.events << Protocol::SchemaChangeEventResponse::TYPE if @connection_options.synchronize_schema?
197
+
198
+ f = connection.send_request(request)
167
199
  f = f.map do |r|
168
200
  case r
169
201
  when Protocol::ReadyResponse
@@ -179,26 +211,7 @@ module Cassandra
179
211
  @logger.debug("Event received #{event}")
180
212
 
181
213
  if event.type == 'SCHEMA_CHANGE'
182
- case event.change
183
- when 'CREATED'
184
- if event.table.empty?
185
- refresh_schema_async_maybe_retry
186
- else
187
- refresh_keyspace_async_maybe_retry(event.keyspace)
188
- end
189
- when 'DROPPED'
190
- if event.table.empty?
191
- refresh_schema_async_maybe_retry
192
- else
193
- refresh_keyspace_async_maybe_retry(event.keyspace)
194
- end
195
- when 'UPDATED'
196
- if event.table.empty?
197
- refresh_keyspace_async_maybe_retry(event.keyspace)
198
- else
199
- refresh_table_async_maybe_retry(event.keyspace, event.table)
200
- end
201
- end
214
+ handle_schema_change(event)
202
215
  else
203
216
  case event.change
204
217
  when 'UP'
@@ -242,29 +255,6 @@ module Cassandra
242
255
  end
243
256
  end
244
257
 
245
- def refresh_schema_async_maybe_retry
246
- synchronize do
247
- return Ione::Future.resolved if @refreshing_schema
248
- @refreshing_schema = true
249
- end
250
-
251
- refresh_schema_async.fallback do |e|
252
- case e
253
- when Errors::HostError
254
- refresh_schema_async_retry(e, @reconnection_policy.schedule)
255
- else
256
- connection = @connection
257
- connection && connection.close(e)
258
-
259
- Ione::Future.resolved
260
- end
261
- end.map do
262
- synchronize do
263
- @refreshing_schema = false
264
- end
265
- end
266
- end
267
-
268
258
  def refresh_schema_async_retry(error, schedule)
269
259
  timeout = schedule.next
270
260
  @logger.info("Failed to refresh schema (#{error.class.name}: #{error.message}), retrying in #{timeout}")
@@ -279,18 +269,13 @@ module Cassandra
279
269
  connection = @connection
280
270
  connection && connection.close(e)
281
271
 
282
- Ione::Future.resolved
272
+ Ione::Future.failed(e)
283
273
  end
284
274
  end
285
275
  end
286
276
  end
287
277
 
288
278
  def refresh_keyspace_async_maybe_retry(keyspace)
289
- synchronize do
290
- return Ione::Future.resolved if @refreshing_schema || @refreshing_keyspaces[keyspace]
291
- @refreshing_keyspaces[keyspace] = true
292
- end
293
-
294
279
  refresh_keyspace_async(keyspace).fallback do |e|
295
280
  case e
296
281
  when Errors::HostError
@@ -299,11 +284,7 @@ module Cassandra
299
284
  connection = @connection
300
285
  connection && connection.close(e)
301
286
 
302
- Ione::Future.resolved
303
- end
304
- end.map do
305
- synchronize do
306
- @refreshing_keyspaces.delete(host)
287
+ Ione::Future.failed(e)
307
288
  end
308
289
  end
309
290
  end
@@ -322,7 +303,7 @@ module Cassandra
322
303
  connection = @connection
323
304
  connection && connection.close(e)
324
305
 
325
- Ione::Future.resolved
306
+ Ione::Future.failed(e)
326
307
  end
327
308
  end
328
309
  end
@@ -333,25 +314,22 @@ module Cassandra
333
314
 
334
315
  return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
335
316
 
336
- params = [keyspace]
337
- keyspaces = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_keyspaces WHERE keyspace_name = ?", params, nil, :one))
338
- tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = ?", params, nil, :one))
339
- columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = ?", params, nil, :one))
317
+ keyspaces = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_keyspaces WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
318
+ tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
319
+ columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s'" % keyspace, nil, nil, :one))
340
320
 
341
321
  Ione::Future.all(keyspaces, tables, columns).map do |(keyspaces, tables, columns)|
342
322
  host = @registry.host(connection.host)
343
323
 
344
- @schema.update_keyspace(host, keyspaces.first, tables, columns) unless keyspaces.empty?
324
+ if keyspaces.empty?
325
+ @schema.delete_keyspace(keyspace)
326
+ else
327
+ @schema.update_keyspace(host, keyspaces.first, tables, columns)
328
+ end
345
329
  end
346
330
  end
347
331
 
348
332
  def refresh_table_async_maybe_retry(keyspace, table)
349
- synchronize do
350
- return Ione::Future.resolved if @refreshing_schema || @refreshing_keyspaces[keyspace] || @refreshing_tables[keyspace][table]
351
- @refreshing_tables[keyspace] ||= ::Hash.new(false)
352
- @refreshing_tables[keyspace][table] = true
353
- end
354
-
355
333
  refresh_table_async(keyspace, table).fallback do |e|
356
334
  case e
357
335
  when Errors::HostError
@@ -360,12 +338,7 @@ module Cassandra
360
338
  connection = @connection
361
339
  connection && connection.close(e)
362
340
 
363
- Ione::Future.resolved
364
- end
365
- end.map do
366
- synchronize do
367
- @refreshing_tables[keyspace].delete(table)
368
- @refreshing_tables.delete(keyspace) if @refreshing_tables[keyspace].empty?
341
+ Ione::Future.failed(e)
369
342
  end
370
343
  end
371
344
  end
@@ -384,7 +357,7 @@ module Cassandra
384
357
  connection = @connection
385
358
  connection && connection.close(e)
386
359
 
387
- Ione::Future.resolved
360
+ Ione::Future.failed(e)
388
361
  end
389
362
  end
390
363
  end
@@ -396,13 +369,17 @@ module Cassandra
396
369
  return Ione::Future.failed(Errors::ClientError.new('Not connected')) if connection.nil?
397
370
 
398
371
  params = [keyspace, table]
399
- table = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = ? AND columnfamily_name = ?", params, nil, :one))
400
- columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = ? AND columnfamily_name = ?", params, nil, :one))
372
+ tables = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, nil, nil, :one))
373
+ columns = send_select_request(connection, Protocol::QueryRequest.new("SELECT * FROM system.schema_columns WHERE keyspace_name = '%s' AND columnfamily_name = '%s'" % params, nil, nil, :one))
401
374
 
402
- Ione::Future.all(table, columns).map do |(table, columns)|
375
+ Ione::Future.all(tables, columns).map do |(tables, columns)|
403
376
  host = @registry.host(connection.host)
404
377
 
405
- @schema.udpate_table(host, keyspace, table, columns)
378
+ if tables.empty?
379
+ @schema.delete_table(keyspace, table)
380
+ else
381
+ @schema.udpate_table(host, keyspace, tables.first, columns)
382
+ end
406
383
  end
407
384
  end
408
385
 
@@ -420,7 +397,7 @@ module Cassandra
420
397
  connection = @connection
421
398
  connection && connection.close(e)
422
399
 
423
- Ione::Future.resolved
400
+ Ione::Future.failed(e)
424
401
  end
425
402
  end.map do
426
403
  synchronize do
@@ -443,7 +420,7 @@ module Cassandra
443
420
  connection = @connection
444
421
  connection && connection.close(e)
445
422
 
446
- Ione::Future.resolved
423
+ Ione::Future.failed(e)
447
424
  end
448
425
  end
449
426
  end
@@ -469,6 +446,7 @@ module Cassandra
469
446
  @metadata.update(data)
470
447
  end
471
448
 
449
+ peers.shuffle!
472
450
  peers.each do |data|
473
451
  ip = peer_ip(data)
474
452
  next unless ip
@@ -525,7 +503,7 @@ module Cassandra
525
503
  connection = @connection
526
504
  connection && connection.close(e)
527
505
 
528
- Ione::Future.resolved
506
+ Ione::Future.failed(e)
529
507
  end
530
508
  end.map do
531
509
  synchronize do
@@ -548,7 +526,7 @@ module Cassandra
548
526
  connection = @connection
549
527
  connection && connection.close(e)
550
528
 
551
- Ione::Future.resolved
529
+ Ione::Future.failed(e)
552
530
  end
553
531
  end
554
532
  end
@@ -563,7 +541,7 @@ module Cassandra
563
541
  if ip == connection.host
564
542
  request = SELECT_LOCAL
565
543
  else
566
- request = Protocol::QueryRequest.new('SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = ?', [address], nil, :one)
544
+ request = Protocol::QueryRequest.new("SELECT rack, data_center, host_id, rpc_address, release_version, tokens FROM system.peers WHERE peer = '%s'" % address, nil, nil, :one)
567
545
  end
568
546
 
569
547
  send_select_request(connection, request).map do |rows|
@@ -662,6 +640,92 @@ Control connection failed and is unlikely to recover.
662
640
  @address_resolver.resolve(ip)
663
641
  end
664
642
 
643
+ def process_schema_changes(schema_changes)
644
+ refresh_keyspaces = ::Hash.new
645
+ refresh_tables = ::Hash.new
646
+
647
+ schema_changes.each do |change|
648
+ keyspace = change.keyspace
649
+ table = change.table
650
+
651
+ next if refresh_keyspaces.has_key?(keyspace)
652
+
653
+ if table.empty?
654
+ refresh_tables.delete(keyspace)
655
+ refresh_keyspaces[keyspace] = true
656
+ else
657
+ tables = refresh_tables[keyspace] ||= ::Hash.new
658
+ tables[table] = true
659
+ end
660
+ end
661
+
662
+ futures = ::Array.new
663
+
664
+ refresh_keyspaces.each do |(keyspace, _)|
665
+ futures << refresh_keyspace_async_maybe_retry(keyspace)
666
+ end
667
+
668
+ refresh_tables.each do |(keyspace, tables)|
669
+ tables.each do |(table, _)|
670
+ futures << refresh_table_async_maybe_retry(keyspace, table)
671
+ end
672
+ end
673
+
674
+ Ione::Future.all(*futures)
675
+ end
676
+
677
+ def handle_schema_change(change)
678
+ timer = nil
679
+ expiration_timer = nil
680
+
681
+ synchronize do
682
+ @schema_changes << change
683
+
684
+ @io_reactor.cancel_timer(@schema_refresh_timer) if @schema_refresh_timer
685
+ timer = @schema_refresh_timer = @io_reactor.schedule_timer(@connection_options.schema_refresh_delay)
686
+
687
+ unless @schema_refresh_window
688
+ expiration_timer = @schema_refresh_window = @io_reactor.schedule_timer(@connection_options.schema_refresh_timeout)
689
+ end
690
+ end
691
+
692
+ if expiration_timer
693
+ expiration_timer.on_value do
694
+ schema_changes = nil
695
+
696
+ synchronize do
697
+ @io_reactor.cancel_timer(@schema_refresh_timer)
698
+
699
+ @schema_refresh_window = nil
700
+ @schema_refresh_timer = nil
701
+
702
+ schema_changes = @schema_changes
703
+ @schema_changes = ::Array.new
704
+ end
705
+
706
+ process_schema_changes(schema_changes)
707
+ end
708
+ end
709
+
710
+ timer.on_value do
711
+ schema_changes = nil
712
+
713
+ synchronize do
714
+ @io_reactor.cancel_timer(@schema_refresh_window)
715
+
716
+ @schema_refresh_window = nil
717
+ @schema_refresh_timer = nil
718
+
719
+ schema_changes = @schema_changes
720
+ @schema_changes = ::Array.new
721
+ end
722
+
723
+ process_schema_changes(schema_changes)
724
+ end
725
+
726
+ nil
727
+ end
728
+
665
729
  def send_select_request(connection, request)
666
730
  connection.send_request(request).map do |r|
667
731
  case r
@@ -17,21 +17,19 @@
17
17
  #++
18
18
 
19
19
  module Cassandra
20
- module Client
20
+ class Cluster
21
21
  # @private
22
- class NullLogger
23
- def close(*); end
24
- def debug(*); end
25
- def debug?; false end
26
- def error(*); end
27
- def error?; false end
28
- def fatal(*); end
29
- def fatal?; false end
30
- def info(*); end
31
- def info?; false end
32
- def unknown(*); end
33
- def warn(*); end
34
- def warn?; false end
22
+ class FailedConnection
23
+ attr_reader :error, :host
24
+
25
+ def initialize(error, host)
26
+ @error = error
27
+ @host = host
28
+ end
29
+
30
+ def connected?
31
+ false
32
+ end
35
33
  end
36
34
  end
37
35
  end