aerospike 2.1.1 → 2.2.0
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/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.
|