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.
- checksums.yaml +4 -4
- data/README.md +58 -18
- data/lib/cassandra.rb +132 -93
- data/lib/cassandra/auth.rb +3 -3
- data/lib/cassandra/cluster.rb +65 -39
- data/lib/cassandra/cluster/client.rb +67 -28
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +9 -3
- data/lib/cassandra/cluster/connector.rb +101 -30
- data/lib/cassandra/cluster/control_connection.rb +160 -96
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +26 -11
- data/lib/cassandra/cluster/schema.rb +22 -1
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/driver.rb +46 -12
- data/lib/cassandra/errors.rb +5 -5
- data/lib/cassandra/execution/options.rb +42 -8
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/executors.rb +111 -0
- data/lib/cassandra/future.rb +88 -64
- data/lib/cassandra/keyspace.rb +12 -0
- data/lib/cassandra/load_balancing.rb +10 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +10 -5
- data/lib/cassandra/load_balancing/policies/round_robin.rb +7 -5
- data/lib/cassandra/load_balancing/policies/token_aware.rb +31 -10
- data/lib/cassandra/load_balancing/policies/white_list.rb +4 -7
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +8 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/result.rb +34 -9
- data/lib/cassandra/session.rb +6 -0
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +5 -0
- data/lib/cassandra/util.rb +130 -0
- data/lib/cassandra/version.rb +1 -1
- metadata +40 -50
- data/lib/cassandra/client.rb +0 -144
- data/lib/cassandra/client/batch.rb +0 -212
- data/lib/cassandra/client/client.rb +0 -591
- data/lib/cassandra/client/column_metadata.rb +0 -54
- data/lib/cassandra/client/connector.rb +0 -273
- data/lib/cassandra/client/execute_options_decoder.rb +0 -59
- data/lib/cassandra/client/peer_discovery.rb +0 -50
- data/lib/cassandra/client/prepared_statement.rb +0 -314
- data/lib/cassandra/client/query_result.rb +0 -230
- data/lib/cassandra/client/request_runner.rb +0 -70
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
data/lib/cassandra/future.rb
CHANGED
@@ -161,18 +161,64 @@ module Cassandra
|
|
161
161
|
end
|
162
162
|
end
|
163
163
|
|
164
|
+
# @private
|
165
|
+
class Factory
|
166
|
+
def initialize(executor)
|
167
|
+
@executor = executor
|
168
|
+
end
|
169
|
+
|
170
|
+
def value(value)
|
171
|
+
Value.new(value)
|
172
|
+
end
|
173
|
+
|
174
|
+
def error(error)
|
175
|
+
Error.new(error)
|
176
|
+
end
|
177
|
+
|
178
|
+
def promise
|
179
|
+
Promise.new(@executor)
|
180
|
+
end
|
181
|
+
|
182
|
+
def all(*futures)
|
183
|
+
futures = Array(futures.first) if futures.one?
|
184
|
+
monitor = Monitor.new
|
185
|
+
promise = Promise.new(@executor)
|
186
|
+
remaining = futures.length
|
187
|
+
values = Array.new(remaining)
|
188
|
+
|
189
|
+
futures.each_with_index do |future, i|
|
190
|
+
future.on_complete do |v, e|
|
191
|
+
if e
|
192
|
+
promise.break(e)
|
193
|
+
else
|
194
|
+
done = false
|
195
|
+
monitor.synchronize do
|
196
|
+
remaining -= 1
|
197
|
+
done = (remaining == 0)
|
198
|
+
values[i] = v
|
199
|
+
end
|
200
|
+
promise.fulfill(values) if done
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
@@factory = Factory.new(Executors::SameThread.new)
|
209
|
+
|
164
210
|
# Returns a future resolved to a given value
|
165
211
|
# @param value [Object] value for the future
|
166
212
|
# @return [Cassandra::Future<Object>] a future value
|
167
213
|
def self.value(value)
|
168
|
-
|
214
|
+
@@factory.value(value)
|
169
215
|
end
|
170
216
|
|
171
217
|
# Returns a future resolved to a given error
|
172
218
|
# @param error [Exception] error for the future
|
173
219
|
# @return [Cassandra::Future<Exception>] a future error
|
174
220
|
def self.error(error)
|
175
|
-
|
221
|
+
@@factory.error(error)
|
176
222
|
end
|
177
223
|
|
178
224
|
# Returns a future that resolves with values of all futures
|
@@ -184,35 +230,7 @@ module Cassandra
|
|
184
230
|
# combine
|
185
231
|
# @return [Cassandra::Future<Array<Object>>] a combined future
|
186
232
|
def self.all(*futures)
|
187
|
-
|
188
|
-
monitor = Monitor.new
|
189
|
-
promise = Promise.new
|
190
|
-
remaining = futures.length
|
191
|
-
values = Array.new(remaining)
|
192
|
-
|
193
|
-
futures.each_with_index do |future, i|
|
194
|
-
future.on_complete do |v, e|
|
195
|
-
if e
|
196
|
-
promise.break(e)
|
197
|
-
else
|
198
|
-
done = false
|
199
|
-
monitor.synchronize do
|
200
|
-
remaining -= 1
|
201
|
-
done = (remaining == 0)
|
202
|
-
values[i] = v
|
203
|
-
end
|
204
|
-
promise.fulfill(values) if done
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
promise.future
|
210
|
-
end
|
211
|
-
|
212
|
-
# @private
|
213
|
-
# Returns a new promise instance
|
214
|
-
def self.promise
|
215
|
-
Promise.new
|
233
|
+
@@factory.all(*futures)
|
216
234
|
end
|
217
235
|
|
218
236
|
# @private
|
@@ -220,24 +238,6 @@ module Cassandra
|
|
220
238
|
@signal = signal
|
221
239
|
end
|
222
240
|
|
223
|
-
# Returns future value or raises future error
|
224
|
-
# @note This method blocks until a future is resolved
|
225
|
-
# @raise [Exception] error used to resolve this future if any
|
226
|
-
# @return [Object] value used to resolve this future if any
|
227
|
-
def get
|
228
|
-
@signal.get
|
229
|
-
end
|
230
|
-
|
231
|
-
# Block until the future has been resolved
|
232
|
-
# @note This method blocks until a future is resolved
|
233
|
-
# @note This method won't raise any errors or return anything but the
|
234
|
-
# future itself
|
235
|
-
# @return [self]
|
236
|
-
def join
|
237
|
-
@signal.join
|
238
|
-
self
|
239
|
-
end
|
240
|
-
|
241
241
|
# Run block when future resolves to a value
|
242
242
|
# @note The block can be called synchronously from current thread if the
|
243
243
|
# future has already been resolved, or, asynchronously, from background
|
@@ -348,6 +348,25 @@ module Cassandra
|
|
348
348
|
raise ::ArgumentError, "no block given" unless block_given?
|
349
349
|
@signal.fallback(&block)
|
350
350
|
end
|
351
|
+
|
352
|
+
# Returns future value or raises future error
|
353
|
+
# @note This method blocks until a future is resolved
|
354
|
+
# @raise [Exception] error used to resolve this future if any
|
355
|
+
# @return [Object] value used to resolve this future if any
|
356
|
+
def get
|
357
|
+
@signal.get
|
358
|
+
|
359
|
+
end
|
360
|
+
|
361
|
+
# Block until the future has been resolved
|
362
|
+
# @note This method blocks until a future is resolved
|
363
|
+
# @note This method won't raise any errors or return anything but the
|
364
|
+
# future itself
|
365
|
+
# @return [self]
|
366
|
+
def join
|
367
|
+
@signal.join
|
368
|
+
self
|
369
|
+
end
|
351
370
|
end
|
352
371
|
|
353
372
|
# @private
|
@@ -455,10 +474,11 @@ module Cassandra
|
|
455
474
|
|
456
475
|
include MonitorMixin
|
457
476
|
|
458
|
-
def initialize
|
477
|
+
def initialize(executor)
|
459
478
|
mon_initialize
|
460
479
|
|
461
480
|
@cond = new_cond
|
481
|
+
@executor = executor
|
462
482
|
@state = :pending
|
463
483
|
@waiting = 0
|
464
484
|
@error = nil
|
@@ -484,12 +504,14 @@ module Cassandra
|
|
484
504
|
listeners, @listeners = @listeners, nil
|
485
505
|
end
|
486
506
|
|
487
|
-
|
488
|
-
|
489
|
-
|
507
|
+
@executor.execute do
|
508
|
+
listeners.each do |listener|
|
509
|
+
listener.failure(error) rescue nil
|
510
|
+
end
|
490
511
|
|
491
|
-
|
492
|
-
|
512
|
+
synchronize do
|
513
|
+
@cond.broadcast if @waiting > 0
|
514
|
+
end
|
493
515
|
end
|
494
516
|
|
495
517
|
self
|
@@ -509,12 +531,14 @@ module Cassandra
|
|
509
531
|
listeners, @listeners = @listeners, nil
|
510
532
|
end
|
511
533
|
|
512
|
-
|
513
|
-
|
514
|
-
|
534
|
+
@executor.execute do
|
535
|
+
listeners.each do |listener|
|
536
|
+
listener.success(value) rescue nil
|
537
|
+
end
|
515
538
|
|
516
|
-
|
517
|
-
|
539
|
+
synchronize do
|
540
|
+
@cond.broadcast if @waiting > 0
|
541
|
+
end
|
518
542
|
end
|
519
543
|
|
520
544
|
self
|
@@ -608,7 +632,7 @@ module Cassandra
|
|
608
632
|
if @state == :pending
|
609
633
|
synchronize do
|
610
634
|
if @state == :pending
|
611
|
-
promise = Promise.new
|
635
|
+
promise = Promise.new(@executor)
|
612
636
|
listener = Listeners::Then.new(promise, &block)
|
613
637
|
@listeners << listener
|
614
638
|
return promise.future
|
@@ -631,7 +655,7 @@ module Cassandra
|
|
631
655
|
if @state == :pending
|
632
656
|
synchronize do
|
633
657
|
if @state == :pending
|
634
|
-
promise = Promise.new
|
658
|
+
promise = Promise.new(@executor)
|
635
659
|
listener = Listeners::Fallback.new(promise, &block)
|
636
660
|
@listeners << listener
|
637
661
|
return promise.future
|
@@ -653,8 +677,8 @@ module Cassandra
|
|
653
677
|
|
654
678
|
attr_reader :future
|
655
679
|
|
656
|
-
def initialize
|
657
|
-
@signal = Signal.new
|
680
|
+
def initialize(executor)
|
681
|
+
@signal = Signal.new(executor)
|
658
682
|
@future = Future.new(@signal)
|
659
683
|
end
|
660
684
|
|
data/lib/cassandra/keyspace.rb
CHANGED
@@ -106,6 +106,11 @@ module Cassandra
|
|
106
106
|
end
|
107
107
|
alias :== :eql?
|
108
108
|
|
109
|
+
# @return [String] a CLI-friendly keyspace representation
|
110
|
+
def inspect
|
111
|
+
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} @name=#{@name}>"
|
112
|
+
end
|
113
|
+
|
109
114
|
# @private
|
110
115
|
def update_table(table)
|
111
116
|
tables = @tables.dup
|
@@ -113,6 +118,13 @@ module Cassandra
|
|
113
118
|
Keyspace.new(@name, @durable_writes, @replication, tables)
|
114
119
|
end
|
115
120
|
|
121
|
+
# @private
|
122
|
+
def delete_table(table_name)
|
123
|
+
tables = @tables.dup
|
124
|
+
tables.delete(table_name)
|
125
|
+
Keyspace.new(@name, @durable_writes, @replication, tables)
|
126
|
+
end
|
127
|
+
|
116
128
|
# @private
|
117
129
|
def create_partition_key(table, values)
|
118
130
|
table = @tables[table]
|
@@ -28,11 +28,21 @@ module Cassandra
|
|
28
28
|
class Policy
|
29
29
|
# Allows policy to initialize with the cluster instance. This method is
|
30
30
|
# called once before connecting to the cluster.
|
31
|
+
#
|
31
32
|
# @param cluster [Cassandra::Cluster] current cluster instance
|
32
33
|
# @return [void]
|
33
34
|
def setup(cluster)
|
34
35
|
end
|
35
36
|
|
37
|
+
# Allows policy to release any external resources it might be holding.
|
38
|
+
# This method is called once the cluster has been terminated after calling
|
39
|
+
# {Cassandra::Cluster#close}
|
40
|
+
#
|
41
|
+
# @param cluster [Cassandra::Cluster] current cluster instance
|
42
|
+
# @return [void]
|
43
|
+
def teardown(cluster)
|
44
|
+
end
|
45
|
+
|
36
46
|
# @see Cassandra::Listener#host_up
|
37
47
|
def host_up(host)
|
38
48
|
end
|
@@ -60,8 +60,13 @@ module Cassandra
|
|
60
60
|
datacenter = datacenter && String(datacenter)
|
61
61
|
max_remote_hosts_to_use = max_remote_hosts_to_use && Integer(max_remote_hosts_to_use)
|
62
62
|
|
63
|
-
|
64
|
-
|
63
|
+
unless datacenter.nil?
|
64
|
+
Util.assert_not_empty(datacenter) { "datacenter cannot be empty" }
|
65
|
+
end
|
66
|
+
|
67
|
+
unless max_remote_hosts_to_use.nil?
|
68
|
+
Util.assert(max_remote_hosts_to_use >= 0) { "max_remote_hosts_to_use must be nil or >= 0" }
|
69
|
+
end
|
65
70
|
|
66
71
|
@datacenter = datacenter
|
67
72
|
@max_remote = max_remote_hosts_to_use
|
@@ -131,12 +136,12 @@ module Cassandra
|
|
131
136
|
remote = @remote
|
132
137
|
end
|
133
138
|
|
134
|
-
|
135
|
-
total = local.size + remote.size
|
139
|
+
total = local.size + remote.size
|
136
140
|
|
137
141
|
return EMPTY_PLAN if total == 0
|
138
142
|
|
139
|
-
|
143
|
+
position = @position % total
|
144
|
+
@position = position + 1
|
140
145
|
|
141
146
|
Plan.new(local, remote, position)
|
142
147
|
end
|
@@ -37,7 +37,8 @@ module Cassandra
|
|
37
37
|
return if @remaining == 0
|
38
38
|
|
39
39
|
@remaining -= 1
|
40
|
-
index
|
40
|
+
index = @index
|
41
|
+
@index = (index + 1) % @total
|
41
42
|
|
42
43
|
@hosts[index]
|
43
44
|
end
|
@@ -117,12 +118,13 @@ module Cassandra
|
|
117
118
|
# @return [Cassandra::LoadBalancing::Plan] a rotated load balancing plan
|
118
119
|
# @see Cassandra::LoadBalancing::Policy#plan
|
119
120
|
def plan(keyspace, statement, options)
|
120
|
-
hosts
|
121
|
-
|
122
|
-
|
121
|
+
hosts = @hosts
|
122
|
+
total = hosts.size
|
123
|
+
|
123
124
|
return EMPTY_PLAN if total == 0
|
124
125
|
|
125
|
-
|
126
|
+
position = @position % total
|
127
|
+
@position = position + 1
|
126
128
|
|
127
129
|
Plan.new(hosts, position)
|
128
130
|
end
|
@@ -88,15 +88,24 @@ module Cassandra
|
|
88
88
|
# @see Cassandra::LoadBalancing::Policy#host_lost
|
89
89
|
def_delegators :@policy, :distance, :host_found, :host_up, :host_down, :host_lost
|
90
90
|
|
91
|
-
# @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
91
|
+
# @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual
|
92
|
+
# policy to filter
|
93
|
+
# @param shuffle [Boolean] (true) whether or not to shuffle the replicas
|
94
|
+
#
|
95
|
+
# @note If replicas are not shuffled (`shuffle = false`), then it is
|
96
|
+
# possibile to create hotspots in a write-heavy scenario, where most
|
97
|
+
# of the write requests will be handled by the same node(s). The
|
98
|
+
# default behavior of shuffling replicas helps mitigate this by
|
99
|
+
# universally distributing write load between replicas. However, it
|
100
|
+
# under-utilizes read caching and forces multiple replicas to cache
|
101
|
+
# the same read statements.
|
102
|
+
def initialize(wrapped_policy, shuffle = true)
|
103
|
+
methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown, :distance, :plan]
|
104
|
+
|
105
|
+
Util.assert_responds_to_all(methods, wrapped_policy) { "supplied policy must respond to #{methods.inspect}, but doesn't" }
|
106
|
+
|
107
|
+
@policy = wrapped_policy
|
108
|
+
@shuffle = !!shuffle
|
100
109
|
end
|
101
110
|
|
102
111
|
def setup(cluster)
|
@@ -105,13 +114,25 @@ module Cassandra
|
|
105
114
|
nil
|
106
115
|
end
|
107
116
|
|
117
|
+
def teardown(cluster)
|
118
|
+
@cluster = nil
|
119
|
+
@policy.teardown(cluster)
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
108
123
|
def plan(keyspace, statement, options)
|
109
124
|
return @policy.plan(keyspace, statement, options) unless @cluster
|
110
125
|
|
111
126
|
replicas = @cluster.find_replicas(keyspace, statement)
|
112
127
|
return @policy.plan(keyspace, statement, options) if replicas.empty?
|
113
128
|
|
114
|
-
|
129
|
+
if @shuffle
|
130
|
+
replicas = replicas.shuffle
|
131
|
+
else
|
132
|
+
replicas = replicas.dup
|
133
|
+
end
|
134
|
+
|
135
|
+
Plan.new(replicas, @policy, keyspace, statement, options)
|
115
136
|
end
|
116
137
|
end
|
117
138
|
end
|
@@ -35,12 +35,9 @@ module Cassandra
|
|
35
35
|
# @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual policy to filter
|
36
36
|
# @raise [ArgumentError] if arguments are of unexpected types
|
37
37
|
def initialize(ips, wrapped_policy)
|
38
|
-
|
39
|
-
methods = [:host_up, :host_down, :host_found, :host_lost, :distance, :plan]
|
40
|
-
|
41
|
-
unless methods.all? {|method| wrapped_policy.respond_to?(method)}
|
42
|
-
raise ::ArgumentError, "supplied policy must be a Cassandra::LoadBalancing::Policy, #{wrapped_policy.inspect} given"
|
43
|
-
end
|
38
|
+
Util.assert_instance_of(::Enumerable, ips) { "ips must be an Enumerable, #{ips.inspect} given" }
|
39
|
+
methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :teardown, :distance, :plan]
|
40
|
+
Util.assert_responds_to_all(methods, wrapped_policy) { "supplied policy must respond to #{methods.inspect}, but doesn't" }
|
44
41
|
|
45
42
|
@ips = ::Set.new
|
46
43
|
@policy = wrapped_policy
|
@@ -52,7 +49,7 @@ module Cassandra
|
|
52
49
|
when ::String
|
53
50
|
@ips << ::IPAddr.new(ip)
|
54
51
|
else
|
55
|
-
raise ::ArgumentError, "
|
52
|
+
raise ::ArgumentError, "each ip must be a String or IPAddr, #{ip.inspect} given"
|
56
53
|
end
|
57
54
|
end
|
58
55
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2014 DataStax, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
module Cassandra
|
20
|
+
# @private
|
21
|
+
class NullLogger
|
22
|
+
def close(*); end
|
23
|
+
def debug(*); end
|
24
|
+
def debug?; false end
|
25
|
+
def error(*); end
|
26
|
+
def error?; false end
|
27
|
+
def fatal(*); end
|
28
|
+
def fatal?; false end
|
29
|
+
def info(*); end
|
30
|
+
def info?; false end
|
31
|
+
def unknown(*); end
|
32
|
+
def warn(*); end
|
33
|
+
def warn?; false end
|
34
|
+
end
|
35
|
+
end
|