yugabyte-ycql-driver 3.2.3.1
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 +13 -0
- data/README.md +242 -0
- data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
- data/ext/cassandra_murmur3/extconf.rb +2 -0
- data/lib/cassandra/address_resolution.rb +36 -0
- data/lib/cassandra/address_resolution/policies.rb +2 -0
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
- data/lib/cassandra/address_resolution/policies/none.rb +35 -0
- data/lib/cassandra/aggregate.rb +123 -0
- data/lib/cassandra/argument.rb +51 -0
- data/lib/cassandra/attr_boolean.rb +33 -0
- data/lib/cassandra/auth.rb +100 -0
- data/lib/cassandra/auth/providers.rb +17 -0
- data/lib/cassandra/auth/providers/password.rb +65 -0
- data/lib/cassandra/cassandra_logger.rb +80 -0
- data/lib/cassandra/cluster.rb +331 -0
- data/lib/cassandra/cluster/client.rb +1612 -0
- data/lib/cassandra/cluster/connection_pool.rb +78 -0
- data/lib/cassandra/cluster/connector.rb +372 -0
- data/lib/cassandra/cluster/control_connection.rb +962 -0
- data/lib/cassandra/cluster/failed_connection.rb +35 -0
- data/lib/cassandra/cluster/metadata.rb +142 -0
- data/lib/cassandra/cluster/options.rb +145 -0
- data/lib/cassandra/cluster/registry.rb +284 -0
- data/lib/cassandra/cluster/schema.rb +405 -0
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
- data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
- data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
- data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -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/replication_strategies.rb +21 -0
- data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -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/column.rb +66 -0
- data/lib/cassandra/column_container.rb +326 -0
- data/lib/cassandra/compression.rb +69 -0
- data/lib/cassandra/compression/compressors/lz4.rb +73 -0
- data/lib/cassandra/compression/compressors/snappy.rb +69 -0
- data/lib/cassandra/custom_data.rb +53 -0
- data/lib/cassandra/driver.rb +260 -0
- data/lib/cassandra/errors.rb +784 -0
- data/lib/cassandra/execution/info.rb +69 -0
- data/lib/cassandra/execution/options.rb +267 -0
- data/lib/cassandra/execution/profile.rb +153 -0
- data/lib/cassandra/execution/profile_manager.rb +71 -0
- data/lib/cassandra/execution/trace.rb +192 -0
- data/lib/cassandra/executors.rb +113 -0
- data/lib/cassandra/function.rb +156 -0
- data/lib/cassandra/function_collection.rb +85 -0
- data/lib/cassandra/future.rb +794 -0
- data/lib/cassandra/host.rb +102 -0
- data/lib/cassandra/index.rb +118 -0
- data/lib/cassandra/keyspace.rb +473 -0
- data/lib/cassandra/listener.rb +87 -0
- data/lib/cassandra/load_balancing.rb +121 -0
- data/lib/cassandra/load_balancing/policies.rb +20 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
- data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
- data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
- data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
- data/lib/cassandra/materialized_view.rb +92 -0
- data/lib/cassandra/null_logger.rb +56 -0
- data/lib/cassandra/protocol.rb +102 -0
- data/lib/cassandra/protocol/coder.rb +1085 -0
- data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
- data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
- data/lib/cassandra/protocol/request.rb +41 -0
- data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
- data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
- data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
- data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
- data/lib/cassandra/protocol/requests/options_request.rb +39 -0
- data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
- data/lib/cassandra/protocol/requests/query_request.rb +112 -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 +28 -0
- data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
- data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
- data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
- data/lib/cassandra/protocol/responses/error_response.rb +142 -0
- data/lib/cassandra/protocol/responses/event_response.rb +30 -0
- data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
- data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
- data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
- data/lib/cassandra/protocol/responses/result_response.rb +42 -0
- data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
- data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
- data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
- data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
- data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
- data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
- data/lib/cassandra/protocol/v1.rb +326 -0
- data/lib/cassandra/protocol/v3.rb +358 -0
- data/lib/cassandra/protocol/v4.rb +478 -0
- data/lib/cassandra/reconnection.rb +49 -0
- data/lib/cassandra/reconnection/policies.rb +20 -0
- data/lib/cassandra/reconnection/policies/constant.rb +46 -0
- data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
- data/lib/cassandra/result.rb +276 -0
- data/lib/cassandra/retry.rb +154 -0
- data/lib/cassandra/retry/policies.rb +21 -0
- data/lib/cassandra/retry/policies/default.rb +53 -0
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
- data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
- data/lib/cassandra/session.rb +270 -0
- data/lib/cassandra/statement.rb +32 -0
- data/lib/cassandra/statements.rb +23 -0
- data/lib/cassandra/statements/batch.rb +146 -0
- data/lib/cassandra/statements/bound.rb +65 -0
- data/lib/cassandra/statements/prepared.rb +235 -0
- data/lib/cassandra/statements/simple.rb +118 -0
- data/lib/cassandra/statements/void.rb +38 -0
- data/lib/cassandra/table.rb +240 -0
- data/lib/cassandra/time.rb +103 -0
- data/lib/cassandra/time_uuid.rb +78 -0
- data/lib/cassandra/timestamp_generator.rb +37 -0
- data/lib/cassandra/timestamp_generator/simple.rb +38 -0
- data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
- data/lib/cassandra/trigger.rb +67 -0
- data/lib/cassandra/tuple.rb +131 -0
- data/lib/cassandra/types.rb +1704 -0
- data/lib/cassandra/udt.rb +443 -0
- data/lib/cassandra/util.rb +464 -0
- data/lib/cassandra/uuid.rb +110 -0
- data/lib/cassandra/uuid/generator.rb +212 -0
- data/lib/cassandra/version.rb +21 -0
- data/lib/datastax/cassandra.rb +47 -0
- data/lib/ycql.rb +842 -0
- metadata +243 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright 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
|
+
# This class encapsulates a collection of functions or aggregates.
|
|
22
|
+
# Really used internally, so it should not be documented.
|
|
23
|
+
class FunctionCollection
|
|
24
|
+
def initialize
|
|
25
|
+
@function_hash = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get the Function or Aggregate with the given name and argument-types.
|
|
29
|
+
# @param name [String] the name of the function/aggregate.
|
|
30
|
+
# @param argument_types [Array<Cassandra::Type>] list of argument-types.
|
|
31
|
+
# @return [Cassandra::Function] or [Cassandra::Aggregate] if found;
|
|
32
|
+
# nil otherwise.
|
|
33
|
+
def get(name, argument_types)
|
|
34
|
+
@function_hash[[name, argument_types]]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_or_update(function)
|
|
38
|
+
@function_hash[[function.name, function.argument_types]] = function
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def delete(name, argument_types)
|
|
42
|
+
@function_hash.delete([name, argument_types])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [Boolean] whether this FunctionCollection is equal to the other
|
|
46
|
+
def eql?(other)
|
|
47
|
+
other.is_a?(FunctionCollection) &&
|
|
48
|
+
@function_hash == other.raw_functions
|
|
49
|
+
end
|
|
50
|
+
alias == eql?
|
|
51
|
+
|
|
52
|
+
def hash
|
|
53
|
+
@function_hash.hash
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Yield or enumerate each function defined in this collection
|
|
57
|
+
# @overload each_function
|
|
58
|
+
# @yieldparam function [Cassandra::Function or Cassandra::Aggregate]
|
|
59
|
+
# current function or aggregate
|
|
60
|
+
# @return [Cassandra::FunctionCollection] self
|
|
61
|
+
# @overload each_function
|
|
62
|
+
# @return [Array<Cassandra::Function> or Array<Cassandra::Aggregate>]
|
|
63
|
+
# a list of functions or aggregates.
|
|
64
|
+
def each_function(&block)
|
|
65
|
+
if block_given?
|
|
66
|
+
@function_hash.each_value(&block)
|
|
67
|
+
self
|
|
68
|
+
else
|
|
69
|
+
@function_hash.values
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
alias functions each_function
|
|
73
|
+
|
|
74
|
+
def inspect
|
|
75
|
+
"#<Cassandra::FunctionCollection:0x#{object_id.to_s(16)} " \
|
|
76
|
+
"@function_hash=#{@function_hash.inspect}>"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
protected
|
|
80
|
+
|
|
81
|
+
def raw_functions
|
|
82
|
+
@function_hash
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,794 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
#--
|
|
4
|
+
# Copyright 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(timeout = nil)
|
|
55
|
+
raise(@error, @error.message, @error.backtrace)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
alias join get
|
|
59
|
+
|
|
60
|
+
def on_success
|
|
61
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def on_failure
|
|
66
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
67
|
+
begin
|
|
68
|
+
yield(@error)
|
|
69
|
+
rescue
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def on_complete
|
|
76
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
77
|
+
begin
|
|
78
|
+
yield(nil, @error)
|
|
79
|
+
rescue
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def add_listener(listener)
|
|
86
|
+
unless listener.respond_to?(:success) && listener.respond_to?(:failure)
|
|
87
|
+
raise ::ArgumentError, 'listener must respond to both #success and #failure'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
begin
|
|
91
|
+
listener.failure(@error)
|
|
92
|
+
rescue
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
self
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def then
|
|
99
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
100
|
+
self
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def fallback
|
|
104
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
105
|
+
|
|
106
|
+
begin
|
|
107
|
+
result = yield(@error)
|
|
108
|
+
result = Value.new(result) unless result.is_a?(Future)
|
|
109
|
+
result
|
|
110
|
+
rescue => e
|
|
111
|
+
Error.new(e)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @private
|
|
117
|
+
class Value < Future
|
|
118
|
+
def initialize(value)
|
|
119
|
+
@value = value
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def get(timeout = nil)
|
|
123
|
+
@value
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
alias join get
|
|
127
|
+
|
|
128
|
+
def on_success
|
|
129
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
130
|
+
begin
|
|
131
|
+
yield(@value)
|
|
132
|
+
rescue
|
|
133
|
+
nil
|
|
134
|
+
end
|
|
135
|
+
self
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def on_failure
|
|
139
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
140
|
+
self
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def on_complete
|
|
144
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
145
|
+
begin
|
|
146
|
+
yield(@value, nil)
|
|
147
|
+
rescue
|
|
148
|
+
nil
|
|
149
|
+
end
|
|
150
|
+
self
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def add_listener(listener)
|
|
154
|
+
unless listener.respond_to?(:success) && listener.respond_to?(:failure)
|
|
155
|
+
raise ::ArgumentError, 'listener must respond to both #success and #failure'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
begin
|
|
159
|
+
listener.success(@value)
|
|
160
|
+
rescue
|
|
161
|
+
nil
|
|
162
|
+
end
|
|
163
|
+
self
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def join
|
|
167
|
+
self
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def then
|
|
171
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
172
|
+
|
|
173
|
+
begin
|
|
174
|
+
result = yield(@value)
|
|
175
|
+
result = Value.new(result) unless result.is_a?(Future)
|
|
176
|
+
result
|
|
177
|
+
rescue => e
|
|
178
|
+
Error.new(e)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def fallback
|
|
183
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
184
|
+
self
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# @private
|
|
189
|
+
class Factory
|
|
190
|
+
def initialize(executor)
|
|
191
|
+
@executor = executor
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def value(value)
|
|
195
|
+
Value.new(value)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def error(error)
|
|
199
|
+
Error.new(error)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def promise
|
|
203
|
+
Promise.new(@executor)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def all(*futures)
|
|
207
|
+
# May get called with varargs or an array of futures. In the latter case,
|
|
208
|
+
# the first element in futures is the array of futures. Promote it.
|
|
209
|
+
futures = Array(futures.first) if futures.one?
|
|
210
|
+
|
|
211
|
+
# Special case where there are no futures to aggregate.
|
|
212
|
+
return Value.new([]) if futures.empty?
|
|
213
|
+
|
|
214
|
+
monitor = Monitor.new
|
|
215
|
+
promise = Promise.new(@executor)
|
|
216
|
+
remaining = futures.length
|
|
217
|
+
values = Array.new(remaining)
|
|
218
|
+
|
|
219
|
+
futures.each_with_index do |future, i|
|
|
220
|
+
future.on_complete do |v, e|
|
|
221
|
+
if e
|
|
222
|
+
promise.break(e)
|
|
223
|
+
else
|
|
224
|
+
done = false
|
|
225
|
+
monitor.synchronize do
|
|
226
|
+
remaining -= 1
|
|
227
|
+
done = (remaining == 0)
|
|
228
|
+
values[i] = v
|
|
229
|
+
end
|
|
230
|
+
promise.fulfill(values) if done
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
promise.future
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# @private
|
|
239
|
+
@@factory = Factory.new(Executors::SameThread.new)
|
|
240
|
+
|
|
241
|
+
# Returns a future resolved to a given value
|
|
242
|
+
# @param value [Object] value for the future
|
|
243
|
+
# @return [Cassandra::Future<Object>] a future value
|
|
244
|
+
def self.value(value)
|
|
245
|
+
@@factory.value(value)
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Returns a future resolved to a given error
|
|
249
|
+
# @param error [Exception] error for the future
|
|
250
|
+
# @return [Cassandra::Future<Exception>] a future error
|
|
251
|
+
def self.error(error)
|
|
252
|
+
@@factory.error(error)
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
# Returns a future that resolves with values of all futures
|
|
256
|
+
# @overload all(*futures)
|
|
257
|
+
# @param *futures [Cassandra::Future] futures to combine
|
|
258
|
+
# @return [Cassandra::Future<Array<Object>>] a combined future
|
|
259
|
+
# @overload all(futures)
|
|
260
|
+
# @param futures [Enumerable<Cassandra::Future>] list of futures to
|
|
261
|
+
# combine
|
|
262
|
+
# @return [Cassandra::Future<Array<Object>>] a combined future
|
|
263
|
+
def self.all(*futures)
|
|
264
|
+
@@factory.all(*futures)
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Returns a new promise instance
|
|
268
|
+
def self.promise
|
|
269
|
+
@@factory.promise
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# @private
|
|
273
|
+
def initialize(signal)
|
|
274
|
+
@signal = signal
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Run block when future resolves to a value
|
|
278
|
+
# @note The block can be called synchronously from current thread if the
|
|
279
|
+
# future has already been resolved, or, asynchronously, from background
|
|
280
|
+
# thread upon resolution.
|
|
281
|
+
# @yieldparam value [Object] a value
|
|
282
|
+
# @raise [ArgumentError] if no block given
|
|
283
|
+
# @return [self]
|
|
284
|
+
def on_success(&block)
|
|
285
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
286
|
+
@signal.on_success(&block)
|
|
287
|
+
self
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Run block when future resolves to error
|
|
291
|
+
# @note The block can be called synchronously from current thread if the
|
|
292
|
+
# future has already been resolved, or, asynchronously, from background
|
|
293
|
+
# thread upon resolution.
|
|
294
|
+
# @yieldparam error [Exception] an error
|
|
295
|
+
# @raise [ArgumentError] if no block given
|
|
296
|
+
# @return [self]
|
|
297
|
+
def on_failure(&block)
|
|
298
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
299
|
+
@signal.on_failure(&block)
|
|
300
|
+
self
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Run block when future resolves. The block will always be called with 2
|
|
304
|
+
# arguments - value and error. In case a future resolves to an error, the
|
|
305
|
+
# error argument will be non-nil.
|
|
306
|
+
# @note The block can be called synchronously from current thread if the
|
|
307
|
+
# future has already been resolved, or, asynchronously, from background
|
|
308
|
+
# thread upon resolution.
|
|
309
|
+
# @yieldparam value [Object, nil] a value or nil
|
|
310
|
+
# @yieldparam error [Exception, nil] an error or nil
|
|
311
|
+
# @raise [ArgumentError] if no block given
|
|
312
|
+
# @return [self]
|
|
313
|
+
def on_complete(&block)
|
|
314
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
315
|
+
@signal.on_complete(&block)
|
|
316
|
+
self
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Add future listener
|
|
320
|
+
# @note The listener can be notified synchronously, from current thread, if
|
|
321
|
+
# the future has already been resolved, or, asynchronously, from
|
|
322
|
+
# background thread upon resolution.
|
|
323
|
+
# @note that provided listener doesn't have to extend
|
|
324
|
+
# {Cassandra::Future::Listener}, only conform to the same interface
|
|
325
|
+
# @param listener [Cassandra::Future::Listener] an object that responds to
|
|
326
|
+
# `#success` and `#failure`
|
|
327
|
+
# @return [self]
|
|
328
|
+
def add_listener(listener)
|
|
329
|
+
unless listener.respond_to?(:success) && listener.respond_to?(:failure)
|
|
330
|
+
raise ::ArgumentError, 'listener must respond to both #success and #failure'
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
@signal.add_listener(listener)
|
|
334
|
+
self
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Returns a new future that will resolve to the result of the block.
|
|
338
|
+
# Besides regular values, block can return other futures, which will be
|
|
339
|
+
# transparently unwrapped before resolving the future from this method.
|
|
340
|
+
#
|
|
341
|
+
# @example Block returns a value
|
|
342
|
+
# future_users = session.execute_async('SELECT * FROM users WHERE user_name = ?', 'Sam')
|
|
343
|
+
# future_user = future_users.then {|users| users.first}
|
|
344
|
+
#
|
|
345
|
+
# @example Block returns a future
|
|
346
|
+
# future_statement = session.prepare_async('SELECT * FROM users WHERE user_name = ?')
|
|
347
|
+
# future_users = future_statement.then {|statement| session.execute_async(statement, 'Sam')}
|
|
348
|
+
#
|
|
349
|
+
# @note The block can be called synchronously from current thread if the
|
|
350
|
+
# future has already been resolved, or, asynchronously, from background
|
|
351
|
+
# thread upon resolution.
|
|
352
|
+
# @yieldparam value [Object] a value
|
|
353
|
+
# @yieldreturn [Cassandra::Future, Object] a future or a value to be
|
|
354
|
+
# wrapped in a future
|
|
355
|
+
# @raise [ArgumentError] if no block given
|
|
356
|
+
# @return [Cassandra::Future] a new future
|
|
357
|
+
def then(&block)
|
|
358
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
359
|
+
@signal.then(&block)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Returns a new future that will resolve to the result of the block in case
|
|
363
|
+
# of an error. Besides regular values, block can return other futures,
|
|
364
|
+
# which will be transparently unwrapped before resolving the future from
|
|
365
|
+
# this method.
|
|
366
|
+
#
|
|
367
|
+
# @example Recovering from errors
|
|
368
|
+
# future_error = session.execute_async('SELECT * FROM invalid-table')
|
|
369
|
+
# future = future_error.fallback {|error| "Execution failed with #{error.class.name}: #{error.message}"}
|
|
370
|
+
#
|
|
371
|
+
# @example Executing something else on error
|
|
372
|
+
# future_error = session.execute_async('SELECT * FROM invalid-table')
|
|
373
|
+
# future = future_error.fallback {|e| session.execute_async('SELECT * FROM another-table')}
|
|
374
|
+
#
|
|
375
|
+
# @note The block can be called synchronously from current thread if the
|
|
376
|
+
# future has already been resolved, or, asynchronously, from background
|
|
377
|
+
# thread upon resolution.
|
|
378
|
+
# @yieldparam error [Exception] an error
|
|
379
|
+
# @yieldreturn [Cassandra::Future, Object] a future or a value to be
|
|
380
|
+
# wrapped in a future
|
|
381
|
+
# @raise [ArgumentError] if no block given
|
|
382
|
+
# @return [Cassandra::Future] a new future
|
|
383
|
+
def fallback(&block)
|
|
384
|
+
raise ::ArgumentError, 'no block given' unless block_given?
|
|
385
|
+
@signal.fallback(&block)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# Returns future value or raises future error
|
|
389
|
+
#
|
|
390
|
+
# @note This method blocks until a future is resolved or a times out
|
|
391
|
+
#
|
|
392
|
+
# @param timeout [nil, Numeric] a maximum number of seconds to block
|
|
393
|
+
# current thread for while waiting for this future to resolve. Will
|
|
394
|
+
# wait indefinitely if passed `nil`.
|
|
395
|
+
#
|
|
396
|
+
# @raise [Errors::TimeoutError] raised when wait time exceeds the timeout
|
|
397
|
+
# @raise [Exception] raises when the future has been resolved with an
|
|
398
|
+
# error. The original exception will be raised.
|
|
399
|
+
#
|
|
400
|
+
# @return [Object] the value that the future has been resolved with
|
|
401
|
+
def get(timeout = nil)
|
|
402
|
+
@signal.get(timeout)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
alias join get
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# @private
|
|
409
|
+
class Promise
|
|
410
|
+
# @private
|
|
411
|
+
class Signal
|
|
412
|
+
# @private
|
|
413
|
+
module Listeners
|
|
414
|
+
class Success < Future::Listener
|
|
415
|
+
def initialize(&block)
|
|
416
|
+
@block = block
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def success(value)
|
|
420
|
+
@block.call(value)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def failure(error)
|
|
424
|
+
nil
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
class Failure < Future::Listener
|
|
429
|
+
def initialize(&block)
|
|
430
|
+
@block = block
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def success(value)
|
|
434
|
+
nil
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def failure(error)
|
|
438
|
+
@block.call(error)
|
|
439
|
+
end
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
class Complete < Future::Listener
|
|
443
|
+
def initialize(&block)
|
|
444
|
+
@block = block
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def success(value)
|
|
448
|
+
@block.call(value, nil)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def failure(error)
|
|
452
|
+
@block.call(nil, error)
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
class Then < Future::Listener
|
|
457
|
+
def initialize(promise, &block)
|
|
458
|
+
@promise = promise
|
|
459
|
+
@block = block
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def success(value)
|
|
463
|
+
result = @block.call(value)
|
|
464
|
+
|
|
465
|
+
if result.is_a?(Future)
|
|
466
|
+
@promise.observe(result)
|
|
467
|
+
else
|
|
468
|
+
@promise.fulfill(result)
|
|
469
|
+
end
|
|
470
|
+
rescue => e
|
|
471
|
+
@promise.break(e)
|
|
472
|
+
ensure
|
|
473
|
+
@promise = @block = nil
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def failure(error)
|
|
477
|
+
@promise.break(error)
|
|
478
|
+
ensure
|
|
479
|
+
@promise = @block = nil
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
class Fallback < Future::Listener
|
|
484
|
+
def initialize(promise, &block)
|
|
485
|
+
@promise = promise
|
|
486
|
+
@block = block
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
def success(value)
|
|
490
|
+
@promise.fulfill(value)
|
|
491
|
+
ensure
|
|
492
|
+
@promise = @block = nil
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
def failure(error)
|
|
496
|
+
result = @block.call(error)
|
|
497
|
+
|
|
498
|
+
if result.is_a?(Future)
|
|
499
|
+
@promise.observe(result)
|
|
500
|
+
else
|
|
501
|
+
@promise.fulfill(result)
|
|
502
|
+
end
|
|
503
|
+
rescue => e
|
|
504
|
+
@promise.break(e)
|
|
505
|
+
ensure
|
|
506
|
+
@promise = @block = nil
|
|
507
|
+
end
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
include MonitorMixin
|
|
512
|
+
|
|
513
|
+
def initialize(executor)
|
|
514
|
+
mon_initialize
|
|
515
|
+
|
|
516
|
+
@cond = new_cond
|
|
517
|
+
@executor = executor
|
|
518
|
+
@state = :pending
|
|
519
|
+
@waiting = 0
|
|
520
|
+
@error = nil
|
|
521
|
+
@value = nil
|
|
522
|
+
@listeners = []
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def failure(error)
|
|
526
|
+
raise ::ArgumentError, "error must be an exception, #{error.inspect} given" unless error.is_a?(::Exception)
|
|
527
|
+
|
|
528
|
+
return unless @state == :pending
|
|
529
|
+
|
|
530
|
+
listeners = nil
|
|
531
|
+
|
|
532
|
+
synchronize do
|
|
533
|
+
return unless @state == :pending
|
|
534
|
+
|
|
535
|
+
@error = error
|
|
536
|
+
@state = :broken
|
|
537
|
+
|
|
538
|
+
listeners = @listeners
|
|
539
|
+
@listeners = nil
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
@executor.execute do
|
|
543
|
+
listeners.each do |listener|
|
|
544
|
+
begin
|
|
545
|
+
listener.failure(error)
|
|
546
|
+
rescue
|
|
547
|
+
nil
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
synchronize do
|
|
552
|
+
@cond.broadcast if @waiting > 0
|
|
553
|
+
end
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
self
|
|
557
|
+
end
|
|
558
|
+
|
|
559
|
+
def success(value)
|
|
560
|
+
return unless @state == :pending
|
|
561
|
+
|
|
562
|
+
listeners = nil
|
|
563
|
+
|
|
564
|
+
synchronize do
|
|
565
|
+
return unless @state == :pending
|
|
566
|
+
|
|
567
|
+
@value = value
|
|
568
|
+
@state = :fulfilled
|
|
569
|
+
|
|
570
|
+
listeners = @listeners
|
|
571
|
+
@listeners = nil
|
|
572
|
+
end
|
|
573
|
+
|
|
574
|
+
@executor.execute do
|
|
575
|
+
listeners.each do |listener|
|
|
576
|
+
begin
|
|
577
|
+
listener.success(value)
|
|
578
|
+
rescue
|
|
579
|
+
nil
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
synchronize do
|
|
584
|
+
@cond.broadcast if @waiting > 0
|
|
585
|
+
end
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
self
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# @param timeout [nil, Numeric] a maximum number of seconds to block
|
|
592
|
+
# current thread for while waiting for this future to resolve. Will
|
|
593
|
+
# wait indefinitely if passed `nil`.
|
|
594
|
+
#
|
|
595
|
+
# @raise [ArgumentError] raised when a negative timeout is given
|
|
596
|
+
# @raise [Errors::TimeoutError] raised when wait time exceeds the timeout
|
|
597
|
+
# @raise [Exception] raises when the future has been resolved with an
|
|
598
|
+
# error. The original exception will be raised.
|
|
599
|
+
#
|
|
600
|
+
# @return [Object] the value that the future has been resolved with
|
|
601
|
+
def get(timeout = nil)
|
|
602
|
+
timeout &&= Float(timeout)
|
|
603
|
+
|
|
604
|
+
if timeout
|
|
605
|
+
raise ::ArgumentError, "timeout cannot be negative, #{timeout.inspect} given" if timeout < 0
|
|
606
|
+
|
|
607
|
+
start = ::Time.now
|
|
608
|
+
now = start
|
|
609
|
+
deadline = start + timeout
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
if @state == :pending
|
|
613
|
+
synchronize do
|
|
614
|
+
if @state == :pending
|
|
615
|
+
@waiting += 1
|
|
616
|
+
while @state == :pending
|
|
617
|
+
if deadline
|
|
618
|
+
@cond.wait(deadline - now)
|
|
619
|
+
now = ::Time.now
|
|
620
|
+
break if now >= deadline
|
|
621
|
+
else
|
|
622
|
+
@cond.wait
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
@waiting -= 1
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
if @state == :pending
|
|
630
|
+
total_wait = deadline - start
|
|
631
|
+
raise Errors::TimeoutError,
|
|
632
|
+
"Future did not complete within #{timeout.inspect} seconds. " \
|
|
633
|
+
"Wait time: #{total_wait.inspect}"
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
raise(@error, @error.message, @error.backtrace) if @state == :broken
|
|
638
|
+
|
|
639
|
+
@value
|
|
640
|
+
end
|
|
641
|
+
|
|
642
|
+
alias join get
|
|
643
|
+
|
|
644
|
+
def add_listener(listener)
|
|
645
|
+
if @state == :pending
|
|
646
|
+
synchronize do
|
|
647
|
+
if @state == :pending
|
|
648
|
+
@listeners << listener
|
|
649
|
+
|
|
650
|
+
return self
|
|
651
|
+
end
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
begin
|
|
656
|
+
listener.success(@value)
|
|
657
|
+
rescue
|
|
658
|
+
nil
|
|
659
|
+
end if @state == :fulfilled
|
|
660
|
+
begin
|
|
661
|
+
listener.failure(@error)
|
|
662
|
+
rescue
|
|
663
|
+
nil
|
|
664
|
+
end if @state == :broken
|
|
665
|
+
|
|
666
|
+
self
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
def on_success(&block)
|
|
670
|
+
if @state == :pending
|
|
671
|
+
synchronize do
|
|
672
|
+
if @state == :pending
|
|
673
|
+
@listeners << Listeners::Success.new(&block)
|
|
674
|
+
return self
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
begin
|
|
680
|
+
yield(@value)
|
|
681
|
+
rescue
|
|
682
|
+
nil
|
|
683
|
+
end if @state == :fulfilled
|
|
684
|
+
|
|
685
|
+
self
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
def on_failure(&block)
|
|
689
|
+
if @state == :pending
|
|
690
|
+
synchronize do
|
|
691
|
+
if @state == :pending
|
|
692
|
+
@listeners << Listeners::Failure.new(&block)
|
|
693
|
+
return self
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
begin
|
|
699
|
+
yield(@error)
|
|
700
|
+
rescue
|
|
701
|
+
nil
|
|
702
|
+
end if @state == :broken
|
|
703
|
+
|
|
704
|
+
self
|
|
705
|
+
end
|
|
706
|
+
|
|
707
|
+
def on_complete(&block)
|
|
708
|
+
if @state == :pending
|
|
709
|
+
synchronize do
|
|
710
|
+
if @state == :pending
|
|
711
|
+
@listeners << Listeners::Complete.new(&block)
|
|
712
|
+
return self
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
begin
|
|
718
|
+
yield(@value, @error)
|
|
719
|
+
rescue
|
|
720
|
+
nil
|
|
721
|
+
end
|
|
722
|
+
|
|
723
|
+
self
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def then(&block)
|
|
727
|
+
if @state == :pending
|
|
728
|
+
synchronize do
|
|
729
|
+
if @state == :pending
|
|
730
|
+
promise = Promise.new(@executor)
|
|
731
|
+
listener = Listeners::Then.new(promise, &block)
|
|
732
|
+
@listeners << listener
|
|
733
|
+
return promise.future
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
return Future::Error.new(@error) if @state == :broken
|
|
739
|
+
|
|
740
|
+
begin
|
|
741
|
+
result = yield(@value)
|
|
742
|
+
result = Future::Value.new(result) unless result.is_a?(Future)
|
|
743
|
+
result
|
|
744
|
+
rescue => e
|
|
745
|
+
Future::Error.new(e)
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def fallback(&block)
|
|
750
|
+
if @state == :pending
|
|
751
|
+
synchronize do
|
|
752
|
+
if @state == :pending
|
|
753
|
+
promise = Promise.new(@executor)
|
|
754
|
+
listener = Listeners::Fallback.new(promise, &block)
|
|
755
|
+
@listeners << listener
|
|
756
|
+
return promise.future
|
|
757
|
+
end
|
|
758
|
+
end
|
|
759
|
+
end
|
|
760
|
+
|
|
761
|
+
return Future::Value.new(@value) if @state == :fulfilled
|
|
762
|
+
|
|
763
|
+
begin
|
|
764
|
+
result = yield(@error)
|
|
765
|
+
result = Future::Value.new(result) unless result.is_a?(Future)
|
|
766
|
+
result
|
|
767
|
+
rescue => e
|
|
768
|
+
Future::Error.new(e)
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
attr_reader :future
|
|
774
|
+
|
|
775
|
+
def initialize(executor)
|
|
776
|
+
@signal = Signal.new(executor)
|
|
777
|
+
@future = Future.new(@signal)
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def break(error)
|
|
781
|
+
@signal.failure(error)
|
|
782
|
+
self
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
def fulfill(value)
|
|
786
|
+
@signal.success(value)
|
|
787
|
+
self
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
def observe(future)
|
|
791
|
+
future.add_listener(@signal)
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
end
|