aerospike 2.1.1 → 2.2.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 +20 -0
- data/README.md +4 -11
- data/lib/aerospike/atomic/atomic.rb +2 -0
- data/lib/aerospike/client.rb +24 -39
- data/lib/aerospike/cluster/cluster.rb +14 -10
- data/lib/aerospike/cluster/node.rb +24 -17
- data/lib/aerospike/cluster/node_validator.rb +3 -2
- data/lib/aerospike/command/command.rb +3 -2
- data/lib/aerospike/command/read_command.rb +12 -3
- data/lib/aerospike/host.rb +2 -1
- data/lib/aerospike/policy/client_policy.rb +4 -0
- data/lib/aerospike/policy/operate_policy.rb +35 -0
- data/lib/aerospike/policy/record_bin_multiplicity.rb +28 -0
- data/lib/aerospike/policy/write_policy.rb +8 -1
- data/lib/aerospike/result_code.rb +6 -0
- data/lib/aerospike/utils/pool.rb +9 -10
- data/lib/aerospike/version.rb +1 -1
- metadata +12 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 903b61fdf1d17d80049e051d70b90ce8159d0403
|
4
|
+
data.tar.gz: d87f7a61c12f457c94ebe2319adf06f3ce0fa8db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: feaa5085e9fb331fc43f5b8c45b4f765f75c0b5ed02e056623ceacf57b7a9c4d39ea817e5c18b7b059c2564273ba106793adb632923719c2ffcb0f5825e36115
|
7
|
+
data.tar.gz: 72985529453d486919b11827d74ad4d6884a038e4390d740c90ef48246341727435bcb47e6d2563a3aa5ca4a11904c02c42a2fa1b6b068d2a309c10a1ae47193
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
v2.2.0 / 2016-09-20
|
2
|
+
===================
|
3
|
+
|
4
|
+
* **New Features**
|
5
|
+
* Support for durable delete write policy [CLIENT-768]; requires Aerospike
|
6
|
+
Server Enterprise Edition v3.10 or later.
|
7
|
+
* Support Cluster Name verification [CLIENT-776]; requires Aerospike Server v3.10 or later.
|
8
|
+
|
9
|
+
* **Bug Fixes**
|
10
|
+
* Fix error handling in node refresh during cluster tend.
|
11
|
+
|
12
|
+
* **Improvements**
|
13
|
+
* Optionally return multiple results from read operations on same record bin.
|
14
|
+
[#39](https://github.com/aerospike/aerospike-client-ruby/issues/39) Thanks
|
15
|
+
to [@zingoba](https://github.com/zingoba).
|
16
|
+
|
17
|
+
* **Documentation**
|
18
|
+
* Added note about potential issues with usage in Ruby on Rails with Phusion Passenger.
|
19
|
+
* Amend/clean up documentation of client policies.
|
20
|
+
|
1
21
|
v2.1.1 / 2016-08-16
|
2
22
|
===================
|
3
23
|
|
data/README.md
CHANGED
@@ -13,7 +13,6 @@ This library is compatible with Ruby 2.0+ and supports Linux, Mac OS X and vario
|
|
13
13
|
- [Usage](#Usage)
|
14
14
|
- [Prerequisites](#Prerequisites)
|
15
15
|
- [Installation](#Installation)
|
16
|
-
- [Tweaking Performance](#Performance)
|
17
16
|
- [Benchmarks](#Benchmarks)
|
18
17
|
- [API Documentaion](#API-Documentation)
|
19
18
|
- [Tests](#Tests)
|
@@ -75,11 +74,13 @@ Supported operating systems:
|
|
75
74
|
- other BSDs (untested)
|
76
75
|
|
77
76
|
<a name="Installation"></a>
|
78
|
-
## Installation
|
77
|
+
## Installation
|
78
|
+
|
79
|
+
### Installation from Ruby gems
|
79
80
|
|
80
81
|
1. gem install aerospike
|
81
82
|
|
82
|
-
|
83
|
+
### Installation from source
|
83
84
|
|
84
85
|
1. Install Ruby 2.0+
|
85
86
|
2. Install RubyGems
|
@@ -88,13 +89,6 @@ Supported operating systems:
|
|
88
89
|
5. Build and Install the gem locally: ```rake build && rake install```
|
89
90
|
6. Run the benchmark: ```./tools/benchmark/benchmark.rb -u```
|
90
91
|
|
91
|
-
<a name="Performance"></a>
|
92
|
-
## Performance Tweaking
|
93
|
-
|
94
|
-
We are bending all efforts to improve the client's performance. In out reference benchmarks, Go client performs almost as good as the C client.
|
95
|
-
|
96
|
-
To read about performance variables, please refer to [`docs/performance.md`](docs/performance.md)
|
97
|
-
|
98
92
|
<a name="Tests"></a>
|
99
93
|
## Tests
|
100
94
|
|
@@ -104,7 +98,6 @@ To run all the test cases:
|
|
104
98
|
|
105
99
|
$ bundle exec rspec
|
106
100
|
|
107
|
-
|
108
101
|
<a name="Examples"></a>
|
109
102
|
## Examples
|
110
103
|
|
data/lib/aerospike/client.rb
CHANGED
@@ -88,9 +88,7 @@ module Aerospike
|
|
88
88
|
# Returns list of active server node names in the cluster.
|
89
89
|
|
90
90
|
def node_names
|
91
|
-
@cluster.nodes.map
|
92
|
-
node.get_name
|
93
|
-
end
|
91
|
+
@cluster.nodes.map(&:get_name)
|
94
92
|
end
|
95
93
|
|
96
94
|
def supports_feature?(feature)
|
@@ -252,11 +250,9 @@ module Aerospike
|
|
252
250
|
|
253
251
|
key_map = BatchItem.generate_map(keys)
|
254
252
|
|
255
|
-
|
253
|
+
batch_execute(keys) do |node, bns|
|
256
254
|
BatchCommandExists.new(node, bns, policy, key_map, exists_array)
|
257
255
|
end
|
258
|
-
|
259
|
-
batch_execute(keys, &cmd_gen)
|
260
256
|
exists_array
|
261
257
|
end
|
262
258
|
|
@@ -304,11 +300,9 @@ module Aerospike
|
|
304
300
|
|
305
301
|
key_map = BatchItem.generate_map(keys)
|
306
302
|
|
307
|
-
|
303
|
+
batch_execute(keys) do |node, bns|
|
308
304
|
BatchCommandGet.new(node, bns, policy, key_map, bin_names.uniq, records, INFO1_READ)
|
309
305
|
end
|
310
|
-
|
311
|
-
batch_execute(keys, &cmd_gen)
|
312
306
|
records
|
313
307
|
end
|
314
308
|
|
@@ -329,11 +323,10 @@ module Aerospike
|
|
329
323
|
|
330
324
|
key_map = BatchItem.generate_map(keys)
|
331
325
|
|
332
|
-
|
326
|
+
batch_execute(keys) do |node, bns|
|
333
327
|
BatchCommandGet.new(node, bns, policy, key_map, nil, records, INFO1_READ | INFO1_NOBINDATA)
|
334
328
|
end
|
335
329
|
|
336
|
-
batch_execute(keys, &cmd_gen)
|
337
330
|
records
|
338
331
|
end
|
339
332
|
|
@@ -343,10 +336,8 @@ module Aerospike
|
|
343
336
|
|
344
337
|
# Perform multiple read/write operations on a single key in one batch call.
|
345
338
|
# An example would be to add an integer value to an existing record and then
|
346
|
-
# read the result, all in one database call.
|
347
|
-
#
|
348
|
-
# Write operations are always performed first, regardless of operation order
|
349
|
-
# relative to read operations.
|
339
|
+
# read the result, all in one database call. Operations are executed in
|
340
|
+
# the order they are specified.
|
350
341
|
def operate(key, operations, options={})
|
351
342
|
policy = create_policy(options, WritePolicy)
|
352
343
|
|
@@ -410,7 +401,7 @@ module Aerospike
|
|
410
401
|
# This method is only supported by Aerospike 3 servers.
|
411
402
|
def register_udf_from_file(client_path, server_path, language, options={})
|
412
403
|
udf_body = File.read(client_path)
|
413
|
-
register_udf(udf_body, server_path, language, options
|
404
|
+
register_udf(udf_body, server_path, language, options)
|
414
405
|
end
|
415
406
|
|
416
407
|
# Register package containing user defined functions with server.
|
@@ -510,22 +501,17 @@ module Aerospike
|
|
510
501
|
|
511
502
|
record = command.record
|
512
503
|
|
513
|
-
return nil if !record || record.bins.
|
504
|
+
return nil if !record || record.bins.empty?
|
514
505
|
|
515
506
|
result_map = record.bins
|
516
507
|
|
517
508
|
# User defined functions don't have to return a value.
|
518
|
-
key, obj = result_map.detect{|k,
|
519
|
-
if key
|
520
|
-
return obj
|
521
|
-
end
|
522
|
-
|
523
|
-
key, obj = result_map.detect{|k, v| k.include?('FAILURE')}
|
524
|
-
if key
|
525
|
-
raise Aerospike::Exceptions::Aerospike.new(UDF_BAD_RESPONSE, "#{obj}")
|
526
|
-
end
|
509
|
+
key, obj = result_map.detect{ |k, _| k.include?('SUCCESS') }
|
510
|
+
return obj if key
|
527
511
|
|
528
|
-
|
512
|
+
key, obj = result_map.detect{ |k, _| k.include?('FAILURE') }
|
513
|
+
message = key ? obj.to_s : "Invalid UDF return value"
|
514
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::UDF_BAD_RESPONSE, message)
|
529
515
|
end
|
530
516
|
|
531
517
|
# execute_udf_on_query applies user defined function on records that match the statement filter.
|
@@ -540,7 +526,7 @@ module Aerospike
|
|
540
526
|
policy = create_policy(options, QueryPolicy)
|
541
527
|
|
542
528
|
nodes = @cluster.nodes
|
543
|
-
if nodes.
|
529
|
+
if nodes.empty?
|
544
530
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing UDF failed because cluster is empty.")
|
545
531
|
end
|
546
532
|
|
@@ -644,7 +630,7 @@ module Aerospike
|
|
644
630
|
new_policy = policy.clone
|
645
631
|
|
646
632
|
nodes = @cluster.nodes
|
647
|
-
if nodes.
|
633
|
+
if nodes.empty?
|
648
634
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
|
649
635
|
end
|
650
636
|
|
@@ -699,7 +685,7 @@ module Aerospike
|
|
699
685
|
new_policy = policy.clone
|
700
686
|
new_policy.max_retries = 0
|
701
687
|
|
702
|
-
node = @cluster.get_node_by_name(node)
|
688
|
+
node = @cluster.get_node_by_name(node) unless node.is_a?(Aerospike::Node)
|
703
689
|
|
704
690
|
recordset = Recordset.new(policy.record_queue_size, 1, :scan)
|
705
691
|
|
@@ -735,7 +721,7 @@ module Aerospike
|
|
735
721
|
new_policy = policy.clone
|
736
722
|
|
737
723
|
nodes = @cluster.nodes
|
738
|
-
if nodes.
|
724
|
+
if nodes.empty?
|
739
725
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
|
740
726
|
end
|
741
727
|
|
@@ -782,10 +768,8 @@ module Aerospike
|
|
782
768
|
|
783
769
|
# Change user's password. Clear-text password will be hashed using bcrypt before sending to server.
|
784
770
|
def change_password(user, password, options={})
|
771
|
+
raise Aerospike::Exceptions::Aerospike.new(INVALID_USER) unless @cluster.user && @cluster.user != ""
|
785
772
|
policy = create_policy(options, AdminPolicy)
|
786
|
-
if @cluster.user == ''
|
787
|
-
return NewAerospikeError(INVALID_USER)
|
788
|
-
end
|
789
773
|
|
790
774
|
hash = AdminCommand.hash_password(password)
|
791
775
|
command = AdminCommand.new
|
@@ -832,7 +816,8 @@ module Aerospike
|
|
832
816
|
private
|
833
817
|
|
834
818
|
def send_info_command(policy, command)
|
835
|
-
|
819
|
+
policy ||= default_policy
|
820
|
+
@cluster.request_info(policy, command)
|
836
821
|
end
|
837
822
|
|
838
823
|
def hash_to_bins(hash)
|
@@ -912,7 +897,7 @@ module Aerospike
|
|
912
897
|
command.execute
|
913
898
|
end
|
914
899
|
|
915
|
-
def batch_execute(keys
|
900
|
+
def batch_execute(keys)
|
916
901
|
batch_nodes = BatchNode.generate_list(@cluster, keys)
|
917
902
|
threads = []
|
918
903
|
|
@@ -923,15 +908,15 @@ module Aerospike
|
|
923
908
|
bn.batch_namespaces.each do |bns|
|
924
909
|
threads << Thread.new do
|
925
910
|
Thread.current.abort_on_exception = true
|
926
|
-
command =
|
911
|
+
command = yield bn.node, bns
|
927
912
|
execute_command(command)
|
928
913
|
end
|
929
914
|
end
|
930
915
|
end
|
931
916
|
|
932
|
-
threads.each
|
917
|
+
threads.each(&:join)
|
933
918
|
end
|
934
919
|
|
935
920
|
end # class
|
936
921
|
|
937
|
-
end #module
|
922
|
+
end # module
|
@@ -35,6 +35,7 @@ module Aerospike
|
|
35
35
|
@connection_queue_size = policy.connection_queue_size
|
36
36
|
@connection_timeout = policy.timeout
|
37
37
|
@tend_interval = policy.tend_interval
|
38
|
+
@cluster_name = policy.cluster_name
|
38
39
|
@aliases = {}
|
39
40
|
@cluster_nodes = []
|
40
41
|
@partition_write_map = {}
|
@@ -44,7 +45,7 @@ module Aerospike
|
|
44
45
|
@mutex = Mutex.new
|
45
46
|
@cluster_config_change_listeners = Atomic.new([])
|
46
47
|
|
47
|
-
@
|
48
|
+
@old_node_count = 0
|
48
49
|
|
49
50
|
# setup auth info for cluster
|
50
51
|
if policy.requires_authentication
|
@@ -208,6 +209,10 @@ module Aerospike
|
|
208
209
|
end
|
209
210
|
end
|
210
211
|
|
212
|
+
def inspect
|
213
|
+
"#<Aerospike::Cluster @cluster_nodes=#{@cluster_nodes}>"
|
214
|
+
end
|
215
|
+
|
211
216
|
private
|
212
217
|
|
213
218
|
def launch_tend_thread
|
@@ -254,7 +259,8 @@ module Aerospike
|
|
254
259
|
refresh_count += 1
|
255
260
|
friend_list.concat(friends) if friends
|
256
261
|
rescue => e
|
257
|
-
Aerospike.logger.error("Node `#{node}` refresh failed: #{e
|
262
|
+
Aerospike.logger.error("Node `#{node}` refresh failed: #{e}")
|
263
|
+
Aerospike.logger.error(e.backtrace.join("\n"))
|
258
264
|
end
|
259
265
|
end
|
260
266
|
end
|
@@ -279,12 +285,10 @@ module Aerospike
|
|
279
285
|
|
280
286
|
# only log the tend finish IF the number of nodes has been changed.
|
281
287
|
# This prevents spamming the log on every tend interval
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
end
|
287
|
-
@old_node_cound = nodes.length
|
288
|
+
diff = nodes.length - @old_node_count
|
289
|
+
action = "#{diff.abs} #{diff.abs == 1 ? "node has" : "nodes have"} #{diff > 0 ? "joined" : "left"} the cluster."
|
290
|
+
Aerospike.logger.info("Tend finished. #{action} Old node count: #{@old_node_count}, New node count: #{nodes.length}")
|
291
|
+
@old_node_count = nodes.length
|
288
292
|
|
289
293
|
notify_cluster_config_changed
|
290
294
|
end
|
@@ -362,7 +366,7 @@ module Aerospike
|
|
362
366
|
|
363
367
|
seed_array.each do |seed|
|
364
368
|
begin
|
365
|
-
seed_node_validator = NodeValidator.new(self, seed, @connection_timeout)
|
369
|
+
seed_node_validator = NodeValidator.new(self, seed, @connection_timeout, @cluster_name)
|
366
370
|
rescue => e
|
367
371
|
Aerospike.logger.error("Seed #{seed.to_s} failed: #{e.backtrace.join("\n")}")
|
368
372
|
next
|
@@ -376,7 +380,7 @@ module Aerospike
|
|
376
380
|
nv = seed_node_validator
|
377
381
|
else
|
378
382
|
begin
|
379
|
-
nv = NodeValidator.new(self, aliass, @connection_timeout)
|
383
|
+
nv = NodeValidator.new(self, aliass, @connection_timeout, @cluster_name)
|
380
384
|
rescue Exection => e
|
381
385
|
Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
|
382
386
|
next
|
@@ -22,7 +22,7 @@ module Aerospike
|
|
22
22
|
|
23
23
|
class Node
|
24
24
|
|
25
|
-
attr_reader :reference_count, :responded, :name, :features
|
25
|
+
attr_reader :reference_count, :responded, :name, :features, :cluster_name
|
26
26
|
|
27
27
|
PARTITIONS = 4096
|
28
28
|
FULL_HEALTH = 100
|
@@ -35,17 +35,18 @@ module Aerospike
|
|
35
35
|
@host = nv.host
|
36
36
|
@use_new_info = Atomic.new(nv.use_new_info)
|
37
37
|
@features = nv.features
|
38
|
+
@cluster_name = nv.cluster_name
|
38
39
|
|
39
40
|
# Assign host to first IP alias because the server identifies nodes
|
40
41
|
# by IP address (not hostname).
|
41
|
-
@host =
|
42
|
-
@health =
|
42
|
+
@host = nv.aliases[0]
|
43
|
+
@health = Atomic.new(FULL_HEALTH)
|
43
44
|
@partition_generation = Atomic.new(-1)
|
44
|
-
@reference_count =
|
45
|
-
@responded =
|
46
|
-
@active =
|
45
|
+
@reference_count = Atomic.new(0)
|
46
|
+
@responded = Atomic.new(false)
|
47
|
+
@active = Atomic.new(true)
|
47
48
|
|
48
|
-
@connections =
|
49
|
+
@connections = Pool.new(@cluster.connection_queue_size)
|
49
50
|
@connections.create_block = Proc.new do
|
50
51
|
while conn = Connection.new(@host.name, @host.port, @cluster.connection_timeout)
|
51
52
|
|
@@ -75,9 +76,10 @@ module Aerospike
|
|
75
76
|
|
76
77
|
begin
|
77
78
|
conn = get_connection(1)
|
78
|
-
info_map = Info.request(conn, "node", "partition-generation", "services")
|
79
|
+
info_map = Info.request(conn, "node", "partition-generation", "services", "cluster-name")
|
79
80
|
rescue => e
|
80
81
|
Aerospike.logger.error("Error during refresh for node #{self}: #{e}")
|
82
|
+
Aerospike.logger.error(e.backtrace.join("\n"))
|
81
83
|
|
82
84
|
conn.close if conn
|
83
85
|
decrease_health
|
@@ -85,7 +87,7 @@ module Aerospike
|
|
85
87
|
return friends
|
86
88
|
end
|
87
89
|
|
88
|
-
|
90
|
+
verify_node_name_and_cluster_name(info_map)
|
89
91
|
restore_health
|
90
92
|
|
91
93
|
@responded.update{|v| true}
|
@@ -173,10 +175,6 @@ module Aerospike
|
|
173
175
|
@features.include?(feature.to_s)
|
174
176
|
end
|
175
177
|
|
176
|
-
def to_s
|
177
|
-
"#{@name}:#{@host}"
|
178
|
-
end
|
179
|
-
|
180
178
|
def ==(other)
|
181
179
|
other && other.is_a?(Node) && (@name == other.name)
|
182
180
|
end
|
@@ -190,6 +188,10 @@ module Aerospike
|
|
190
188
|
@name.hash
|
191
189
|
end
|
192
190
|
|
191
|
+
def inspect
|
192
|
+
"#<Aerospike::Node: @name=#{@name}, @host=#{@host}>"
|
193
|
+
end
|
194
|
+
|
193
195
|
private
|
194
196
|
|
195
197
|
def close_connections
|
@@ -206,18 +208,23 @@ module Aerospike
|
|
206
208
|
@aliases.value = aliases
|
207
209
|
end
|
208
210
|
|
209
|
-
def
|
211
|
+
def verify_node_name_and_cluster_name(info_map)
|
210
212
|
info_name = info_map['node']
|
211
213
|
|
212
214
|
if !info_name
|
213
215
|
decrease_health
|
214
|
-
raise Aerospike::Exceptions
|
216
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Node name is empty")
|
215
217
|
end
|
216
218
|
|
217
219
|
if !(@name == info_name)
|
218
220
|
# Set node to inactive immediately.
|
219
221
|
@active.update{|v| false}
|
220
|
-
raise Aerospike::Exceptions
|
222
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Node name has changed. Old=#{@name} New= #{info_name}")
|
223
|
+
end
|
224
|
+
|
225
|
+
if cluster_name && cluster_name != info_map['cluster-name']
|
226
|
+
@active.update{|v| false}
|
227
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Cluster name does not match. expected: #{cluster_name}, got: #{info_map['cluster-name']}")
|
221
228
|
end
|
222
229
|
end
|
223
230
|
|
@@ -239,7 +246,7 @@ module Aerospike
|
|
239
246
|
if node
|
240
247
|
node.reference_count.update{|v| v + 1}
|
241
248
|
else
|
242
|
-
unless friends.any? {|
|
249
|
+
unless friends.any? {|h| h == aliass}
|
243
250
|
friends << aliass
|
244
251
|
end
|
245
252
|
end
|
@@ -20,13 +20,14 @@ module Aerospike
|
|
20
20
|
|
21
21
|
class NodeValidator # :nodoc:
|
22
22
|
|
23
|
-
attr_reader :host, :aliases, :name, :use_new_info, :features
|
23
|
+
attr_reader :host, :aliases, :name, :use_new_info, :features, :cluster_name
|
24
24
|
|
25
|
-
def initialize(cluster, host, timeout)
|
25
|
+
def initialize(cluster, host, timeout, cluster_name)
|
26
26
|
@cluster = cluster
|
27
27
|
@use_new_info = true
|
28
28
|
@features = Set.new
|
29
29
|
@host = host
|
30
|
+
@cluster_name = cluster_name
|
30
31
|
|
31
32
|
set_aliases(host)
|
32
33
|
set_address(timeout)
|
@@ -48,8 +48,8 @@ module Aerospike
|
|
48
48
|
INFO2_GENERATION = Integer(1 << 2)
|
49
49
|
# Update if new generation >= old, good for restore.
|
50
50
|
INFO2_GENERATION_GT = Integer(1 << 3)
|
51
|
-
#
|
52
|
-
|
51
|
+
# Transaction resulting in record deletion leaves tombstone (Enterprise only).
|
52
|
+
INFO2_DURABLE_DELETE = Integer(1 << 4)
|
53
53
|
# Create only. Fail if record already exists.
|
54
54
|
INFO2_CREATE_ONLY = Integer(1 << 5)
|
55
55
|
|
@@ -600,6 +600,7 @@ module Aerospike
|
|
600
600
|
|
601
601
|
info_attr |= INFO3_COMMIT_MASTER if policy.commit_level == Aerospike::CommitLevel::COMMIT_MASTER
|
602
602
|
read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
|
603
|
+
write_attr |= INFO2_DURABLE_DELETE if policy.durable_delete
|
603
604
|
|
604
605
|
# Write all header data except total size which must be written last.
|
605
606
|
@data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message heade.length.
|
@@ -17,6 +17,7 @@
|
|
17
17
|
require 'aerospike/record'
|
18
18
|
|
19
19
|
require 'aerospike/command/single_command'
|
20
|
+
require 'aerospike/policy/operate_policy'
|
20
21
|
require 'aerospike/utils/epoc'
|
21
22
|
require 'aerospike/value/value'
|
22
23
|
|
@@ -26,7 +27,7 @@ module Aerospike
|
|
26
27
|
|
27
28
|
class ReadCommand < SingleCommand #:nodoc:
|
28
29
|
|
29
|
-
attr_reader :record
|
30
|
+
attr_reader :record, :policy
|
30
31
|
|
31
32
|
def initialize(cluster, policy, key, bin_names)
|
32
33
|
super(cluster, key)
|
@@ -108,6 +109,7 @@ module Aerospike
|
|
108
109
|
def parse_record(op_count, field_count, generation, expiration)
|
109
110
|
bins = op_count > 0 ? {} : nil
|
110
111
|
receive_offset = 0
|
112
|
+
single_bin_value = (!(OperatePolicy === policy) || policy.record_bin_multiplicity == RecordBinMultiplicity::SINGLE)
|
111
113
|
|
112
114
|
# There can be fields in the response (setname etc).
|
113
115
|
# But for now, ignore them. Expose them to the API if needed in the future.
|
@@ -129,12 +131,17 @@ module Aerospike
|
|
129
131
|
name = @data_buffer.read(receive_offset+8, name_size).force_encoding('utf-8')
|
130
132
|
receive_offset += 4 + 4 + name_size
|
131
133
|
|
132
|
-
|
133
134
|
particle_bytes_size = op_size - (4 + name_size)
|
134
135
|
value = Aerospike.bytes_to_particle(particle_type, @data_buffer, receive_offset, particle_bytes_size)
|
135
136
|
receive_offset += particle_bytes_size
|
136
137
|
|
137
|
-
bins
|
138
|
+
if single_bin_value || !bins.has_key?(name)
|
139
|
+
bins[name] = value
|
140
|
+
elsif (prev = bins[name]).kind_of?(OpResults)
|
141
|
+
prev << value
|
142
|
+
else
|
143
|
+
bins[name] = OpResults.new << prev << value
|
144
|
+
end
|
138
145
|
|
139
146
|
i = i.succ
|
140
147
|
end
|
@@ -144,4 +151,6 @@ module Aerospike
|
|
144
151
|
|
145
152
|
end # class
|
146
153
|
|
154
|
+
class OpResults < Array; end
|
155
|
+
|
147
156
|
end # module
|
data/lib/aerospike/host.rb
CHANGED
@@ -20,6 +20,7 @@ module Aerospike
|
|
20
20
|
|
21
21
|
attr_accessor :user, :password
|
22
22
|
attr_accessor :timeout, :connection_queue_size, :fail_if_not_connected, :tend_interval
|
23
|
+
attr_accessor :cluster_name
|
23
24
|
|
24
25
|
def initialize(opt={})
|
25
26
|
# Initial host connection timeout in seconds. The timeout when opening a connection
|
@@ -41,6 +42,9 @@ module Aerospike
|
|
41
42
|
|
42
43
|
# password
|
43
44
|
@password = opt[:password]
|
45
|
+
|
46
|
+
# Cluster Name
|
47
|
+
@cluster_name = opt[:cluster_name]
|
44
48
|
end
|
45
49
|
|
46
50
|
def requires_authentication
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2016 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http:#www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'aerospike/policy/write_policy'
|
17
|
+
require 'aerospike/policy/record_bin_multiplicity'
|
18
|
+
|
19
|
+
module Aerospike
|
20
|
+
|
21
|
+
class OperatePolicy < WritePolicy
|
22
|
+
|
23
|
+
attr_accessor :record_bin_multiplicity
|
24
|
+
|
25
|
+
def initialize(opt = {})
|
26
|
+
super(opt)
|
27
|
+
|
28
|
+
# Specifies how to merge results from multiple operations returning
|
29
|
+
# results for the same record bin.
|
30
|
+
@record_bin_multiplicity = opt[:record_bin_multiplicity] || RecordBinMultiplicity::SINGLE
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2016 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http:#www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Aerospike
|
17
|
+
|
18
|
+
module RecordBinMultiplicity
|
19
|
+
|
20
|
+
# Returns only the result of the last operation on a given record bin.
|
21
|
+
SINGLE = 0
|
22
|
+
|
23
|
+
# Returns the results of all operations on a given record bin as a list.
|
24
|
+
ARRAY = 1
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -24,7 +24,8 @@ module Aerospike
|
|
24
24
|
class WritePolicy < Policy
|
25
25
|
|
26
26
|
attr_accessor :record_exists_action, :generation_policy,
|
27
|
-
:generation, :expiration, :send_key, :commit_level
|
27
|
+
:generation, :expiration, :send_key, :commit_level,
|
28
|
+
:durable_delete
|
28
29
|
|
29
30
|
def initialize(opt={})
|
30
31
|
super(opt)
|
@@ -59,6 +60,12 @@ module Aerospike
|
|
59
60
|
# The default is to send the user defined key.
|
60
61
|
@send_key = opt[:send_key].nil? ? true : opt[:send_key]
|
61
62
|
|
63
|
+
# If the transaction results in a record deletion, leave a tombstone for
|
64
|
+
# the record. This prevents deleted records from reappearing after node
|
65
|
+
# failures.
|
66
|
+
# Valid for Aerospike Server Enterprise Edition 3.10+ only.
|
67
|
+
@durable_delete = opt.fetch(:durable_delete, false)
|
68
|
+
|
62
69
|
self
|
63
70
|
end
|
64
71
|
|
@@ -120,6 +120,9 @@ module Aerospike
|
|
120
120
|
# Returned by Map put and put_items operations when policy is CREATE_ONLY but key already exists
|
121
121
|
ELEMENT_EXISTS = 24
|
122
122
|
|
123
|
+
# Enterprise-only feature not supported by the community edition
|
124
|
+
ENTERPRISE_ONLY = 25
|
125
|
+
|
123
126
|
# There are no more records left for query.
|
124
127
|
QUERY_END = 50
|
125
128
|
|
@@ -302,6 +305,9 @@ module Aerospike
|
|
302
305
|
when ELEMENT_EXISTS
|
303
306
|
"Element already exists"
|
304
307
|
|
308
|
+
when ENTERPRISE_ONLY
|
309
|
+
"Enterprise-only feature not supported by community edition"
|
310
|
+
|
305
311
|
when QUERY_END
|
306
312
|
"Query end"
|
307
313
|
|
data/lib/aerospike/utils/pool.rb
CHANGED
@@ -14,9 +14,6 @@
|
|
14
14
|
# License for the specific language governing permissions and limitations under
|
15
15
|
# the License.
|
16
16
|
|
17
|
-
require 'thread'
|
18
|
-
require 'timeout'
|
19
|
-
|
20
17
|
module Aerospike
|
21
18
|
|
22
19
|
private
|
@@ -43,13 +40,10 @@ module Aerospike
|
|
43
40
|
alias_method :<<, :offer
|
44
41
|
|
45
42
|
def poll(create_new=true)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
rescue
|
51
|
-
return @create_block.call if @create_block && create_new
|
52
|
-
end
|
43
|
+
non_block = true
|
44
|
+
@pool.pop(non_block)
|
45
|
+
rescue
|
46
|
+
@create_block.call() if @create_block && create_new
|
53
47
|
end
|
54
48
|
|
55
49
|
def empty?
|
@@ -59,6 +53,11 @@ module Aerospike
|
|
59
53
|
def length
|
60
54
|
@pool.length
|
61
55
|
end
|
56
|
+
alias_method :size, :length
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
"#<Aerospike::Pool: size=#{size}>"
|
60
|
+
end
|
62
61
|
|
63
62
|
end
|
64
63
|
|
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.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Khosrow Afroozeh
|
@@ -9,14 +9,9 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-09-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
version_requirements: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.0'
|
20
15
|
name: msgpack
|
21
16
|
requirement: !ruby/object:Gem::Requirement
|
22
17
|
requirements:
|
@@ -25,12 +20,12 @@ dependencies:
|
|
25
20
|
version: '1.0'
|
26
21
|
type: :runtime
|
27
22
|
prerelease: false
|
28
|
-
- !ruby/object:Gem::Dependency
|
29
23
|
version_requirements: !ruby/object:Gem::Requirement
|
30
24
|
requirements:
|
31
25
|
- - "~>"
|
32
26
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
27
|
+
version: '1.0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
34
29
|
name: bcrypt
|
35
30
|
requirement: !ruby/object:Gem::Requirement
|
36
31
|
requirements:
|
@@ -39,6 +34,11 @@ dependencies:
|
|
39
34
|
version: '3.1'
|
40
35
|
type: :runtime
|
41
36
|
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '3.1'
|
42
42
|
description: Official Aerospike Client for ruby. Access your Aerospike cluster with
|
43
43
|
ease of Ruby.
|
44
44
|
email:
|
@@ -106,9 +106,11 @@ files:
|
|
106
106
|
- lib/aerospike/policy/commit_level.rb
|
107
107
|
- lib/aerospike/policy/consistency_level.rb
|
108
108
|
- lib/aerospike/policy/generation_policy.rb
|
109
|
+
- lib/aerospike/policy/operate_policy.rb
|
109
110
|
- lib/aerospike/policy/policy.rb
|
110
111
|
- lib/aerospike/policy/priority.rb
|
111
112
|
- lib/aerospike/policy/query_policy.rb
|
113
|
+
- lib/aerospike/policy/record_bin_multiplicity.rb
|
112
114
|
- lib/aerospike/policy/record_exists_action.rb
|
113
115
|
- lib/aerospike/policy/scan_policy.rb
|
114
116
|
- lib/aerospike/policy/write_policy.rb
|
@@ -157,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
159
|
version: '0'
|
158
160
|
requirements: []
|
159
161
|
rubyforge_project:
|
160
|
-
rubygems_version: 2.
|
162
|
+
rubygems_version: 2.5.1
|
161
163
|
signing_key:
|
162
164
|
specification_version: 4
|
163
165
|
summary: An Aerospike driver for Ruby.
|