cassandra-driver 1.0.0.beta.2-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 +7 -0
- data/.yardopts +4 -0
- data/README.md +125 -0
- data/lib/cassandra/auth/providers/password.rb +73 -0
- data/lib/cassandra/auth/providers.rb +16 -0
- data/lib/cassandra/auth.rb +97 -0
- data/lib/cassandra/client/batch.rb +212 -0
- data/lib/cassandra/client/client.rb +591 -0
- data/lib/cassandra/client/column_metadata.rb +54 -0
- data/lib/cassandra/client/connection_manager.rb +72 -0
- data/lib/cassandra/client/connector.rb +277 -0
- data/lib/cassandra/client/execute_options_decoder.rb +59 -0
- data/lib/cassandra/client/null_logger.rb +37 -0
- data/lib/cassandra/client/peer_discovery.rb +50 -0
- data/lib/cassandra/client/prepared_statement.rb +314 -0
- data/lib/cassandra/client/query_result.rb +230 -0
- data/lib/cassandra/client/request_runner.rb +71 -0
- data/lib/cassandra/client/result_metadata.rb +48 -0
- data/lib/cassandra/client/void_result.rb +78 -0
- data/lib/cassandra/client.rb +144 -0
- data/lib/cassandra/cluster/client.rb +768 -0
- data/lib/cassandra/cluster/connector.rb +244 -0
- data/lib/cassandra/cluster/control_connection.rb +425 -0
- data/lib/cassandra/cluster/metadata.rb +124 -0
- data/lib/cassandra/cluster/options.rb +42 -0
- data/lib/cassandra/cluster/registry.rb +198 -0
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +47 -0
- data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
- data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
- data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
- data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +92 -0
- data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
- data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
- data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
- data/lib/cassandra/cluster/schema/type_parser.rb +138 -0
- data/lib/cassandra/cluster/schema.rb +340 -0
- data/lib/cassandra/cluster.rb +215 -0
- data/lib/cassandra/column.rb +92 -0
- data/lib/cassandra/compression/compressors/lz4.rb +72 -0
- data/lib/cassandra/compression/compressors/snappy.rb +66 -0
- data/lib/cassandra/compression.rb +66 -0
- data/lib/cassandra/driver.rb +111 -0
- data/lib/cassandra/errors.rb +79 -0
- data/lib/cassandra/execution/info.rb +51 -0
- data/lib/cassandra/execution/options.rb +80 -0
- data/lib/cassandra/execution/trace.rb +152 -0
- data/lib/cassandra/future.rb +675 -0
- data/lib/cassandra/host.rb +79 -0
- data/lib/cassandra/keyspace.rb +133 -0
- data/lib/cassandra/listener.rb +87 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +149 -0
- data/lib/cassandra/load_balancing/policies/round_robin.rb +132 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
- data/lib/cassandra/load_balancing/policies/white_list.rb +90 -0
- data/lib/cassandra/load_balancing/policies.rb +19 -0
- data/lib/cassandra/load_balancing.rb +113 -0
- data/lib/cassandra/protocol/cql_byte_buffer.rb +307 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +323 -0
- data/lib/cassandra/protocol/frame_decoder.rb +128 -0
- data/lib/cassandra/protocol/frame_encoder.rb +48 -0
- data/lib/cassandra/protocol/request.rb +38 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +47 -0
- data/lib/cassandra/protocol/requests/batch_request.rb +76 -0
- data/lib/cassandra/protocol/requests/credentials_request.rb +47 -0
- data/lib/cassandra/protocol/requests/execute_request.rb +103 -0
- data/lib/cassandra/protocol/requests/options_request.rb +39 -0
- data/lib/cassandra/protocol/requests/prepare_request.rb +50 -0
- data/lib/cassandra/protocol/requests/query_request.rb +153 -0
- data/lib/cassandra/protocol/requests/register_request.rb +38 -0
- data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
- data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
- data/lib/cassandra/protocol/response.rb +38 -0
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +41 -0
- data/lib/cassandra/protocol/responses/auth_success_response.rb +41 -0
- data/lib/cassandra/protocol/responses/authenticate_response.rb +41 -0
- data/lib/cassandra/protocol/responses/detailed_error_response.rb +60 -0
- data/lib/cassandra/protocol/responses/error_response.rb +50 -0
- data/lib/cassandra/protocol/responses/event_response.rb +39 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +64 -0
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +43 -0
- data/lib/cassandra/protocol/responses/ready_response.rb +44 -0
- data/lib/cassandra/protocol/responses/result_response.rb +48 -0
- data/lib/cassandra/protocol/responses/rows_result_response.rb +139 -0
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +60 -0
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +57 -0
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +42 -0
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +44 -0
- data/lib/cassandra/protocol/responses/supported_response.rb +41 -0
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +34 -0
- data/lib/cassandra/protocol/responses/void_result_response.rb +39 -0
- data/lib/cassandra/protocol/type_converter.rb +384 -0
- data/lib/cassandra/protocol.rb +93 -0
- data/lib/cassandra/reconnection/policies/constant.rb +48 -0
- data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
- data/lib/cassandra/reconnection/policies.rb +20 -0
- data/lib/cassandra/reconnection.rb +49 -0
- data/lib/cassandra/result.rb +215 -0
- data/lib/cassandra/retry/policies/default.rb +47 -0
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +71 -0
- data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
- data/lib/cassandra/retry/policies.rb +21 -0
- data/lib/cassandra/retry.rb +142 -0
- data/lib/cassandra/session.rb +202 -0
- data/lib/cassandra/statement.rb +22 -0
- data/lib/cassandra/statements/batch.rb +95 -0
- data/lib/cassandra/statements/bound.rb +48 -0
- data/lib/cassandra/statements/prepared.rb +81 -0
- data/lib/cassandra/statements/simple.rb +58 -0
- data/lib/cassandra/statements/void.rb +33 -0
- data/lib/cassandra/statements.rb +23 -0
- data/lib/cassandra/table.rb +299 -0
- data/lib/cassandra/time_uuid.rb +142 -0
- data/lib/cassandra/util.rb +167 -0
- data/lib/cassandra/uuid.rb +104 -0
- data/lib/cassandra/version.rb +21 -0
- data/lib/cassandra.rb +428 -0
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +211 -0
|
@@ -0,0 +1,675 @@
|
|
|
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
|
+
# A Future represents a result of asynchronous execution. It can be used to
|
|
21
|
+
# block until a value is available or an error has happened, or register a
|
|
22
|
+
# listener to be notified whenever the execution is complete.
|
|
23
|
+
class Future
|
|
24
|
+
# a Future listener to be passed to {Cassandra::Future#add_listener}
|
|
25
|
+
#
|
|
26
|
+
# @note Listener methods can be called from application if a future has
|
|
27
|
+
# been resolved or failed by the time the listener is registered; or from
|
|
28
|
+
# background thread if it is resolved/failed after the listener has been
|
|
29
|
+
# registered.
|
|
30
|
+
#
|
|
31
|
+
# @abstract Actual listeners passed to {Cassandra::Future#add_listener} don't
|
|
32
|
+
# need to extend this class as long as they implement `#success` and
|
|
33
|
+
# `#failure` methods
|
|
34
|
+
class Listener
|
|
35
|
+
# @param value [Object] actual value the future has been resolved with
|
|
36
|
+
# @return [void]
|
|
37
|
+
def success(value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @param error [Exception] an exception used to fail the future
|
|
41
|
+
# @return [void]
|
|
42
|
+
def failure(error)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @private
|
|
47
|
+
class Error < Future
|
|
48
|
+
def initialize(error)
|
|
49
|
+
raise ::ArgumentError, "error must be an exception, #{error.inspect} given" unless error.is_a?(::Exception)
|
|
50
|
+
|
|
51
|
+
@error = error
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def get
|
|
55
|
+
raise(@error, @error.message, @error.backtrace)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def on_success
|
|
59
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
60
|
+
self
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def on_failure
|
|
64
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
65
|
+
yield(@error) rescue nil
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def on_complete
|
|
70
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
71
|
+
yield(nil, @error) rescue nil
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def add_listener(listener)
|
|
76
|
+
unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
|
|
77
|
+
raise ::ArgumentError, "listener must respond to both #success and #failure"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
listener.failure(@error) rescue nil
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def join
|
|
85
|
+
self
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def then
|
|
89
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def fallback
|
|
94
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
95
|
+
|
|
96
|
+
begin
|
|
97
|
+
result = yield(@error)
|
|
98
|
+
result = Value.new(result) unless result.is_a?(Future)
|
|
99
|
+
result
|
|
100
|
+
rescue => e
|
|
101
|
+
Error.new(e)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @private
|
|
107
|
+
class Value < Future
|
|
108
|
+
def initialize(value)
|
|
109
|
+
@value = value
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def get
|
|
113
|
+
@value
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def on_success
|
|
117
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
118
|
+
yield(@value) rescue nil
|
|
119
|
+
self
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def on_failure
|
|
123
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
124
|
+
self
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def on_complete
|
|
128
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
129
|
+
yield(@value, nil) rescue nil
|
|
130
|
+
self
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def add_listener(listener)
|
|
134
|
+
unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
|
|
135
|
+
raise ::ArgumentError, "listener must respond to both #success and #failure"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
listener.success(@value) rescue nil
|
|
139
|
+
self
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def join
|
|
143
|
+
self
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def then
|
|
147
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
148
|
+
|
|
149
|
+
begin
|
|
150
|
+
result = yield(@value)
|
|
151
|
+
result = Value.new(result) unless result.is_a?(Future)
|
|
152
|
+
result
|
|
153
|
+
rescue => e
|
|
154
|
+
Error.new(e)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def fallback
|
|
159
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
160
|
+
self
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Returns a future resolved to a given value
|
|
165
|
+
# @param value [Object] value for the future
|
|
166
|
+
# @return [Cassandra::Future<Object>] a future value
|
|
167
|
+
def self.value(value)
|
|
168
|
+
Value.new(value)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Returns a future resolved to a given error
|
|
172
|
+
# @param error [Exception] error for the future
|
|
173
|
+
# @return [Cassandra::Future<Exception>] a future error
|
|
174
|
+
def self.error(error)
|
|
175
|
+
Error.new(error)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Returns a future that resolves with values of all futures
|
|
179
|
+
# @overload all(*futures)
|
|
180
|
+
# @param *futures [Cassandra::Future] futures to combine
|
|
181
|
+
# @return [Cassandra::Future<Array<Object>>] a combined future
|
|
182
|
+
# @overload all(futures)
|
|
183
|
+
# @param futures [Enumerable<Cassandra::Future>] list of futures to
|
|
184
|
+
# combine
|
|
185
|
+
# @return [Cassandra::Future<Array<Object>>] a combined future
|
|
186
|
+
def self.all(*futures)
|
|
187
|
+
futures = Array(futures.first) if futures.one?
|
|
188
|
+
monitor = Monitor.new
|
|
189
|
+
promise = Promise.new
|
|
190
|
+
remaining = futures.length
|
|
191
|
+
values = Array.new(length)
|
|
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
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# @private
|
|
219
|
+
def initialize(signal)
|
|
220
|
+
@signal = signal
|
|
221
|
+
end
|
|
222
|
+
|
|
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
|
+
# Run block when future resolves to a value
|
|
242
|
+
# @note The block can be called synchronously from current thread if the
|
|
243
|
+
# future has already been resolved, or, asynchronously, from background
|
|
244
|
+
# thread upon resolution.
|
|
245
|
+
# @yieldparam value [Object] a value
|
|
246
|
+
# @raise [ArgumentError] if no block given
|
|
247
|
+
# @return [self]
|
|
248
|
+
def on_success(&block)
|
|
249
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
250
|
+
@signal.on_success(&block)
|
|
251
|
+
self
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Run block when future resolves to error
|
|
255
|
+
# @note The block can be called synchronously from current thread if the
|
|
256
|
+
# future has already been resolved, or, asynchronously, from background
|
|
257
|
+
# thread upon resolution.
|
|
258
|
+
# @yieldparam error [Exception] an error
|
|
259
|
+
# @raise [ArgumentError] if no block given
|
|
260
|
+
# @return [self]
|
|
261
|
+
def on_failure(&block)
|
|
262
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
263
|
+
@signal.on_failure(&block)
|
|
264
|
+
self
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Run block when future resolves. The block will always be called with 2
|
|
268
|
+
# arguments - value and error. In case a future resolves to an error, the
|
|
269
|
+
# error argument will be non-nil.
|
|
270
|
+
# @note The block can be called synchronously from current thread if the
|
|
271
|
+
# future has already been resolved, or, asynchronously, from background
|
|
272
|
+
# thread upon resolution.
|
|
273
|
+
# @yieldparam value [Object, nil] a value or nil
|
|
274
|
+
# @yieldparam error [Exception, nil] an error or nil
|
|
275
|
+
# @raise [ArgumentError] if no block given
|
|
276
|
+
# @return [self]
|
|
277
|
+
def on_complete(&block)
|
|
278
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
279
|
+
@signal.on_complete(&block)
|
|
280
|
+
self
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# Add future listener
|
|
284
|
+
# @note The listener can be notified synchronously, from current thread, if
|
|
285
|
+
# the future has already been resolved, or, asynchronously, from
|
|
286
|
+
# background thread upon resolution.
|
|
287
|
+
# @note that provided listener doesn't have to extend
|
|
288
|
+
# {Cassandra::Future::Listener}, only conform to the same interface
|
|
289
|
+
# @param listener [Cassandra::Future::Listener] an object that responds to
|
|
290
|
+
# `#success` and `#failure`
|
|
291
|
+
# @return [self]
|
|
292
|
+
def add_listener(listener)
|
|
293
|
+
unless (listener.respond_to?(:success) && listener.respond_to?(:failure))
|
|
294
|
+
raise ::ArgumentError, "listener must respond to both #success and #failure"
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
@signal.add_listener(listener)
|
|
298
|
+
self
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Returns a new future that will resolve to the result of the block.
|
|
302
|
+
# Besides regular values, block can return other futures, which will be
|
|
303
|
+
# transparently unwrapped before resolving the future from this method.
|
|
304
|
+
#
|
|
305
|
+
# @example Block returns a value
|
|
306
|
+
# future_users = session.execute_async('SELECT * FROM users WHERE user_name = ?', 'Sam')
|
|
307
|
+
# future_user = future_users.then {|users| users.first}
|
|
308
|
+
#
|
|
309
|
+
# @example Block returns a future
|
|
310
|
+
# future_statement = session.prepare_async('SELECT * FROM users WHERE user_name = ?')
|
|
311
|
+
# future_users = future_statement.then {|statement| session.execute_async(statement, 'Sam')}
|
|
312
|
+
#
|
|
313
|
+
# @note The block can be called synchronously from current thread if the
|
|
314
|
+
# future has already been resolved, or, asynchronously, from background
|
|
315
|
+
# thread upon resolution.
|
|
316
|
+
# @yieldparam value [Object] a value
|
|
317
|
+
# @yieldreturn [Cassandra::Future, Object] a future or a value to be
|
|
318
|
+
# wrapped in a future
|
|
319
|
+
# @raise [ArgumentError] if no block given
|
|
320
|
+
# @return [Cassandra::Future] a new future
|
|
321
|
+
def then(&block)
|
|
322
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
323
|
+
@signal.then(&block)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Returns a new future that will resolve to the result of the block in case
|
|
327
|
+
# of an error. Besides regular values, block can return other futures,
|
|
328
|
+
# which will be transparently unwrapped before resolving the future from
|
|
329
|
+
# this method.
|
|
330
|
+
#
|
|
331
|
+
# @example Recovering from errors
|
|
332
|
+
# future_error = session.execute_async('SELECT * FROM invalid-table')
|
|
333
|
+
# future = future_error.fallback {|error| "Execution failed with #{error.class.name}: #{error.message}"}
|
|
334
|
+
#
|
|
335
|
+
# @example Executing something else on error
|
|
336
|
+
# future_error = session.execute_async('SELECT * FROM invalid-table')
|
|
337
|
+
# future = future_error.fallback {|e| session.execute_async('SELECT * FROM another-table')}
|
|
338
|
+
#
|
|
339
|
+
# @note The block can be called synchronously from current thread if the
|
|
340
|
+
# future has already been resolved, or, asynchronously, from background
|
|
341
|
+
# thread upon resolution.
|
|
342
|
+
# @yieldparam error [Exception] an error
|
|
343
|
+
# @yieldreturn [Cassandra::Future, Object] a future or a value to be
|
|
344
|
+
# wrapped in a future
|
|
345
|
+
# @raise [ArgumentError] if no block given
|
|
346
|
+
# @return [Cassandra::Future] a new future
|
|
347
|
+
def fallback(&block)
|
|
348
|
+
raise ::ArgumentError, "no block given" unless block_given?
|
|
349
|
+
@signal.fallback(&block)
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# @private
|
|
354
|
+
class Promise
|
|
355
|
+
# @private
|
|
356
|
+
class Signal
|
|
357
|
+
# @private
|
|
358
|
+
module Listeners
|
|
359
|
+
class Success < Future::Listener
|
|
360
|
+
def initialize(&block)
|
|
361
|
+
@block = block
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def success(value)
|
|
365
|
+
@block.call(value)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def failure(error)
|
|
369
|
+
nil
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
class Failure < Future::Listener
|
|
374
|
+
def initialize(&block)
|
|
375
|
+
@block = block
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def success(value)
|
|
379
|
+
nil
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def failure(error)
|
|
383
|
+
@block.call(error)
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
class Complete < Future::Listener
|
|
388
|
+
def initialize(&block)
|
|
389
|
+
@block = block
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def success(value)
|
|
393
|
+
@block.call(nil, value)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def failure(error)
|
|
397
|
+
@block.call(error, nil)
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
class Then < Future::Listener
|
|
402
|
+
def initialize(promise, &block)
|
|
403
|
+
@promise = promise
|
|
404
|
+
@block = block
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
def success(value)
|
|
408
|
+
result = @block.call(value)
|
|
409
|
+
|
|
410
|
+
if result.is_a?(Future)
|
|
411
|
+
@promise.observe(result)
|
|
412
|
+
else
|
|
413
|
+
@promise.fulfill(result)
|
|
414
|
+
end
|
|
415
|
+
rescue => e
|
|
416
|
+
@promise.break(e)
|
|
417
|
+
ensure
|
|
418
|
+
@promise = @block = nil
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def failure(error)
|
|
422
|
+
@promise.break(error)
|
|
423
|
+
ensure
|
|
424
|
+
@promise = @block = nil
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
class Fallback < Future::Listener
|
|
429
|
+
def initialize(promise, &block)
|
|
430
|
+
@promise = promise
|
|
431
|
+
@block = block
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def success(value)
|
|
435
|
+
@promise.fulfill(value)
|
|
436
|
+
ensure
|
|
437
|
+
@promise = @block = nil
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def failure(error)
|
|
441
|
+
result = @block.call(error)
|
|
442
|
+
|
|
443
|
+
if result.is_a?(Future)
|
|
444
|
+
@promise.observe(result)
|
|
445
|
+
else
|
|
446
|
+
@promise.fulfill(result)
|
|
447
|
+
end
|
|
448
|
+
rescue => e
|
|
449
|
+
@promise.break(e)
|
|
450
|
+
ensure
|
|
451
|
+
@promise = @block = nil
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
include MonitorMixin
|
|
457
|
+
|
|
458
|
+
def initialize
|
|
459
|
+
mon_initialize
|
|
460
|
+
|
|
461
|
+
@cond = new_cond
|
|
462
|
+
@state = :pending
|
|
463
|
+
@waiting = 0
|
|
464
|
+
@error = nil
|
|
465
|
+
@value = nil
|
|
466
|
+
@listeners = []
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def failure(error)
|
|
470
|
+
unless error.is_a?(::Exception)
|
|
471
|
+
raise ::ArgumentError, "error must be an exception, #{error.inspect} given"
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
return unless @state == :pending
|
|
475
|
+
|
|
476
|
+
listeners = nil
|
|
477
|
+
|
|
478
|
+
synchronize do
|
|
479
|
+
return unless @state == :pending
|
|
480
|
+
|
|
481
|
+
@error = error
|
|
482
|
+
@state = :broken
|
|
483
|
+
|
|
484
|
+
listeners, @listeners = @listeners, nil
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
listeners.each do |listener|
|
|
488
|
+
listener.failure(error) rescue nil
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
synchronize do
|
|
492
|
+
@cond.broadcast if @waiting > 0
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
self
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
def success(value)
|
|
499
|
+
return unless @state == :pending
|
|
500
|
+
|
|
501
|
+
listeners = nil
|
|
502
|
+
|
|
503
|
+
synchronize do
|
|
504
|
+
return unless @state == :pending
|
|
505
|
+
|
|
506
|
+
@value = value
|
|
507
|
+
@state = :fulfilled
|
|
508
|
+
|
|
509
|
+
listeners, @listeners = @listeners, nil
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
listeners.each do |listener|
|
|
513
|
+
listener.success(value) rescue nil
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
synchronize do
|
|
517
|
+
@cond.broadcast if @waiting > 0
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
self
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def join
|
|
524
|
+
return unless @state == :pending
|
|
525
|
+
|
|
526
|
+
synchronize do
|
|
527
|
+
return unless @state == :pending
|
|
528
|
+
|
|
529
|
+
@waiting += 1
|
|
530
|
+
@cond.wait while @state == :pending
|
|
531
|
+
@waiting -= 1
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
nil
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
def get
|
|
538
|
+
join if @state == :pending
|
|
539
|
+
|
|
540
|
+
raise(@error, @error.message, @error.backtrace) if @state == :broken
|
|
541
|
+
|
|
542
|
+
@value
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
def add_listener(listener)
|
|
546
|
+
if @state == :pending
|
|
547
|
+
synchronize do
|
|
548
|
+
if @state == :pending
|
|
549
|
+
@listeners << listener
|
|
550
|
+
|
|
551
|
+
return self
|
|
552
|
+
end
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
listener.success(@value) rescue nil if @state == :fulfilled
|
|
557
|
+
listener.failure(@error) rescue nil if @state == :broken
|
|
558
|
+
|
|
559
|
+
self
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def on_success(&block)
|
|
563
|
+
if @state == :pending
|
|
564
|
+
synchronize do
|
|
565
|
+
if @state == :pending
|
|
566
|
+
@listeners << Listeners::Success.new(&block)
|
|
567
|
+
return self
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
yield(@value) rescue nil if @state == :fulfilled
|
|
573
|
+
|
|
574
|
+
self
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def on_failure(&block)
|
|
578
|
+
if @state == :pending
|
|
579
|
+
synchronize do
|
|
580
|
+
if @state == :pending
|
|
581
|
+
@listeners << Listeners::Failure.new(&block)
|
|
582
|
+
return self
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
yield(@error) rescue nil if @state == :broken
|
|
588
|
+
|
|
589
|
+
self
|
|
590
|
+
end
|
|
591
|
+
|
|
592
|
+
def on_complete(&block)
|
|
593
|
+
if @state == :pending
|
|
594
|
+
synchronize do
|
|
595
|
+
if @state == :pending
|
|
596
|
+
@listeners << Listeners::Complete.new(&block)
|
|
597
|
+
return self
|
|
598
|
+
end
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
yield(@value, @error) rescue nil
|
|
603
|
+
|
|
604
|
+
self
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def then(&block)
|
|
608
|
+
if @state == :pending
|
|
609
|
+
synchronize do
|
|
610
|
+
if @state == :pending
|
|
611
|
+
promise = Promise.new
|
|
612
|
+
listener = Listeners::Then.new(promise, &block)
|
|
613
|
+
@listeners << listener
|
|
614
|
+
return promise.future
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
return Future::Error.new(@error) if @state == :broken
|
|
620
|
+
|
|
621
|
+
begin
|
|
622
|
+
result = yield(@value)
|
|
623
|
+
result = Future::Value.new(result) unless result.is_a?(Future)
|
|
624
|
+
result
|
|
625
|
+
rescue => e
|
|
626
|
+
Future::Error.new(e)
|
|
627
|
+
end
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
def fallback(&block)
|
|
631
|
+
if @state == :pending
|
|
632
|
+
synchronize do
|
|
633
|
+
if @state == :pending
|
|
634
|
+
promise = Promise.new
|
|
635
|
+
listener = Listeners::Fallback.new(promise, &block)
|
|
636
|
+
@listeners << listener
|
|
637
|
+
return promise.future
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
return Future::Value.new(@value) if @state == :fulfilled
|
|
643
|
+
|
|
644
|
+
begin
|
|
645
|
+
result = yield(@error)
|
|
646
|
+
result = Future::Value.new(result) unless result.is_a?(Future)
|
|
647
|
+
result
|
|
648
|
+
rescue => e
|
|
649
|
+
Future::Error.new(e)
|
|
650
|
+
end
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
|
|
654
|
+
attr_reader :future
|
|
655
|
+
|
|
656
|
+
def initialize
|
|
657
|
+
@signal = Signal.new
|
|
658
|
+
@future = Future.new(@signal)
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
def break(error)
|
|
662
|
+
@signal.failure(error)
|
|
663
|
+
self
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
def fulfill(value)
|
|
667
|
+
@signal.success(value)
|
|
668
|
+
self
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def observe(future)
|
|
672
|
+
future.add_listener(@signal)
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|