aerospike 2.13.0 → 2.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/lib/aerospike.rb +5 -0
- data/lib/aerospike/client.rb +21 -6
- data/lib/aerospike/cluster.rb +47 -0
- data/lib/aerospike/cluster/rack_parser.rb +117 -0
- data/lib/aerospike/command/batch_direct_command.rb +1 -0
- data/lib/aerospike/command/batch_index_command.rb +1 -0
- data/lib/aerospike/command/command.rb +55 -0
- data/lib/aerospike/command/multi_command.rb +44 -1
- data/lib/aerospike/command/read_command.rb +34 -2
- data/lib/aerospike/command/touch_command.rb +34 -1
- data/lib/aerospike/features.rb +2 -0
- data/lib/aerospike/node.rb +18 -1
- data/lib/aerospike/node/rebalance.rb +50 -0
- data/lib/aerospike/node/refresh/info.rb +4 -1
- data/lib/aerospike/node/refresh/racks.rb +47 -0
- data/lib/aerospike/node/refresh/reset.rb +1 -0
- data/lib/aerospike/node/verify/rebalance_generation.rb +43 -0
- data/lib/aerospike/policy/client_policy.rb +15 -0
- data/lib/aerospike/policy/policy.rb +11 -3
- data/lib/aerospike/policy/replica.rb +7 -0
- data/lib/aerospike/socket/base.rb +3 -2
- data/lib/aerospike/utils/buffer.rb +13 -3
- data/lib/aerospike/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0452d4d35ee6d5ce56586cc99b3a68c7e1b4a6c4f6334c6794414a483e2ef01
|
4
|
+
data.tar.gz: 328a5672510bb68e044a92c39fc1f04059daa53b4332eaa5a64dda04f5b3de78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44c883336f3993d532c7989e1c6bf737deca2773cb444a4cfa6021bca35311c9d4fe5c74ddb73fa1274661435a127892f9a368bd1d94120e6965bee38b870216
|
7
|
+
data.tar.gz: ebac442b5b2ddc345b7d7713b0e8d7f0aaaba9da24aabe811e1a10a26555c2a85ba1d2bad0a0266674fdcc1c3deb573ed1839ffe98294dc979ccc69e42eab187
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [2.14.0] - 2019-08-06
|
6
|
+
|
7
|
+
* **New Features**
|
8
|
+
* Adds support for rake-aware reads.
|
9
|
+
* Adds support for client-server compression.
|
10
|
+
|
11
|
+
* **Improvements**
|
12
|
+
* Adds support for `truncate-namespace` command.
|
13
|
+
|
5
14
|
## [2.13.0] - 2019-07-17
|
6
15
|
|
7
16
|
* **New Features**
|
data/lib/aerospike.rb
CHANGED
@@ -22,6 +22,7 @@ require "timeout"
|
|
22
22
|
require 'resolv'
|
23
23
|
require 'msgpack'
|
24
24
|
require 'bcrypt'
|
25
|
+
require 'zlib'
|
25
26
|
|
26
27
|
require 'aerospike/atomic/atomic'
|
27
28
|
|
@@ -105,17 +106,21 @@ require 'aerospike/cluster/find_nodes_to_remove'
|
|
105
106
|
require 'aerospike/cluster/find_node'
|
106
107
|
require 'aerospike/cluster/partition'
|
107
108
|
require 'aerospike/cluster/partition_parser'
|
109
|
+
require 'aerospike/cluster/rack_parser'
|
108
110
|
require 'aerospike/node'
|
109
111
|
require 'aerospike/node/generation'
|
112
|
+
require 'aerospike/node/rebalance'
|
110
113
|
require 'aerospike/node/refresh/failed'
|
111
114
|
require 'aerospike/node/refresh/friends'
|
112
115
|
require 'aerospike/node/refresh/info'
|
113
116
|
require 'aerospike/node/refresh/partitions'
|
117
|
+
require 'aerospike/node/refresh/racks'
|
114
118
|
require 'aerospike/node/refresh/peers'
|
115
119
|
require 'aerospike/node/refresh/reset'
|
116
120
|
require 'aerospike/node/verify/cluster_name'
|
117
121
|
require 'aerospike/node/verify/name'
|
118
122
|
require 'aerospike/node/verify/partition_generation'
|
123
|
+
require 'aerospike/node/verify/rebalance_generation'
|
119
124
|
require 'aerospike/node/verify/peers_generation'
|
120
125
|
require 'aerospike/node_validator'
|
121
126
|
require 'aerospike/peer'
|
data/lib/aerospike/client.rb
CHANGED
@@ -44,6 +44,7 @@ module Aerospike
|
|
44
44
|
attr_accessor :default_read_policy
|
45
45
|
attr_accessor :default_scan_policy
|
46
46
|
attr_accessor :default_write_policy
|
47
|
+
attr_accessor :cluster
|
47
48
|
|
48
49
|
def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
|
49
50
|
|
@@ -224,8 +225,19 @@ module Aerospike
|
|
224
225
|
def truncate(namespace, set_name = nil, before_last_update = nil, options = {})
|
225
226
|
policy = create_policy(options, Policy, default_info_policy)
|
226
227
|
|
227
|
-
|
228
|
-
|
228
|
+
node = @cluster.random_node
|
229
|
+
conn = node.get_connection(policy.timeout)
|
230
|
+
|
231
|
+
if set_name && !set_name.to_s.strip.empty?
|
232
|
+
str_cmd = "truncate:namespace=#{namespace}"
|
233
|
+
str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
|
234
|
+
else
|
235
|
+
if node.supports_feature(Aerospike::Features::TRUNCATE_NAMESPACE)
|
236
|
+
str_cmd = "truncate-namespace:namespace=#{namespace}"
|
237
|
+
else
|
238
|
+
str_cmd = "truncate:namespace=#{namespace}"
|
239
|
+
end
|
240
|
+
end
|
229
241
|
|
230
242
|
if before_last_update
|
231
243
|
lut_nanos = (before_last_update.to_f * 1_000_000_000.0).round
|
@@ -235,8 +247,7 @@ module Aerospike
|
|
235
247
|
str_cmd << ";lut=now"
|
236
248
|
end
|
237
249
|
|
238
|
-
|
239
|
-
response = send_info_command(policy, str_cmd).upcase
|
250
|
+
response = send_info_command(policy, str_cmd, node).upcase
|
240
251
|
return if response == 'OK'
|
241
252
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, "Truncate failed: #{response}")
|
242
253
|
end
|
@@ -818,9 +829,13 @@ module Aerospike
|
|
818
829
|
self.default_write_policy = create_policy(policies[:write], WritePolicy)
|
819
830
|
end
|
820
831
|
|
821
|
-
def send_info_command(policy, command)
|
832
|
+
def send_info_command(policy, command, node = nil)
|
822
833
|
Aerospike.logger.debug { "Sending info command: #{command}" }
|
823
|
-
|
834
|
+
if node
|
835
|
+
_, response = @cluster.request_node_info(node, policy, command).first
|
836
|
+
else
|
837
|
+
_, response = @cluster.request_info(policy, command).first
|
838
|
+
end
|
824
839
|
response.to_s
|
825
840
|
end
|
826
841
|
|
data/lib/aerospike/cluster.rb
CHANGED
@@ -28,6 +28,7 @@ module Aerospike
|
|
28
28
|
attr_reader :features, :tls_options
|
29
29
|
attr_reader :cluster_id, :aliases
|
30
30
|
attr_reader :cluster_name
|
31
|
+
attr_accessor :rack_aware, :rack_id
|
31
32
|
|
32
33
|
def initialize(policy, hosts)
|
33
34
|
@cluster_seeds = hosts
|
@@ -37,6 +38,8 @@ module Aerospike
|
|
37
38
|
@tend_interval = policy.tend_interval
|
38
39
|
@cluster_name = policy.cluster_name
|
39
40
|
@tls_options = policy.tls
|
41
|
+
@rack_aware = policy.rack_aware
|
42
|
+
@rack_id = policy.rack_id
|
40
43
|
|
41
44
|
@replica_index = Atomic.new(0)
|
42
45
|
|
@@ -111,6 +114,8 @@ module Aerospike
|
|
111
114
|
return master_node(partition)
|
112
115
|
when Aerospike::Replica::MASTER_PROLES
|
113
116
|
return master_proles_node(partition)
|
117
|
+
when Aerospike::Replica::PREFER_RACK
|
118
|
+
return rack_node(partition, seq)
|
114
119
|
when Aerospike::Replica::RANDOM
|
115
120
|
return random_node
|
116
121
|
else
|
@@ -125,6 +130,8 @@ module Aerospike
|
|
125
130
|
return master_node(partition)
|
126
131
|
when Aerospike::Replica::MASTER_PROLES
|
127
132
|
return master_proles_node(partition)
|
133
|
+
when Aerospike::Replica::PREFER_RACK
|
134
|
+
return rack_node(partition, seq)
|
128
135
|
when Aerospike::Replica::SEQUENCE
|
129
136
|
return sequence_node(partition, seq)
|
130
137
|
when Aerospike::Replica::RANDOM
|
@@ -149,6 +156,38 @@ module Aerospike
|
|
149
156
|
node
|
150
157
|
end
|
151
158
|
|
159
|
+
# Returns a node on the cluster
|
160
|
+
def rack_node(partition, seq)
|
161
|
+
partition_map = partitions
|
162
|
+
replica_array = partition_map[partition.namespace]
|
163
|
+
raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
|
164
|
+
|
165
|
+
replica_array = replica_array.get
|
166
|
+
|
167
|
+
is_retry = seq.value > -1
|
168
|
+
|
169
|
+
node = nil
|
170
|
+
fallback = nil
|
171
|
+
for i in 1..replica_array.length
|
172
|
+
idx = (seq.update{|v| v.succ} % replica_array.size).abs
|
173
|
+
node = (replica_array[idx].get)[partition.partition_id]
|
174
|
+
|
175
|
+
next if !node
|
176
|
+
|
177
|
+
fallback = node
|
178
|
+
|
179
|
+
# If fallback exists, do not retry on node where command failed,
|
180
|
+
# even if fallback is not on the same rack.
|
181
|
+
return fallback if is_retry && fallback && i == replica_array.length
|
182
|
+
|
183
|
+
return node if node && node.active? && node.has_rack(partition.namespace, @rack_id)
|
184
|
+
end
|
185
|
+
|
186
|
+
return fallback if fallback
|
187
|
+
|
188
|
+
raise Aerospike::Exceptions::InvalidNode
|
189
|
+
end
|
190
|
+
|
152
191
|
# Returns a node on the cluster for read operations
|
153
192
|
def master_proles_node(partition)
|
154
193
|
partition_map = partitions
|
@@ -256,6 +295,13 @@ module Aerospike
|
|
256
295
|
end
|
257
296
|
end
|
258
297
|
|
298
|
+
def request_node_info(node, policy, *commands)
|
299
|
+
conn = node.get_connection(policy.timeout)
|
300
|
+
Info.request(conn, *commands).tap do
|
301
|
+
node.put_connection(conn)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
259
305
|
def supports_feature?(feature)
|
260
306
|
@features.get.include?(feature.to_s)
|
261
307
|
end
|
@@ -352,6 +398,7 @@ module Aerospike
|
|
352
398
|
|
353
399
|
nodes.each do |node|
|
354
400
|
node.refresh_partitions(peers) if node.partition_generation.changed?
|
401
|
+
node.refresh_racks if node.rebalance_generation.changed?
|
355
402
|
end
|
356
403
|
|
357
404
|
if peers.generation_changed? || !peers.use_peers?
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2014-2020 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at 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, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
require 'base64'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
class RackParser #:nodoc:
|
23
|
+
|
24
|
+
attr_accessor :rebalance_generation, :racks
|
25
|
+
|
26
|
+
REBALANCE_GENERATION = "rebalance-generation"
|
27
|
+
RACK_IDS = "rack-ids"
|
28
|
+
|
29
|
+
def initialize(node, conn)
|
30
|
+
@node = node
|
31
|
+
@conn = conn
|
32
|
+
@racks = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_racks
|
36
|
+
# Use low-level info methods and parse byte array directly for maximum performance.
|
37
|
+
# Receive format: rack-ids\t
|
38
|
+
# <ns1>:<rack-id>...;
|
39
|
+
# <ns2>:<rack-id>...; ...
|
40
|
+
info_map = Info.request(@conn, REBALANCE_GENERATION, RACK_IDS)
|
41
|
+
|
42
|
+
@rebalance_generation = info_map[REBALANCE_GENERATION].to_i
|
43
|
+
|
44
|
+
info = info_map[RACK_IDS]
|
45
|
+
if !info || info.length == 0
|
46
|
+
raise Aerospike::Exceptions::Connection.new("#{RACK_IDS} response for node #{@node.name} is empty")
|
47
|
+
end
|
48
|
+
|
49
|
+
@buffer = info
|
50
|
+
@length = info.length
|
51
|
+
@offset = 0
|
52
|
+
|
53
|
+
while @offset < @length && @buffer[@offset] != '\n'
|
54
|
+
namespace = parse_name
|
55
|
+
rack_id = parse_rack_id
|
56
|
+
|
57
|
+
@racks = {} if !@racks
|
58
|
+
@racks[namespace] = rack_id
|
59
|
+
end
|
60
|
+
|
61
|
+
@racks
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def parse_name
|
67
|
+
beginning = @offset
|
68
|
+
while @offset < @length
|
69
|
+
break if @buffer[@offset] == ':'
|
70
|
+
@offset+=1
|
71
|
+
end
|
72
|
+
|
73
|
+
# Parse namespace.
|
74
|
+
namespace = @buffer[beginning...@offset].strip
|
75
|
+
|
76
|
+
if namespace.length <= 0 || namespace.length >= 32
|
77
|
+
response = get_truncated_response
|
78
|
+
raise Aerospike::Exceptions::Parse.new(
|
79
|
+
"Invalid rack namespace #{namespace}. Response=#{response}"
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
@offset+=1
|
84
|
+
namespace
|
85
|
+
end
|
86
|
+
|
87
|
+
def parse_rack_id
|
88
|
+
beginning = @offset
|
89
|
+
while @offset < @length
|
90
|
+
break if @buffer[@offset] == ';'
|
91
|
+
@offset+=1
|
92
|
+
end
|
93
|
+
|
94
|
+
# Parse rack_id
|
95
|
+
rack_id = @buffer[beginning...@offset].strip.to_i
|
96
|
+
|
97
|
+
if rack_id < 0
|
98
|
+
response = get_truncated_response
|
99
|
+
raise Aerospike::Exceptions::Parse.new(
|
100
|
+
"Invalid rack_id #{rack_id}. Response=#{response}"
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
@offset+=1
|
105
|
+
rack_id
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_truncated_response
|
109
|
+
max = @length
|
110
|
+
@length = max if @length > 200
|
111
|
+
@buffer[0...max]
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
end # class
|
116
|
+
|
117
|
+
end # module
|
@@ -16,6 +16,7 @@
|
|
16
16
|
# the License.
|
17
17
|
|
18
18
|
require 'time'
|
19
|
+
require 'zlib'
|
19
20
|
|
20
21
|
require 'msgpack'
|
21
22
|
require 'aerospike/result_code'
|
@@ -42,6 +43,9 @@ module Aerospike
|
|
42
43
|
# Involve all replicas in read operation.
|
43
44
|
INFO1_CONSISTENCY_ALL = Integer(1 << 6)
|
44
45
|
|
46
|
+
# Tell server to compress it's response.
|
47
|
+
INFO1_COMPRESS_RESPONSE = (1 << 7)
|
48
|
+
|
45
49
|
# Create or update record
|
46
50
|
INFO2_WRITE = Integer(1 << 0)
|
47
51
|
# Fling a record into the belly of Moloch.
|
@@ -72,8 +76,10 @@ module Aerospike
|
|
72
76
|
OPERATION_HEADER_SIZE = 8
|
73
77
|
MSG_REMAINING_HEADER_SIZE = 22
|
74
78
|
DIGEST_SIZE = 20
|
79
|
+
COMPRESS_THRESHOLD = 128
|
75
80
|
CL_MSG_VERSION = 2
|
76
81
|
AS_MSG_TYPE = 3
|
82
|
+
AS_MSG_TYPE_COMPRESSED = 4
|
77
83
|
|
78
84
|
class Command #:nodoc:
|
79
85
|
|
@@ -83,6 +89,8 @@ module Aerospike
|
|
83
89
|
|
84
90
|
@node = node
|
85
91
|
|
92
|
+
@compress = false
|
93
|
+
|
86
94
|
# will add before use
|
87
95
|
@sequence = Atomic.new(-1)
|
88
96
|
|
@@ -118,6 +126,7 @@ module Aerospike
|
|
118
126
|
end
|
119
127
|
|
120
128
|
end_cmd
|
129
|
+
mark_compressed(policy)
|
121
130
|
end
|
122
131
|
|
123
132
|
# Writes the command for delete operations
|
@@ -288,6 +297,7 @@ module Aerospike
|
|
288
297
|
write_operation_for_bin(nil, Aerospike::Operation::READ) if read_header
|
289
298
|
|
290
299
|
end_cmd
|
300
|
+
mark_compressed(policy)
|
291
301
|
end
|
292
302
|
|
293
303
|
def set_udf(policy, key, package_name, function_name, args)
|
@@ -310,6 +320,7 @@ module Aerospike
|
|
310
320
|
write_field_bytes(arg_bytes, Aerospike::FieldType::UDF_ARGLIST)
|
311
321
|
|
312
322
|
end_cmd
|
323
|
+
mark_compressed(policy)
|
313
324
|
end
|
314
325
|
|
315
326
|
def set_scan(policy, namespace, set_name, bin_names)
|
@@ -579,6 +590,7 @@ module Aerospike
|
|
579
590
|
# Generic header write.
|
580
591
|
def write_header(policy, read_attr, write_attr, field_count, operation_count)
|
581
592
|
read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
|
593
|
+
read_attr |= INFO1_COMPRESS_RESPONSE if policy.use_compression
|
582
594
|
|
583
595
|
# Write all header data except total size which must be written last.
|
584
596
|
@data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message heade.length.
|
@@ -628,6 +640,7 @@ module Aerospike
|
|
628
640
|
info_attr |= INFO3_COMMIT_MASTER if policy.commit_level == Aerospike::CommitLevel::COMMIT_MASTER
|
629
641
|
read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
|
630
642
|
write_attr |= INFO2_DURABLE_DELETE if policy.durable_delete
|
643
|
+
read_attr |= INFO1_COMPRESS_RESPONSE if policy.use_compression
|
631
644
|
|
632
645
|
# Write all header data except total size which must be written last.
|
633
646
|
@data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message heade.length.
|
@@ -810,6 +823,48 @@ module Aerospike
|
|
810
823
|
@data_buffer.write_int64(size, 0)
|
811
824
|
end
|
812
825
|
|
826
|
+
def use_compression?
|
827
|
+
@compress
|
828
|
+
end
|
829
|
+
|
830
|
+
def compress_buffer
|
831
|
+
if @data_offset > COMPRESS_THRESHOLD
|
832
|
+
compressed = Zlib::deflate(@data_buffer.buf, Zlib::DEFAULT_COMPRESSION)
|
833
|
+
|
834
|
+
# write original size as header
|
835
|
+
proto_s = "%08d" % 0
|
836
|
+
proto_s[0, 8] = [@data_offset].pack('q>')
|
837
|
+
compressed.prepend(proto_s)
|
838
|
+
|
839
|
+
# write proto
|
840
|
+
proto = (compressed.size+8) | Integer(CL_MSG_VERSION << 56) | Integer(AS_MSG_TYPE << 48)
|
841
|
+
proto_s = "%08d" % 0
|
842
|
+
proto_s[0, 8] = [proto].pack('q>')
|
843
|
+
compressed.prepend(proto_s)
|
844
|
+
|
845
|
+
@data_buffer = Buffer.new(-1, compressed)
|
846
|
+
@data_offset = @data_buffer.size
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
# isCompressed returns the length of the compressed buffer.
|
851
|
+
# If the buffer is not compressed, the result will be -1
|
852
|
+
def compressed_size
|
853
|
+
# A number of these are commented out because we just don't care enough to read
|
854
|
+
# that section of the header. If we do care, uncomment and check!
|
855
|
+
proto = @data_buffer.read_int64(0)
|
856
|
+
size = proto & 0xFFFFFFFFFFFF
|
857
|
+
msg_type = (proto >> 48) & 0xFF
|
858
|
+
|
859
|
+
return nil if msg_type != AS_MSG_TYPE_COMPRESSED
|
860
|
+
|
861
|
+
size
|
862
|
+
end
|
863
|
+
|
864
|
+
def mark_compressed(policy)
|
865
|
+
@compress = policy.use_compression
|
866
|
+
end
|
867
|
+
|
813
868
|
end # class
|
814
869
|
|
815
870
|
end # module
|
@@ -29,6 +29,9 @@ module Aerospike
|
|
29
29
|
@valid = true
|
30
30
|
@mutex = Mutex.new
|
31
31
|
|
32
|
+
@compressed_data_buffer = nil
|
33
|
+
@compressed_data_offset = nil
|
34
|
+
|
32
35
|
self
|
33
36
|
end
|
34
37
|
|
@@ -42,12 +45,41 @@ module Aerospike
|
|
42
45
|
status = true
|
43
46
|
|
44
47
|
while status
|
48
|
+
@data_offset = 0
|
49
|
+
@compressed_data_buffer = nil
|
50
|
+
|
45
51
|
# Read header.
|
46
52
|
read_bytes(8)
|
47
53
|
|
48
54
|
size = @data_buffer.read_int64(0)
|
49
55
|
receive_size = size & 0xFFFFFFFFFFFF
|
50
56
|
|
57
|
+
# inflate if compressed
|
58
|
+
compressed_sz = compressed_size
|
59
|
+
if compressed_sz
|
60
|
+
begin
|
61
|
+
# read compressed msg header
|
62
|
+
@conn.read(@data_buffer, 8)
|
63
|
+
|
64
|
+
# read compressed message
|
65
|
+
@conn.read(@data_buffer, compressed_sz - 8)
|
66
|
+
|
67
|
+
# inflate the results
|
68
|
+
# TODO: reuse the current buffer
|
69
|
+
uncompressed = Zlib::inflate(@data_buffer.buf)
|
70
|
+
receive_size = uncompressed.size - 8
|
71
|
+
|
72
|
+
@compressed_data_buffer = Buffer.new(-1, uncompressed)
|
73
|
+
@compressed_data_offset = 0
|
74
|
+
|
75
|
+
# waste the first 8 header bytes
|
76
|
+
@compressed_data_buffer.eat!(8)
|
77
|
+
rescue => e
|
78
|
+
Aerospike.logger.error("parse result error: #{e}")
|
79
|
+
raise e
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
51
83
|
if receive_size > 0
|
52
84
|
status = parse_group(receive_size)
|
53
85
|
else
|
@@ -157,7 +189,13 @@ module Aerospike
|
|
157
189
|
@data_buffer = Buffer.new(length)
|
158
190
|
end
|
159
191
|
|
160
|
-
|
192
|
+
if compressed?
|
193
|
+
@data_buffer.write_binary(@compressed_data_buffer.buf[@compressed_data_offset...@compressed_data_offset+length], 0)
|
194
|
+
@compressed_data_offset += length
|
195
|
+
else
|
196
|
+
@conn.read(@data_buffer, length)
|
197
|
+
end
|
198
|
+
|
161
199
|
@data_offset += length
|
162
200
|
end
|
163
201
|
|
@@ -176,6 +214,11 @@ module Aerospike
|
|
176
214
|
res
|
177
215
|
end
|
178
216
|
|
217
|
+
def compressed?
|
218
|
+
@compressed_data_buffer != nil
|
219
|
+
end
|
220
|
+
|
221
|
+
|
179
222
|
end # class
|
180
223
|
|
181
224
|
end # module
|
@@ -15,6 +15,8 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
+
require 'zlib'
|
19
|
+
|
18
20
|
require 'aerospike/record'
|
19
21
|
|
20
22
|
require 'aerospike/command/single_command'
|
@@ -50,12 +52,40 @@ module Aerospike
|
|
50
52
|
def parse_result
|
51
53
|
# Read header.
|
52
54
|
begin
|
53
|
-
@conn.read(@data_buffer,
|
55
|
+
@conn.read(@data_buffer, 8)
|
54
56
|
rescue => e
|
55
57
|
Aerospike.logger.error("parse result error: #{e}")
|
56
58
|
raise e
|
57
59
|
end
|
58
60
|
|
61
|
+
# inflate if compressed
|
62
|
+
compressed_sz = compressed_size
|
63
|
+
if compressed_sz
|
64
|
+
begin
|
65
|
+
# waste 8 size bytes
|
66
|
+
@conn.read(@data_buffer, 8)
|
67
|
+
|
68
|
+
# read compressed message
|
69
|
+
@conn.read(@data_buffer, compressed_sz - 8)
|
70
|
+
|
71
|
+
# inflate the results
|
72
|
+
# TODO: reuse the current buffer
|
73
|
+
uncompressed = Zlib::inflate(@data_buffer.buf)
|
74
|
+
|
75
|
+
@data_buffer = Buffer.new(-1, uncompressed)
|
76
|
+
rescue => e
|
77
|
+
Aerospike.logger.error("parse result error: #{e}")
|
78
|
+
raise e
|
79
|
+
end
|
80
|
+
else
|
81
|
+
begin
|
82
|
+
bytes_read = @conn.read(@data_buffer, MSG_TOTAL_HEADER_SIZE - 8, 8)
|
83
|
+
rescue => e
|
84
|
+
Aerospike.logger.error("parse result error: #{e}")
|
85
|
+
raise e
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
59
89
|
# A number of these are commented out because we just don't care enough to read
|
60
90
|
# that section of the header. If we do care, uncomment and check!
|
61
91
|
sz = @data_buffer.read_int64(0)
|
@@ -68,7 +98,9 @@ module Aerospike
|
|
68
98
|
receive_size = (sz & 0xFFFFFFFFFFFF) - header_length
|
69
99
|
|
70
100
|
# Read remaining message bytes.
|
71
|
-
if
|
101
|
+
if compressed_sz
|
102
|
+
@data_buffer.eat!(MSG_TOTAL_HEADER_SIZE)
|
103
|
+
elsif receive_size > 0
|
72
104
|
size_buffer_sz(receive_size)
|
73
105
|
|
74
106
|
begin
|
@@ -40,7 +40,40 @@ module Aerospike
|
|
40
40
|
|
41
41
|
def parse_result
|
42
42
|
# Read header.
|
43
|
-
|
43
|
+
begin
|
44
|
+
@conn.read(@data_buffer, 8)
|
45
|
+
rescue => e
|
46
|
+
Aerospike.logger.error("parse result error: #{e}")
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
|
50
|
+
# inflate if compressed
|
51
|
+
compressed_sz = compressed_size
|
52
|
+
if compressed_sz
|
53
|
+
begin
|
54
|
+
#waste 8 size bytes
|
55
|
+
@conn.read(@data_buffer, 8)
|
56
|
+
|
57
|
+
# read compressed message
|
58
|
+
@conn.read(@data_buffer, sz - 8)
|
59
|
+
|
60
|
+
# inflate the results
|
61
|
+
# TODO: reuse the current buffer
|
62
|
+
uncompressed = Zlib::inflate(@data_buffer.buf)
|
63
|
+
|
64
|
+
@data_buffer = Buffer.new(-1, uncompressed)
|
65
|
+
rescue => e
|
66
|
+
Aerospike.logger.error("parse result error: #{e}")
|
67
|
+
raise e
|
68
|
+
end
|
69
|
+
else
|
70
|
+
begin
|
71
|
+
bytes_read = @conn.read(@data_buffer, MSG_TOTAL_HEADER_SIZE - 8, 8)
|
72
|
+
rescue => e
|
73
|
+
Aerospike.logger.error("parse result error: #{e}")
|
74
|
+
raise e
|
75
|
+
end
|
76
|
+
end
|
44
77
|
|
45
78
|
result_code = @data_buffer.read(13).ord & 0xFF
|
46
79
|
|
data/lib/aerospike/features.rb
CHANGED
data/lib/aerospike/node.rb
CHANGED
@@ -22,7 +22,7 @@ require 'aerospike/atomic/atomic'
|
|
22
22
|
module Aerospike
|
23
23
|
class Node
|
24
24
|
|
25
|
-
attr_reader :reference_count, :responded, :name, :features, :cluster_name, :partition_generation, :peers_generation, :failures, :cluster, :peers_count, :host
|
25
|
+
attr_reader :reference_count, :responded, :name, :features, :cluster_name, :partition_generation, :rebalance_generation, :peers_generation, :failures, :cluster, :peers_count, :host
|
26
26
|
|
27
27
|
PARTITIONS = 4096
|
28
28
|
FULL_HEALTH = 100
|
@@ -46,16 +46,29 @@ module Aerospike
|
|
46
46
|
@peers_count = Atomic.new(0)
|
47
47
|
@peers_generation = ::Aerospike::Node::Generation.new
|
48
48
|
@partition_generation = ::Aerospike::Node::Generation.new
|
49
|
+
@rebalance_generation = ::Aerospike::Node::Rebalance.new
|
49
50
|
@reference_count = Atomic.new(0)
|
50
51
|
@responded = Atomic.new(false)
|
51
52
|
@active = Atomic.new(true)
|
52
53
|
@failures = Atomic.new(0)
|
53
54
|
|
54
55
|
@replica_index = Atomic.new(0)
|
56
|
+
@racks = Atomic.new(nil)
|
55
57
|
|
56
58
|
@connections = ::Aerospike::ConnectionPool.new(cluster, host)
|
57
59
|
end
|
58
60
|
|
61
|
+
def update_racks(parser)
|
62
|
+
new_racks = parser.update_racks
|
63
|
+
@racks.value = new_racks if new_racks
|
64
|
+
end
|
65
|
+
|
66
|
+
def has_rack(ns, rack_id)
|
67
|
+
racks = @racks.value
|
68
|
+
return false if !racks
|
69
|
+
racks[ns] == rack_id
|
70
|
+
end
|
71
|
+
|
59
72
|
# Get a connection to the node. If no cached connection is not available,
|
60
73
|
# a new connection will be created
|
61
74
|
def get_connection(timeout)
|
@@ -199,6 +212,10 @@ module Aerospike
|
|
199
212
|
Node::Refresh::Partitions.(self, peers)
|
200
213
|
end
|
201
214
|
|
215
|
+
def refresh_racks()
|
216
|
+
Node::Refresh::Racks.(self)
|
217
|
+
end
|
218
|
+
|
202
219
|
def refresh_peers(peers)
|
203
220
|
Node::Refresh::Peers.(self, peers)
|
204
221
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
# generic class for representing changes in eg. peer and partition generation
|
23
|
+
class Rebalance
|
24
|
+
attr_reader :generation
|
25
|
+
|
26
|
+
def initialize(generation = -1)
|
27
|
+
@generation = ::Aerospike::Atomic.new(generation)
|
28
|
+
@changed = ::Aerospike::Atomic.new(false)
|
29
|
+
end
|
30
|
+
|
31
|
+
def changed?
|
32
|
+
@changed.value == true
|
33
|
+
end
|
34
|
+
|
35
|
+
def eql?(generation)
|
36
|
+
@generation.value == generation
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset_changed!
|
40
|
+
@changed.value = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def update(new_generation)
|
44
|
+
return if @generation.value == new_generation
|
45
|
+
@generation.value = new_generation
|
46
|
+
@changed.value = true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -24,14 +24,17 @@ module Aerospike
|
|
24
24
|
CMDS_BASE = %w[node partition-generation cluster-name].freeze
|
25
25
|
CMDS_PEERS = (CMDS_BASE + ['peers-generation']).freeze
|
26
26
|
CMDS_SERVICES = (CMDS_BASE + ['services']).freeze
|
27
|
+
CMDS_REBALANCE = (CMDS_PEERS + ['rebalance-generation']).freeze
|
27
28
|
|
28
29
|
class << self
|
29
30
|
def call(node, peers)
|
30
31
|
conn = node.tend_connection
|
31
32
|
if peers.use_peers?
|
32
|
-
|
33
|
+
cmds = node.cluster.rack_aware ? CMDS_REBALANCE : CMDS_PEERS
|
34
|
+
info_map = ::Aerospike::Info.request(conn, *cmds)
|
33
35
|
Verify::PeersGeneration.(node, info_map, peers)
|
34
36
|
Verify::PartitionGeneration.(node, info_map)
|
37
|
+
Verify::RebalanceGeneration.(node, info_map) if node.cluster.rack_aware
|
35
38
|
Verify::Name.(node, info_map)
|
36
39
|
Verify::ClusterName.(node, info_map)
|
37
40
|
else
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018-2020 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
module Racks
|
24
|
+
class << self
|
25
|
+
def call(node)
|
26
|
+
return unless should_refresh?(node)
|
27
|
+
|
28
|
+
Aerospike.logger.info("Updating racks for node #{node.name}")
|
29
|
+
conn = node.tend_connection
|
30
|
+
parser = RackParser.new(node, conn)
|
31
|
+
node.update_racks(parser)
|
32
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
33
|
+
conn.close
|
34
|
+
Refresh::Failed.(node, e)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Do not refresh racks when node connection has already failed
|
38
|
+
# during this cluster tend iteration.
|
39
|
+
def should_refresh?(node)
|
40
|
+
return false if node.failed? || !node.active?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Verify
|
23
|
+
# Fetch and set rebalance generation. If racks needs to be refreshed
|
24
|
+
# this will be indicated in node.rebalance_changed
|
25
|
+
module RebalanceGeneration
|
26
|
+
class << self
|
27
|
+
def call(node, info_map)
|
28
|
+
gen_string = info_map.fetch('rebalance-generation', nil)
|
29
|
+
|
30
|
+
raise Aerospike::Exceptions::Parse.new('rebalance-generation is empty') if gen_string.to_s.empty?
|
31
|
+
|
32
|
+
generation = gen_string.to_i
|
33
|
+
|
34
|
+
node.rebalance_generation.update(generation)
|
35
|
+
|
36
|
+
return unless node.rebalance_generation.changed?
|
37
|
+
Aerospike.logger.info("Node #{node.name} rebalance generation #{generation} changed")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -27,6 +27,7 @@ module Aerospike
|
|
27
27
|
attr_accessor :cluster_name
|
28
28
|
attr_accessor :tls
|
29
29
|
attr_accessor :policies
|
30
|
+
attr_accessor :rack_aware, :rack_id
|
30
31
|
|
31
32
|
def initialize(opt={})
|
32
33
|
# Initial host connection timeout in seconds. The timeout when opening a connection
|
@@ -56,6 +57,20 @@ module Aerospike
|
|
56
57
|
|
57
58
|
# Default Policies
|
58
59
|
@policies = opt.fetch(:policies) { Hash.new }
|
60
|
+
|
61
|
+
# Track server rack data. This field is useful when directing read commands to the server node
|
62
|
+
# that contains the key and exists on the same rack as the client. This serves to lower cloud
|
63
|
+
# provider costs when nodes are distributed across different racks/data centers.
|
64
|
+
#
|
65
|
+
# ClientPolicy#rack_id, Replica#PREFER_RACK and server rack
|
66
|
+
# configuration must also be set to enable this functionality.
|
67
|
+
@rack_aware = opt[:rack_aware] || false
|
68
|
+
|
69
|
+
# Rack where this client instance resides.
|
70
|
+
#
|
71
|
+
# ClientPolicy#rack_aware, Replica#PREFER_RACK and server rack
|
72
|
+
# configuration must also be set to enable this functionality.
|
73
|
+
@rack_id = opt[:rack_id] || 0
|
59
74
|
end
|
60
75
|
|
61
76
|
def requires_authentication
|
@@ -24,7 +24,7 @@ module Aerospike
|
|
24
24
|
class Policy
|
25
25
|
|
26
26
|
attr_accessor :priority, :timeout, :max_retries, :sleep_between_retries, :consistency_level,
|
27
|
-
:predexp, :fail_on_filtered_out, :replica
|
27
|
+
:predexp, :fail_on_filtered_out, :replica, :use_compression
|
28
28
|
|
29
29
|
def initialize(opt={})
|
30
30
|
# Container object for transaction policy attributes used in all database
|
@@ -89,9 +89,17 @@ module Aerospike
|
|
89
89
|
# to the node containing the key's master partition.
|
90
90
|
#
|
91
91
|
# Default to sending read commands to the node containing the key's master partition.
|
92
|
-
@replica = opt[:replica] || Aerospike::Replica::MASTER
|
92
|
+
@replica = opt[:replica] || Aerospike::Replica::MASTER
|
93
93
|
|
94
|
-
|
94
|
+
# Use zlib compression on write or batch read commands when the command buffer size is greater
|
95
|
+
# than 128 bytes. In addition, tell the server to compress its response on read commands.
|
96
|
+
# The server response compression threshold is also 128 bytes.
|
97
|
+
#
|
98
|
+
# This option will increase cpu and memory usage (for extra compressed buffers), but
|
99
|
+
# decrease the size of data sent over the network.
|
100
|
+
@use_compression = opt[:use_compression] || false
|
101
|
+
|
102
|
+
# Transaction timeout.
|
95
103
|
# This timeout is used to set the socket timeout and is also sent to the
|
96
104
|
# server along with the transaction in the wire protocol.
|
97
105
|
# Default to no timeout (0).
|
@@ -28,6 +28,13 @@ module Aerospike
|
|
28
28
|
# Policy#retryOnTimeout is true, try nodes containing prole partition.
|
29
29
|
SEQUENCE = 2
|
30
30
|
|
31
|
+
# Try node on the same rack as the client first. If there are no nodes on the
|
32
|
+
# same rack, use SEQUENCE instead.
|
33
|
+
#
|
34
|
+
# ClientPolicy#rack_aware}, ClientPolicy#rack_id, and server rack
|
35
|
+
# configuration must also be set to enable this functionality.
|
36
|
+
PREFER_RACK = 3
|
37
|
+
|
31
38
|
# Distribute reads across all nodes in cluster in round-robin fashion.
|
32
39
|
# This option is useful when the replication factor equals the number
|
33
40
|
# of nodes in the cluster and the overhead of requesting proles is not desired.
|
@@ -25,13 +25,14 @@ module Aerospike
|
|
25
25
|
@timeout = nil
|
26
26
|
end
|
27
27
|
|
28
|
-
def read(buffer, length)
|
28
|
+
def read(buffer, length, offset = 0)
|
29
29
|
bytes_read = 0
|
30
30
|
until bytes_read >= length
|
31
31
|
result = read_from_socket(length - bytes_read)
|
32
|
-
buffer.write_binary(result, bytes_read)
|
32
|
+
buffer.write_binary(result, offset + bytes_read)
|
33
33
|
bytes_read += result.bytesize
|
34
34
|
end
|
35
|
+
bytes_read
|
35
36
|
end
|
36
37
|
|
37
38
|
def read_from_socket(length)
|
@@ -42,9 +42,9 @@ module Aerospike
|
|
42
42
|
DEFAULT_BUFFER_SIZE = 16 * 1024
|
43
43
|
MAX_BUFFER_SIZE = 10 * 1024 * 1024
|
44
44
|
|
45
|
-
def initialize(size=DEFAULT_BUFFER_SIZE)
|
46
|
-
@buf = "%0#{size}d" % 0
|
47
|
-
|
45
|
+
def initialize(size=DEFAULT_BUFFER_SIZE, buf = nil)
|
46
|
+
@buf = (buf ? buf : ("%0#{size}d" % 0))
|
47
|
+
@buf.force_encoding('binary')
|
48
48
|
@slice_end = @buf.bytesize
|
49
49
|
end
|
50
50
|
|
@@ -61,6 +61,10 @@ module Aerospike
|
|
61
61
|
end
|
62
62
|
alias_method :length, :size
|
63
63
|
|
64
|
+
def eat!(n)
|
65
|
+
@buf.replace(@buf[n..-1])
|
66
|
+
end
|
67
|
+
|
64
68
|
def resize(length)
|
65
69
|
if @buf.bytesize < length
|
66
70
|
@buf.concat("%0#{length - @buf.bytesize}d" % 0)
|
@@ -156,6 +160,12 @@ module Aerospike
|
|
156
160
|
@buf[0..@slice_end-1]
|
157
161
|
end
|
158
162
|
|
163
|
+
def reset
|
164
|
+
for i in 0..@buf.size-1
|
165
|
+
@buf[i] = ' '
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
159
169
|
def dump(from=nil, to=nil)
|
160
170
|
from ||= 0
|
161
171
|
to ||= @slice_end - 1
|
data/lib/aerospike/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aerospike
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Khosrow Afroozeh
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-08-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/aerospike/cluster/find_nodes_to_remove.rb
|
75
75
|
- lib/aerospike/cluster/partition.rb
|
76
76
|
- lib/aerospike/cluster/partition_parser.rb
|
77
|
+
- lib/aerospike/cluster/rack_parser.rb
|
77
78
|
- lib/aerospike/command/admin_command.rb
|
78
79
|
- lib/aerospike/command/batch_direct_command.rb
|
79
80
|
- lib/aerospike/command/batch_direct_exists_command.rb
|
@@ -108,16 +109,19 @@ files:
|
|
108
109
|
- lib/aerospike/loggable.rb
|
109
110
|
- lib/aerospike/node.rb
|
110
111
|
- lib/aerospike/node/generation.rb
|
112
|
+
- lib/aerospike/node/rebalance.rb
|
111
113
|
- lib/aerospike/node/refresh/failed.rb
|
112
114
|
- lib/aerospike/node/refresh/friends.rb
|
113
115
|
- lib/aerospike/node/refresh/info.rb
|
114
116
|
- lib/aerospike/node/refresh/partitions.rb
|
115
117
|
- lib/aerospike/node/refresh/peers.rb
|
118
|
+
- lib/aerospike/node/refresh/racks.rb
|
116
119
|
- lib/aerospike/node/refresh/reset.rb
|
117
120
|
- lib/aerospike/node/verify/cluster_name.rb
|
118
121
|
- lib/aerospike/node/verify/name.rb
|
119
122
|
- lib/aerospike/node/verify/partition_generation.rb
|
120
123
|
- lib/aerospike/node/verify/peers_generation.rb
|
124
|
+
- lib/aerospike/node/verify/rebalance_generation.rb
|
121
125
|
- lib/aerospike/node_validator.rb
|
122
126
|
- lib/aerospike/operation.rb
|
123
127
|
- lib/aerospike/peer.rb
|