aerospike 0.1.3 → 0.1.5
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 +13 -0
- data/README.md +12 -5
- data/lib/aerospike.rb +12 -1
- data/lib/aerospike/atomic/atomic.rb +51 -0
- data/lib/aerospike/client.rb +172 -9
- data/lib/aerospike/cluster/cluster.rb +6 -6
- data/lib/aerospike/cluster/node.rb +3 -1
- data/lib/aerospike/command/batch_command.rb +70 -2
- data/lib/aerospike/command/batch_command_get.rb +0 -66
- data/lib/aerospike/command/command.rb +81 -8
- data/lib/aerospike/command/read_command.rb +2 -2
- data/lib/aerospike/command/single_command.rb +1 -1
- data/lib/aerospike/command/write_command.rb +1 -1
- data/lib/aerospike/info.rb +1 -2
- data/lib/aerospike/ldt/large_list.rb +1 -0
- data/lib/aerospike/ldt/large_map.rb +1 -0
- data/lib/aerospike/policy/batch_policy.rb +38 -0
- data/lib/aerospike/policy/query_policy.rb +33 -0
- data/lib/aerospike/policy/scan_policy.rb +41 -0
- data/lib/aerospike/query/filter.rb +66 -0
- data/lib/aerospike/query/query_command.rb +200 -0
- data/lib/aerospike/query/recordset.rb +121 -0
- data/lib/aerospike/query/scan_command.rb +42 -0
- data/lib/aerospike/query/statement.rb +70 -0
- data/lib/aerospike/query/stream_command.rb +68 -0
- data/lib/aerospike/task/task.rb +2 -1
- data/lib/aerospike/utils/epoc.rb +8 -1
- data/lib/aerospike/value/value.rb +1 -1
- data/lib/aerospike/version.rb +1 -1
- metadata +28 -24
@@ -14,7 +14,7 @@
|
|
14
14
|
# License for the specific language governing permissions and limitations under
|
15
15
|
# the License.
|
16
16
|
|
17
|
-
require 'atomic'
|
17
|
+
require 'aerospike/atomic/atomic'
|
18
18
|
|
19
19
|
module Aerospike
|
20
20
|
|
@@ -63,6 +63,8 @@ module Aerospike
|
|
63
63
|
begin
|
64
64
|
info_map = Info.request(conn, "node", "partition-generation", "services")
|
65
65
|
rescue => e
|
66
|
+
Aerospike.logger.error(e)
|
67
|
+
|
66
68
|
conn.close
|
67
69
|
decrease_health
|
68
70
|
|
@@ -31,7 +31,6 @@ module Aerospike
|
|
31
31
|
|
32
32
|
@valid = true
|
33
33
|
@mutex = Mutex.new
|
34
|
-
@records = Queue.new
|
35
34
|
|
36
35
|
self
|
37
36
|
end
|
@@ -79,13 +78,82 @@ module Aerospike
|
|
79
78
|
when Aerospike::FieldType::TABLE
|
80
79
|
set_name = @data_buffer.read(1, size).force_encoding('utf-8')
|
81
80
|
when Aerospike::FieldType::KEY
|
82
|
-
user_key =
|
81
|
+
user_key = Aerospike::bytes_to_key_value(@data_buffer.read(1).ord, @data_buffer, 2, size-1)
|
83
82
|
end
|
84
83
|
end
|
85
84
|
|
86
85
|
Aerospike::Key.new(namespace, set_name, user_key, digest)
|
87
86
|
end
|
88
87
|
|
88
|
+
# Parses the given byte buffer and populate the result object.
|
89
|
+
# Returns the number of bytes that were parsed from the given buffer.
|
90
|
+
def parse_record(key, op_count, generation, expiration)
|
91
|
+
bins = nil
|
92
|
+
duplicates = nil
|
93
|
+
|
94
|
+
for i in 0...op_count
|
95
|
+
raise Aerospike::Exceptions::QueryTerminated.new unless valid?
|
96
|
+
|
97
|
+
read_bytes(8)
|
98
|
+
|
99
|
+
op_size = @data_buffer.read_int32(0).ord
|
100
|
+
particle_type = @data_buffer.read(5).ord
|
101
|
+
version = @data_buffer.read(6).ord
|
102
|
+
name_size = @data_buffer.read(7).ord
|
103
|
+
|
104
|
+
read_bytes(name_size)
|
105
|
+
name = @data_buffer.read(0, name_size).force_encoding('utf-8')
|
106
|
+
|
107
|
+
particle_bytes_size = op_size - (4 + name_size)
|
108
|
+
read_bytes(particle_bytes_size)
|
109
|
+
value = Aerospike.bytes_to_particle(particle_type, @data_buffer, 0, particle_bytes_size)
|
110
|
+
|
111
|
+
# Currently, the batch command returns all the bins even if a subset of
|
112
|
+
# the bins are requested. We have to filter it on the client side.
|
113
|
+
# TODO: Filter batch bins on server!
|
114
|
+
# if !@bin_names || @bin_names.any?{|bn| bn == name}
|
115
|
+
# if !@bin_names || (@bin_names == []) || @bin_names.any?{|bn| bn == name}
|
116
|
+
if !@bin_names || (@bin_names.empty?) || @bin_names.any?{|bn| bn == name}
|
117
|
+
|
118
|
+
vmap = nil
|
119
|
+
|
120
|
+
if version > 0 || duplicates
|
121
|
+
unless duplicates
|
122
|
+
duplicates = []
|
123
|
+
duplicates << bins
|
124
|
+
bins = nil
|
125
|
+
|
126
|
+
for j in 0...version
|
127
|
+
duplicates << nil
|
128
|
+
end
|
129
|
+
else
|
130
|
+
for j in duplicates.length..version
|
131
|
+
duplicates << nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
vmap = duplicates[version]
|
136
|
+
unless vmap
|
137
|
+
vmap = {}
|
138
|
+
duplicates[version] = vmap
|
139
|
+
end
|
140
|
+
else
|
141
|
+
unless bins
|
142
|
+
bins = {}
|
143
|
+
end
|
144
|
+
vmap = bins
|
145
|
+
end
|
146
|
+
vmap[name] = value
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Remove nil duplicates just in case there were holes in the version number space.
|
151
|
+
# TODO: this seems to be a bad idea; O(n) algorithm after another O(n) algorithm
|
152
|
+
duplicates.compact! if duplicates
|
153
|
+
|
154
|
+
Record.new(@node, key, bins, duplicates, generation, expiration)
|
155
|
+
end
|
156
|
+
|
89
157
|
def read_bytes(length)
|
90
158
|
if length > @data_buffer.length
|
91
159
|
# Corrupted data streams can result in a huge length.
|
@@ -79,72 +79,6 @@ module Aerospike
|
|
79
79
|
true
|
80
80
|
end
|
81
81
|
|
82
|
-
# Parses the given byte buffer and populate the result object.
|
83
|
-
# Returns the number of bytes that were parsed from the given buffer.
|
84
|
-
def parse_record(key, op_count, generation, expiration)
|
85
|
-
bins = nil
|
86
|
-
duplicates = nil
|
87
|
-
|
88
|
-
for i in 0...op_count
|
89
|
-
raise Aerospike::Exceptions::QueryTerminated.new unless valid?
|
90
|
-
|
91
|
-
read_bytes(8)
|
92
|
-
|
93
|
-
op_size = @data_buffer.read_int32(0).ord
|
94
|
-
particle_type = @data_buffer.read(5).ord
|
95
|
-
version = @data_buffer.read(6).ord
|
96
|
-
name_size = @data_buffer.read(7).ord
|
97
|
-
|
98
|
-
read_bytes(name_size)
|
99
|
-
name = @data_buffer.read(0, name_size).force_encoding('utf-8')
|
100
|
-
|
101
|
-
particle_bytes_size = op_size - (4 + name_size)
|
102
|
-
read_bytes(particle_bytes_size)
|
103
|
-
value = Aerospike.bytes_to_particle(particle_type, @data_buffer, 0, particle_bytes_size)
|
104
|
-
|
105
|
-
# Currently, the batch command returns all the bins even if a subset of
|
106
|
-
# the bins are requested. We have to filter it on the client side.
|
107
|
-
# TODO: Filter batch bins on server!
|
108
|
-
if !@bin_names || @bin_names.any?{|bn| bn == name}
|
109
|
-
vmap = nil
|
110
|
-
|
111
|
-
if version > 0 || duplicates
|
112
|
-
unless duplicates
|
113
|
-
duplicates = []
|
114
|
-
duplicates << bins
|
115
|
-
bins = nil
|
116
|
-
|
117
|
-
for j in 0...version
|
118
|
-
duplicates << nil
|
119
|
-
end
|
120
|
-
else
|
121
|
-
for j in duplicates.length..version
|
122
|
-
duplicates << nil
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
vmap = duplicates[version]
|
127
|
-
unless vmap
|
128
|
-
vmap = {}
|
129
|
-
duplicates[version] = vmap
|
130
|
-
end
|
131
|
-
else
|
132
|
-
unless bins
|
133
|
-
bins = {}
|
134
|
-
end
|
135
|
-
vmap = bins
|
136
|
-
end
|
137
|
-
vmap[name] = value
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Remove nil duplicates just in case there were holes in the version number space.
|
142
|
-
# TODO: this seems to be a bad idea; O(n) algorithm after another O(n) algorithm
|
143
|
-
duplicates.compact! if duplicates
|
144
|
-
|
145
|
-
Record.new(@node, key, bins, duplicates, generation, expiration)
|
146
|
-
end
|
147
|
-
|
148
82
|
end # class
|
149
83
|
|
150
84
|
end # module
|
@@ -314,6 +314,75 @@ module Aerospike
|
|
314
314
|
end_cmd
|
315
315
|
end
|
316
316
|
|
317
|
+
def set_scan(policy, namespace, set_name, bin_names)
|
318
|
+
# Estimate buffer size
|
319
|
+
begin_cmd
|
320
|
+
field_count = 0
|
321
|
+
|
322
|
+
if namespace
|
323
|
+
@data_offset += namespace.bytesize + FIELD_HEADER_SIZE
|
324
|
+
field_count += 1
|
325
|
+
end
|
326
|
+
|
327
|
+
if set_name
|
328
|
+
@data_offset += set_name.bytesize + FIELD_HEADER_SIZE
|
329
|
+
field_count += 1
|
330
|
+
end
|
331
|
+
|
332
|
+
# Estimate scan options size.
|
333
|
+
@data_offset += 2 + FIELD_HEADER_SIZE
|
334
|
+
field_count += 1
|
335
|
+
|
336
|
+
if bin_names
|
337
|
+
bin_names.each do |bin_name|
|
338
|
+
estimate_operation_size_for_bin_name(bin_name)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
size_buffer
|
343
|
+
read_attr = INFO1_READ
|
344
|
+
|
345
|
+
if !policy.include_bin_data
|
346
|
+
read_attr |= INFO1_NOBINDATA
|
347
|
+
end
|
348
|
+
|
349
|
+
operation_count = 0
|
350
|
+
if bin_names
|
351
|
+
operation_count = bin_names.length
|
352
|
+
end
|
353
|
+
|
354
|
+
write_header(read_attr, 0, field_count, operation_count)
|
355
|
+
|
356
|
+
if namespace
|
357
|
+
write_field_string(namespace, Aerospike::FieldType::NAMESPACE)
|
358
|
+
end
|
359
|
+
|
360
|
+
if set_name
|
361
|
+
write_field_string(set_name, Aerospike::FieldType::TABLE)
|
362
|
+
end
|
363
|
+
|
364
|
+
write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
|
365
|
+
|
366
|
+
priority = policy.priority & 0xFF
|
367
|
+
priority <<= 4
|
368
|
+
if policy.fail_on_cluster_change
|
369
|
+
priority |= 0x08
|
370
|
+
end
|
371
|
+
|
372
|
+
@data_buffer.write_byte(priority, @data_offset)
|
373
|
+
@data_offset += 1
|
374
|
+
@data_buffer.write_byte(policy.scan_percent.to_i.ord, @data_offset)
|
375
|
+
@data_offset += 1
|
376
|
+
|
377
|
+
if bin_names
|
378
|
+
bin_names.each do |bin_name|
|
379
|
+
write_operation_for_bin_name(bin_name, Aerospike::Operation::READ)
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
end_cmd
|
384
|
+
end
|
385
|
+
|
317
386
|
def execute
|
318
387
|
iterations = 0
|
319
388
|
|
@@ -338,7 +407,7 @@ module Aerospike
|
|
338
407
|
# Socket connection error has occurred. Decrease health and retry.
|
339
408
|
@node.decrease_health
|
340
409
|
|
341
|
-
Aerospike.logger.
|
410
|
+
Aerospike.logger.error("Node #{@node.to_s}: #{e}")
|
342
411
|
next
|
343
412
|
end
|
344
413
|
|
@@ -350,6 +419,8 @@ module Aerospike
|
|
350
419
|
begin
|
351
420
|
write_buffer
|
352
421
|
rescue => e
|
422
|
+
Aerospike.logger.error(e)
|
423
|
+
|
353
424
|
# All runtime exceptions are considered fatal. Do not retry.
|
354
425
|
# Close socket to flush out possible garbage. Do not put back in pool.
|
355
426
|
@conn.close
|
@@ -367,7 +438,7 @@ module Aerospike
|
|
367
438
|
# Close socket to flush out possible garbage. Do not put back in pool.
|
368
439
|
@conn.close
|
369
440
|
|
370
|
-
Aerospike.logger.
|
441
|
+
Aerospike.logger.error("Node #{@node.to_s}: #{e}")
|
371
442
|
# IO error means connection to server @node is unhealthy.
|
372
443
|
# Reflect cmd status.
|
373
444
|
@node.decrease_health
|
@@ -378,6 +449,8 @@ module Aerospike
|
|
378
449
|
begin
|
379
450
|
parse_result
|
380
451
|
rescue => e
|
452
|
+
Aerospike.logger.error(e)
|
453
|
+
|
381
454
|
# close the connection
|
382
455
|
# cancelling/closing the batch/multi commands will return an error, which will
|
383
456
|
# close the connection to throw away its data and signal the server about the
|
@@ -411,16 +484,16 @@ module Aerospike
|
|
411
484
|
field_count = 0
|
412
485
|
|
413
486
|
if key.namespace
|
414
|
-
@data_offset += key.namespace.
|
487
|
+
@data_offset += key.namespace.bytesize + FIELD_HEADER_SIZE
|
415
488
|
field_count += 1
|
416
489
|
end
|
417
490
|
|
418
491
|
if key.set_name
|
419
|
-
@data_offset += key.set_name.
|
492
|
+
@data_offset += key.set_name.bytesize + FIELD_HEADER_SIZE
|
420
493
|
field_count += 1
|
421
494
|
end
|
422
495
|
|
423
|
-
@data_offset += key.digest.
|
496
|
+
@data_offset += key.digest.bytesize + FIELD_HEADER_SIZE
|
424
497
|
field_count += 1
|
425
498
|
|
426
499
|
return field_count
|
@@ -434,7 +507,7 @@ module Aerospike
|
|
434
507
|
end
|
435
508
|
|
436
509
|
def estimate_operation_size_for_bin(bin)
|
437
|
-
@data_offset += bin.name.
|
510
|
+
@data_offset += bin.name.bytesize + OPERATION_HEADER_SIZE
|
438
511
|
@data_offset += bin.value_object.estimate_size
|
439
512
|
end
|
440
513
|
|
@@ -442,7 +515,7 @@ module Aerospike
|
|
442
515
|
bin_len = 0
|
443
516
|
|
444
517
|
if operation.bin_name
|
445
|
-
bin_len = operation.bin_name.
|
518
|
+
bin_len = operation.bin_name.bytesize
|
446
519
|
end
|
447
520
|
|
448
521
|
@data_offset += bin_len + OPERATION_HEADER_SIZE
|
@@ -453,7 +526,7 @@ module Aerospike
|
|
453
526
|
end
|
454
527
|
|
455
528
|
def estimate_operation_size_for_bin_name(bin_name)
|
456
|
-
@data_offset += bin_name.
|
529
|
+
@data_offset += bin_name.bytesize + OPERATION_HEADER_SIZE
|
457
530
|
end
|
458
531
|
|
459
532
|
def estimate_operation_size
|
@@ -68,7 +68,7 @@ module Aerospike
|
|
68
68
|
begin
|
69
69
|
@conn.read(@data_buffer, receive_size)
|
70
70
|
rescue => e
|
71
|
-
Aerospike.logger.
|
71
|
+
Aerospike.logger.error("parse result error: #{e}")
|
72
72
|
raise e
|
73
73
|
end
|
74
74
|
|
@@ -82,7 +82,7 @@ module Aerospike
|
|
82
82
|
@record = parse_record(op_count, field_count, generation, expiration)
|
83
83
|
handle_udf_error(result_code)
|
84
84
|
rescue => e
|
85
|
-
Aerospike.logger.
|
85
|
+
Aerospike.logger.error("UDF execution error: #{e}")
|
86
86
|
raise e
|
87
87
|
end
|
88
88
|
|
data/lib/aerospike/info.rb
CHANGED
@@ -49,8 +49,6 @@ module Aerospike
|
|
49
49
|
begin
|
50
50
|
buf_length = send_command(conn, offset, buffer)
|
51
51
|
parse_multiple_response(buf_length, buffer)
|
52
|
-
rescue => e
|
53
|
-
Aerospike.logger.error("#{e}")
|
54
52
|
ensure
|
55
53
|
Buffer.put(buffer)
|
56
54
|
end
|
@@ -86,6 +84,7 @@ module Aerospike
|
|
86
84
|
conn.read(buffer, length)
|
87
85
|
return length
|
88
86
|
rescue => e
|
87
|
+
Aerospike.logger.error(e)
|
89
88
|
conn.close
|
90
89
|
raise e
|
91
90
|
end
|
@@ -70,6 +70,7 @@ module Aerospike
|
|
70
70
|
@client.execute_udf(@key, @PACKAGE_NAME, 'find', [@bin_name, value], @policy)
|
71
71
|
rescue Aerospike::Exceptions::Aerospike => e
|
72
72
|
unless e.result_code == Aerospike::ResultCode::UDF_BAD_RESPONSE && e.message.index("Item Not Found")
|
73
|
+
Aerospike.logger.error(e)
|
73
74
|
raise e
|
74
75
|
end
|
75
76
|
nil
|
@@ -54,6 +54,7 @@ module Aerospike
|
|
54
54
|
@client.execute_udf(@key, @PACKAGE_NAME, 'get', [@bin_name, name, @user_module], @policy)
|
55
55
|
rescue Aerospike::Exceptions::Aerospike => e
|
56
56
|
unless e.result_code == Aerospike::ResultCode::UDF_BAD_RESPONSE && e.message.index("Item Not Found")
|
57
|
+
Aerospike.logger.error(e)
|
57
58
|
raise e
|
58
59
|
end
|
59
60
|
nil
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014 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/policy'
|
17
|
+
|
18
|
+
module Aerospike
|
19
|
+
|
20
|
+
# Container object for batch policy command.
|
21
|
+
class BatchPolicy < Policy
|
22
|
+
|
23
|
+
attr_accessor :max_concurrent_nodes, :record_queue_size,
|
24
|
+
:wait_until_migrations_are_over
|
25
|
+
|
26
|
+
def initialize(max_concurrent_nodes=nil, record_queue_size=nil, wait_until_migrations_are_over=nil)
|
27
|
+
super()
|
28
|
+
|
29
|
+
@max_concurrent_nodes = max_concurrent_nodes || 0
|
30
|
+
@record_queue_size = record_queue_size || 5000
|
31
|
+
@wait_until_migrations_are_over = wait_until_migrations_are_over.nil? ? false : wait_until_migrations_are_over
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
end # class
|
37
|
+
|
38
|
+
end # module
|