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.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -39
  3. data/lib/cassandra.rb +396 -148
  4. data/lib/cassandra/address_resolution.rb +1 -1
  5. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +1 -1
  6. data/lib/cassandra/address_resolution/policies/none.rb +1 -1
  7. data/lib/cassandra/aggregate.rb +21 -7
  8. data/lib/cassandra/argument.rb +2 -2
  9. data/lib/cassandra/attr_boolean.rb +33 -0
  10. data/lib/cassandra/auth.rb +6 -5
  11. data/lib/cassandra/auth/providers.rb +1 -1
  12. data/lib/cassandra/auth/providers/password.rb +5 -13
  13. data/lib/cassandra/cassandra_logger.rb +80 -0
  14. data/lib/cassandra/cluster.rb +49 -9
  15. data/lib/cassandra/cluster/client.rb +835 -209
  16. data/lib/cassandra/cluster/connection_pool.rb +2 -2
  17. data/lib/cassandra/cluster/connector.rb +86 -27
  18. data/lib/cassandra/cluster/control_connection.rb +222 -95
  19. data/lib/cassandra/cluster/failed_connection.rb +1 -1
  20. data/lib/cassandra/cluster/metadata.rb +14 -8
  21. data/lib/cassandra/cluster/options.rb +68 -22
  22. data/lib/cassandra/cluster/registry.rb +81 -17
  23. data/lib/cassandra/cluster/schema.rb +70 -8
  24. data/lib/cassandra/cluster/schema/cql_type_parser.rb +15 -10
  25. data/lib/cassandra/cluster/schema/fetchers.rb +601 -241
  26. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +39 -38
  27. data/lib/cassandra/cluster/schema/partitioners.rb +1 -1
  28. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +6 -8
  29. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +1 -1
  30. data/lib/cassandra/cluster/schema/partitioners/random.rb +1 -1
  31. data/lib/cassandra/cluster/schema/replication_strategies.rb +1 -1
  32. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +19 -18
  33. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +1 -1
  34. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +1 -1
  35. data/lib/cassandra/column.rb +4 -23
  36. data/lib/cassandra/column_container.rb +322 -0
  37. data/lib/cassandra/compression.rb +1 -1
  38. data/lib/cassandra/compression/compressors/lz4.rb +7 -8
  39. data/lib/cassandra/compression/compressors/snappy.rb +4 -3
  40. data/lib/cassandra/driver.rb +107 -46
  41. data/lib/cassandra/errors.rb +303 -52
  42. data/lib/cassandra/execution/info.rb +16 -5
  43. data/lib/cassandra/execution/options.rb +102 -55
  44. data/lib/cassandra/execution/trace.rb +16 -9
  45. data/lib/cassandra/executors.rb +1 -1
  46. data/lib/cassandra/function.rb +19 -13
  47. data/lib/cassandra/function_collection.rb +85 -0
  48. data/lib/cassandra/future.rb +101 -49
  49. data/lib/cassandra/host.rb +25 -5
  50. data/lib/cassandra/index.rb +118 -0
  51. data/lib/cassandra/keyspace.rb +169 -33
  52. data/lib/cassandra/listener.rb +1 -1
  53. data/lib/cassandra/load_balancing.rb +2 -2
  54. data/lib/cassandra/load_balancing/policies.rb +1 -1
  55. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +39 -25
  56. data/lib/cassandra/load_balancing/policies/round_robin.rb +8 -1
  57. data/lib/cassandra/load_balancing/policies/token_aware.rb +22 -13
  58. data/lib/cassandra/load_balancing/policies/white_list.rb +18 -5
  59. data/lib/cassandra/materialized_view.rb +90 -0
  60. data/lib/cassandra/null_logger.rb +27 -6
  61. data/lib/cassandra/protocol.rb +1 -1
  62. data/lib/cassandra/protocol/coder.rb +81 -42
  63. data/lib/cassandra/protocol/cql_byte_buffer.rb +58 -44
  64. data/lib/cassandra/protocol/cql_protocol_handler.rb +57 -54
  65. data/lib/cassandra/protocol/request.rb +6 -7
  66. data/lib/cassandra/protocol/requests/auth_response_request.rb +3 -3
  67. data/lib/cassandra/protocol/requests/batch_request.rb +17 -8
  68. data/lib/cassandra/protocol/requests/credentials_request.rb +3 -3
  69. data/lib/cassandra/protocol/requests/execute_request.rb +39 -20
  70. data/lib/cassandra/protocol/requests/options_request.rb +1 -1
  71. data/lib/cassandra/protocol/requests/prepare_request.rb +5 -5
  72. data/lib/cassandra/protocol/requests/query_request.rb +28 -23
  73. data/lib/cassandra/protocol/requests/register_request.rb +2 -2
  74. data/lib/cassandra/protocol/requests/startup_request.rb +8 -8
  75. data/lib/cassandra/protocol/requests/void_query_request.rb +1 -1
  76. data/lib/cassandra/protocol/response.rb +3 -4
  77. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +12 -2
  78. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +4 -5
  79. data/lib/cassandra/protocol/responses/auth_success_response.rb +4 -5
  80. data/lib/cassandra/protocol/responses/authenticate_response.rb +4 -5
  81. data/lib/cassandra/protocol/responses/error_response.rb +104 -17
  82. data/lib/cassandra/protocol/responses/event_response.rb +3 -4
  83. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +13 -2
  84. data/lib/cassandra/protocol/responses/prepared_result_response.rb +14 -9
  85. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +14 -9
  86. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +26 -4
  87. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +22 -3
  88. data/lib/cassandra/protocol/responses/ready_response.rb +6 -7
  89. data/lib/cassandra/protocol/responses/result_response.rb +11 -10
  90. data/lib/cassandra/protocol/responses/rows_result_response.rb +8 -7
  91. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +8 -8
  92. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +19 -13
  93. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +5 -6
  94. data/lib/cassandra/protocol/responses/status_change_event_response.rb +5 -6
  95. data/lib/cassandra/protocol/responses/supported_response.rb +4 -5
  96. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +4 -5
  97. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +20 -3
  98. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +11 -2
  99. data/lib/cassandra/protocol/responses/void_result_response.rb +4 -5
  100. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +26 -4
  101. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +22 -3
  102. data/lib/cassandra/protocol/v1.rb +98 -37
  103. data/lib/cassandra/protocol/v3.rb +121 -50
  104. data/lib/cassandra/protocol/v4.rb +172 -68
  105. data/lib/cassandra/reconnection.rb +1 -1
  106. data/lib/cassandra/reconnection/policies.rb +1 -1
  107. data/lib/cassandra/reconnection/policies/constant.rb +2 -4
  108. data/lib/cassandra/reconnection/policies/exponential.rb +6 -6
  109. data/lib/cassandra/result.rb +55 -20
  110. data/lib/cassandra/retry.rb +8 -8
  111. data/lib/cassandra/retry/policies.rb +1 -1
  112. data/lib/cassandra/retry/policies/default.rb +1 -1
  113. data/lib/cassandra/retry/policies/downgrading_consistency.rb +4 -2
  114. data/lib/cassandra/retry/policies/fallthrough.rb +1 -1
  115. data/lib/cassandra/session.rb +24 -16
  116. data/lib/cassandra/statement.rb +1 -1
  117. data/lib/cassandra/statements.rb +1 -1
  118. data/lib/cassandra/statements/batch.rb +16 -10
  119. data/lib/cassandra/statements/bound.rb +10 -3
  120. data/lib/cassandra/statements/prepared.rb +62 -18
  121. data/lib/cassandra/statements/simple.rb +23 -10
  122. data/lib/cassandra/statements/void.rb +1 -1
  123. data/lib/cassandra/table.rb +53 -185
  124. data/lib/cassandra/time.rb +11 -6
  125. data/lib/cassandra/time_uuid.rb +12 -14
  126. data/lib/cassandra/timestamp_generator.rb +37 -0
  127. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  128. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  129. data/lib/cassandra/tuple.rb +4 -4
  130. data/lib/cassandra/types.rb +109 -71
  131. data/lib/cassandra/udt.rb +66 -50
  132. data/lib/cassandra/util.rb +155 -15
  133. data/lib/cassandra/uuid.rb +20 -21
  134. data/lib/cassandra/uuid/generator.rb +7 -5
  135. data/lib/cassandra/version.rb +2 -2
  136. data/lib/cassandra_murmur3.jar +0 -0
  137. data/lib/datastax/cassandra.rb +1 -1
  138. metadata +27 -16
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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.
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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.
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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.
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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, name, type, argument_types, state_type, initial_state, state_function, final_function)
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 :== :eql?
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#{self.object_id.to_s(16)} @keyspace=#{@keyspace.inspect}, @name=#{@name.inspect}, @type=#{@type.inspect}, @argument_types=#{@argument_types.inspect}, @initial_state=#{@initial_state.inspect}, @state_function=#{@state_function.inspect}, @final_function=#{@final_function.inspect}>"
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 = "CREATE AGGREGATE simplex.average("
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
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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 :== :eql?
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
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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} instances (or objects matching that interface). Its
22
- # {#create_authenticator} will be called once for each connection that
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 native protocol v2 SASL authentication
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,5 +1,5 @@
1
1
  #--
