aerospike 1.0.10 → 1.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +31 -2
- data/README.md +0 -1
- data/lib/aerospike.rb +2 -0
- data/lib/aerospike/bin.rb +4 -0
- data/lib/aerospike/client.rb +54 -19
- data/lib/aerospike/cluster/cluster.rb +70 -6
- data/lib/aerospike/cluster/node.rb +6 -2
- data/lib/aerospike/cluster/node_validator.rb +8 -2
- data/lib/aerospike/command/command.rb +13 -1
- data/lib/aerospike/command/operate_command.rb +4 -0
- data/lib/aerospike/command/read_command.rb +1 -2
- data/lib/aerospike/command/roles.rb +5 -2
- data/lib/aerospike/command/unsupported_particle_type_validator.rb +34 -0
- data/lib/aerospike/command/write_command.rb +4 -0
- data/lib/aerospike/geo_json.rb +61 -0
- data/lib/aerospike/operation.rb +4 -0
- data/lib/aerospike/policy/client_policy.rb +14 -2
- data/lib/aerospike/query/filter.rb +26 -2
- data/lib/aerospike/query/recordset.rb +2 -2
- data/lib/aerospike/query/stream_command.rb +3 -0
- data/lib/aerospike/result_code.rb +0 -1
- data/lib/aerospike/utils/buffer.rb +11 -0
- data/lib/aerospike/value/particle_type.rb +2 -1
- data/lib/aerospike/value/value.rb +101 -0
- data/lib/aerospike/version.rb +1 -1
- metadata +20 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7cb691e571b83e9b270f5de08850950f8cb61be6
|
4
|
+
data.tar.gz: 20ef98d1d88b118da73e6230c3bd2c1cc86cbdfa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 093c7bc1db1b636d607d63921cc50acb122a523314b64ce6f4de719672480c359473d5083ef07ae53b516e049cc4cacc9e041686bb717b4e42fd662e0a240a69
|
7
|
+
data.tar.gz: c5168149d2c0ce5ab34f29bd4c968126c61dec7e9923beec9727a77ccfb57cad926ce9554c59e726d9c6fc764886b1fa7830991dc478fa46faf04bb649f9b6ec
|
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,41 @@
|
|
1
|
+
## December 4 2015 (1.0.11)
|
2
|
+
|
3
|
+
Major feature and bug fix release.
|
4
|
+
|
5
|
+
* **Fixes**:
|
6
|
+
|
7
|
+
* Fix `ClientPolicy` to actually accept `fail_if_not_connected` parameter from constructor opts. PR #29, thanks to [Nick Recobra](https://github.com/oruen)
|
8
|
+
|
9
|
+
* Fix record initialization issue. PR #28, thanks to [jzhua](https://github.com/jzhua)
|
10
|
+
|
11
|
+
* Consume the rest of the stream when scan/query is finished.
|
12
|
+
|
13
|
+
* **Improvements**:
|
14
|
+
|
15
|
+
* Support for double precision floating point data type in record bins.
|
16
|
+
Requires server version 3.6.0 or later. [CLIENT-599]
|
17
|
+
|
18
|
+
* Support for geospatial data in record bins using GeoJSON format; support
|
19
|
+
for querying geospatial indexes using points-within-region and
|
20
|
+
region-contains-point filters. Requires server version 3.7.0 or later.
|
21
|
+
[CLIENT-594]
|
22
|
+
|
23
|
+
* Tend intervale is now configurable via the client policy. Default is 1
|
24
|
+
second as before.
|
25
|
+
|
26
|
+
* Only logs tend messages when the number of cluster nodes have changed.
|
27
|
+
|
28
|
+
* Scan and Query termination has been fixed.
|
29
|
+
|
1
30
|
## September 22 2015 (1.0.10)
|
2
31
|
|
3
32
|
Major fix release.
|
4
33
|
|
5
34
|
* **Fixes**:
|
6
35
|
|
7
|
-
* Fixes find_node_in_partition_map logic.
|
36
|
+
* Fixes `find_node_in_partition_map` logic.
|
8
37
|
|
9
|
-
* Fixes Node.Refresh logic.
|
38
|
+
* Fixes `Node.Refresh` logic.
|
10
39
|
|
11
40
|
* Fixes an issue with dead connections that would cause an infinite loop.
|
12
41
|
|
data/README.md
CHANGED
data/lib/aerospike.rb
CHANGED
@@ -37,8 +37,10 @@ require 'aerospike/command/batch_command_exists'
|
|
37
37
|
require 'aerospike/command/read_command'
|
38
38
|
require 'aerospike/command/delete_command'
|
39
39
|
require 'aerospike/command/admin_command'
|
40
|
+
require 'aerospike/command/unsupported_particle_type_validator'
|
40
41
|
require 'aerospike/key'
|
41
42
|
require 'aerospike/operation'
|
43
|
+
require 'aerospike/geo_json'
|
42
44
|
|
43
45
|
require 'aerospike/policy/client_policy'
|
44
46
|
require 'aerospike/policy/priority'
|
data/lib/aerospike/bin.rb
CHANGED
data/lib/aerospike/client.rb
CHANGED
@@ -49,6 +49,8 @@ module Aerospike
|
|
49
49
|
policy = opt_to_client_policy(options)
|
50
50
|
|
51
51
|
@cluster = Cluster.new(policy, Host.new(host, port))
|
52
|
+
@cluster.add_cluster_config_change_listener(self)
|
53
|
+
@cluster.connect
|
52
54
|
|
53
55
|
self
|
54
56
|
end
|
@@ -65,7 +67,10 @@ module Aerospike
|
|
65
67
|
|
66
68
|
policy = client.send(:opt_to_client_policy , options)
|
67
69
|
|
68
|
-
|
70
|
+
cluster = Cluster.new(policy, *hosts)
|
71
|
+
cluster.add_cluster_config_change_listener(client)
|
72
|
+
client.send(:cluster=, cluster)
|
73
|
+
cluster.connect
|
69
74
|
|
70
75
|
client
|
71
76
|
end
|
@@ -119,7 +124,7 @@ module Aerospike
|
|
119
124
|
def put(key, bins, options={})
|
120
125
|
policy = opt_to_write_policy(options)
|
121
126
|
command = WriteCommand.new(@cluster, policy, key, hash_to_bins(bins), Aerospike::Operation::WRITE)
|
122
|
-
command
|
127
|
+
execute_command(command)
|
123
128
|
end
|
124
129
|
|
125
130
|
#-------------------------------------------------------
|
@@ -142,7 +147,7 @@ module Aerospike
|
|
142
147
|
def append(key, bins, options={})
|
143
148
|
policy = opt_to_write_policy(options)
|
144
149
|
command = WriteCommand.new(@cluster, policy, key, hash_to_bins(bins), Aerospike::Operation::APPEND)
|
145
|
-
command
|
150
|
+
execute_command(command)
|
146
151
|
end
|
147
152
|
|
148
153
|
##
|
@@ -161,7 +166,7 @@ module Aerospike
|
|
161
166
|
def prepend(key, bins, options={})
|
162
167
|
policy = opt_to_write_policy(options)
|
163
168
|
command = WriteCommand.new(@cluster, policy, key, hash_to_bins(bins), Aerospike::Operation::PREPEND)
|
164
|
-
command
|
169
|
+
execute_command(command)
|
165
170
|
end
|
166
171
|
|
167
172
|
#-------------------------------------------------------
|
@@ -184,7 +189,7 @@ module Aerospike
|
|
184
189
|
def add(key, bins, options={})
|
185
190
|
policy = opt_to_write_policy(options)
|
186
191
|
command = WriteCommand.new(@cluster, policy, key, hash_to_bins(bins), Aerospike::Operation::ADD)
|
187
|
-
command
|
192
|
+
execute_command(command)
|
188
193
|
end
|
189
194
|
|
190
195
|
#-------------------------------------------------------
|
@@ -206,7 +211,7 @@ module Aerospike
|
|
206
211
|
def delete(key, options={})
|
207
212
|
policy = opt_to_write_policy(options)
|
208
213
|
command = DeleteCommand.new(@cluster, policy, key)
|
209
|
-
command
|
214
|
+
execute_command(command)
|
210
215
|
command.existed
|
211
216
|
end
|
212
217
|
|
@@ -227,7 +232,7 @@ module Aerospike
|
|
227
232
|
def touch(key, options={})
|
228
233
|
policy = opt_to_write_policy(options)
|
229
234
|
command = TouchCommand.new(@cluster, policy, key)
|
230
|
-
command
|
235
|
+
execute_command(command)
|
231
236
|
end
|
232
237
|
|
233
238
|
#-------------------------------------------------------
|
@@ -240,7 +245,7 @@ module Aerospike
|
|
240
245
|
def exists(key, options={})
|
241
246
|
policy = opt_to_policy(options)
|
242
247
|
command = ExistsCommand.new(@cluster, policy, key)
|
243
|
-
command
|
248
|
+
execute_command(command)
|
244
249
|
command.exists
|
245
250
|
end
|
246
251
|
|
@@ -274,7 +279,7 @@ module Aerospike
|
|
274
279
|
policy = opt_to_policy(options)
|
275
280
|
|
276
281
|
command = ReadCommand.new(@cluster, policy, key, bin_names)
|
277
|
-
command
|
282
|
+
execute_command(command)
|
278
283
|
command.record
|
279
284
|
end
|
280
285
|
|
@@ -283,7 +288,7 @@ module Aerospike
|
|
283
288
|
def get_header(key, options={})
|
284
289
|
policy = opt_to_policy(options)
|
285
290
|
command = ReadHeaderCommand.new(@cluster, policy, key)
|
286
|
-
command
|
291
|
+
execute_command(command)
|
287
292
|
command.record
|
288
293
|
end
|
289
294
|
|
@@ -355,7 +360,7 @@ module Aerospike
|
|
355
360
|
policy = opt_to_write_policy(options)
|
356
361
|
|
357
362
|
command = OperateCommand.new(@cluster, policy, key, operations)
|
358
|
-
command
|
363
|
+
execute_command(command)
|
359
364
|
command.record
|
360
365
|
end
|
361
366
|
|
@@ -506,7 +511,7 @@ module Aerospike
|
|
506
511
|
policy = opt_to_write_policy(options)
|
507
512
|
|
508
513
|
command = ExecuteCommand.new(@cluster, policy, key, package_name, function_name, args)
|
509
|
-
command
|
514
|
+
execute_command(command)
|
510
515
|
|
511
516
|
record = command.record
|
512
517
|
|
@@ -553,7 +558,7 @@ module Aerospike
|
|
553
558
|
abort_on_exception = true
|
554
559
|
begin
|
555
560
|
command = QueryCommand.new(node, policy, statement, nil)
|
556
|
-
command
|
561
|
+
execute_command(command)
|
557
562
|
rescue => e
|
558
563
|
Aerospike.logger.error(e)
|
559
564
|
raise e
|
@@ -571,7 +576,7 @@ module Aerospike
|
|
571
576
|
# IndexTask instance.
|
572
577
|
#
|
573
578
|
# This method is only supported by Aerospike 3 servers.
|
574
|
-
# index_type should be
|
579
|
+
# index_type should be :string, :numeric or :geo2dsphere (requires server version 3.7 or later)
|
575
580
|
def create_index(namespace, set_name, index_name, bin_name, index_type, options={})
|
576
581
|
policy = opt_to_write_policy(options)
|
577
582
|
str_cmd = "sindex-create:ns=#{namespace}"
|
@@ -651,7 +656,7 @@ module Aerospike
|
|
651
656
|
abort_on_exception = true
|
652
657
|
command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
|
653
658
|
begin
|
654
|
-
command
|
659
|
+
execute_command(command)
|
655
660
|
rescue => e
|
656
661
|
Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
|
657
662
|
recordset.cancel(e)
|
@@ -666,7 +671,7 @@ module Aerospike
|
|
666
671
|
nodes.each do |node|
|
667
672
|
command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
|
668
673
|
begin
|
669
|
-
command
|
674
|
+
execute_command(command)
|
670
675
|
rescue => e
|
671
676
|
Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
|
672
677
|
recordset.cancel(e)
|
@@ -701,7 +706,7 @@ module Aerospike
|
|
701
706
|
abort_on_exception = true
|
702
707
|
command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
|
703
708
|
begin
|
704
|
-
command
|
709
|
+
execute_command(command)
|
705
710
|
rescue => e
|
706
711
|
Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
|
707
712
|
recordset.cancel(e)
|
@@ -741,7 +746,7 @@ module Aerospike
|
|
741
746
|
abort_on_exception = true
|
742
747
|
command = QueryCommand.new(node, new_policy, statement, recordset)
|
743
748
|
begin
|
744
|
-
command
|
749
|
+
execute_command(command)
|
745
750
|
rescue => e
|
746
751
|
Aerospike.logger.error(e.backtrace.join("\n")) unless e == QUERY_TERMINATED_EXCEPTION
|
747
752
|
recordset.cancel(e)
|
@@ -906,6 +911,36 @@ module Aerospike
|
|
906
911
|
@cluster = cluster
|
907
912
|
end
|
908
913
|
|
914
|
+
def cluster_config_changed(cluster)
|
915
|
+
Aerospike.logger.debug { "Cluster config change detected; active nodes: #{cluster.nodes.map(&:name)}" }
|
916
|
+
setup_command_validators
|
917
|
+
end
|
918
|
+
|
919
|
+
def setup_command_validators
|
920
|
+
Aerospike.logger.debug { "Cluster features: #{@cluster.features.get.to_a}" }
|
921
|
+
validators = []
|
922
|
+
|
923
|
+
# guard against unsupported particle types
|
924
|
+
unsupported_particle_types = []
|
925
|
+
unsupported_particle_types << Aerospike::ParticleType::DOUBLE unless @cluster.supports_feature?("float")
|
926
|
+
unsupported_particle_types << Aerospike::ParticleType::GEOJSON unless @cluster.supports_feature?("geo")
|
927
|
+
validators << UnsupportedParticleTypeValidator.new(*unsupported_particle_types) unless unsupported_particle_types.empty?
|
928
|
+
|
929
|
+
@command_validators = validators
|
930
|
+
end
|
931
|
+
|
932
|
+
def validate_command(command)
|
933
|
+
return unless @command_validators
|
934
|
+
@command_validators.each do |validator|
|
935
|
+
validator.call(command)
|
936
|
+
end
|
937
|
+
end
|
938
|
+
|
939
|
+
def execute_command(command)
|
940
|
+
validate_command(command)
|
941
|
+
command.execute
|
942
|
+
end
|
943
|
+
|
909
944
|
def batch_execute(keys, &cmd_gen)
|
910
945
|
batch_nodes = BatchNode.generate_list(@cluster, keys)
|
911
946
|
threads = []
|
@@ -918,7 +953,7 @@ module Aerospike
|
|
918
953
|
threads << Thread.new do
|
919
954
|
abort_on_exception=true
|
920
955
|
command = cmd_gen.call(bn.node, bns)
|
921
|
-
command
|
956
|
+
execute_command(command)
|
922
957
|
end
|
923
958
|
end
|
924
959
|
end
|
@@ -14,6 +14,7 @@
|
|
14
14
|
# License for the specific language governing permissions and limitations under
|
15
15
|
# the License.
|
16
16
|
|
17
|
+
require 'set'
|
17
18
|
require 'thread'
|
18
19
|
require 'timeout'
|
19
20
|
|
@@ -26,17 +27,24 @@ module Aerospike
|
|
26
27
|
class Cluster
|
27
28
|
|
28
29
|
attr_reader :connection_timeout, :connection_queue_size, :user, :password
|
30
|
+
attr_reader :features
|
29
31
|
|
30
32
|
def initialize(policy, *hosts)
|
31
33
|
@cluster_seeds = hosts
|
34
|
+
@fail_if_not_connected = policy.fail_if_not_connected
|
32
35
|
@connection_queue_size = policy.connection_queue_size
|
33
36
|
@connection_timeout = policy.timeout
|
37
|
+
@tend_interval = policy.tend_interval
|
34
38
|
@aliases = {}
|
35
39
|
@cluster_nodes = []
|
36
40
|
@partition_write_map = {}
|
37
41
|
@node_index = Atomic.new(0)
|
42
|
+
@features = Atomic.new(Set.new)
|
38
43
|
@closed = Atomic.new(true)
|
39
44
|
@mutex = Mutex.new
|
45
|
+
@cluster_config_change_listeners = Atomic.new([])
|
46
|
+
|
47
|
+
@old_node_cound = 0
|
40
48
|
|
41
49
|
# setup auth info for cluster
|
42
50
|
if policy.requires_authentication
|
@@ -44,9 +52,13 @@ module Aerospike
|
|
44
52
|
@password = AdminCommand.hash_password(policy.password)
|
45
53
|
end
|
46
54
|
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def connect
|
47
59
|
wait_till_stablized
|
48
60
|
|
49
|
-
if
|
61
|
+
if @fail_if_not_connected && !connected?
|
50
62
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE)
|
51
63
|
end
|
52
64
|
|
@@ -175,11 +187,27 @@ module Aerospike
|
|
175
187
|
end
|
176
188
|
end
|
177
189
|
|
190
|
+
def supports_feature?(feature)
|
191
|
+
@features.get.include?(feature.to_s)
|
192
|
+
end
|
193
|
+
|
178
194
|
def change_password(user, password)
|
179
195
|
# change password ONLY if the user is the same
|
180
196
|
@password = password if @user == user
|
181
197
|
end
|
182
198
|
|
199
|
+
def add_cluster_config_change_listener(listener)
|
200
|
+
@cluster_config_change_listeners.update do |listeners|
|
201
|
+
listeners.push(listener)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def remove_cluster_config_change_listener(listener)
|
206
|
+
@cluster_config_change_listeners.update do |listeners|
|
207
|
+
listeners.delete(listener)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
183
211
|
private
|
184
212
|
|
185
213
|
def launch_tend_thread
|
@@ -188,7 +216,7 @@ module Aerospike
|
|
188
216
|
while true
|
189
217
|
begin
|
190
218
|
tend
|
191
|
-
sleep
|
219
|
+
sleep(@tend_interval / 1000.0)
|
192
220
|
rescue => e
|
193
221
|
Aerospike.logger.error("Exception occured during tend: #{e}")
|
194
222
|
end
|
@@ -198,12 +226,14 @@ module Aerospike
|
|
198
226
|
|
199
227
|
def tend
|
200
228
|
nodes = self.nodes
|
229
|
+
cluster_config_changed = false
|
201
230
|
|
202
231
|
# All node additions/deletions are performed in tend thread.
|
203
232
|
# If active nodes don't exist, seed cluster.
|
204
233
|
if nodes.empty?
|
205
234
|
Aerospike.logger.info("No connections available; seeding...")
|
206
235
|
seed_nodes
|
236
|
+
cluster_config_changed = true
|
207
237
|
|
208
238
|
# refresh nodes list after seeding
|
209
239
|
nodes = self.nodes
|
@@ -231,14 +261,33 @@ module Aerospike
|
|
231
261
|
|
232
262
|
# Add nodes in a batch.
|
233
263
|
add_list = find_nodes_to_add(friend_list)
|
234
|
-
|
264
|
+
unless add_list.empty?
|
265
|
+
add_nodes(add_list)
|
266
|
+
cluster_config_changed = true
|
267
|
+
end
|
235
268
|
|
236
269
|
# Handle nodes changes determined from refreshes.
|
237
270
|
# Remove nodes in a batch.
|
238
271
|
remove_list = find_nodes_to_remove(refresh_count)
|
239
|
-
|
272
|
+
unless remove_list.empty?
|
273
|
+
remove_nodes(remove_list)
|
274
|
+
cluster_config_changed = true
|
275
|
+
end
|
276
|
+
|
277
|
+
if cluster_config_changed
|
278
|
+
update_cluster_features
|
279
|
+
|
280
|
+
# only log the tend finish IF the number of nodes has been changed.
|
281
|
+
# This prevents spamming the log on every tend interval
|
282
|
+
if @old_node_cound > nodes.length
|
283
|
+
Aerospike.logger.info("Tend finished. #{@old_node_cound - nodes.length} nodes have left the cluster. Old node count: #{@old_node_cound}, New node count #{nodes.length} #{nodes}")
|
284
|
+
else
|
285
|
+
Aerospike.logger.info("Tend finished. #{nodes.length - @old_node_cound} nodes have joined the cluster. Old node count: #{@old_node_cound}, New node count #{nodes.length} #{nodes}")
|
286
|
+
end
|
287
|
+
@old_node_cound = nodes.length
|
240
288
|
|
241
|
-
|
289
|
+
notify_cluster_config_changed
|
290
|
+
end
|
242
291
|
end
|
243
292
|
|
244
293
|
def wait_till_stablized
|
@@ -263,7 +312,7 @@ module Aerospike
|
|
263
312
|
|
264
313
|
# wait for the thread to finish or timeout
|
265
314
|
begin
|
266
|
-
Timeout.timeout(
|
315
|
+
Timeout.timeout(@connection_timeout) do
|
267
316
|
thr.join
|
268
317
|
end
|
269
318
|
rescue Timeout::Error
|
@@ -274,6 +323,21 @@ module Aerospike
|
|
274
323
|
|
275
324
|
end
|
276
325
|
|
326
|
+
def update_cluster_features
|
327
|
+
# Cluster supports features that are supported by all nodes
|
328
|
+
@features.update do |cluster_features|
|
329
|
+
node_featues = self.nodes.map(&:features)
|
330
|
+
cluster_features.replace(node_featues.reduce(&:intersection))
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def notify_cluster_config_changed
|
335
|
+
listeners = @cluster_config_change_listeners.get
|
336
|
+
listeners.each do |listener|
|
337
|
+
listener.send(:cluster_config_changed, self)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
277
341
|
def set_partitions(part_map)
|
278
342
|
@mutex.synchronize do
|
279
343
|
@partition_write_map = part_map
|
@@ -22,7 +22,7 @@ module Aerospike
|
|
22
22
|
|
23
23
|
class Node
|
24
24
|
|
25
|
-
attr_reader :reference_count, :responded, :name
|
25
|
+
attr_reader :reference_count, :responded, :name, :features
|
26
26
|
|
27
27
|
PARTITIONS = 4096
|
28
28
|
FULL_HEALTH = 100
|
@@ -34,6 +34,7 @@ module Aerospike
|
|
34
34
|
@aliases = Atomic.new(nv.aliases)
|
35
35
|
@host = nv.host
|
36
36
|
@use_new_info = Atomic.new(nv.use_new_info)
|
37
|
+
@features = nv.features
|
37
38
|
|
38
39
|
# Assign host to first IP alias because the server identifies nodes
|
39
40
|
# by IP address (not hostname).
|
@@ -168,7 +169,10 @@ module Aerospike
|
|
168
169
|
close_connections
|
169
170
|
end
|
170
171
|
|
171
|
-
|
172
|
+
def supports_feature?(feature)
|
173
|
+
@features.include?(feature.to_s)
|
174
|
+
end
|
175
|
+
|
172
176
|
def to_s
|
173
177
|
"#{@name}:#{@host}"
|
174
178
|
end
|
@@ -20,11 +20,12 @@ module Aerospike
|
|
20
20
|
|
21
21
|
class NodeValidator # :nodoc:
|
22
22
|
|
23
|
-
attr_reader :host, :aliases, :name, :use_new_info
|
23
|
+
attr_reader :host, :aliases, :name, :use_new_info, :features
|
24
24
|
|
25
25
|
def initialize(cluster, host, timeout)
|
26
26
|
@cluster = cluster
|
27
27
|
@use_new_info = true
|
28
|
+
@features = Set.new
|
28
29
|
@host = host
|
29
30
|
|
30
31
|
set_aliases(host)
|
@@ -70,10 +71,15 @@ module Aerospike
|
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
73
|
-
info_map= Info.request(conn, 'node', 'build')
|
74
|
+
info_map = Info.request(conn, 'node', 'build', 'features')
|
74
75
|
if node_name = info_map['node']
|
75
76
|
@name = node_name
|
76
77
|
|
78
|
+
# Set features
|
79
|
+
if features = info_map['features']
|
80
|
+
@features = features.split(';').to_set
|
81
|
+
end
|
82
|
+
|
77
83
|
# Check new info protocol support for >= 2.6.6 build
|
78
84
|
if build_version = info_map['build']
|
79
85
|
v1, v2, v3 = parse_version_string(build_version)
|
@@ -81,6 +81,12 @@ module Aerospike
|
|
81
81
|
self
|
82
82
|
end
|
83
83
|
|
84
|
+
# List of all bins that this command will write to - sub-classes should
|
85
|
+
# overrite this as appropriate.
|
86
|
+
def write_bins
|
87
|
+
[]
|
88
|
+
end
|
89
|
+
|
84
90
|
# Writes the command for write operations
|
85
91
|
def set_write(policy, operation, key, bins)
|
86
92
|
begin_cmd
|
@@ -447,7 +453,13 @@ module Aerospike
|
|
447
453
|
begin
|
448
454
|
parse_result
|
449
455
|
rescue => e
|
450
|
-
|
456
|
+
case e
|
457
|
+
# do not log the following exceptions
|
458
|
+
when Aerospike::Exceptions::ScanTerminated
|
459
|
+
when Aerospike::Exceptions::QueryTerminated
|
460
|
+
else
|
461
|
+
Aerospike.logger.error(e)
|
462
|
+
end
|
451
463
|
|
452
464
|
# close the connection
|
453
465
|
# cancelling/closing the batch/multi commands will return an error, which will
|
@@ -19,12 +19,15 @@ module Aerospike
|
|
19
19
|
# Pre-defined user roles.
|
20
20
|
module Role
|
21
21
|
|
22
|
-
# Manage users their roles.
|
22
|
+
# Manage users and their roles.
|
23
23
|
USER_ADMIN = 'user-admin'
|
24
24
|
|
25
|
-
# Manage indicies, user
|
25
|
+
# Manage indicies, user-defined functions and server configuration.
|
26
26
|
SYS_ADMIN = 'sys-admin'
|
27
27
|
|
28
|
+
# Allow read, write and UDF transactions with the database.
|
29
|
+
READ_WRITE_UDF = "read-write-udf"
|
30
|
+
|
28
31
|
# Allow read and write transactions with the database.
|
29
32
|
READ_WRITE = 'read-write'
|
30
33
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2015 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
|
+
class UnsupportedParticleTypeValidator
|
19
|
+
|
20
|
+
def initialize(*particle_types)
|
21
|
+
@unsupported_types = particle_types.to_set
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(*commands)
|
25
|
+
used = commands.flat_map(&:write_bins).map(&:type)
|
26
|
+
unsupported = @unsupported_types.intersection(used)
|
27
|
+
unless unsupported.empty?
|
28
|
+
fail Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Particle type(s) not supported by cluster: #{@unsupported_types.to_a}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end # class
|
33
|
+
|
34
|
+
end # module
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2015 Aerospike, Inc.
|
3
|
+
#
|
4
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
5
|
+
# license agreements.
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
8
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
9
|
+
# the License at http:#www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations under
|
15
|
+
# the License.
|
16
|
+
|
17
|
+
require "json"
|
18
|
+
|
19
|
+
module Aerospike
|
20
|
+
|
21
|
+
##
|
22
|
+
# Wrapper for GeoJSON data.
|
23
|
+
# GeoJSON data needs to be wrapped to allow the client to distinguish
|
24
|
+
# geospatial data from string (or hash) data. Geospatial data from a record's
|
25
|
+
# bin will be returned as an instance of this class.
|
26
|
+
# The wrapper accepts GeoJSON data either as a String or a Hash.
|
27
|
+
|
28
|
+
class GeoJSON
|
29
|
+
|
30
|
+
def initialize(data)
|
31
|
+
self.json_data =
|
32
|
+
case data
|
33
|
+
when String
|
34
|
+
data
|
35
|
+
else
|
36
|
+
data.to_json
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_json
|
41
|
+
json_data
|
42
|
+
end
|
43
|
+
alias_method :to_s, :to_json
|
44
|
+
|
45
|
+
def to_hash
|
46
|
+
JSON.parse(json_data)
|
47
|
+
end
|
48
|
+
alias_method :to_h, :to_hash
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
return false unless other.class == self.class
|
52
|
+
other.to_json == self.to_json
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
attr_accessor :json_data
|
58
|
+
|
59
|
+
end # class
|
60
|
+
|
61
|
+
end # module
|
data/lib/aerospike/operation.rb
CHANGED
@@ -19,7 +19,7 @@ module Aerospike
|
|
19
19
|
class ClientPolicy
|
20
20
|
|
21
21
|
attr_accessor :user, :password
|
22
|
-
attr_accessor :timeout, :connection_queue_size, :fail_if_not_connected
|
22
|
+
attr_accessor :timeout, :connection_queue_size, :fail_if_not_connected, :tend_interval
|
23
23
|
|
24
24
|
def initialize(opt={})
|
25
25
|
# Initial host connection timeout in seconds. The timeout when opening a connection
|
@@ -30,7 +30,11 @@ module Aerospike
|
|
30
30
|
@connection_queue_size = opt[:connection_queue_size] || 64
|
31
31
|
|
32
32
|
# Throw exception if host connection fails during add_host.
|
33
|
-
@fail_if_not_connected = opt[:fail_if_not_connected]
|
33
|
+
@fail_if_not_connected = opt.has_key?(:fail_if_not_connected) ? opt[:fail_if_not_connected] : true
|
34
|
+
|
35
|
+
# Tend interval in milliseconds; determines the interval at
|
36
|
+
# which the client checks for cluster state changes. Minimum interval is 10ms.
|
37
|
+
self.tend_interval = opt[:tend_interval] || 1000 # 1 second
|
34
38
|
|
35
39
|
# user name
|
36
40
|
@user = opt[:user]
|
@@ -43,6 +47,14 @@ module Aerospike
|
|
43
47
|
(@user && @user != '') || (@password && @password != '')
|
44
48
|
end
|
45
49
|
|
50
|
+
def tend_interval=(interval)
|
51
|
+
if interval < 10
|
52
|
+
Aerospike.logger.warn("Minimum tend interval is 10 milliseconds (client policy: #{interval}).")
|
53
|
+
interval = 10
|
54
|
+
end
|
55
|
+
@tend_interval = interval
|
56
|
+
end
|
57
|
+
|
46
58
|
end # class
|
47
59
|
|
48
60
|
end # module
|
@@ -26,6 +26,26 @@ module Aerospike
|
|
26
26
|
Filter.new(bin_name, from, to)
|
27
27
|
end
|
28
28
|
|
29
|
+
def self.geoWithinGeoJSONRegion(bin_name, region)
|
30
|
+
region = region.to_json
|
31
|
+
Filter.new(bin_name, region, region, ParticleType::GEOJSON)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.geoWithinRadius(bin_name, lon, lat, radius_meter)
|
35
|
+
region = GeoJSON.new({type: "AeroCircle", coordinates: [[lon, lat], radius_meter]})
|
36
|
+
geoWithinGeoJSONRegion(bin_name, region)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.geoContainsGeoJSONPoint(bin_name, point)
|
40
|
+
point = point.to_json
|
41
|
+
Filter.new(bin_name, point, point, ParticleType::GEOJSON)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.geoContainsPoint(bin_name, lon, lat)
|
45
|
+
point = GeoJSON.new({type: "Point", coordinates: [lon, lat]})
|
46
|
+
geoContainsGeoJSONPoint(bin_name, point)
|
47
|
+
end
|
48
|
+
|
29
49
|
def estimate_size
|
30
50
|
return @name.bytesize + @begin.estimate_size + @end.estimate_size + 10
|
31
51
|
end
|
@@ -37,7 +57,7 @@ module Aerospike
|
|
37
57
|
offset += len + 1
|
38
58
|
|
39
59
|
# Write particle type.
|
40
|
-
buf.write_byte(@
|
60
|
+
buf.write_byte(@val_type, offset)
|
41
61
|
offset+=1
|
42
62
|
|
43
63
|
# Write filter begin.
|
@@ -63,10 +83,14 @@ module Aerospike
|
|
63
83
|
|
64
84
|
private
|
65
85
|
|
66
|
-
def initialize(bin_name, begin_value, end_value)
|
86
|
+
def initialize(bin_name, begin_value, end_value, val_type = nil)
|
67
87
|
@name = bin_name
|
68
88
|
@begin = Aerospike::Value.of(begin_value)
|
69
89
|
@end = Aerospike::Value.of(end_value)
|
90
|
+
|
91
|
+
# The type of the filter values can usually be inferred automatically;
|
92
|
+
# but in certain cases caller can override the type.
|
93
|
+
@val_type = val_type || @begin.type
|
70
94
|
end
|
71
95
|
|
72
96
|
end # class
|
@@ -115,7 +115,7 @@ module Aerospike
|
|
115
115
|
|
116
116
|
private
|
117
117
|
|
118
|
-
SCAN_TERMINATED_EXCEPTION = Aerospike::Exceptions::
|
119
|
-
QUERY_TERMINATED_EXCEPTION = Aerospike::Exceptions::
|
118
|
+
SCAN_TERMINATED_EXCEPTION = Aerospike::Exceptions::ScanTerminated.new()
|
119
|
+
QUERY_TERMINATED_EXCEPTION = Aerospike::Exceptions::QueryTerminated.new()
|
120
120
|
|
121
121
|
end
|
@@ -39,6 +39,9 @@ module Aerospike
|
|
39
39
|
# if there is no recordset defined, it means this is an Execute UDF On Query command
|
40
40
|
# return successfully
|
41
41
|
if (@recordset == nil) && (result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR)
|
42
|
+
# consume the rest of the input buffer from the socket
|
43
|
+
read_bytes(receive_size - data_offset) if @data_offset < receive_size
|
44
|
+
|
42
45
|
return nil
|
43
46
|
end
|
44
47
|
raise Aerospike::Exceptions::Aerospike.new(result_code)
|
@@ -34,6 +34,7 @@ module Aerospike
|
|
34
34
|
UINT32 = 'N'
|
35
35
|
INT64 = 'q>'
|
36
36
|
UINT64 = 'Q>'
|
37
|
+
DOUBLE = 'G'
|
37
38
|
|
38
39
|
DEFAULT_BUFFER_SIZE = 16 * 1024
|
39
40
|
MAX_BUFFER_SIZE = 10 * 1024 * 1024
|
@@ -104,6 +105,11 @@ module Aerospike
|
|
104
105
|
8
|
105
106
|
end
|
106
107
|
|
108
|
+
def write_double(f, offset)
|
109
|
+
@buf[offset, 8] = [f].pack(DOUBLE)
|
110
|
+
8
|
111
|
+
end
|
112
|
+
|
107
113
|
def read(offset, len=nil)
|
108
114
|
start = offset
|
109
115
|
|
@@ -140,6 +146,11 @@ module Aerospike
|
|
140
146
|
val
|
141
147
|
end
|
142
148
|
|
149
|
+
def read_double(offset)
|
150
|
+
vals = @buf[offset..offset+7]
|
151
|
+
vals.unpack(DOUBLE)[0]
|
152
|
+
end
|
153
|
+
|
143
154
|
def to_s
|
144
155
|
@buf[0..@slice_end-1]
|
145
156
|
end
|
@@ -20,7 +20,7 @@ module Aerospike
|
|
20
20
|
# Server particle types. Unsupported types are commented out.
|
21
21
|
NULL = 0
|
22
22
|
INTEGER = 1
|
23
|
-
|
23
|
+
DOUBLE = 2
|
24
24
|
STRING = 3
|
25
25
|
BLOB = 4
|
26
26
|
#TIMESTAMP = 5
|
@@ -39,6 +39,7 @@ module Aerospike
|
|
39
39
|
#LUA_BLOB = 18
|
40
40
|
MAP = 19
|
41
41
|
LIST = 20
|
42
|
+
GEOJSON = 23
|
42
43
|
|
43
44
|
end # module
|
44
45
|
|
@@ -51,6 +51,8 @@ module Aerospike
|
|
51
51
|
# big nums > 2**63 are not supported
|
52
52
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported.")
|
53
53
|
end
|
54
|
+
when Float
|
55
|
+
res = FloatValue.new(value)
|
54
56
|
when String
|
55
57
|
res = StringValue.new(value)
|
56
58
|
when Symbol
|
@@ -61,6 +63,8 @@ module Aerospike
|
|
61
63
|
res = MapValue.new(value)
|
62
64
|
when Array
|
63
65
|
res = ListValue.new(value)
|
66
|
+
when GeoJSON
|
67
|
+
res = GeoJSONValue.new(value)
|
64
68
|
else
|
65
69
|
# throw an exception for anything that is not supported.
|
66
70
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported.")
|
@@ -234,6 +238,49 @@ module Aerospike
|
|
234
238
|
|
235
239
|
end # IntegerValue
|
236
240
|
|
241
|
+
#######################################
|
242
|
+
|
243
|
+
# Float value.
|
244
|
+
class FloatValue < Value #:nodoc:
|
245
|
+
|
246
|
+
def initialize(val)
|
247
|
+
@value = val || 0.0
|
248
|
+
self
|
249
|
+
end
|
250
|
+
|
251
|
+
def estimate_size
|
252
|
+
8
|
253
|
+
end
|
254
|
+
|
255
|
+
def write(buffer, offset)
|
256
|
+
buffer.write_double(@value, offset)
|
257
|
+
8
|
258
|
+
end
|
259
|
+
|
260
|
+
def pack(packer)
|
261
|
+
packer.write(@value)
|
262
|
+
end
|
263
|
+
|
264
|
+
def type
|
265
|
+
Aerospike::ParticleType::DOUBLE
|
266
|
+
end
|
267
|
+
|
268
|
+
def get
|
269
|
+
@value
|
270
|
+
end
|
271
|
+
|
272
|
+
def to_bytes
|
273
|
+
[@value].pack('G')
|
274
|
+
end
|
275
|
+
|
276
|
+
def to_s
|
277
|
+
@value.to_s
|
278
|
+
end
|
279
|
+
|
280
|
+
end # FloatValue
|
281
|
+
|
282
|
+
#######################################
|
283
|
+
|
237
284
|
# List value.
|
238
285
|
# Supported by Aerospike 3 servers only.
|
239
286
|
class ListValue < Value #:nodoc:
|
@@ -335,6 +382,51 @@ module Aerospike
|
|
335
382
|
|
336
383
|
end
|
337
384
|
|
385
|
+
# #######################################/
|
386
|
+
|
387
|
+
# GeoJSON value.
|
388
|
+
# Supported by Aerospike server version 3.7 and later.
|
389
|
+
class GeoJSONValue < Value #:nodoc:
|
390
|
+
|
391
|
+
def initialize(json)
|
392
|
+
@json = json
|
393
|
+
@bytes = json.to_json
|
394
|
+
self
|
395
|
+
end
|
396
|
+
|
397
|
+
def estimate_size
|
398
|
+
# flags + ncells + jsonstr
|
399
|
+
1 + 2 + @bytes.bytesize
|
400
|
+
end
|
401
|
+
|
402
|
+
def write(buffer, offset)
|
403
|
+
buffer.write_byte(0, offset) # flags
|
404
|
+
buffer.write_uint16(0, offset + 1) # ncells
|
405
|
+
return 1 + 2 + buffer.write_binary(@bytes, offset + 3) # JSON string
|
406
|
+
end
|
407
|
+
|
408
|
+
def pack(packer)
|
409
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR, "Can't pack GeoJSON")
|
410
|
+
end
|
411
|
+
|
412
|
+
def type
|
413
|
+
Aerospike::ParticleType::GEOJSON
|
414
|
+
end
|
415
|
+
|
416
|
+
def get
|
417
|
+
@json
|
418
|
+
end
|
419
|
+
|
420
|
+
def to_bytes
|
421
|
+
@bytes
|
422
|
+
end
|
423
|
+
|
424
|
+
def to_s
|
425
|
+
@json
|
426
|
+
end
|
427
|
+
|
428
|
+
end
|
429
|
+
|
338
430
|
#######################################
|
339
431
|
|
340
432
|
protected
|
@@ -371,6 +463,9 @@ module Aerospike
|
|
371
463
|
when Aerospike::ParticleType::INTEGER
|
372
464
|
buf.read_int64(offset)
|
373
465
|
|
466
|
+
when Aerospike::ParticleType::DOUBLE
|
467
|
+
buf.read_double(offset)
|
468
|
+
|
374
469
|
when Aerospike::ParticleType::BLOB
|
375
470
|
buf.read(offset,length)
|
376
471
|
|
@@ -380,6 +475,12 @@ module Aerospike
|
|
380
475
|
when Aerospike::ParticleType::MAP
|
381
476
|
normalize_strings_in_map(MessagePack.unpack(buf.read(offset, length)))
|
382
477
|
|
478
|
+
when Aerospike::ParticleType::GEOJSON
|
479
|
+
# ignore the flags for now
|
480
|
+
ncells = buf.read_int16(offset + 1)
|
481
|
+
hdrsz = 1 + 2 + (ncells * 8)
|
482
|
+
Aerospike::GeoJSON.new(buf.read(offset + hdrsz, length - hdrsz))
|
483
|
+
|
383
484
|
else
|
384
485
|
nil
|
385
486
|
end
|
data/lib/aerospike/version.rb
CHANGED
metadata
CHANGED
@@ -1,46 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aerospike
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.11
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Khosrow Afroozeh
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2015-
|
11
|
+
date: 2015-12-07 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: msgpack
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0.5'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0.5'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: bcrypt
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '3.1'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '3.1'
|
46
41
|
description: Official Aerospike Client for ruby. Access your Aerospike cluster with
|
@@ -51,6 +46,10 @@ executables: []
|
|
51
46
|
extensions: []
|
52
47
|
extra_rdoc_files: []
|
53
48
|
files:
|
49
|
+
- CHANGELOG.md
|
50
|
+
- LICENSE
|
51
|
+
- README.md
|
52
|
+
- lib/aerospike.rb
|
54
53
|
- lib/aerospike/aerospike_exception.rb
|
55
54
|
- lib/aerospike/atomic/atomic.rb
|
56
55
|
- lib/aerospike/bin.rb
|
@@ -79,7 +78,9 @@ files:
|
|
79
78
|
- lib/aerospike/command/roles.rb
|
80
79
|
- lib/aerospike/command/single_command.rb
|
81
80
|
- lib/aerospike/command/touch_command.rb
|
81
|
+
- lib/aerospike/command/unsupported_particle_type_validator.rb
|
82
82
|
- lib/aerospike/command/write_command.rb
|
83
|
+
- lib/aerospike/geo_json.rb
|
83
84
|
- lib/aerospike/host.rb
|
84
85
|
- lib/aerospike/info.rb
|
85
86
|
- lib/aerospike/key.rb
|
@@ -124,35 +125,30 @@ files:
|
|
124
125
|
- lib/aerospike/value/particle_type.rb
|
125
126
|
- lib/aerospike/value/value.rb
|
126
127
|
- lib/aerospike/version.rb
|
127
|
-
- lib/aerospike.rb
|
128
|
-
- CHANGELOG.md
|
129
|
-
- LICENSE
|
130
|
-
- README.md
|
131
128
|
homepage: http://www.github.com/aerospike/aerospike-client-ruby
|
132
129
|
licenses:
|
133
130
|
- Apache2.0
|
134
|
-
|
135
|
-
|
136
|
-
|
131
|
+
metadata: {}
|
132
|
+
post_install_message: |-
|
133
|
+
Thank you for using Aerospike!
|
134
|
+
You can report issues on github.com/aerospike/aerospike-client-ruby
|
137
135
|
rdoc_options: []
|
138
136
|
require_paths:
|
139
137
|
- lib
|
140
138
|
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
-
none: false
|
142
139
|
requirements:
|
143
|
-
- -
|
140
|
+
- - ">="
|
144
141
|
- !ruby/object:Gem::Version
|
145
142
|
version: 1.9.3
|
146
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
-
none: false
|
148
144
|
requirements:
|
149
|
-
- -
|
145
|
+
- - ">="
|
150
146
|
- !ruby/object:Gem::Version
|
151
147
|
version: '0'
|
152
148
|
requirements: []
|
153
149
|
rubyforge_project:
|
154
|
-
rubygems_version:
|
150
|
+
rubygems_version: 2.4.6
|
155
151
|
signing_key:
|
156
|
-
specification_version:
|
152
|
+
specification_version: 4
|
157
153
|
summary: An Aerospike driver for Ruby.
|
158
154
|
test_files: []
|