cassandra-driver 3.0.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +46 -31
- data/lib/cassandra.rb +35 -44
- data/lib/cassandra/cluster.rb +40 -11
- data/lib/cassandra/cluster/client.rb +193 -159
- data/lib/cassandra/cluster/connector.rb +12 -10
- data/lib/cassandra/cluster/control_connection.rb +38 -10
- data/lib/cassandra/cluster/options.rb +8 -4
- data/lib/cassandra/cluster/registry.rb +1 -2
- data/lib/cassandra/cluster/schema/fetchers.rb +122 -26
- data/lib/cassandra/column_container.rb +9 -4
- data/lib/cassandra/custom_data.rb +24 -22
- data/lib/cassandra/driver.rb +30 -13
- data/lib/cassandra/errors.rb +12 -2
- data/lib/cassandra/execution/options.rb +52 -16
- data/lib/cassandra/execution/profile.rb +150 -0
- data/lib/cassandra/execution/profile_manager.rb +71 -0
- data/lib/cassandra/execution/trace.rb +5 -4
- data/lib/cassandra/executors.rb +1 -1
- data/lib/cassandra/index.rb +1 -1
- data/lib/cassandra/keyspace.rb +36 -1
- data/lib/cassandra/protocol.rb +5 -0
- data/lib/cassandra/protocol/coder.rb +2 -1
- data/lib/cassandra/protocol/cql_byte_buffer.rb +21 -0
- data/lib/cassandra/protocol/responses/read_failure_error_response.rb +10 -4
- data/lib/cassandra/protocol/responses/write_failure_error_response.rb +14 -8
- data/lib/cassandra/protocol/v3.rb +2 -1
- data/lib/cassandra/protocol/v4.rb +58 -20
- data/lib/cassandra/result.rb +1 -1
- data/lib/cassandra/session.rb +43 -16
- data/lib/cassandra/statements/bound.rb +5 -1
- data/lib/cassandra/statements/prepared.rb +8 -3
- data/lib/cassandra/table.rb +72 -0
- data/lib/cassandra/trigger.rb +67 -0
- data/lib/cassandra/types.rb +12 -24
- data/lib/cassandra/udt.rb +3 -6
- data/lib/cassandra/uuid/generator.rb +6 -3
- data/lib/cassandra/version.rb +1 -1
- metadata +5 -2
@@ -0,0 +1,71 @@
|
|
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
|
+
module Cassandra
|
20
|
+
module Execution
|
21
|
+
# @private
|
22
|
+
class ProfileManager
|
23
|
+
attr_reader :profiles
|
24
|
+
attr_reader :load_balancing_policies
|
25
|
+
|
26
|
+
def initialize(default_profile, profiles)
|
27
|
+
# default_profile is the default profile that we constructed internally. However, the user can override it
|
28
|
+
# with their own :default profile. If that happens, ignore the internally generated default profile.
|
29
|
+
|
30
|
+
profiles[:default] = default_profile unless profiles.key?(:default)
|
31
|
+
|
32
|
+
# Save off all of the load-balancing policies for easy access.
|
33
|
+
@load_balancing_policies = Set.new
|
34
|
+
profiles.each do |name, profile|
|
35
|
+
@load_balancing_policies << profile.load_balancing_policy
|
36
|
+
end
|
37
|
+
@profiles = profiles
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_profile
|
41
|
+
@profiles[:default]
|
42
|
+
end
|
43
|
+
|
44
|
+
def distance(host)
|
45
|
+
# Return the min distance to the host, as per each lbp.
|
46
|
+
distances = Set.new
|
47
|
+
@load_balancing_policies.each do |lbp|
|
48
|
+
distances.add(lbp.distance(host))
|
49
|
+
end
|
50
|
+
return :local if distances.include?(:local)
|
51
|
+
return :remote if distances.include?(:remote)
|
52
|
+
|
53
|
+
# Fall back to ignore the host.
|
54
|
+
:ignore
|
55
|
+
end
|
56
|
+
|
57
|
+
# NOTE: It's only safe to call add_profile when setting up the cluster object. In particular,
|
58
|
+
# this is only ok before calling Driver#connect.
|
59
|
+
def add_profile(name, profile)
|
60
|
+
@profiles[name] = profile
|
61
|
+
@load_balancing_policies << profile.load_balancing_policy
|
62
|
+
end
|
63
|
+
|
64
|
+
# @private
|
65
|
+
def inspect
|
66
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} " \
|
67
|
+
"profiles=#{@profiles.inspect}>"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -53,7 +53,7 @@ module Cassandra
|
|
53
53
|
attr_reader :id
|
54
54
|
|
55
55
|
# @private
|
56
|
-
def initialize(id, client)
|
56
|
+
def initialize(id, client, load_balancing_policy)
|
57
57
|
@id = id
|
58
58
|
@client = client
|
59
59
|
@coordinator = nil
|
@@ -65,6 +65,7 @@ module Cassandra
|
|
65
65
|
@client_ip = nil
|
66
66
|
@loaded = false
|
67
67
|
@loaded_events = false
|
68
|
+
@load_balancing_policy = load_balancing_policy
|
68
69
|
|
69
70
|
mon_initialize
|
70
71
|
end
|
@@ -141,12 +142,12 @@ module Cassandra
|
|
141
142
|
|
142
143
|
attempt = 1
|
143
144
|
data = @client.query(Statements::Simple.new(SELECT_SESSION % @id),
|
144
|
-
VOID_OPTIONS).get.first
|
145
|
+
VOID_OPTIONS.override(load_balancing_policy: @load_balancing_policy)).get.first
|
145
146
|
|
146
147
|
while data.nil? && attempt <= 5
|
147
148
|
sleep(attempt * 0.4)
|
148
149
|
data = @client.query(Statements::Simple.new(SELECT_SESSION % @id),
|
149
|
-
VOID_OPTIONS).get.first
|
150
|
+
VOID_OPTIONS.override(load_balancing_policy: @load_balancing_policy)).get.first
|
150
151
|
break if data
|
151
152
|
attempt += 1
|
152
153
|
end
|
@@ -173,7 +174,7 @@ module Cassandra
|
|
173
174
|
@events = []
|
174
175
|
|
175
176
|
@client.query(Statements::Simple.new(SELECT_EVENTS % @id),
|
176
|
-
VOID_OPTIONS).get.each do |row|
|
177
|
+
VOID_OPTIONS.override(load_balancing_policy: @load_balancing_policy)).get.each do |row|
|
177
178
|
@events << Event.new(row['event_id'],
|
178
179
|
row['activity'],
|
179
180
|
row['source'],
|
data/lib/cassandra/executors.rb
CHANGED
data/lib/cassandra/index.rb
CHANGED
@@ -62,7 +62,7 @@ module Cassandra
|
|
62
62
|
@options['class_name']
|
63
63
|
end
|
64
64
|
|
65
|
-
# @return [String] a cql representation of this
|
65
|
+
# @return [String] a cql representation of this index
|
66
66
|
def to_cql
|
67
67
|
keyspace_name = Util.escape_name(@table.keyspace.name)
|
68
68
|
table_name = Util.escape_name(@table.name)
|
data/lib/cassandra/keyspace.rb
CHANGED
@@ -69,11 +69,18 @@ module Cassandra
|
|
69
69
|
@views = views
|
70
70
|
|
71
71
|
# Set the keyspace attribute on the tables and views.
|
72
|
+
# Also set up the index collection on the keyspace and the view-collection on each table.
|
73
|
+
@indexes_hash = {}
|
72
74
|
@tables.each_value do |t|
|
73
75
|
t.set_keyspace(self)
|
76
|
+
t.each_index do |index|
|
77
|
+
@indexes_hash[index.name] = index
|
78
|
+
end
|
74
79
|
end
|
75
80
|
@views.each_value do |v|
|
76
81
|
v.set_keyspace(self)
|
82
|
+
table = v.base_table
|
83
|
+
table.add_view(v) if table
|
77
84
|
end
|
78
85
|
end
|
79
86
|
|
@@ -110,6 +117,34 @@ module Cassandra
|
|
110
117
|
end
|
111
118
|
alias tables each_table
|
112
119
|
|
120
|
+
# @return [Boolean] whether this keyspace has an index with the given name
|
121
|
+
# @param name [String] index name
|
122
|
+
def has_index?(name)
|
123
|
+
@indexes_hash.key?(name)
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Cassandra::Index, nil] an index or nil
|
127
|
+
# @param name [String] index name
|
128
|
+
def index(name)
|
129
|
+
@indexes_hash[name]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Yield or enumerate each index defined in this keyspace
|
133
|
+
# @overload each_index
|
134
|
+
# @yieldparam index [Cassandra::Index] current index
|
135
|
+
# @return [Cassandra::Keyspace] self
|
136
|
+
# @overload each_index
|
137
|
+
# @return [Array<Cassandra::Index>] a list of indexes
|
138
|
+
def each_index(&block)
|
139
|
+
if block_given?
|
140
|
+
@indexes_hash.each_value(&block)
|
141
|
+
self
|
142
|
+
else
|
143
|
+
@indexes_hash.values
|
144
|
+
end
|
145
|
+
end
|
146
|
+
alias indexes each_index
|
147
|
+
|
113
148
|
# @return [Boolean] whether this keyspace has a materialized view with the given name
|
114
149
|
# @param name [String] materialized view name
|
115
150
|
def has_materialized_view?(name)
|
@@ -133,7 +168,7 @@ module Cassandra
|
|
133
168
|
def each_materialized_view(&block)
|
134
169
|
if block_given?
|
135
170
|
@views.each_value do |v|
|
136
|
-
|
171
|
+
yield(v) if v.base_table
|
137
172
|
end
|
138
173
|
self
|
139
174
|
else
|
data/lib/cassandra/protocol.rb
CHANGED
@@ -268,7 +268,8 @@ module Cassandra
|
|
268
268
|
value = ::Hash.new
|
269
269
|
|
270
270
|
buffer.read_signed_int.times do
|
271
|
-
value[read_value_v4(buffer, key_type, custom_type_handlers)] =
|
271
|
+
value[read_value_v4(buffer, key_type, custom_type_handlers)] =
|
272
|
+
read_value_v4(buffer, value_type, custom_type_handlers)
|
272
273
|
end
|
273
274
|
|
274
275
|
value
|
@@ -204,6 +204,15 @@ module Cassandra
|
|
204
204
|
e.backtrace
|
205
205
|
end
|
206
206
|
|
207
|
+
def read_inet_addr
|
208
|
+
size = read_byte
|
209
|
+
IPAddr.new_ntoh(read(size))
|
210
|
+
rescue RangeError => e
|
211
|
+
raise Errors::DecodingError,
|
212
|
+
"Not enough bytes available to decode an INET addr: #{e.message}",
|
213
|
+
e.backtrace
|
214
|
+
end
|
215
|
+
|
207
216
|
def read_consistency
|
208
217
|
index = read_unsigned_short
|
209
218
|
if index >= CONSISTENCIES.size || CONSISTENCIES[index].nil?
|
@@ -232,6 +241,18 @@ module Cassandra
|
|
232
241
|
map
|
233
242
|
end
|
234
243
|
|
244
|
+
def read_reason_map
|
245
|
+
# reason_map is new in v5. Starts with an int indicating the number of key-value pairs, followed by
|
246
|
+
# the key-value pairs. Keys are inet's, values are short int's.
|
247
|
+
map = {}
|
248
|
+
map_size = read_int
|
249
|
+
map_size.times do
|
250
|
+
key = read_inet_addr
|
251
|
+
map[key] = read_short
|
252
|
+
end
|
253
|
+
map
|
254
|
+
end
|
255
|
+
|
235
256
|
def read_string_multimap
|
236
257
|
map = {}
|
237
258
|
map_size = read_unsigned_short
|
@@ -19,7 +19,7 @@
|
|
19
19
|
module Cassandra
|
20
20
|
module Protocol
|
21
21
|
class ReadFailureErrorResponse < ErrorResponse
|
22
|
-
attr_reader :consistency, :received, :blockfor, :numfailures, :data_present
|
22
|
+
attr_reader :consistency, :received, :blockfor, :numfailures, :data_present, :failures_by_node
|
23
23
|
|
24
24
|
def initialize(custom_payload,
|
25
25
|
warnings,
|
@@ -29,14 +29,19 @@ module Cassandra
|
|
29
29
|
received,
|
30
30
|
blockfor,
|
31
31
|
numfailures,
|
32
|
-
data_present
|
32
|
+
data_present,
|
33
|
+
failures_by_node)
|
33
34
|
super(custom_payload, warnings, code, message)
|
34
35
|
|
35
36
|
@consistency = consistency
|
36
37
|
@received = received
|
37
38
|
@blockfor = blockfor
|
38
|
-
@numfailures = numfailures
|
39
39
|
@data_present = data_present
|
40
|
+
@failures_by_node = failures_by_node
|
41
|
+
|
42
|
+
# If failures_by_node is set, numfailures isn't, and v.v. Set @numfailures to the size of the failure-map
|
43
|
+
# if numfailures is nil.
|
44
|
+
@numfailures = numfailures || @failures_by_node.size
|
40
45
|
end
|
41
46
|
|
42
47
|
def to_error(keyspace, statement, options, hosts, consistency, retries)
|
@@ -53,7 +58,8 @@ module Cassandra
|
|
53
58
|
@consistency,
|
54
59
|
@blockfor,
|
55
60
|
@numfailures,
|
56
|
-
@received
|
61
|
+
@received,
|
62
|
+
@failures_by_node)
|
57
63
|
end
|
58
64
|
|
59
65
|
def to_s
|
@@ -19,7 +19,7 @@
|
|
19
19
|
module Cassandra
|
20
20
|
module Protocol
|
21
21
|
class WriteFailureErrorResponse < ErrorResponse
|
22
|
-
attr_reader :consistency, :received, :blockfor, :numfailures, :write_type
|
22
|
+
attr_reader :consistency, :received, :blockfor, :numfailures, :write_type, :failures_by_node
|
23
23
|
|
24
24
|
def initialize(custom_payload,
|
25
25
|
warnings,
|
@@ -29,16 +29,21 @@ module Cassandra
|
|
29
29
|
received,
|
30
30
|
blockfor,
|
31
31
|
numfailures,
|
32
|
-
write_type
|
32
|
+
write_type,
|
33
|
+
failures_by_node)
|
33
34
|
super(custom_payload, warnings, code, message)
|
34
35
|
|
35
36
|
write_type.downcase!
|
36
37
|
|
37
|
-
@consistency
|
38
|
-
@received
|
39
|
-
@blockfor
|
40
|
-
@
|
41
|
-
@
|
38
|
+
@consistency = consistency
|
39
|
+
@received = received
|
40
|
+
@blockfor = blockfor
|
41
|
+
@write_type = write_type.to_sym
|
42
|
+
@failures_by_node = failures_by_node
|
43
|
+
|
44
|
+
# If failures_by_node is set, numfailures isn't, and v.v. Set @numfailures to the size of the failure-map
|
45
|
+
# if numfailures is nil.
|
46
|
+
@numfailures = numfailures || @failures_by_node.size
|
42
47
|
end
|
43
48
|
|
44
49
|
def to_error(keyspace, statement, options, hosts, consistency, retries)
|
@@ -55,7 +60,8 @@ module Cassandra
|
|
55
60
|
@consistency,
|
56
61
|
@blockfor,
|
57
62
|
@numfailures,
|
58
|
-
@received
|
63
|
+
@received,
|
64
|
+
@failures_by_node)
|
59
65
|
end
|
60
66
|
|
61
67
|
def to_s
|
@@ -166,7 +166,8 @@ module Cassandra
|
|
166
166
|
if compression == 1
|
167
167
|
if @compressor
|
168
168
|
buffer = CqlByteBuffer.new(
|
169
|
-
@compressor.decompress(buffer.read(frame_length))
|
169
|
+
@compressor.decompress(buffer.read(frame_length))
|
170
|
+
)
|
170
171
|
frame_length = buffer.size
|
171
172
|
else
|
172
173
|
raise Errors::DecodingError,
|
@@ -23,7 +23,7 @@ module Cassandra
|
|
23
23
|
class Encoder
|
24
24
|
HEADER_FORMAT = 'c2ncN'.freeze
|
25
25
|
|
26
|
-
def initialize(compressor
|
26
|
+
def initialize(compressor, protocol_version)
|
27
27
|
@compressor = compressor
|
28
28
|
@protocol_version = protocol_version
|
29
29
|
end
|
@@ -31,6 +31,7 @@ module Cassandra
|
|
31
31
|
def encode(buffer, request, stream_id)
|
32
32
|
flags = 0
|
33
33
|
flags |= 0x02 if request.trace?
|
34
|
+
flags |= 0x10 if @protocol_version == Cassandra::Protocol::Versions::BETA_VERSION
|
34
35
|
|
35
36
|
body = CqlByteBuffer.new
|
36
37
|
|
@@ -178,7 +179,8 @@ module Cassandra
|
|
178
179
|
if compression
|
179
180
|
if @compressor
|
180
181
|
buffer = CqlByteBuffer.new(
|
181
|
-
@compressor.decompress(buffer.read(frame_length))
|
182
|
+
@compressor.decompress(buffer.read(frame_length))
|
183
|
+
)
|
182
184
|
frame_length = buffer.size
|
183
185
|
else
|
184
186
|
raise Errors::DecodingError,
|
@@ -259,15 +261,33 @@ module Cassandra
|
|
259
261
|
buffer.read_int,
|
260
262
|
(buffer.read_byte != 0))
|
261
263
|
when 0x1300
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
264
|
+
cl = buffer.read_consistency
|
265
|
+
received = buffer.read_int
|
266
|
+
block_for = buffer.read_int
|
267
|
+
if protocol_version < 5
|
268
|
+
ReadFailureErrorResponse.new(custom_payload,
|
269
|
+
warnings,
|
270
|
+
code,
|
271
|
+
message,
|
272
|
+
cl,
|
273
|
+
received,
|
274
|
+
block_for,
|
275
|
+
buffer.read_int,
|
276
|
+
(buffer.read_byte != 0),
|
277
|
+
nil)
|
278
|
+
else
|
279
|
+
failures_by_node = buffer.read_reason_map
|
280
|
+
ReadFailureErrorResponse.new(custom_payload,
|
281
|
+
warnings,
|
282
|
+
code,
|
283
|
+
message,
|
284
|
+
cl,
|
285
|
+
received,
|
286
|
+
block_for,
|
287
|
+
nil,
|
288
|
+
(buffer.read_byte != 0),
|
289
|
+
failures_by_node)
|
290
|
+
end
|
271
291
|
when 0x1400
|
272
292
|
FunctionFailureErrorResponse.new(custom_payload,
|
273
293
|
warnings,
|
@@ -277,15 +297,33 @@ module Cassandra
|
|
277
297
|
buffer.read_string,
|
278
298
|
buffer.read_string_list)
|
279
299
|
when 0x1500
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
300
|
+
cl = buffer.read_consistency
|
301
|
+
received = buffer.read_int
|
302
|
+
block_for = buffer.read_int
|
303
|
+
if protocol_version < 5
|
304
|
+
WriteFailureErrorResponse.new(custom_payload,
|
305
|
+
warnings,
|
306
|
+
code,
|
307
|
+
message,
|
308
|
+
cl,
|
309
|
+
received,
|
310
|
+
block_for,
|
311
|
+
buffer.read_int,
|
312
|
+
buffer.read_string,
|
313
|
+
nil)
|
314
|
+
else
|
315
|
+
failures_by_node = buffer.read_reason_map
|
316
|
+
WriteFailureErrorResponse.new(custom_payload,
|
317
|
+
warnings,
|
318
|
+
code,
|
319
|
+
message,
|
320
|
+
cl,
|
321
|
+
received,
|
322
|
+
block_for,
|
323
|
+
nil,
|
324
|
+
buffer.read_string,
|
325
|
+
failures_by_node)
|
326
|
+
end
|
289
327
|
when 0x2400
|
290
328
|
AlreadyExistsErrorResponse.new(custom_payload,
|
291
329
|
warnings,
|