2
- # Copyright 2013-2015 DataStax, Inc.
2
+ # Copyright 2013-2016 DataStax, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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 only if `org.apache.cassandra.auth.PasswordAuthenticator` is given.
57
- # @param authentication_class [String] must equal to `org.apache.cassandra.auth.PasswordAuthenticator`
58
- # @return [Cassandra::Auth::Authenticator] when `authentication_class == "org.apache.cassandra.auth.PasswordAuthenticator"`
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
- if authentication_class == PASSWORD_AUTHENTICATOR_FQCN
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
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  #--
4
- # Copyright 2013-2015 DataStax, Inc.
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 {Cassandra::Session session factory} factory and a collection of metadata.
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, io_reactor, executor, control_connection, cluster_registry, cluster_schema, cluster_metadata, execution_options, connection_options, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connector, futures_factory)
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 |cause|
47
- @load_balancing_policy.teardown(self) rescue nil
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 :hosts :each_host
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 :keyspaces :each_keyspace
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, @registry, @schema, @io_reactor, @connector, @load_balancing_policy, @reconnection_policy, @retry_policy, @address_resolver, @connection_options, @futures)
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#{self.object_id.to_s(16)}>"
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-2015 DataStax, Inc.
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, cluster_registry, cluster_schema, io_reactor, connector, load_balancing_policy, reconnection_policy, retry_policy, address_resolution_policy, connection_options, futures_factory)
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 distance. Distance must be one of #{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
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, connecting_hosts[f.host], @reconnection_policy.schedule)
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, @state = @state, :closing
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
- f = @connected_future.recover.flat_map { close_connections }
131
- else
132
- f = close_connections
133
- end
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} - invalid load balancing distance. Distance must be one of #{LoadBalancing::DISTANCES.inspect}, #{distance.inspect} given")
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.has_key?(host)
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! {|c| c.close}).map(nil)
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
- return @futures.error(Errors::ClientError.new("Positional arguments are not supported by the current version of Apache Cassandra")) if !statement.params.empty? && @connection_options.protocol_version == 1
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 = nil
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 @connection_options.protocol_version >= 4
214
- request = Protocol::QueryRequest.new(statement.cql, statement.params, statement.params_types, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, statement.params_names, timestamp, payload)
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, keyspace, statement, options, request, plan, timeout)
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 @connection_options.protocol_version >= 4
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, keyspace, statement, options, request, plan, timeout)
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 = nil
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 @connection_options.protocol_version >= 4
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, statement.params_types, statement.params, result_metadata.nil?, options.consistency, options.serial_consistency, options.page_size, options.paging_state, options.trace?, timestamp, payload)
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
- return @futures.error(Errors::ClientError.new("Batch statements are not supported by the current version of Apache Cassandra")) if @connection_options.protocol_version < 2
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 = nil
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 @connection_options.protocol_version >= 4
323
+ payload = options.payload if @connection_options.protocol_version >= 4
267
324
  timeout = options.timeout
