aerospike 1.0.10 → 1.0.11
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 +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: []
|