cassandra-driver 3.0.0.beta.1-java → 3.0.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 +106 -39
- data/lib/cassandra.rb +396 -148
- data/lib/cassandra/address_resolution.rb +1 -1
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +1 -1
- data/lib/cassandra/address_resolution/policies/none.rb +1 -1
- data/lib/cassandra/aggregate.rb +21 -7
- data/lib/cassandra/argument.rb +2 -2
- data/lib/cassandra/attr_boolean.rb +33 -0
- data/lib/cassandra/auth.rb +6 -5
- data/lib/cassandra/auth/providers.rb +1 -1
- data/lib/cassandra/auth/providers/password.rb +5 -13
- data/lib/cassandra/cassandra_logger.rb +80 -0
- data/lib/cassandra/cluster.rb +49 -9
- data/lib/cassandra/cluster/client.rb +835 -209
- data/lib/cassandra/cluster/connection_pool.rb +2 -2
- data/lib/cassandra/cluster/connector.rb +86 -27
- data/lib/cassandra/cluster/control_connection.rb +222 -95
- data/lib/cassandra/cluster/failed_connection.rb +1 -1
- data/lib/cassandra/cluster/metadata.rb +14 -8
- data/lib/cassandra/cluster/options.rb +68 -22
- data/lib/cassandra/cluster/registry.rb +81 -17
- data/lib/cassandra/cluster/schema.rb +70 -8
- data/lib/cassandra/cluster/schema/cql_type_parser.rb +15 -10
- data/lib/cassandra/cluster/schema/fetchers.rb +601 -241
- data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +39 -38
- data/lib/cassandra/cluster/schema/partitioners.rb +1 -1
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +6 -8
- data/lib/cassandra/cluster/schema/partitioners/ordered.rb +1 -1
- data/lib/cassandra/cluster/schema/partitioners/random.rb +1 -1
- data/lib/cassandra/cluster/schema/replication_strategies.rb +1 -1
- data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +19 -18
- data/lib/cassandra/cluster/schema/replication_strategies/none.rb +1 -1
- data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +1 -1
- data/lib/cassandra/column.rb +4 -23
- data/lib/cassandra/column_container.rb +322 -0
- data/lib/cassandra/compression.rb +1 -1
- data/lib/cassandra/compression/compressors/lz4.rb +7 -8
- data/lib/cassandra/compression/compressors/snappy.rb +4 -3
- data/lib/cassandra/driver.rb +107 -46
- data/lib/cassandra/errors.rb +303 -52
- data/lib/cassandra/execution/info.rb +16 -5
- data/lib/cassandra/execution/options.rb +102 -55
- data/lib/cassandra/execution/trace.rb +16 -9
- data/lib/cassandra/executors.rb +1 -1
- data/lib/cassandra/function.rb +19 -13
- data/lib/cassandra/function_collection.rb +85 -0
- data/lib/cassandra/future.rb +101 -49
- data/lib/cassandra/host.rb +25 -5
- data/lib/cassandra/index.rb +118 -0
- data/lib/cassandra/keyspace.rb +169 -33
- data/lib/cassandra/listener.rb +1 -1
- data/lib/cassandra/load_balancing.rb +2 -2
- data/lib/cassandra/load_balancing/policies.rb +1 -1
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +39 -25
- data/lib/cassandra/load_balancing/policies/round_robin.rb +8 -1
- data/lib/cassandra/load_balancing/policies/token_aware.rb +22 -13
- data/lib/cassandra/load_balancing/policies/white_list.rb +18 -5
- data/lib/cassandra/materialized_view.rb +90 -0
- data/lib/cassandra/null_logger.rb +27 -6
- data/lib/cassandra/protocol.rb +1 -1
- data/lib/cassandra/protocol/coder.rb +81 -42
- data/lib/cassandra/protocol/cql_byte_buffer.rb +58 -44
- data/lib/cassandra/protocol/cql_protocol_handler.rb +57 -54
- data/lib/cassandra/protocol/request.rb +6 -7
- data/lib/cassandra/protocol/requests/auth_response_request.rb +3 -3
- data/lib/cassandra/protocol/requests/batch_request.rb +17 -8
- data/lib/cassandra/protocol/requests/credentials_request.rb +3 -3
- data/lib/cassandra/protocol/requests/execute_request.rb +39 -20
- data/lib/cassandra/protocol/requests/options_request.rb +1 -1
- data/lib/cassandra/protocol/requests/prepare_request.rb +5 -5
- data/lib/cassandra/protocol/requests/query_request.rb +28 -23
- data/lib/cassandra/protocol/requests/register_request.rb +2 -2
- data/lib/cassandra/protocol/requests/startup_request.rb +8 -8
- data/lib/cassandra/protocol/requests/void_query_request.rb +1 -1
- data/lib/cassandra/protocol/response.rb +3 -4
- data/lib/cassandra/protocol/responses/already_exists_error_response.rb +12 -2
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +4 -5
- data/lib/cassandra/protocol/responses/auth_success_response.rb +4 -5
- data/lib/cassandra/protocol/responses/authenticate_response.rb +4 -5
- data/lib/cassandra/protocol/responses/error_response.rb +104 -17
- data/lib/cassandra/protocol/responses/event_response.rb +3 -4
- data/lib/cassandra/protocol/responses/function_failure_error_response.rb +13 -2
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +14 -9
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +14 -9
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +26 -4
- data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +22 -3
- data/lib/cassandra/protocol/responses/ready_response.rb +6 -7
- data/lib/cassandra/protocol/responses/result_response.rb +11 -10
- data/lib/cassandra/protocol/responses/rows_result_response.rb +8 -7
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +8 -8
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +19 -13
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +5 -6
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +5 -6
- data/lib/cassandra/protocol/responses/supported_response.rb +4 -5
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +4 -5
- data/lib/cassandra/protocol/responses/unavailable_error_response.rb +20 -3
- data/lib/cassandra/protocol/responses/unprepared_error_response.rb +11 -2
- data/lib/cassandra/protocol/responses/void_result_response.rb +4 -5
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +26 -4
- data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +22 -3
- data/lib/cassandra/protocol/v1.rb +98 -37
- data/lib/cassandra/protocol/v3.rb +121 -50
- data/lib/cassandra/protocol/v4.rb +172 -68
- data/lib/cassandra/reconnection.rb +1 -1
- data/lib/cassandra/reconnection/policies.rb +1 -1
- data/lib/cassandra/reconnection/policies/constant.rb +2 -4
- data/lib/cassandra/reconnection/policies/exponential.rb +6 -6
- data/lib/cassandra/result.rb +55 -20
- data/lib/cassandra/retry.rb +8 -8
- data/lib/cassandra/retry/policies.rb +1 -1
- data/lib/cassandra/retry/policies/default.rb +1 -1
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +4 -2
- data/lib/cassandra/retry/policies/fallthrough.rb +1 -1
- data/lib/cassandra/session.rb +24 -16
- data/lib/cassandra/statement.rb +1 -1
- data/lib/cassandra/statements.rb +1 -1
- data/lib/cassandra/statements/batch.rb +16 -10
- data/lib/cassandra/statements/bound.rb +10 -3
- data/lib/cassandra/statements/prepared.rb +62 -18
- data/lib/cassandra/statements/simple.rb +23 -10
- data/lib/cassandra/statements/void.rb +1 -1
- data/lib/cassandra/table.rb +53 -185
- data/lib/cassandra/time.rb +11 -6
- data/lib/cassandra/time_uuid.rb +12 -14
- 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/tuple.rb +4 -4
- data/lib/cassandra/types.rb +109 -71
- data/lib/cassandra/udt.rb +66 -50
- data/lib/cassandra/util.rb +155 -15
- data/lib/cassandra/uuid.rb +20 -21
- data/lib/cassandra/uuid/generator.rb +7 -5
- data/lib/cassandra/version.rb +2 -2
- data/lib/cassandra_murmur3.jar +0 -0
- data/lib/datastax/cassandra.rb +1 -1
- metadata +27 -16
data/lib/cassandra/aggregate.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -40,7 +40,14 @@ module Cassandra
|
|
40
40
|
attr_reader :final_function
|
41
41
|
|
42
42
|
# @private
|
43
|
-
def initialize(keyspace,
|
43
|
+
def initialize(keyspace,
|
44
|
+
name,
|
45
|
+
type,
|
46
|
+
argument_types,
|
47
|
+
state_type,
|
48
|
+
initial_state,
|
49
|
+
state_function,
|
50
|
+
final_function)
|
44
51
|
@keyspace = keyspace
|
45
52
|
@name = name
|
46
53
|
@type = type
|
@@ -63,7 +70,7 @@ module Cassandra
|
|
63
70
|
@state_function == other.state_function && \
|
64
71
|
@final_function == other.final_function
|
65
72
|
end
|
66
|
-
alias
|
73
|
+
alias == eql?
|
67
74
|
|
68
75
|
# @private
|
69
76
|
def hash
|
@@ -83,12 +90,19 @@ module Cassandra
|
|
83
90
|
|
84
91
|
# @private
|
85
92
|
def inspect
|
86
|
-
"#<Cassandra::Aggregate:0x#{
|
93
|
+
"#<Cassandra::Aggregate:0x#{object_id.to_s(16)} " \
|
94
|
+
"@keyspace=#{@keyspace.inspect}, " \
|
95
|
+
"@name=#{@name.inspect}, " \
|
96
|
+
"@type=#{@type.inspect}, " \
|
97
|
+
"@argument_types=#{@argument_types.inspect}, " \
|
98
|
+
"@initial_state=#{@initial_state.inspect}, " \
|
99
|
+
"@state_function=#{@state_function.inspect}, " \
|
100
|
+
"@final_function=#{@final_function.inspect}>"
|
87
101
|
end
|
88
102
|
|
89
103
|
# @return [String] a cql representation of this aggregate
|
90
104
|
def to_cql
|
91
|
-
cql =
|
105
|
+
cql = 'CREATE AGGREGATE simplex.average('
|
92
106
|
first = true
|
93
107
|
@argument_types.each do |type|
|
94
108
|
if first
|
@@ -98,12 +112,12 @@ module Cassandra
|
|
98
112
|
end
|
99
113
|
cql << type.to_s
|
100
114
|
end
|
101
|
-
cql <<
|
115
|
+
cql << ')'
|
102
116
|
cql << "\n SFUNC #{@state_function.name}"
|
103
117
|
cql << "\n STYPE #{@state_type}"
|
104
118
|
cql << "\n FINALFUNC #{@final_function.name}" if @final_function
|
105
119
|
cql << "\n INITCOND #{@initial_state}"
|
106
|
-
cql <<
|
120
|
+
cql << ';'
|
107
121
|
end
|
108
122
|
end
|
109
123
|
end
|
data/lib/cassandra/argument.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -36,7 +36,7 @@ module Cassandra
|
|
36
36
|
@name == other.name && \
|
37
37
|
@type == other.type
|
38
38
|
end
|
39
|
-
alias
|
39
|
+
alias == eql?
|
40
40
|
|
41
41
|
# @private
|
42
42
|
def hash
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2016 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
|
+
# This file monkey-patches Module to have an attr_boolean method to make it easy
|
20
|
+
# for classes to define boolean instance variables with "foo?" reader methods.
|
21
|
+
# Inspired by http://stackoverflow.com/questions/4013591/attr-reader-with-question-mark-in-a-name
|
22
|
+
module Cassandra
|
23
|
+
module AttrBoolean
|
24
|
+
def attr_boolean(*names)
|
25
|
+
names.each do |name|
|
26
|
+
define_method(:"#{name}?") do
|
27
|
+
res = instance_variable_get(:"@#{name}")
|
28
|
+
!res.nil? && res != false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/cassandra/auth.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -18,9 +18,9 @@
|
|
18
18
|
|
19
19
|
module Cassandra
|
20
20
|
module Auth
|
21
|
-
# An auth provider is a factory for {Cassandra::Auth::Authenticator authenticator}
|
22
|
-
#
|
23
|
-
# requires authentication.
|
21
|
+
# An auth provider is a factory for {Cassandra::Auth::Authenticator authenticator}
|
22
|
+
# instances (or objects matching that interface). Its {#create_authenticator} will
|
23
|
+
# be called once for each connection that requires authentication.
|
24
24
|
#
|
25
25
|
# If the authentication requires keeping state, keep that in the
|
26
26
|
# authenticator instances, not in the auth provider.
|
@@ -59,7 +59,8 @@ module Cassandra
|
|
59
59
|
# subclasses of this class, but need to implement the same methods. This
|
60
60
|
# class exists only for documentation purposes.
|
61
61
|
#
|
62
|
-
# @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L257-L273 Cassandra
|
62
|
+
# @see https://github.com/apache/cassandra/blob/cassandra-2.0.16/doc/native_protocol_v2.spec#L257-L273 Cassandra
|
63
|
+
# native protocol v2 SASL authentication
|
63
64
|
# @see Cassandra::Auth::Provider#create_authenticator
|
64
65
|
class Authenticator
|
65
66
|
# @!method initial_response
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -53,20 +53,12 @@ module Cassandra
|
|
53
53
|
@password = password
|
54
54
|
end
|
55
55
|
|
56
|
-
# Returns a Password Authenticator
|
57
|
-
# @param authentication_class [String]
|
58
|
-
# @return [Cassandra::Auth::Authenticator]
|
59
|
-
# @return [nil] for all other values of `authentication_class`
|
56
|
+
# Returns a Password Authenticator
|
57
|
+
# @param authentication_class [String] ignored
|
58
|
+
# @return [Cassandra::Auth::Authenticator]
|
60
59
|
def create_authenticator(authentication_class)
|
61
|
-
|
62
|
-
Authenticator.new(@username, @password)
|
63
|
-
end
|
60
|
+
Authenticator.new(@username, @password)
|
64
61
|
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
# @private
|
69
|
-
PASSWORD_AUTHENTICATOR_FQCN = 'org.apache.cassandra.auth.PasswordAuthenticator'.freeze
|
70
62
|
end
|
71
63
|
end
|
72
64
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2016 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
|
+
require 'logger'
|
20
|
+
module Cassandra
|
21
|
+
# This class is a logger that may be used by the client to log the driver's actions.
|
22
|
+
# It is a subclass of the standard Ruby Logger class, so it is instantiated the
|
23
|
+
# same way.
|
24
|
+
#
|
25
|
+
# The format of log output is set to include the timestamp, thread-id, log severity,
|
26
|
+
# and message. <b>This format may change in newer versions of the driver to account
|
27
|
+
# for new/deprecated metadata.</b>
|
28
|
+
#
|
29
|
+
# @example Configuring {Cassandra::Cluster} to use a logger.
|
30
|
+
# cluster = Cassandra.cluster(logger: Cassandra::Logger.new($stderr))
|
31
|
+
#
|
32
|
+
# @example The log format may be changed the same way as in the standard Ruby Logger class
|
33
|
+
# logger = Cassandra::Logger.new($stderr)
|
34
|
+
# logger.formatter = proc { |severity, time, program_name, message|
|
35
|
+
# "[%s]: %s\n" % [severity, message]
|
36
|
+
# }
|
37
|
+
#
|
38
|
+
# @example Create a logger and use it in your own business logic
|
39
|
+
# logger = Cassandra::Logger.new($stderr)
|
40
|
+
# cluster = Cassandra.cluster(logger: logger)
|
41
|
+
# <various logic>
|
42
|
+
# logger.debug("something interesting happened.")
|
43
|
+
|
44
|
+
class Logger < ::Logger
|
45
|
+
# @private
|
46
|
+
# This class is mostly copied from the Ruby Logger::Format class.
|
47
|
+
class Formatter
|
48
|
+
Format = "[%s#%d] %5s: %s\n".freeze
|
49
|
+
|
50
|
+
def call(severity, time, _, msg)
|
51
|
+
format(Format,
|
52
|
+
format_datetime(time),
|
53
|
+
Thread.current.object_id,
|
54
|
+
severity,
|
55
|
+
msg2str(msg))
|
56
|
+
end
|
57
|
+
|
58
|
+
def format_datetime(time)
|
59
|
+
time.strftime('%H:%M:%S.') << format('%06d ', time.usec)
|
60
|
+
end
|
61
|
+
|
62
|
+
def msg2str(msg)
|
63
|
+
case msg
|
64
|
+
when ::String
|
65
|
+
msg
|
66
|
+
when ::Exception
|
67
|
+
"#{msg.message} (#{msg.class})\n" <<
|
68
|
+
(msg.backtrace || []).join("\n")
|
69
|
+
else
|
70
|
+
msg.inspect
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def initialize(*args)
|
76
|
+
super(*args)
|
77
|
+
self.formatter = Formatter.new
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/cassandra/cluster.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -17,7 +17,8 @@
|
|
17
17
|
#++
|
18
18
|
|
19
19
|
module Cassandra
|
20
|
-
# Cluster represents a cassandra cluster. It serves as a
|
20
|
+
# Cluster represents a cassandra cluster. It serves as a
|
21
|
+
# {Cassandra::Session session factory} factory and a collection of metadata.
|
21
22
|
#
|
22
23
|
# @see Cassandra::Cluster#connect Creating a new session
|
23
24
|
# @see Cassandra::Cluster#each_host Getting all peers in the cluster
|
@@ -26,7 +27,22 @@ module Cassandra
|
|
26
27
|
extend Forwardable
|
27
28
|
|
28
29
|
# @private
|
29
|
-
def initialize(logger,
|
30
|
+
def initialize(logger,
|
31
|
+
io_reactor,
|
32
|
+
executor,
|
33
|
+
control_connection,
|
34
|
+
cluster_registry,
|
35
|
+
cluster_schema,
|
36
|
+
cluster_metadata,
|
37
|
+
execution_options,
|
38
|
+
connection_options,
|
39
|
+
load_balancing_policy,
|
40
|
+
reconnection_policy,
|
41
|
+
retry_policy,
|
42
|
+
address_resolution_policy,
|
43
|
+
connector,
|
44
|
+
futures_factory,
|
45
|
+
timestamp_generator)
|
30
46
|
@logger = logger
|
31
47
|
@io_reactor = io_reactor
|
32
48
|
@executor = executor
|
@@ -42,9 +58,14 @@ module Cassandra
|
|
42
58
|
@address_resolver = address_resolution_policy
|
43
59
|
@connector = connector
|
44
60
|
@futures = futures_factory
|
61
|
+
@timestamp_generator = timestamp_generator
|
45
62
|
|
46
|
-
@control_connection.on_close do |
|
47
|
-
|
63
|
+
@control_connection.on_close do |_cause|
|
64
|
+
begin
|
65
|
+
@load_balancing_policy.teardown(self)
|
66
|
+
rescue
|
67
|
+
nil
|
68
|
+
end
|
48
69
|
end
|
49
70
|
end
|
50
71
|
|
@@ -95,7 +116,7 @@ module Cassandra
|
|
95
116
|
return self if r == @registry
|
96
117
|
r
|
97
118
|
end
|
98
|
-
alias
|
119
|
+
alias hosts each_host
|
99
120
|
|
100
121
|
# @!method host(address)
|
101
122
|
# Find a host by its address
|
@@ -119,7 +140,7 @@ module Cassandra
|
|
119
140
|
return self if r == @schema
|
120
141
|
r
|
121
142
|
end
|
122
|
-
alias
|
143
|
+
alias keyspaces each_keyspace
|
123
144
|
|
124
145
|
# @!method keyspace(name)
|
125
146
|
# Find a keyspace by name
|
@@ -175,7 +196,18 @@ module Cassandra
|
|
175
196
|
return @futures.error(::ArgumentError.new("keyspace must be a string, #{keyspace.inspect} given"))
|
176
197
|
end
|
177
198
|
|
178
|
-
client = Client.new(@logger,
|
199
|
+
client = Client.new(@logger,
|
200
|
+
@registry,
|
201
|
+
@schema,
|
202
|
+
@io_reactor,
|
203
|
+
@connector,
|
204
|
+
@load_balancing_policy,
|
205
|
+
@reconnection_policy,
|
206
|
+
@retry_policy,
|
207
|
+
@address_resolver,
|
208
|
+
@connection_options,
|
209
|
+
@futures,
|
210
|
+
@timestamp_generator)
|
179
211
|
session = Session.new(client, @execution_options, @futures)
|
180
212
|
promise = @futures.promise
|
181
213
|
|
@@ -246,7 +278,15 @@ module Cassandra
|
|
246
278
|
|
247
279
|
# @private
|
248
280
|
def inspect
|
249
|
-
"#<#{self.class.name}:0x#{
|
281
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
282
|
+
"name=#{name.inspect}, " \
|
283
|
+
"port=#{@connection_options.port}, " \
|
284
|
+
"protocol_version=#{@connection_options.protocol_version}, " \
|
285
|
+
"load_balancing_policy=#{@load_balancing_policy.inspect}, " \
|
286
|
+
"consistency=#{@execution_options.consistency.inspect}, " \
|
287
|
+
"timeout=#{@execution_options.timeout.inspect}, " \
|
288
|
+
"hosts=#{hosts.inspect}, " \
|
289
|
+
"keyspaces=#{keyspaces.inspect}>"
|
250
290
|
end
|
251
291
|
end
|
252
292
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright 2013-
|
4
|
+
# Copyright 2013-2016 DataStax, Inc.
|
5
5
|
#
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
7
|
# you may not use this file except in compliance with the License.
|
@@ -24,7 +24,18 @@ module Cassandra
|
|
24
24
|
|
25
25
|
attr_reader :keyspace
|
26
26
|
|
27
|
-
def initialize(logger,
|
27
|
+
def initialize(logger,
|
28
|
+
cluster_registry,
|
29
|
+
cluster_schema,
|
30
|
+
io_reactor,
|
31
|
+
connector,
|
32
|
+
load_balancing_policy,
|
33
|
+
reconnection_policy,
|
34
|
+
retry_policy,
|
35
|
+
address_resolution_policy,
|
36
|
+
connection_options,
|
37
|
+
futures_factory,
|
38
|
+
timestamp_generator)
|
28
39
|
@logger = logger
|
29
40
|
@registry = cluster_registry
|
30
41
|
@schema = cluster_schema
|
@@ -42,6 +53,7 @@ module Cassandra
|
|
42
53
|
@pending_connections = ::Hash.new
|
43
54
|
@keyspace = nil
|
44
55
|
@state = :idle
|
56
|
+
@timestamp_generator = timestamp_generator
|
45
57
|
|
46
58
|
mon_initialize
|
47
59
|
end
|
@@ -65,7 +77,9 @@ module Cassandra
|
|
65
77
|
when :remote
|
66
78
|
pool_size = @connection_options.connections_per_remote_node
|
67
79
|
else
|
68
|
-
@logger.error("Not connecting to #{host.ip} - invalid load balancing
|
80
|
+
@logger.error("Not connecting to #{host.ip} - invalid load balancing " \
|
81
|
+
'distance. Distance must be one of ' \
|
82
|
+
"#{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
|
69
83
|
next
|
70
84
|
end
|
71
85
|
|
@@ -101,7 +115,9 @@ module Cassandra
|
|
101
115
|
raise Errors::NoHostsAvailable.new(errors)
|
102
116
|
else
|
103
117
|
failed_connections.each do |f|
|
104
|
-
connect_to_host_with_retry(f.host,
|
118
|
+
connect_to_host_with_retry(f.host,
|
119
|
+
connecting_hosts[f.host],
|
120
|
+
@reconnection_policy.schedule)
|
105
121
|
end
|
106
122
|
end
|
107
123
|
|
@@ -119,18 +135,19 @@ module Cassandra
|
|
119
135
|
return CLIENT_NOT_CONNECTED if @state == :idle
|
120
136
|
return @closed_future if @state == :closed || @state == :closing
|
121
137
|
|
122
|
-
state
|
138
|
+
state = @state
|
139
|
+
@state = :closing
|
123
140
|
end
|
124
141
|
|
125
142
|
@closed_future = begin
|
126
143
|
@registry.remove_listener(self)
|
127
144
|
@schema.remove_listener(self)
|
128
145
|
|
129
|
-
if state == :connecting
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
146
|
+
f = if state == :connecting
|
147
|
+
@connected_future.recover.flat_map { close_connections }
|
148
|
+
else
|
149
|
+
close_connections
|
150
|
+
end
|
134
151
|
|
135
152
|
f.map(self)
|
136
153
|
end
|
@@ -160,7 +177,9 @@ module Cassandra
|
|
160
177
|
when :remote
|
161
178
|
pool_size = @connection_options.connections_per_remote_node
|
162
179
|
else
|
163
|
-
@logger.error("Not connecting to #{host.ip} -
|
180
|
+
@logger.error("Not connecting to #{host.ip} - " \
|
181
|
+
'invalid load balancing distance. Distance must be one of ' \
|
182
|
+
"#{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
|
164
183
|
return Ione::Future.resolved
|
165
184
|
end
|
166
185
|
|
@@ -177,7 +196,7 @@ module Cassandra
|
|
177
196
|
pool = nil
|
178
197
|
|
179
198
|
synchronize do
|
180
|
-
return Ione::Future.resolved unless @connections.
|
199
|
+
return Ione::Future.resolved unless @connections.key?(host)
|
181
200
|
|
182
201
|
@pending_connections.delete(host) unless @pending_connections[host] > 0
|
183
202
|
@prepared_statements.delete(host)
|
@@ -186,7 +205,7 @@ module Cassandra
|
|
186
205
|
end
|
187
206
|
|
188
207
|
if pool
|
189
|
-
Ione::Future.all(*pool.snapshot.map!
|
208
|
+
Ione::Future.all(*pool.snapshot.map!(&:close)).map(nil)
|
190
209
|
else
|
191
210
|
Ione::Future.resolved
|
192
211
|
end
|
@@ -203,29 +222,48 @@ module Cassandra
|
|
203
222
|
nil
|
204
223
|
end
|
205
224
|
|
206
|
-
|
207
225
|
def query(statement, options)
|
208
|
-
|
226
|
+
if !statement.params.empty? && @connection_options.protocol_version == 1
|
227
|
+
return @futures.error(
|
228
|
+
Errors::ClientError.new(
|
229
|
+
'Positional arguments are not supported by the current version of ' \
|
230
|
+
'Apache Cassandra'))
|
231
|
+
end
|
209
232
|
|
210
|
-
timestamp =
|
211
|
-
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
233
|
+
timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
|
212
234
|
payload = nil
|
213
|
-
payload = options.payload if
|
214
|
-
request = Protocol::QueryRequest.new(statement.cql,
|
235
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
236
|
+
request = Protocol::QueryRequest.new(statement.cql,
|
237
|
+
statement.params,
|
238
|
+
statement.params_types,
|
239
|
+
options.consistency,
|
240
|
+
options.serial_consistency,
|
241
|
+
options.page_size,
|
242
|
+
options.paging_state,
|
243
|
+
options.trace?,
|
244
|
+
statement.params_names,
|
245
|
+
timestamp,
|
246
|
+
payload)
|
215
247
|
timeout = options.timeout
|
216
248
|
promise = @futures.promise
|
217
249
|
|
218
250
|
keyspace = @keyspace
|
219
251
|
plan = @load_balancing_policy.plan(keyspace, statement, options)
|
220
252
|
|
221
|
-
send_request_by_plan(promise,
|
253
|
+
send_request_by_plan(promise,
|
254
|
+
keyspace,
|
255
|
+
statement,
|
256
|
+
options,
|
257
|
+
request,
|
258
|
+
plan,
|
259
|
+
timeout)
|
222
260
|
|
223
261
|
promise.future
|
224
262
|
end
|
225
263
|
|
226
264
|
def prepare(cql, options)
|
227
265
|
payload = nil
|
228
|
-
payload = options.payload if
|
266
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
229
267
|
request = Protocol::PrepareRequest.new(cql, options.trace?, payload)
|
230
268
|
timeout = options.timeout
|
231
269
|
promise = @futures.promise
|
@@ -234,19 +272,34 @@ module Cassandra
|
|
234
272
|
statement = VOID_STATEMENT
|
235
273
|
plan = @load_balancing_policy.plan(keyspace, statement, options)
|
236
274
|
|
237
|
-
send_request_by_plan(promise,
|
275
|
+
send_request_by_plan(promise,
|
276
|
+
keyspace,
|
277
|
+
statement,
|
278
|
+
options,
|
279
|
+
request,
|
280
|
+
plan,
|
281
|
+
timeout)
|
238
282
|
|
239
283
|
promise.future
|
240
284
|
end
|
241
285
|
|
242
286
|
def execute(statement, options)
|
243
|
-
timestamp
|
244
|
-
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
287
|
+
timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
|
245
288
|
payload = nil
|
246
|
-
payload = options.payload if
|
289
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
247
290
|
timeout = options.timeout
|
248
291
|
result_metadata = statement.result_metadata
|
249
|
-
request = Protocol::ExecuteRequest.new(nil,
|
292
|
+
request = Protocol::ExecuteRequest.new(nil,
|
293
|
+
statement.params_types,
|
294
|
+
statement.params,
|
295
|
+
result_metadata.nil?,
|
296
|
+
options.consistency,
|
297
|
+
options.serial_consistency,
|
298
|
+
options.page_size,
|
299
|
+
options.paging_state,
|
300
|
+
options.trace?,
|
301
|
+
timestamp,
|
302
|
+
payload)
|
250
303
|
promise = @futures.promise
|
251
304
|
|
252
305
|
keyspace = @keyspace
|
@@ -258,14 +311,23 @@ module Cassandra
|
|
258
311
|
end
|
259
312
|
|
260
313
|
def batch(statement, options)
|
261
|
-
|
314
|
+
if @connection_options.protocol_version < 2
|
315
|
+
return @futures.error(
|
316
|
+
Errors::ClientError.new(
|
317
|
+
'Batch statements are not supported by the current version of ' \
|
318
|
+
'Apache Cassandra'))
|
319
|
+
end
|
262
320
|
|
263
|
-
timestamp =
|
264
|
-
timestamp = ::Time.now if @connection_options.client_timestamps? && @connection_options.protocol_version > 2
|
321
|
+
timestamp = @timestamp_generator.next if @timestamp_generator && @connection_options.protocol_version > 2
|
265
322
|
payload = nil
|
266
|
-
payload = options.payload if
|
323
|
+
payload = options.payload if @connection_options.protocol_version >= 4
|
267
324
|
timeout = options.timeout
|
268
|
-
request = Protocol::BatchRequest.new(BATCH_TYPES[statement.type],
|
325
|
+
request = Protocol::BatchRequest.new(BATCH_TYPES[statement.type],
|
326
|
+
options.consistency,
|
327
|
+
options.trace?,
|
328
|
+
options.serial_consistency,
|
329
|
+
timestamp,
|
330
|
+
payload)
|
269
331
|
keyspace = @keyspace
|
270
332
|
plan = @load_balancing_policy.plan(keyspace, statement, options)
|
271
333
|
promise = @futures.promise
|
@@ -276,16 +338,16 @@ module Cassandra
|
|
276
338
|
end
|
277
339
|
|
278
340
|
def inspect
|
279
|
-
"#<#{self.class.name}:0x#{
|
341
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)}>"
|
280
342
|
end
|
281
343
|
|
282
344
|
private
|
283
345
|
|
284
346
|
NO_CONNECTIONS = Ione::Future.resolved([])
|
285
347
|
BATCH_TYPES = {
|
286
|
-
:
|
287
|
-
:
|
288
|
-
:
|
348
|
+
logged: Protocol::BatchRequest::LOGGED_TYPE,
|
349
|
+
unlogged: Protocol::BatchRequest::UNLOGGED_TYPE,
|
350
|
+
counter: Protocol::BatchRequest::COUNTER_TYPE
|
289
351
|
}.freeze
|
290
352
|
CLIENT_CLOSED = Ione::Future.failed(Errors::ClientError.new('Client closed'))
|
291
353
|
NOT_CONNECTED = Errors::ClientError.new('Client not connected')
|
@@ -299,8 +361,18 @@ module Cassandra
|
|
299
361
|
BOOTSTRAPPING_ERROR_CODE = 0x1002
|
300
362
|
UNPREPARED_ERROR_CODE = 0x2500
|
301
363
|
|
302
|
-
SELECT_SCHEMA_PEERS =
|
303
|
-
|
364
|
+
SELECT_SCHEMA_PEERS =
|
365
|
+
Protocol::QueryRequest.new(
|
366
|
+
'SELECT peer, rpc_address, schema_version FROM system.peers',
|
367
|
+
EMPTY_LIST,
|
368
|
+
EMPTY_LIST,
|
369
|
+
:one)
|
370
|
+
SELECT_SCHEMA_LOCAL =
|
371
|
+
Protocol::QueryRequest.new(
|
372
|
+
"SELECT schema_version FROM system.local WHERE key='local'",
|
373
|
+
EMPTY_LIST,
|
374
|
+
EMPTY_LIST,
|
375
|
+
:one)
|
304
376
|
|
305
377
|
def connected(f)
|
306
378
|
if f.resolved?
|
@@ -339,7 +411,7 @@ module Cassandra
|
|
339
411
|
def close_connections
|
340
412
|
futures = []
|
341
413
|
synchronize do
|
342
|
-
@connections.each do |
|
414
|
+
@connections.each do |_host, connections|
|
343
415
|
connections.snapshot.each do |c|
|
344
416
|
futures << c.close
|
345
417
|
end
|
@@ -351,7 +423,8 @@ module Cassandra
|
|
351
423
|
|
352
424
|
def connect_to_host_maybe_retry(host, pool_size)
|
353
425
|
connect_to_host(host, pool_size).fallback do |e|
|
354
|
-
@logger.error(
|
426
|
+
@logger.error('Scheduling initial connection retry to ' \
|
427
|
+
"#{host.ip} (#{e.class.name}: #{e.message})")
|
355
428
|
connect_to_host_with_retry(host, pool_size, @reconnection_policy.schedule)
|
356
429
|
end.map(nil)
|
357
430
|
end
|
@@ -364,7 +437,8 @@ module Cassandra
|
|
364
437
|
f = @reactor.schedule_timer(interval)
|
365
438
|
f.flat_map do
|
366
439
|
connect_to_host(host, pool_size).fallback do |e|
|
367
|
-
@logger.error(
|
440
|
+
@logger.error('Scheduling connection retry to ' \
|
441
|
+
"#{host.ip} (#{e.class.name}: #{e.message})")
|
368
442
|
connect_to_host_with_retry(host, pool_size, schedule)
|
369
443
|
end
|
370
444
|
end
|
@@ -390,7 +464,8 @@ module Cassandra
|
|
390
464
|
size -= @pending_connections[host]
|
391
465
|
|
392
466
|
if size <= 0
|
393
|
-
@logger.info("Not connecting to #{host.ip} -
|
467
|
+
@logger.info("Not connecting to #{host.ip} - " \
|
468
|
+
'host is already pending connections')
|
394
469
|
return NO_CONNECTIONS
|
395
470
|
end
|
396
471
|
|
@@ -439,7 +514,7 @@ module Cassandra
|
|
439
514
|
end
|
440
515
|
end
|
441
516
|
else
|
442
|
-
connections.each
|
517
|
+
connections.each(&:close)
|
443
518
|
end
|
444
519
|
|
445
520
|
if error
|
@@ -450,7 +525,15 @@ module Cassandra
|
|
450
525
|
end
|
451
526
|
end
|
452
527
|
|
453
|
-
def execute_by_plan(promise,
|
528
|
+
def execute_by_plan(promise,
|
529
|
+
keyspace,
|
530
|
+
statement,
|
531
|
+
options,
|
532
|
+
request,
|
533
|
+
plan,
|
534
|
+
timeout,
|
535
|
+
errors = nil,
|
536
|
+
hosts = [])
|
454
537
|
unless plan.has_next?
|
455
538
|
promise.break(Errors::NoHostsAvailable.new(errors))
|
456
539
|
return
|
@@ -463,7 +546,15 @@ module Cassandra
|
|
463
546
|
unless pool
|
464
547
|
errors ||= {}
|
465
548
|
errors[host] = NOT_CONNECTED
|
466
|
-
return execute_by_plan(promise,
|
549
|
+
return execute_by_plan(promise,
|
550
|
+
keyspace,
|
551
|
+
statement,
|
552
|
+
options,
|
553
|
+
request,
|
554
|
+
plan,
|
555
|
+
timeout,
|
556
|
+
errors,
|
557
|
+
hosts)
|
467
558
|
end
|
468
559
|
|
469
560
|
connection = pool.random_connection
|
@@ -472,13 +563,32 @@ module Cassandra
|
|
472
563
|
switch = switch_keyspace(connection, keyspace, timeout)
|
473
564
|
switch.on_complete do |s|
|
474
565
|
if s.resolved?
|
475
|
-
prepare_and_send_request_by_plan(host,
|
566
|
+
prepare_and_send_request_by_plan(host,
|
567
|
+
connection,
|
568
|
+
promise,
|
569
|
+
keyspace,
|
570
|
+
statement,
|
571
|
+
options,
|
572
|
+
request,
|
573
|
+
plan,
|
574
|
+
timeout,
|
575
|
+
errors,
|
576
|
+
hosts)
|
476
577
|
else
|
477
578
|
s.on_failure do |e|
|
478
|
-
if e.is_a?(Errors::HostError) ||
|
579
|
+
if e.is_a?(Errors::HostError) ||
|
580
|
+
(e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
479
581
|
errors ||= {}
|
480
582
|
errors[host] = e
|
481
|
-
execute_by_plan(promise,
|
583
|
+
execute_by_plan(promise,
|
584
|
+
keyspace,
|
585
|
+
statement,
|
586
|
+
options,
|
587
|
+
request,
|
588
|
+
plan,
|
589
|
+
timeout,
|
590
|
+
errors,
|
591
|
+
hosts)
|
482
592
|
else
|
483
593
|
promise.break(e)
|
484
594
|
end
|
@@ -486,33 +596,111 @@ module Cassandra
|
|
486
596
|
end
|
487
597
|
end
|
488
598
|
else
|
489
|
-
prepare_and_send_request_by_plan(host,
|
599
|
+
prepare_and_send_request_by_plan(host,
|
600
|
+
connection,
|
601
|
+
promise,
|
602
|
+
keyspace,
|
603
|
+
statement,
|
604
|
+
options,
|
605
|
+
request,
|
606
|
+
plan,
|
607
|
+
timeout,
|
608
|
+
errors,
|
609
|
+
hosts)
|
490
610
|
end
|
491
611
|
rescue => e
|
492
612
|
errors ||= {}
|
493
613
|
errors[host] = e
|
494
|
-
execute_by_plan(promise,
|
614
|
+
execute_by_plan(promise,
|
615
|
+
keyspace,
|
616
|
+
statement,
|
617
|
+
options,
|
618
|
+
request,
|
619
|
+
plan,
|
620
|
+
timeout,
|
621
|
+
errors,
|
622
|
+
hosts)
|
495
623
|
end
|
496
624
|
|
497
|
-
def prepare_and_send_request_by_plan(host,
|
625
|
+
def prepare_and_send_request_by_plan(host,
|
626
|
+
connection,
|
627
|
+
promise,
|
628
|
+
keyspace,
|
629
|
+
statement,
|
630
|
+
options,
|
631
|
+
request,
|
632
|
+
plan,
|
633
|
+
timeout,
|
634
|
+
errors,
|
635
|
+
hosts)
|
498
636
|
cql = statement.cql
|
499
|
-
id
|
637
|
+
id = nil
|
638
|
+
host_is_up = true
|
639
|
+
synchronize do
|
640
|
+
if @prepared_statements[host].nil?
|
641
|
+
host_is_up = false
|
642
|
+
else
|
643
|
+
id = @prepared_statements[host][cql]
|
644
|
+
end
|
645
|
+
end
|
500
646
|
|
501
647
|
if id
|
502
648
|
request.id = id
|
503
|
-
do_send_request_by_plan(host,
|
649
|
+
do_send_request_by_plan(host,
|
650
|
+
connection,
|
651
|
+
promise,
|
652
|
+
keyspace,
|
653
|
+
statement,
|
654
|
+
options,
|
655
|
+
request,
|
656
|
+
plan,
|
657
|
+
timeout,
|
658
|
+
errors,
|
659
|
+
hosts)
|
660
|
+
elsif !host_is_up
|
661
|
+
# We've hit a race condition where the plan says we can query this host, but the host has gone
|
662
|
+
# down in the mean time. Just execute the plan again on the next host.
|
663
|
+
@logger.debug("#{host} is down; executing plan on next host")
|
664
|
+
execute_by_plan(promise,
|
665
|
+
keyspace,
|
666
|
+
statement,
|
667
|
+
options,
|
668
|
+
request,
|
669
|
+
plan,
|
670
|
+
timeout,
|
671
|
+
errors,
|
672
|
+
hosts)
|
504
673
|
else
|
505
674
|
prepare = prepare_statement(host, connection, cql, timeout)
|
506
675
|
prepare.on_complete do |_|
|
507
676
|
if prepare.resolved?
|
508
677
|
request.id = prepare.value
|
509
|
-
do_send_request_by_plan(host,
|
678
|
+
do_send_request_by_plan(host,
|
679
|
+
connection,
|
680
|
+
promise,
|
681
|
+
keyspace,
|
682
|
+
statement,
|
683
|
+
options,
|
684
|
+
request,
|
685
|
+
plan,
|
686
|
+
timeout,
|
687
|
+
errors,
|
688
|
+
hosts)
|
510
689
|
else
|
511
690
|
prepare.on_failure do |e|
|
512
|
-
if e.is_a?(Errors::HostError) ||
|
691
|
+
if e.is_a?(Errors::HostError) ||
|
692
|
+
(e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
513
693
|
errors ||= {}
|
514
694
|
errors[host] = e
|
515
|
-
execute_by_plan(promise,
|
695
|
+
execute_by_plan(promise,
|
696
|
+
keyspace,
|
697
|
+
statement,
|
698
|
+
options,
|
699
|
+
request,
|
700
|
+
plan,
|
701
|
+
timeout,
|
702
|
+
errors,
|
703
|
+
hosts)
|
516
704
|
else
|
517
705
|
promise.break(e)
|
518
706
|
end
|
@@ -524,7 +712,15 @@ module Cassandra
|
|
524
712
|
promise.break(e)
|
525
713
|
end
|
526
714
|
|
527
|
-
def batch_by_plan(promise,
|
715
|
+
def batch_by_plan(promise,
|
716
|
+
keyspace,
|
717
|
+
statement,
|
718
|
+
options,
|
719
|
+
request,
|
720
|
+
plan,
|
721
|
+
timeout,
|
722
|
+
errors = nil,
|
723
|
+
hosts = [])
|
528
724
|
unless plan.has_next?
|
529
725
|
promise.break(Errors::NoHostsAvailable.new(errors))
|
530
726
|
return
|
@@ -537,7 +733,15 @@ module Cassandra
|
|
537
733
|
unless pool
|
538
734
|
errors ||= {}
|
539
735
|
errors[host] = NOT_CONNECTED
|
540
|
-
return batch_by_plan(promise,
|
736
|
+
return batch_by_plan(promise,
|
737
|
+
keyspace,
|
738
|
+
statement,
|
739
|
+
options,
|
740
|
+
request,
|
741
|
+
plan,
|
742
|
+
timeout,
|
743
|
+
errors,
|
744
|
+
hosts)
|
541
745
|
end
|
542
746
|
|
543
747
|
connection = pool.random_connection
|
@@ -546,13 +750,32 @@ module Cassandra
|
|
546
750
|
switch = switch_keyspace(connection, keyspace, timeout)
|
547
751
|
switch.on_complete do |s|
|
548
752
|
if s.resolved?
|
549
|
-
batch_and_send_request_by_plan(host,
|
753
|
+
batch_and_send_request_by_plan(host,
|
754
|
+
connection,
|
755
|
+
promise,
|
756
|
+
keyspace,
|
757
|
+
statement,
|
758
|
+
request,
|
759
|
+
options,
|
760
|
+
plan,
|
761
|
+
timeout,
|
762
|
+
errors,
|
763
|
+
hosts)
|
550
764
|
else
|
551
765
|
s.on_failure do |e|
|
552
|
-
if e.is_a?(Errors::HostError) ||
|
766
|
+
if e.is_a?(Errors::HostError) ||
|
767
|
+
(e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
553
768
|
errors ||= {}
|
554
769
|
errors[host] = e
|
555
|
-
batch_by_plan(promise,
|
770
|
+
batch_by_plan(promise,
|
771
|
+
keyspace,
|
772
|
+
statement,
|
773
|
+
options,
|
774
|
+
request,
|
775
|
+
plan,
|
776
|
+
timeout,
|
777
|
+
errors,
|
778
|
+
hosts)
|
556
779
|
else
|
557
780
|
promise.break(e)
|
558
781
|
end
|
@@ -560,26 +783,73 @@ module Cassandra
|
|
560
783
|
end
|
561
784
|
end
|
562
785
|
else
|
563
|
-
batch_and_send_request_by_plan(host,
|
786
|
+
batch_and_send_request_by_plan(host,
|
787
|
+
connection,
|
788
|
+
promise,
|
789
|
+
keyspace,
|
790
|
+
statement,
|
791
|
+
request,
|
792
|
+
options,
|
793
|
+
plan,
|
794
|
+
timeout,
|
795
|
+
errors,
|
796
|
+
hosts)
|
564
797
|
end
|
565
798
|
rescue => e
|
566
799
|
errors ||= {}
|
567
800
|
errors[host] = e
|
568
|
-
batch_by_plan(promise,
|
801
|
+
batch_by_plan(promise,
|
802
|
+
keyspace,
|
803
|
+
statement,
|
804
|
+
options,
|
805
|
+
request,
|
806
|
+
plan,
|
807
|
+
timeout,
|
808
|
+
errors,
|
809
|
+
hosts)
|
569
810
|
end
|
570
811
|
|
571
|
-
def batch_and_send_request_by_plan(host,
|
812
|
+
def batch_and_send_request_by_plan(host,
|
813
|
+
connection,
|
814
|
+
promise,
|
815
|
+
keyspace,
|
816
|
+
batch_statement,
|
817
|
+
request,
|
818
|
+
options,
|
819
|
+
plan,
|
820
|
+
timeout,
|
821
|
+
errors,
|
822
|
+
hosts)
|
572
823
|
request.clear
|
573
824
|
unprepared = Hash.new {|hash, cql| hash[cql] = []}
|
574
825
|
|
575
|
-
|
826
|
+
batch_statement.statements.each do |statement|
|
576
827
|
cql = statement.cql
|
577
828
|
|
578
829
|
if statement.is_a?(Statements::Bound)
|
579
|
-
|
830
|
+
host_is_up = true
|
831
|
+
id = nil
|
832
|
+
synchronize do
|
833
|
+
if @prepared_statements[host].nil?
|
834
|
+
host_is_up = false
|
835
|
+
else
|
836
|
+
id = @prepared_statements[host][cql]
|
837
|
+
end
|
838
|
+
end
|
580
839
|
|
581
840
|
if id
|
582
841
|
request.add_prepared(id, statement.params, statement.params_types)
|
842
|
+
elsif !host_is_up
|
843
|
+
@logger.debug("#{host} is down; executing on next host in plan")
|
844
|
+
return batch_by_plan(promise,
|
845
|
+
keyspace,
|
846
|
+
batch_statement,
|
847
|
+
options,
|
848
|
+
request,
|
849
|
+
plan,
|
850
|
+
timeout,
|
851
|
+
errors,
|
852
|
+
hosts)
|
583
853
|
else
|
584
854
|
unprepared[cql] << statement
|
585
855
|
end
|
@@ -589,7 +859,17 @@ module Cassandra
|
|
589
859
|
end
|
590
860
|
|
591
861
|
if unprepared.empty?
|
592
|
-
do_send_request_by_plan(host,
|
862
|
+
do_send_request_by_plan(host,
|
863
|
+
connection,
|
864
|
+
promise,
|
865
|
+
keyspace,
|
866
|
+
batch_statement,
|
867
|
+
options,
|
868
|
+
request,
|
869
|
+
plan,
|
870
|
+
timeout,
|
871
|
+
errors,
|
872
|
+
hosts)
|
593
873
|
else
|
594
874
|
to_prepare = unprepared.to_a
|
595
875
|
futures = to_prepare.map do |cql, _|
|
@@ -601,17 +881,38 @@ module Cassandra
|
|
601
881
|
prepared_ids = f.value
|
602
882
|
to_prepare.each_with_index do |(_, statements), i|
|
603
883
|
statements.each do |statement|
|
604
|
-
request.add_prepared(prepared_ids[i],
|
884
|
+
request.add_prepared(prepared_ids[i],
|
885
|
+
statement.params,
|
886
|
+
statement.params_types)
|
605
887
|
end
|
606
888
|
end
|
607
889
|
|
608
|
-
do_send_request_by_plan(host,
|
890
|
+
do_send_request_by_plan(host,
|
891
|
+
connection,
|
892
|
+
promise,
|
893
|
+
keyspace,
|
894
|
+
batch_statement,
|
895
|
+
options,
|
896
|
+
request,
|
897
|
+
plan,
|
898
|
+
timeout,
|
899
|
+
errors,
|
900
|
+
hosts)
|
609
901
|
else
|
610
902
|
f.on_failure do |e|
|
611
|
-
if e.is_a?(Errors::HostError) ||
|
903
|
+
if e.is_a?(Errors::HostError) ||
|
904
|
+
(e.is_a?(Errors::TimeoutError) && batch_statement.idempotent?)
|
612
905
|
errors ||= {}
|
613
906
|
errors[host] = e
|
614
|
-
batch_by_plan(promise,
|
907
|
+
batch_by_plan(promise,
|
908
|
+
keyspace,
|
909
|
+
batch_statement,
|
910
|
+
options,
|
911
|
+
request,
|
912
|
+
plan,
|
913
|
+
timeout,
|
914
|
+
errors,
|
915
|
+
hosts)
|
615
916
|
else
|
616
917
|
promise.break(e)
|
617
918
|
end
|
@@ -621,7 +922,15 @@ module Cassandra
|
|
621
922
|
end
|
622
923
|
end
|
623
924
|
|
624
|
-
def send_request_by_plan(promise,
|
925
|
+
def send_request_by_plan(promise,
|
926
|
+
keyspace,
|
927
|
+
statement,
|
928
|
+
options,
|
929
|
+
request,
|
930
|
+
plan,
|
931
|
+
timeout,
|
932
|
+
errors = nil,
|
933
|
+
hosts = [])
|
625
934
|
unless plan.has_next?
|
626
935
|
promise.break(Errors::NoHostsAvailable.new(errors))
|
627
936
|
return
|
@@ -634,7 +943,15 @@ module Cassandra
|
|
634
943
|
unless pool
|
635
944
|
errors ||= {}
|
636
945
|
errors[host] = NOT_CONNECTED
|
637
|
-
return send_request_by_plan(promise,
|
946
|
+
return send_request_by_plan(promise,
|
947
|
+
keyspace,
|
948
|
+
statement,
|
949
|
+
options,
|
950
|
+
request,
|
951
|
+
plan,
|
952
|
+
timeout,
|
953
|
+
errors,
|
954
|
+
hosts)
|
638
955
|
end
|
639
956
|
|
640
957
|
connection = pool.random_connection
|
@@ -643,13 +960,32 @@ module Cassandra
|
|
643
960
|
switch = switch_keyspace(connection, keyspace, timeout)
|
644
961
|
switch.on_complete do |s|
|
645
962
|
if s.resolved?
|
646
|
-
do_send_request_by_plan(host,
|
963
|
+
do_send_request_by_plan(host,
|
964
|
+
connection,
|
965
|
+
promise,
|
966
|
+
keyspace,
|
967
|
+
statement,
|
968
|
+
options,
|
969
|
+
request,
|
970
|
+
plan,
|
971
|
+
timeout,
|
972
|
+
errors,
|
973
|
+
hosts)
|
647
974
|
else
|
648
975
|
s.on_failure do |e|
|
649
|
-
if e.is_a?(Errors::HostError) ||
|
976
|
+
if e.is_a?(Errors::HostError) ||
|
977
|
+
(e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
650
978
|
errors ||= {}
|
651
979
|
errors[host] = e
|
652
|
-
send_request_by_plan(promise,
|
980
|
+
send_request_by_plan(promise,
|
981
|
+
keyspace,
|
982
|
+
statement,
|
983
|
+
options,
|
984
|
+
request,
|
985
|
+
plan,
|
986
|
+
timeout,
|
987
|
+
errors,
|
988
|
+
hosts)
|
653
989
|
else
|
654
990
|
promise.break(e)
|
655
991
|
end
|
@@ -657,166 +993,447 @@ module Cassandra
|
|
657
993
|
end
|
658
994
|
end
|
659
995
|
else
|
660
|
-
do_send_request_by_plan(host,
|
996
|
+
do_send_request_by_plan(host,
|
997
|
+
connection,
|
998
|
+
promise,
|
999
|
+
keyspace,
|
1000
|
+
statement,
|
1001
|
+
options,
|
1002
|
+
request,
|
1003
|
+
plan,
|
1004
|
+
timeout,
|
1005
|
+
errors,
|
1006
|
+
hosts)
|
661
1007
|
end
|
662
1008
|
rescue => e
|
663
1009
|
errors ||= {}
|
664
1010
|
errors[host] = e
|
665
|
-
send_request_by_plan(promise,
|
1011
|
+
send_request_by_plan(promise,
|
1012
|
+
keyspace,
|
1013
|
+
statement,
|
1014
|
+
options,
|
1015
|
+
request,
|
1016
|
+
plan,
|
1017
|
+
timeout,
|
1018
|
+
errors,
|
1019
|
+
hosts)
|
666
1020
|
end
|
667
1021
|
|
668
|
-
def do_send_request_by_plan(host,
|
1022
|
+
def do_send_request_by_plan(host,
|
1023
|
+
connection,
|
1024
|
+
promise,
|
1025
|
+
keyspace,
|
1026
|
+
statement,
|
1027
|
+
options,
|
1028
|
+
request,
|
1029
|
+
plan,
|
1030
|
+
timeout,
|
1031
|
+
errors,
|
1032
|
+
hosts,
|
1033
|
+
retries = 0)
|
669
1034
|
request.retries = retries
|
670
1035
|
|
671
1036
|
f = connection.send_request(request, timeout)
|
672
|
-
f.on_complete do |
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
@prepared_statements[host].delete(cql)
|
692
|
-
end
|
1037
|
+
f.on_complete do |response_future|
|
1038
|
+
errors ||= {}
|
1039
|
+
handle_response(response_future,
|
1040
|
+
host,
|
1041
|
+
connection,
|
1042
|
+
promise,
|
1043
|
+
keyspace,
|
1044
|
+
statement,
|
1045
|
+
options,
|
1046
|
+
request,
|
1047
|
+
plan,
|
1048
|
+
timeout,
|
1049
|
+
errors,
|
1050
|
+
hosts,
|
1051
|
+
retries)
|
1052
|
+
end
|
1053
|
+
rescue => e
|
1054
|
+
promise.break(e)
|
1055
|
+
end
|
693
1056
|
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
1057
|
+
def handle_response(response_future,
|
1058
|
+
host,
|
1059
|
+
connection,
|
1060
|
+
promise,
|
1061
|
+
keyspace,
|
1062
|
+
statement,
|
1063
|
+
options,
|
1064
|
+
request,
|
1065
|
+
plan,
|
1066
|
+
timeout,
|
1067
|
+
errors,
|
1068
|
+
hosts,
|
1069
|
+
retries)
|
1070
|
+
if response_future.resolved?
|
1071
|
+
r = response_future.value
|
1072
|
+
|
1073
|
+
begin
|
1074
|
+
decision = nil
|
1075
|
+
|
1076
|
+
case r
|
1077
|
+
when Protocol::UnavailableErrorResponse
|
1078
|
+
decision = @retry_policy.unavailable(statement,
|
1079
|
+
r.consistency,
|
1080
|
+
r.required,
|
1081
|
+
r.alive,
|
1082
|
+
retries)
|
1083
|
+
when Protocol::WriteTimeoutErrorResponse
|
1084
|
+
decision = @retry_policy.write_timeout(statement,
|
1085
|
+
r.consistency,
|
1086
|
+
r.write_type,
|
1087
|
+
r.blockfor,
|
1088
|
+
r.received,
|
1089
|
+
retries)
|
1090
|
+
when Protocol::ReadTimeoutErrorResponse
|
1091
|
+
decision = @retry_policy.read_timeout(statement,
|
1092
|
+
r.consistency,
|
1093
|
+
r.blockfor,
|
1094
|
+
r.received,
|
1095
|
+
r.data_present,
|
1096
|
+
retries)
|
1097
|
+
when Protocol::UnpreparedErrorResponse
|
1098
|
+
cql = statement.cql
|
1099
|
+
|
1100
|
+
synchronize do
|
1101
|
+
@preparing_statements[host].delete(cql)
|
1102
|
+
@prepared_statements[host].delete(cql)
|
1103
|
+
end
|
713
1104
|
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
1105
|
+
prepare = prepare_statement(host, connection, cql, timeout)
|
1106
|
+
prepare.on_complete do |_|
|
1107
|
+
if prepare.resolved?
|
1108
|
+
request.id = prepare.value
|
1109
|
+
do_send_request_by_plan(host,
|
1110
|
+
connection,
|
1111
|
+
promise,
|
1112
|
+
keyspace,
|
1113
|
+
statement,
|
1114
|
+
options,
|
1115
|
+
request,
|
1116
|
+
plan,
|
1117
|
+
timeout,
|
1118
|
+
errors,
|
1119
|
+
hosts)
|
726
1120
|
else
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
promise.fulfill(Statements::Prepared.new(r.custom_payload, r.warnings, cql, metadata, r.result_metadata, pk_idx, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @connection_options))
|
744
|
-
when Protocol::RawRowsResultResponse
|
745
|
-
r.materialize(statement.result_metadata)
|
746
|
-
promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
747
|
-
when Protocol::RowsResultResponse
|
748
|
-
promise.fulfill(Results::Paged.new(r.custom_payload, r.warnings, r.rows, r.paging_state, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
749
|
-
when Protocol::SchemaChangeResultResponse
|
750
|
-
@schema.delete_keyspace(r.keyspace) if r.change == 'DROPPED' && r.target == Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
751
|
-
|
752
|
-
@logger.debug('Waiting for schema to propagate to all hosts after a change')
|
753
|
-
wait_for_schema_agreement(connection, @reconnection_policy.schedule).on_complete do |f|
|
754
|
-
unless f.resolved?
|
755
|
-
f.on_failure do |e|
|
756
|
-
@logger.error("Schema agreement failure (#{e.class.name}: #{e.message})")
|
1121
|
+
prepare.on_failure do |e|
|
1122
|
+
if e.is_a?(Errors::HostError) ||
|
1123
|
+
(e.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
1124
|
+
errors[host] = e
|
1125
|
+
execute_by_plan(promise,
|
1126
|
+
keyspace,
|
1127
|
+
statement,
|
1128
|
+
options,
|
1129
|
+
request,
|
1130
|
+
plan,
|
1131
|
+
timeout,
|
1132
|
+
errors,
|
1133
|
+
hosts)
|
1134
|
+
else
|
1135
|
+
promise.break(e)
|
757
1136
|
end
|
758
1137
|
end
|
759
|
-
|
1138
|
+
end
|
1139
|
+
end
|
1140
|
+
when Protocol::ErrorResponse
|
1141
|
+
error = r.to_error(keyspace,
|
1142
|
+
statement,
|
1143
|
+
options,
|
1144
|
+
hosts,
|
1145
|
+
request.consistency,
|
1146
|
+
retries)
|
1147
|
+
|
1148
|
+
if error.is_a?(Errors::HostError) ||
|
1149
|
+
(error.is_a?(Errors::TimeoutError) && statement.idempotent?)
|
1150
|
+
errors[host] = error
|
1151
|
+
|
1152
|
+
case request
|
1153
|
+
when Protocol::QueryRequest, Protocol::PrepareRequest
|
1154
|
+
send_request_by_plan(promise,
|
1155
|
+
keyspace,
|
1156
|
+
statement,
|
1157
|
+
options,
|
1158
|
+
request,
|
1159
|
+
plan,
|
1160
|
+
timeout,
|
1161
|
+
errors,
|
1162
|
+
hosts)
|
1163
|
+
when Protocol::ExecuteRequest
|
1164
|
+
execute_by_plan(promise,
|
1165
|
+
keyspace,
|
1166
|
+
statement,
|
1167
|
+
options,
|
1168
|
+
request,
|
1169
|
+
plan,
|
1170
|
+
timeout,
|
1171
|
+
errors,
|
1172
|
+
hosts)
|
1173
|
+
when Protocol::BatchRequest
|
1174
|
+
batch_by_plan(promise,
|
1175
|
+
keyspace,
|
1176
|
+
statement,
|
1177
|
+
options,
|
1178
|
+
request,
|
1179
|
+
plan,
|
1180
|
+
timeout,
|
1181
|
+
errors,
|
1182
|
+
hosts)
|
760
1183
|
end
|
761
1184
|
else
|
762
|
-
promise.
|
1185
|
+
promise.break(error)
|
1186
|
+
end
|
1187
|
+
when Protocol::SetKeyspaceResultResponse
|
1188
|
+
@keyspace = r.keyspace
|
1189
|
+
promise.fulfill(Cassandra::Results::Void.new(r.custom_payload,
|
1190
|
+
r.warnings,
|
1191
|
+
r.trace_id,
|
1192
|
+
keyspace,
|
1193
|
+
statement,
|
1194
|
+
options,
|
1195
|
+
hosts,
|
1196
|
+
request.consistency,
|
1197
|
+
retries,
|
1198
|
+
self,
|
1199
|
+
@futures))
|
1200
|
+
when Protocol::PreparedResultResponse
|
1201
|
+
cql = request.cql
|
1202
|
+
synchronize do
|
1203
|
+
@prepared_statements[host][cql] = r.id
|
1204
|
+
@preparing_statements[host].delete(cql)
|
763
1205
|
end
|
764
1206
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
1207
|
+
metadata = r.metadata
|
1208
|
+
pk_idx = r.pk_idx
|
1209
|
+
pk_idx ||= @schema.get_pk_idx(metadata)
|
1210
|
+
|
1211
|
+
promise.fulfill(
|
1212
|
+
Statements::Prepared.new(r.custom_payload,
|
1213
|
+
r.warnings,
|
1214
|
+
cql,
|
1215
|
+
metadata,
|
1216
|
+
r.result_metadata,
|
1217
|
+
pk_idx,
|
1218
|
+
r.trace_id,
|
1219
|
+
keyspace,
|
1220
|
+
statement,
|
1221
|
+
options,
|
1222
|
+
hosts,
|
1223
|
+
request.consistency,
|
1224
|
+
retries,
|
1225
|
+
self,
|
1226
|
+
@connection_options))
|
1227
|
+
when Protocol::RawRowsResultResponse
|
1228
|
+
r.materialize(statement.result_metadata)
|
1229
|
+
promise.fulfill(
|
1230
|
+
Results::Paged.new(r.custom_payload,
|
1231
|
+
r.warnings,
|
1232
|
+
r.rows,
|
1233
|
+
r.paging_state,
|
1234
|
+
r.trace_id,
|
1235
|
+
keyspace,
|
1236
|
+
statement,
|
1237
|
+
options,
|
1238
|
+
hosts,
|
1239
|
+
request.consistency,
|
1240
|
+
retries,
|
1241
|
+
self,
|
1242
|
+
@futures))
|
1243
|
+
when Protocol::RowsResultResponse
|
1244
|
+
promise.fulfill(
|
1245
|
+
Results::Paged.new(r.custom_payload,
|
1246
|
+
r.warnings,
|
1247
|
+
r.rows,
|
1248
|
+
r.paging_state,
|
1249
|
+
r.trace_id,
|
1250
|
+
keyspace,
|
1251
|
+
statement,
|
1252
|
+
options,
|
1253
|
+
hosts,
|
1254
|
+
request.consistency,
|
1255
|
+
retries,
|
1256
|
+
self,
|
1257
|
+
@futures))
|
1258
|
+
when Protocol::SchemaChangeResultResponse
|
1259
|
+
if r.change == 'DROPPED' &&
|
1260
|
+
r.target == Protocol::Constants::SCHEMA_CHANGE_TARGET_KEYSPACE
|
1261
|
+
@schema.delete_keyspace(r.keyspace)
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
@logger.debug('Waiting for schema to propagate to all hosts after a change')
|
1265
|
+
wait_for_schema_agreement(connection,
|
1266
|
+
@reconnection_policy.schedule).on_complete do |f|
|
1267
|
+
unless f.resolved?
|
1268
|
+
f.on_failure do |e|
|
1269
|
+
@logger.error(
|
1270
|
+
"Schema agreement failure (#{e.class.name}: #{e.message})")
|
782
1271
|
end
|
783
|
-
when Retry::Decisions::Ignore
|
784
|
-
promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
|
785
|
-
when Retry::Decisions::Reraise
|
786
|
-
promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
|
787
|
-
else
|
788
|
-
promise.break(r.to_error(keyspace, statement, options, hosts, request.consistency, retries))
|
789
1272
|
end
|
1273
|
+
promise.fulfill(
|
1274
|
+
Results::Void.new(r.custom_payload,
|
1275
|
+
r.warnings,
|
1276
|
+
r.trace_id,
|
1277
|
+
keyspace,
|
1278
|
+
statement,
|
1279
|
+
options,
|
1280
|
+
hosts,
|
1281
|
+
request.consistency,
|
1282
|
+
retries,
|
1283
|
+
self,
|
1284
|
+
@futures))
|
790
1285
|
end
|
791
|
-
|
792
|
-
promise.
|
1286
|
+
else
|
1287
|
+
promise.fulfill(Results::Void.new(r.custom_payload,
|
1288
|
+
r.warnings,
|
1289
|
+
r.trace_id,
|
1290
|
+
keyspace,
|
1291
|
+
statement,
|
1292
|
+
options,
|
1293
|
+
hosts,
|
1294
|
+
request.consistency,
|
1295
|
+
retries,
|
1296
|
+
self,
|
1297
|
+
@futures))
|
793
1298
|
end
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
1299
|
+
|
1300
|
+
if decision
|
1301
|
+
case decision
|
1302
|
+
when Retry::Decisions::Retry
|
1303
|
+
request.consistency = decision.consistency
|
1304
|
+
do_send_request_by_plan(host,
|
1305
|
+
connection,
|
1306
|
+
promise,
|
1307
|
+
keyspace,
|
1308
|
+
statement,
|
1309
|
+
options,
|
1310
|
+
request,
|
1311
|
+
plan,
|
1312
|
+
timeout,
|
1313
|
+
errors,
|
1314
|
+
hosts,
|
1315
|
+
retries + 1)
|
1316
|
+
when Retry::Decisions::TryNextHost
|
1317
|
+
errors[host] = r.to_error(keyspace,
|
1318
|
+
statement,
|
1319
|
+
options,
|
1320
|
+
hosts,
|
1321
|
+
request.consistency,
|
1322
|
+
retries)
|
1323
|
+
case request
|
1324
|
+
when Protocol::QueryRequest, Protocol::PrepareRequest
|
1325
|
+
send_request_by_plan(promise,
|
1326
|
+
keyspace,
|
1327
|
+
statement,
|
1328
|
+
options,
|
1329
|
+
request,
|
1330
|
+
plan,
|
1331
|
+
timeout,
|
1332
|
+
errors,
|
1333
|
+
hosts)
|
1334
|
+
when Protocol::ExecuteRequest
|
1335
|
+
execute_by_plan(promise,
|
1336
|
+
keyspace,
|
1337
|
+
statement,
|
1338
|
+
options,
|
1339
|
+
request,
|
1340
|
+
plan,
|
1341
|
+
timeout,
|
1342
|
+
errors,
|
1343
|
+
hosts)
|
1344
|
+
when Protocol::BatchRequest
|
1345
|
+
batch_by_plan(promise,
|
1346
|
+
keyspace,
|
1347
|
+
statement,
|
1348
|
+
options,
|
1349
|
+
request,
|
1350
|
+
plan,
|
1351
|
+
timeout,
|
1352
|
+
errors,
|
1353
|
+
hosts)
|
1354
|
+
else
|
1355
|
+
promise.break(e)
|
1356
|
+
end
|
1357
|
+
when Retry::Decisions::Ignore
|
1358
|
+
promise.fulfill(
|
1359
|
+
Results::Void.new(r.custom_payload,
|
1360
|
+
r.warnings,
|
1361
|
+
nil,
|
1362
|
+
keyspace,
|
1363
|
+
statement,
|
1364
|
+
options,
|
1365
|
+
hosts,
|
1366
|
+
request.consistency,
|
1367
|
+
retries,
|
1368
|
+
self,
|
1369
|
+
@futures))
|
1370
|
+
when Retry::Decisions::Reraise
|
1371
|
+
promise.break(
|
1372
|
+
r.to_error(keyspace,
|
1373
|
+
statement,
|
1374
|
+
options,
|
1375
|
+
hosts,
|
1376
|
+
request.consistency,
|
1377
|
+
retries))
|
805
1378
|
else
|
806
|
-
promise.break(
|
1379
|
+
promise.break(
|
1380
|
+
r.to_error(keyspace,
|
1381
|
+
statement,
|
1382
|
+
options,
|
1383
|
+
hosts,
|
1384
|
+
request.consistency,
|
1385
|
+
retries))
|
807
1386
|
end
|
808
1387
|
end
|
1388
|
+
rescue => e
|
1389
|
+
promise.break(e)
|
1390
|
+
end
|
1391
|
+
else
|
1392
|
+
response_future.on_failure do |ex|
|
1393
|
+
errors[host] = ex
|
1394
|
+
case request
|
1395
|
+
when Protocol::QueryRequest, Protocol::PrepareRequest
|
1396
|
+
send_request_by_plan(promise,
|
1397
|
+
keyspace,
|
1398
|
+
statement,
|
1399
|
+
options,
|
1400
|
+
request,
|
1401
|
+
plan,
|
1402
|
+
timeout,
|
1403
|
+
errors,
|
1404
|
+
hosts)
|
1405
|
+
when Protocol::ExecuteRequest
|
1406
|
+
execute_by_plan(promise,
|
1407
|
+
keyspace,
|
1408
|
+
statement,
|
1409
|
+
options,
|
1410
|
+
request,
|
1411
|
+
plan,
|
1412
|
+
timeout,
|
1413
|
+
errors,
|
1414
|
+
hosts)
|
1415
|
+
when Protocol::BatchRequest
|
1416
|
+
batch_by_plan(promise,
|
1417
|
+
keyspace,
|
1418
|
+
statement,
|
1419
|
+
options,
|
1420
|
+
request,
|
1421
|
+
plan,
|
1422
|
+
timeout,
|
1423
|
+
errors,
|
1424
|
+
hosts)
|
1425
|
+
else
|
1426
|
+
promise.break(ex)
|
1427
|
+
end
|
809
1428
|
end
|
810
1429
|
end
|
811
|
-
rescue => e
|
812
|
-
promise.break(e)
|
813
1430
|
end
|
814
1431
|
|
815
1432
|
def wait_for_schema_agreement(connection, schedule)
|
816
|
-
|
817
|
-
|
1433
|
+
peers_future = send_select_request(connection, SELECT_SCHEMA_PEERS)
|
1434
|
+
local_future = send_select_request(connection, SELECT_SCHEMA_LOCAL)
|
818
1435
|
|
819
|
-
Ione::Future.all(
|
1436
|
+
Ione::Future.all(peers_future, local_future).flat_map do |(peers, local)|
|
820
1437
|
versions = ::Set.new
|
821
1438
|
|
822
1439
|
unless local.empty?
|
@@ -841,7 +1458,8 @@ module Cassandra
|
|
841
1458
|
Ione::Future.resolved
|
842
1459
|
else
|
843
1460
|
interval = schedule.next
|
844
|
-
@logger.info(
|
1461
|
+
@logger.info('Hosts have different schema versions: ' \
|
1462
|
+
"#{versions.to_a.inspect}, retrying in #{interval} seconds")
|
845
1463
|
@reactor.schedule_timer(interval).flat_map do
|
846
1464
|
wait_for_schema_agreement(connection, schedule)
|
847
1465
|
end
|
@@ -862,7 +1480,10 @@ module Cassandra
|
|
862
1480
|
|
863
1481
|
return pending_switch || Ione::Future.resolved if pending_keyspace == keyspace
|
864
1482
|
|
865
|
-
request = Protocol::QueryRequest.new("USE #{Util.escape_name(keyspace)}",
|
1483
|
+
request = Protocol::QueryRequest.new("USE #{Util.escape_name(keyspace)}",
|
1484
|
+
EMPTY_LIST,
|
1485
|
+
EMPTY_LIST,
|
1486
|
+
:one)
|
866
1487
|
|
867
1488
|
f = connection.send_request(request, timeout).map do |r|
|
868
1489
|
case r
|
@@ -870,7 +1491,12 @@ module Cassandra
|
|
870
1491
|
@keyspace = r.keyspace
|
871
1492
|
nil
|
872
1493
|
when Protocol::ErrorResponse
|
873
|
-
raise r.to_error(nil,
|
1494
|
+
raise r.to_error(nil,
|
1495
|
+
Statements::Simple.new("USE #{Util.escape_name(keyspace)}"),
|
1496
|
+
VOID_OPTIONS,
|
1497
|
+
EMPTY_LIST,
|
1498
|
+
:one,
|
1499
|
+
0)
|
874
1500
|
else
|
875
1501
|
raise Errors::InternalError, "Unexpected response #{r.inspect}"
|
876
1502
|
end
|
@@ -879,7 +1505,7 @@ module Cassandra
|
|
879
1505
|
connection[:pending_keyspace] = keyspace
|
880
1506
|
connection[:pending_switch] = f
|
881
1507
|
|
882
|
-
f.on_complete do |
|
1508
|
+
f.on_complete do |_f|
|
883
1509
|
connection[:pending_switch] = nil
|
884
1510
|
connection[:pending_keyspace] = nil
|
885
1511
|
end
|
@@ -891,7 +1517,7 @@ module Cassandra
|
|
891
1517
|
synchronize do
|
892
1518
|
pending = @preparing_statements[host]
|
893
1519
|
|
894
|
-
return pending[cql] if pending.
|
1520
|
+
return pending[cql] if pending.key?(cql)
|
895
1521
|
end
|
896
1522
|
|
897
1523
|
request = Protocol::PrepareRequest.new(cql, false)
|