cassandra-driver 1.0.0.beta.3-java → 1.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 +51 -14
- data/lib/cassandra.rb +164 -78
- data/lib/cassandra/address_resolution.rb +36 -0
- data/lib/cassandra/address_resolution/policies.rb +2 -0
- data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
- data/lib/cassandra/address_resolution/policies/none.rb +35 -0
- data/lib/cassandra/auth.rb +1 -1
- data/lib/cassandra/auth/providers/password.rb +1 -1
- data/lib/cassandra/cluster.rb +18 -5
- data/lib/cassandra/cluster/client.rb +175 -101
- data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +5 -5
- data/lib/cassandra/cluster/connector.rb +142 -56
- data/lib/cassandra/cluster/control_connection.rb +385 -134
- data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
- data/lib/cassandra/cluster/options.rb +13 -2
- data/lib/cassandra/cluster/registry.rb +19 -9
- data/lib/cassandra/column.rb +5 -0
- data/lib/cassandra/compression.rb +1 -1
- data/lib/cassandra/compression/compressors/lz4.rb +1 -1
- data/lib/cassandra/compression/compressors/snappy.rb +1 -1
- data/lib/cassandra/driver.rb +29 -21
- data/lib/cassandra/errors.rb +325 -35
- data/lib/cassandra/execution/options.rb +13 -6
- data/lib/cassandra/execution/trace.rb +4 -4
- data/lib/cassandra/future.rb +7 -3
- data/lib/cassandra/keyspace.rb +5 -0
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +13 -4
- data/lib/cassandra/load_balancing/policies/token_aware.rb +2 -4
- data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
- data/lib/cassandra/null_logger.rb +35 -0
- data/lib/cassandra/protocol.rb +0 -16
- data/lib/cassandra/protocol/cql_byte_buffer.rb +18 -18
- data/lib/cassandra/protocol/cql_protocol_handler.rb +78 -8
- data/lib/cassandra/protocol/frame_decoder.rb +2 -2
- data/lib/cassandra/protocol/frame_encoder.rb +1 -1
- data/lib/cassandra/protocol/requests/query_request.rb +1 -11
- data/lib/cassandra/protocol/response.rb +1 -1
- data/lib/cassandra/protocol/responses/detailed_error_response.rb +16 -1
- data/lib/cassandra/protocol/responses/error_response.rb +17 -0
- data/lib/cassandra/protocol/responses/event_response.rb +1 -1
- data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/result_response.rb +1 -1
- data/lib/cassandra/protocol/responses/rows_result_response.rb +1 -1
- data/lib/cassandra/protocol/type_converter.rb +4 -3
- data/lib/cassandra/reconnection.rb +1 -1
- data/lib/cassandra/result.rb +4 -6
- data/lib/cassandra/retry.rb +3 -5
- data/lib/cassandra/session.rb +14 -5
- data/lib/cassandra/statements/prepared.rb +5 -1
- data/lib/cassandra/table.rb +6 -1
- data/lib/cassandra/time_uuid.rb +21 -83
- data/lib/cassandra/util.rb +131 -1
- data/lib/cassandra/uuid.rb +6 -4
- data/lib/cassandra/uuid/generator.rb +207 -0
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +43 -49
- data/lib/cassandra/client.rb +0 -144
- data/lib/cassandra/client/batch.rb +0 -212
- data/lib/cassandra/client/client.rb +0 -591
- data/lib/cassandra/client/column_metadata.rb +0 -54
- data/lib/cassandra/client/connector.rb +0 -277
- data/lib/cassandra/client/execute_options_decoder.rb +0 -59
- data/lib/cassandra/client/peer_discovery.rb +0 -50
- data/lib/cassandra/client/prepared_statement.rb +0 -314
- data/lib/cassandra/client/query_result.rb +0 -230
- data/lib/cassandra/client/request_runner.rb +0 -71
- data/lib/cassandra/client/result_metadata.rb +0 -48
- data/lib/cassandra/client/void_result.rb +0 -78
@@ -39,14 +39,21 @@ module Cassandra
|
|
39
39
|
timeout = options[:timeout]
|
40
40
|
serial_consistency = options[:serial_consistency]
|
41
41
|
|
42
|
-
|
43
|
-
raise ::ArgumentError, ":serial_consistency must be one of #{SERIAL_CONSISTENCIES.inspect}, #{serial_consistency.inspect} given" if serial_consistency && !SERIAL_CONSISTENCIES.include?(serial_consistency)
|
42
|
+
Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
|
44
43
|
|
45
|
-
|
46
|
-
|
44
|
+
unless serial_consistency.nil?
|
45
|
+
Util.assert_one_of(SERIAL_CONSISTENCIES, serial_consistency) { ":serial_consistency must be one of #{SERIAL_CONSISTENCIES.inspect}, #{serial_consistency.inspect} given" }
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
unless page_size.nil?
|
49
|
+
page_size = options[:page_size] = Integer(page_size)
|
50
|
+
Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
|
51
|
+
end
|
52
|
+
|
53
|
+
unless timeout.nil?
|
54
|
+
Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
|
55
|
+
Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
|
56
|
+
end
|
50
57
|
|
51
58
|
@consistency = consistency
|
52
59
|
@page_size = page_size
|
@@ -108,16 +108,16 @@ module Cassandra
|
|
108
108
|
private
|
109
109
|
|
110
110
|
# @private
|
111
|
-
SELECT_SESSION = "SELECT * FROM system_traces.sessions WHERE session_id =
|
111
|
+
SELECT_SESSION = "SELECT * FROM system_traces.sessions WHERE session_id = %s"
|
112
112
|
# @private
|
113
|
-
SELECT_EVENTS = "SELECT * FROM system_traces.events WHERE session_id =
|
113
|
+
SELECT_EVENTS = "SELECT * FROM system_traces.events WHERE session_id = %s"
|
114
114
|
|
115
115
|
# @private
|
116
116
|
def load
|
117
117
|
synchronize do
|
118
118
|
return if @loaded
|
119
119
|
|
120
|
-
data = @client.query(Statements::Simple.new(SELECT_SESSION
|
120
|
+
data = @client.query(Statements::Simple.new(SELECT_SESSION % @id), VOID_OPTIONS).get.first
|
121
121
|
raise ::RuntimeError, "unable to load trace #{@id}" if data.nil?
|
122
122
|
|
123
123
|
@coordinator = data['coordinator']
|
@@ -138,7 +138,7 @@ module Cassandra
|
|
138
138
|
|
139
139
|
@events = []
|
140
140
|
|
141
|
-
@client.query(Statements::Simple.new(SELECT_EVENTS
|
141
|
+
@client.query(Statements::Simple.new(SELECT_EVENTS % @id), VOID_OPTIONS).get.each do |row|
|
142
142
|
@events << Event.new(row['event_id'], row['activity'], row['source'], row['source_elapsed'], row['thread'])
|
143
143
|
end
|
144
144
|
|
data/lib/cassandra/future.rb
CHANGED
@@ -48,6 +48,8 @@ module Cassandra
|
|
48
48
|
def initialize(error)
|
49
49
|
raise ::ArgumentError, "error must be an exception, #{error.inspect} given" unless error.is_a?(::Exception)
|
50
50
|
|
51
|
+
error.set_backtrace(caller) unless error.backtrace
|
52
|
+
|
51
53
|
@error = error
|
52
54
|
end
|
53
55
|
|
@@ -188,7 +190,7 @@ module Cassandra
|
|
188
190
|
monitor = Monitor.new
|
189
191
|
promise = Promise.new
|
190
192
|
remaining = futures.length
|
191
|
-
values = Array.new(
|
193
|
+
values = Array.new(remaining)
|
192
194
|
|
193
195
|
futures.each_with_index do |future, i|
|
194
196
|
future.on_complete do |v, e|
|
@@ -390,11 +392,11 @@ module Cassandra
|
|
390
392
|
end
|
391
393
|
|
392
394
|
def success(value)
|
393
|
-
@block.call(
|
395
|
+
@block.call(value, nil)
|
394
396
|
end
|
395
397
|
|
396
398
|
def failure(error)
|
397
|
-
@block.call(
|
399
|
+
@block.call(nil, error)
|
398
400
|
end
|
399
401
|
end
|
400
402
|
|
@@ -471,6 +473,8 @@ module Cassandra
|
|
471
473
|
raise ::ArgumentError, "error must be an exception, #{error.inspect} given"
|
472
474
|
end
|
473
475
|
|
476
|
+
error.set_backtrace(caller) unless error.backtrace
|
477
|
+
|
474
478
|
return unless @state == :pending
|
475
479
|
|
476
480
|
listeners = nil
|
data/lib/cassandra/keyspace.rb
CHANGED
@@ -106,6 +106,11 @@ module Cassandra
|
|
106
106
|
end
|
107
107
|
alias :== :eql?
|
108
108
|
|
109
|
+
# @return [String] a CLI-friendly keyspace representation
|
110
|
+
def inspect
|
111
|
+
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} @name=#{@name}>"
|
112
|
+
end
|
113
|
+
|
109
114
|
# @private
|
110
115
|
def update_table(table)
|
111
116
|
tables = @tables.dup
|
@@ -56,12 +56,17 @@ module Cassandra
|
|
56
56
|
|
57
57
|
include MonitorMixin
|
58
58
|
|
59
|
-
def initialize(datacenter, max_remote_hosts_to_use = nil, use_remote_hosts_for_local_consistency = false)
|
60
|
-
datacenter = String(datacenter)
|
59
|
+
def initialize(datacenter = nil, max_remote_hosts_to_use = nil, use_remote_hosts_for_local_consistency = false)
|
60
|
+
datacenter = datacenter && String(datacenter)
|
61
61
|
max_remote_hosts_to_use = max_remote_hosts_to_use && Integer(max_remote_hosts_to_use)
|
62
62
|
|
63
|
-
|
64
|
-
|
63
|
+
unless datacenter.nil?
|
64
|
+
Util.assert_not_empty(datacenter) { "datacenter cannot be empty" }
|
65
|
+
end
|
66
|
+
|
67
|
+
unless max_remote_hosts_to_use.nil?
|
68
|
+
Util.assert(max_remote_hosts_to_use >= 0) { "max_remote_hosts_to_use must be nil or >= 0" }
|
69
|
+
end
|
65
70
|
|
66
71
|
@datacenter = datacenter
|
67
72
|
@max_remote = max_remote_hosts_to_use
|
@@ -75,6 +80,10 @@ module Cassandra
|
|
75
80
|
end
|
76
81
|
|
77
82
|
def host_up(host)
|
83
|
+
if !@datacenter && host.datacenter
|
84
|
+
@datacenter = host.datacenter
|
85
|
+
end
|
86
|
+
|
78
87
|
if host.datacenter.nil? || host.datacenter == @datacenter
|
79
88
|
synchronize { @local = @local.dup.push(host) }
|
80
89
|
else
|
@@ -92,9 +92,7 @@ module Cassandra
|
|
92
92
|
def initialize(wrapped_policy)
|
93
93
|
methods = [:host_up, :host_down, :host_found, :host_lost, :distance, :plan]
|
94
94
|
|
95
|
-
|
96
|
-
raise ::ArgumentError, "supplied policy must be a Cassandra::LoadBalancing::Policy, #{wrapped_policy.inspect} given"
|
97
|
-
end
|
95
|
+
Util.assert_responds_to_all(methods, wrapped_policy) { "supplied policy must respond to #{methods.inspect}, but doesn't" }
|
98
96
|
|
99
97
|
@policy = wrapped_policy
|
100
98
|
end
|
@@ -111,7 +109,7 @@ module Cassandra
|
|
111
109
|
replicas = @cluster.find_replicas(keyspace, statement)
|
112
110
|
return @policy.plan(keyspace, statement, options) if replicas.empty?
|
113
111
|
|
114
|
-
Plan.new(replicas.
|
112
|
+
Plan.new(replicas.shuffle, @policy, keyspace, statement, options)
|
115
113
|
end
|
116
114
|
end
|
117
115
|
end
|
@@ -35,12 +35,9 @@ module Cassandra
|
|
35
35
|
# @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual policy to filter
|
36
36
|
# @raise [ArgumentError] if arguments are of unexpected types
|
37
37
|
def initialize(ips, wrapped_policy)
|
38
|
-
|
38
|
+
Util.assert_instance_of(::Enumerable, ips) { "ips must be an Enumerable, #{ips.inspect} given" }
|
39
39
|
methods = [:host_up, :host_down, :host_found, :host_lost, :distance, :plan]
|
40
|
-
|
41
|
-
unless methods.all? {|method| wrapped_policy.respond_to?(method)}
|
42
|
-
raise ::ArgumentError, "supplied policy must be a Cassandra::LoadBalancing::Policy, #{wrapped_policy.inspect} given"
|
43
|
-
end
|
40
|
+
Util.assert_responds_to_all(methods, wrapped_policy) { "supplied policy must respond to #{methods.inspect}, but doesn't" }
|
44
41
|
|
45
42
|
@ips = ::Set.new
|
46
43
|
@policy = wrapped_policy
|
@@ -52,7 +49,7 @@ module Cassandra
|
|
52
49
|
when ::String
|
53
50
|
@ips << ::IPAddr.new(ip)
|
54
51
|
else
|
55
|
-
raise ::ArgumentError, "
|
52
|
+
raise ::ArgumentError, "each ip must be a String or IPAddr, #{ip.inspect} given"
|
56
53
|
end
|
57
54
|
end
|
58
55
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2013-2014 DataStax, Inc.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
module Cassandra
|
20
|
+
# @private
|
21
|
+
class NullLogger
|
22
|
+
def close(*); end
|
23
|
+
def debug(*); end
|
24
|
+
def debug?; false end
|
25
|
+
def error(*); end
|
26
|
+
def error?; false end
|
27
|
+
def fatal(*); end
|
28
|
+
def fatal?; false end
|
29
|
+
def info(*); end
|
30
|
+
def info?; false end
|
31
|
+
def unknown(*); end
|
32
|
+
def warn(*); end
|
33
|
+
def warn?; false end
|
34
|
+
end
|
35
|
+
end
|
data/lib/cassandra/protocol.rb
CHANGED
@@ -17,24 +17,8 @@
|
|
17
17
|
#++
|
18
18
|
|
19
19
|
module Cassandra
|
20
|
-
# @private
|
21
|
-
ProtocolError = Class.new(Error)
|
22
|
-
|
23
20
|
# @private
|
24
21
|
module Protocol
|
25
|
-
DecodingError = Class.new(ProtocolError)
|
26
|
-
EncodingError = Class.new(ProtocolError)
|
27
|
-
InvalidStreamIdError = Class.new(ProtocolError)
|
28
|
-
InvalidValueError = Class.new(ProtocolError)
|
29
|
-
UnsupportedOperationError = Class.new(ProtocolError)
|
30
|
-
UnsupportedFrameTypeError = Class.new(ProtocolError)
|
31
|
-
UnsupportedResultKindError = Class.new(ProtocolError)
|
32
|
-
UnsupportedColumnTypeError = Class.new(ProtocolError)
|
33
|
-
UnsupportedEventTypeError = Class.new(ProtocolError)
|
34
|
-
UnsupportedFeatureError = Class.new(ProtocolError)
|
35
|
-
UnexpectedCompressionError = Class.new(ProtocolError)
|
36
|
-
UnmaterializedRowsError = Class.new(ProtocolError)
|
37
|
-
|
38
22
|
module Formats
|
39
23
|
CHAR_FORMAT = 'c'.freeze
|
40
24
|
DOUBLE_FORMAT = 'G'.freeze
|
@@ -22,7 +22,7 @@ module Cassandra
|
|
22
22
|
def read_unsigned_byte
|
23
23
|
read_byte
|
24
24
|
rescue RangeError => e
|
25
|
-
raise DecodingError, e.message, e.backtrace
|
25
|
+
raise Errors::DecodingError, e.message, e.backtrace
|
26
26
|
end
|
27
27
|
|
28
28
|
def read_varint(len=bytesize, signed=true)
|
@@ -36,7 +36,7 @@ module Cassandra
|
|
36
36
|
end
|
37
37
|
n
|
38
38
|
rescue RangeError => e
|
39
|
-
raise DecodingError, e.message, e.backtrace
|
39
|
+
raise Errors::DecodingError, e.message, e.backtrace
|
40
40
|
end
|
41
41
|
|
42
42
|
def read_decimal(len=bytesize)
|
@@ -57,8 +57,8 @@ module Cassandra
|
|
57
57
|
fraction_string << number_string[number_string.length - size, number_string.length]
|
58
58
|
end
|
59
59
|
BigDecimal.new(fraction_string)
|
60
|
-
rescue DecodingError => e
|
61
|
-
raise DecodingError, e.message, e.backtrace
|
60
|
+
rescue Errors::DecodingError => e
|
61
|
+
raise Errors::DecodingError, e.message, e.backtrace
|
62
62
|
end
|
63
63
|
|
64
64
|
def read_long
|
@@ -68,19 +68,19 @@ module Cassandra
|
|
68
68
|
bottom ^= 0xffffffff
|
69
69
|
-((top << 32) | bottom) - 1
|
70
70
|
rescue RangeError => e
|
71
|
-
raise DecodingError, e.message, e.backtrace
|
71
|
+
raise Errors::DecodingError, e.message, e.backtrace
|
72
72
|
end
|
73
73
|
|
74
74
|
def read_double
|
75
75
|
read(8).unpack(Formats::DOUBLE_FORMAT).first
|
76
76
|
rescue RangeError => e
|
77
|
-
raise DecodingError, "Not enough bytes available to decode a double: #{e.message}", e.backtrace
|
77
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a double: #{e.message}", e.backtrace
|
78
78
|
end
|
79
79
|
|
80
80
|
def read_float
|
81
81
|
read(4).unpack(Formats::FLOAT_FORMAT).first
|
82
82
|
rescue RangeError => e
|
83
|
-
raise DecodingError, "Not enough bytes available to decode a float: #{e.message}", e.backtrace
|
83
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a float: #{e.message}", e.backtrace
|
84
84
|
end
|
85
85
|
|
86
86
|
def read_signed_int
|
@@ -88,13 +88,13 @@ module Cassandra
|
|
88
88
|
return n if n <= 0x7fffffff
|
89
89
|
n - 0xffffffff - 1
|
90
90
|
rescue RangeError => e
|
91
|
-
raise DecodingError, "Not enough bytes available to decode an int: #{e.message}", e.backtrace
|
91
|
+
raise Errors::DecodingError, "Not enough bytes available to decode an int: #{e.message}", e.backtrace
|
92
92
|
end
|
93
93
|
|
94
94
|
def read_unsigned_short
|
95
95
|
read_short
|
96
96
|
rescue RangeError => e
|
97
|
-
raise DecodingError, "Not enough bytes available to decode a short: #{e.message}", e.backtrace
|
97
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a short: #{e.message}", e.backtrace
|
98
98
|
end
|
99
99
|
|
100
100
|
def read_string
|
@@ -103,7 +103,7 @@ module Cassandra
|
|
103
103
|
string.force_encoding(::Encoding::UTF_8)
|
104
104
|
string
|
105
105
|
rescue RangeError => e
|
106
|
-
raise DecodingError, "Not enough bytes available to decode a string: #{e.message}", e.backtrace
|
106
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a string: #{e.message}", e.backtrace
|
107
107
|
end
|
108
108
|
|
109
109
|
def read_long_string
|
@@ -112,13 +112,13 @@ module Cassandra
|
|
112
112
|
string.force_encoding(::Encoding::UTF_8)
|
113
113
|
string
|
114
114
|
rescue RangeError => e
|
115
|
-
raise DecodingError, "Not enough bytes available to decode a long string: #{e.message}", e.backtrace
|
115
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a long string: #{e.message}", e.backtrace
|
116
116
|
end
|
117
117
|
|
118
118
|
def read_uuid(impl=Uuid)
|
119
119
|
impl.new(read_varint(16, false))
|
120
|
-
rescue DecodingError => e
|
121
|
-
raise DecodingError, "Not enough bytes available to decode a UUID: #{e.message}", e.backtrace
|
120
|
+
rescue Errors::DecodingError => e
|
121
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a UUID: #{e.message}", e.backtrace
|
122
122
|
end
|
123
123
|
|
124
124
|
def read_string_list
|
@@ -131,7 +131,7 @@ module Cassandra
|
|
131
131
|
return nil if size & 0x80000000 == 0x80000000
|
132
132
|
read(size)
|
133
133
|
rescue RangeError => e
|
134
|
-
raise DecodingError, "Not enough bytes available to decode a bytes: #{e.message}", e.backtrace
|
134
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a bytes: #{e.message}", e.backtrace
|
135
135
|
end
|
136
136
|
|
137
137
|
def read_short_bytes
|
@@ -139,7 +139,7 @@ module Cassandra
|
|
139
139
|
return nil if size & 0x8000 == 0x8000
|
140
140
|
read(size)
|
141
141
|
rescue RangeError => e
|
142
|
-
raise DecodingError, "Not enough bytes available to decode a short bytes: #{e.message}", e.backtrace
|
142
|
+
raise Errors::DecodingError, "Not enough bytes available to decode a short bytes: #{e.message}", e.backtrace
|
143
143
|
end
|
144
144
|
|
145
145
|
def read_option
|
@@ -157,12 +157,12 @@ module Cassandra
|
|
157
157
|
port = read_int
|
158
158
|
[ip_addr, port]
|
159
159
|
rescue RangeError => e
|
160
|
-
raise DecodingError, "Not enough bytes available to decode an INET: #{e.message}", e.backtrace
|
160
|
+
raise Errors::DecodingError, "Not enough bytes available to decode an INET: #{e.message}", e.backtrace
|
161
161
|
end
|
162
162
|
|
163
163
|
def read_consistency
|
164
164
|
index = read_unsigned_short
|
165
|
-
raise DecodingError, "Unknown consistency index #{index}" if index >= CONSISTENCIES.size || CONSISTENCIES[index].nil?
|
165
|
+
raise Errors::DecodingError, "Unknown consistency index #{index}" if index >= CONSISTENCIES.size || CONSISTENCIES[index].nil?
|
166
166
|
CONSISTENCIES[index]
|
167
167
|
end
|
168
168
|
|
@@ -241,7 +241,7 @@ module Cassandra
|
|
241
241
|
|
242
242
|
def append_consistency(consistency)
|
243
243
|
index = CONSISTENCIES.index(consistency)
|
244
|
-
raise EncodingError, %(Unknown consistency "#{consistency}") if index.nil? || CONSISTENCIES[index].nil?
|
244
|
+
raise Errors::EncodingError, %(Unknown consistency "#{consistency}") if index.nil? || CONSISTENCIES[index].nil?
|
245
245
|
append_short(index)
|
246
246
|
end
|
247
247
|
|
@@ -35,7 +35,7 @@ module Cassandra
|
|
35
35
|
# @return [String] the current keyspace for the underlying connection
|
36
36
|
attr_reader :keyspace
|
37
37
|
|
38
|
-
def initialize(connection, scheduler, protocol_version, compressor=nil)
|
38
|
+
def initialize(connection, scheduler, protocol_version, compressor=nil, heartbeat_interval = 30, idle_timeout = 60)
|
39
39
|
@connection = connection
|
40
40
|
@scheduler = scheduler
|
41
41
|
@compressor = compressor
|
@@ -53,6 +53,10 @@ module Cassandra
|
|
53
53
|
@lock = Mutex.new
|
54
54
|
@closed_promise = Ione::Promise.new
|
55
55
|
@keyspace = nil
|
56
|
+
@heartbeat = nil
|
57
|
+
@terminate = nil
|
58
|
+
@heartbeat_interval = heartbeat_interval
|
59
|
+
@idle_timeout = idle_timeout
|
56
60
|
end
|
57
61
|
|
58
62
|
# Returns the hostname of the underlying connection
|
@@ -128,7 +132,7 @@ module Cassandra
|
|
128
132
|
# closes the futures of all active requests will be failed with the error
|
129
133
|
# that caused the connection to close, or nil.
|
130
134
|
#
|
131
|
-
# When `timeout` is specified the future will fail with {Cassandra::TimeoutError}
|
135
|
+
# When `timeout` is specified the future will fail with {Cassandra::Errors::TimeoutError}
|
132
136
|
# after that many seconds have passed. If a response arrives after that
|
133
137
|
# time it will be lost. If a response never arrives for the request the
|
134
138
|
# channel occupied by the request will _not_ be reused.
|
@@ -138,8 +142,9 @@ module Cassandra
|
|
138
142
|
# failing the request
|
139
143
|
# @return [Ione::Future<Cassandra::Protocol::Response>] a future that resolves to
|
140
144
|
# the response
|
141
|
-
def send_request(request, timeout=nil)
|
142
|
-
return Ione::Future.failed(Errors::
|
145
|
+
def send_request(request, timeout=nil, with_heartbeat = true)
|
146
|
+
return Ione::Future.failed(Errors::IOError.new('Connection closed')) if closed?
|
147
|
+
schedule_heartbeat if with_heartbeat
|
143
148
|
promise = RequestPromise.new(request, @frame_encoder)
|
144
149
|
id = nil
|
145
150
|
@lock.lock
|
@@ -174,8 +179,18 @@ module Cassandra
|
|
174
179
|
# Closes the underlying connection.
|
175
180
|
#
|
176
181
|
# @return [Ione::Future] a future that completes when the connection has closed
|
177
|
-
def close
|
178
|
-
@
|
182
|
+
def close(cause = nil)
|
183
|
+
if @heartbeat
|
184
|
+
@scheduler.cancel_timer(@heartbeat)
|
185
|
+
@heartbeat = nil
|
186
|
+
end
|
187
|
+
|
188
|
+
if @terminate
|
189
|
+
@scheduler.cancel_timer(@terminate)
|
190
|
+
@terminate = nil
|
191
|
+
end
|
192
|
+
|
193
|
+
@connection.close(cause)
|
179
194
|
@closed_promise.future
|
180
195
|
end
|
181
196
|
|
@@ -199,7 +214,7 @@ module Cassandra
|
|
199
214
|
def time_out!
|
200
215
|
unless future.completed?
|
201
216
|
@timed_out = true
|
202
|
-
fail(TimeoutError.new)
|
217
|
+
fail(Errors::TimeoutError.new('Timed out'))
|
203
218
|
end
|
204
219
|
end
|
205
220
|
|
@@ -209,6 +224,7 @@ module Cassandra
|
|
209
224
|
end
|
210
225
|
|
211
226
|
def receive_data(data)
|
227
|
+
reschedule_termination
|
212
228
|
@read_buffer << data
|
213
229
|
@current_frame = @frame_decoder.decode_frame(@read_buffer, @current_frame)
|
214
230
|
while @current_frame.complete?
|
@@ -248,6 +264,9 @@ module Cassandra
|
|
248
264
|
if response.is_a?(Protocol::SetKeyspaceResultResponse)
|
249
265
|
@keyspace = response.keyspace
|
250
266
|
end
|
267
|
+
if response.is_a?(Protocol::SchemaChangeResultResponse) && response.change == 'DROPPED' && response.keyspace == @keyspace && response.table.empty?
|
268
|
+
@keyspace = nil
|
269
|
+
end
|
251
270
|
flush_request_queue
|
252
271
|
unless promise.timed_out?
|
253
272
|
promise.fulfill(response)
|
@@ -291,9 +310,22 @@ module Cassandra
|
|
291
310
|
end
|
292
311
|
|
293
312
|
def socket_closed(cause)
|
294
|
-
|
313
|
+
if cause
|
314
|
+
e = Errors::IOError.new(cause.message)
|
315
|
+
e.set_backtrace(cause.backtrace)
|
316
|
+
|
317
|
+
cause = e
|
318
|
+
end
|
319
|
+
|
320
|
+
request_failure_cause = cause || Errors::IOError.new('Connection closed')
|
295
321
|
promises_to_fail = nil
|
296
322
|
@lock.synchronize do
|
323
|
+
@scheduler.cancel_timer(@heartbeat) if @heartbeat
|
324
|
+
@scheduler.cancel_timer(@terminate) if @terminate
|
325
|
+
|
326
|
+
@heartbeat = nil
|
327
|
+
@terminate = nil
|
328
|
+
|
297
329
|
promises_to_fail = @promises.compact
|
298
330
|
promises_to_fail.concat(@request_queue_in)
|
299
331
|
promises_to_fail.concat(@request_queue_out)
|
@@ -311,6 +343,41 @@ module Cassandra
|
|
311
343
|
end
|
312
344
|
end
|
313
345
|
|
346
|
+
def schedule_heartbeat
|
347
|
+
return unless @heartbeat_interval
|
348
|
+
|
349
|
+
timer = nil
|
350
|
+
|
351
|
+
@lock.synchronize do
|
352
|
+
@scheduler.cancel_timer(@heartbeat) if @heartbeat && !@heartbeat.resolved?
|
353
|
+
|
354
|
+
@heartbeat = timer = @scheduler.schedule_timer(@heartbeat_interval)
|
355
|
+
end
|
356
|
+
|
357
|
+
timer.on_value do
|
358
|
+
send_request(HEARTBEAT, nil, false).on_value do
|
359
|
+
schedule_heartbeat
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def reschedule_termination
|
365
|
+
return unless @idle_timeout
|
366
|
+
|
367
|
+
timer = nil
|
368
|
+
|
369
|
+
@lock.synchronize do
|
370
|
+
@scheduler.cancel_timer(@terminate) if @terminate
|
371
|
+
|
372
|
+
@terminate = timer = @scheduler.schedule_timer(@idle_timeout)
|
373
|
+
end
|
374
|
+
|
375
|
+
timer.on_value do
|
376
|
+
@terminate = nil
|
377
|
+
@connection.close(TERMINATED)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
314
381
|
def next_stream_id
|
315
382
|
if (stream_id = @promises.index(nil))
|
316
383
|
stream_id
|
@@ -318,6 +385,9 @@ module Cassandra
|
|
318
385
|
nil
|
319
386
|
end
|
320
387
|
end
|
388
|
+
|
389
|
+
HEARTBEAT = OptionsRequest.new
|
390
|
+
TERMINATED = Errors::TimeoutError.new('Terminated due to inactivity')
|
321
391
|
end
|
322
392
|
end
|
323
393
|
end
|