268
- request = Protocol::BatchRequest.new(BATCH_TYPES[statement.type], options.consistency, options.trace?, options.serial_consistency, timestamp, payload)
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#{self.object_id.to_s(16)}>"
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
- :logged => Protocol::BatchRequest::LOGGED_TYPE,
287
- :unlogged => Protocol::BatchRequest::UNLOGGED_TYPE,
288
- :counter => Protocol::BatchRequest::COUNTER_TYPE,
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 = Protocol::QueryRequest.new("SELECT peer, rpc_address, schema_version FROM system.peers", EMPTY_LIST, EMPTY_LIST, :one)
303
- SELECT_SCHEMA_LOCAL = Protocol::QueryRequest.new("SELECT schema_version FROM system.local WHERE key='local'", EMPTY_LIST, EMPTY_LIST, :one)
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 |host, connections|
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("Scheduling initial connection retry to #{host.ip} (#{e.class.name}: #{e.message})")
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("Scheduling connection retry to #{host.ip} (#{e.class.name}: #{e.message})")
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} - host is already pending connections")
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 {|c| c.close}
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, keyspace, statement, options, request, plan, timeout, errors = nil, hosts = [])
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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 = synchronize { @prepared_statements[host][cql] }
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, keyspace, statement, options, request, plan, timeout, errors = nil, hosts = [])
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, request, options, plan, timeout, errors, hosts)
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) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, request, options, plan, timeout, errors, hosts)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, request, options, plan, timeout, errors, hosts)
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
- statement.statements.each do |statement|
826
+ batch_statement.statements.each do |statement|
576
827
  cql = statement.cql
577
828
 
578
829
  if statement.is_a?(Statements::Bound)
579
- id = synchronize { @prepared_statements[host][cql] }
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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], statement.params, statement.params_types)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, keyspace, statement, options, request, plan, timeout, errors = nil, hosts = [])
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, keyspace, statement, options, request, plan, timeout, errors, hosts)
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, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts, retries = 0)
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 |f|
673
- if f.resolved?
674
- r = f.value
675
-
676
- begin
677
- decision = nil
678
-
679
- case r
680
- when Protocol::UnavailableErrorResponse
681
- decision = @retry_policy.unavailable(statement, r.consistency, r.required, r.alive, retries)
682
- when Protocol::WriteTimeoutErrorResponse
683
- decision = @retry_policy.write_timeout(statement, r.consistency, r.write_type, r.blockfor, r.received, retries)
684
- when Protocol::ReadTimeoutErrorResponse
685
- decision = @retry_policy.read_timeout(statement, r.consistency, r.blockfor, r.received, r.data_present, retries)
686
- when Protocol::UnpreparedErrorResponse
687
- cql = statement.cql
688
-
689
- synchronize do
690
- @preparing_statements[host].delete(cql)
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
- prepare = prepare_statement(host, connection, cql, timeout)
695
- prepare.on_complete do |_|
696
- if prepare.resolved?
697
- request.id = prepare.value
698
- do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
699
- else
700
- prepare.on_failure do |e|
701
- if e.is_a?(Errors::HostError) || (e.is_a?(Errors::TimeoutError) && statement.idempotent?)
702
- errors ||= {}
703
- errors[host] = e
704
- execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
705
- else
706
- promise.break(e)
707
- end
708
- end
709
- end
710
- end
711
- when Protocol::ErrorResponse
712
- error = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
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
- if error.is_a?(Errors::HostError) || (error.is_a?(Errors::TimeoutError) && statement.idempotent?)
715
- errors ||= {}
716
- errors[host] = error
717
-
718
- case request
719
- when Protocol::QueryRequest, Protocol::PrepareRequest
720
- send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
721
- when Protocol::ExecuteRequest
722
- execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
723
- when Protocol::BatchRequest
724
- batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
725
- end
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
- promise.break(error)
728
- end
729
- when Protocol::SetKeyspaceResultResponse
730
- @keyspace = r.keyspace
731
- promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
732
- when Protocol::PreparedResultResponse
733
- cql = request.cql
734
- synchronize do
735
- @prepared_statements[host][cql] = r.id
736
- @preparing_statements[host].delete(cql)
737
- end
738
-
739
- metadata = r.metadata
740
- pk_idx = r.pk_idx
741
- pk_idx ||= @schema.get_pk_idx(metadata)
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
- promise.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
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.fulfill(Results::Void.new(r.custom_payload, r.warnings, r.trace_id, keyspace, statement, options, hosts, request.consistency, retries, self, @futures))
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
- if decision
766
- case decision
767
- when Retry::Decisions::Retry
768
- request.consistency = decision.consistency
769
- do_send_request_by_plan(host, connection, promise, keyspace, statement, options, request, plan, timeout, errors, hosts, retries + 1)
770
- when Retry::Decisions::TryNextHost
771
- errors ||= {}
772
- errors[host] = r.to_error(keyspace, statement, options, hosts, request.consistency, retries)
773
- case request
774
- when Protocol::QueryRequest, Protocol::PrepareRequest
775
- send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
776
- when Protocol::ExecuteRequest
777
- execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
778
- when Protocol::BatchRequest
779
- batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
780
- else
781
- promise.break(e)
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
- rescue => e
792
- promise.break(e)
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
- else
795
- f.on_failure do |e|
796
- errors ||= {}
797
- errors[host] = e
798
- case request
799
- when Protocol::QueryRequest, Protocol::PrepareRequest
800
- send_request_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
801
- when Protocol::ExecuteRequest
802
- execute_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
803
- when Protocol::BatchRequest
804
- batch_by_plan(promise, keyspace, statement, options, request, plan, timeout, errors, hosts)
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(e)
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
- peers = send_select_request(connection, SELECT_SCHEMA_PEERS)
817
- local = send_select_request(connection, SELECT_SCHEMA_LOCAL)
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(peers, local).flat_map do |(peers, local)|
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("Hosts have different schema versions: #{versions.to_a.inspect}, retrying in #{interval} seconds")
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)}", EMPTY_LIST, EMPTY_LIST, :one)
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, Statements::Simple.new("USE #{Util.escape_name(keyspace)}"), VOID_OPTIONS, EMPTY_LIST, :one, 0)
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 |f|
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.has_key?(cql)
1520
+ return pending[cql] if pending.key?(cql)
895
1521
  end
896
1522
 
897
1523
  request = Protocol::PrepareRequest.new(cql, false)