aerospike 2.6.0 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +3 -1
- data/lib/aerospike.rb +9 -5
- data/lib/aerospike/client.rb +101 -83
- data/lib/aerospike/cluster.rb +11 -50
- data/lib/aerospike/cluster/create_connection.rb +1 -1
- data/lib/aerospike/cluster/find_nodes_to_remove.rb +66 -0
- data/lib/aerospike/cluster/partition.rb +5 -2
- data/lib/aerospike/command/batch_direct_command.rb +104 -0
- data/lib/aerospike/command/batch_direct_exists_command.rb +51 -0
- data/lib/aerospike/command/batch_direct_node.rb +40 -0
- data/lib/aerospike/command/batch_index_command.rb +119 -0
- data/lib/aerospike/command/batch_index_exists_command.rb +45 -0
- data/lib/aerospike/command/batch_index_node.rb +52 -0
- data/lib/aerospike/command/batch_item.rb +18 -47
- data/lib/aerospike/command/command.rb +6 -65
- data/lib/aerospike/command/field_type.rb +13 -10
- data/lib/aerospike/command/{batch_command.rb → multi_command.rb} +29 -9
- data/lib/aerospike/command/read_command.rb +4 -2
- data/lib/aerospike/command/single_command.rb +6 -9
- data/lib/aerospike/connection/create.rb +3 -3
- data/lib/aerospike/host/parse.rb +28 -2
- data/lib/aerospike/node.rb +6 -2
- data/lib/aerospike/node/refresh/friends.rb +1 -1
- data/lib/aerospike/node/refresh/peers.rb +1 -1
- data/lib/aerospike/node_validator.rb +3 -3
- data/lib/aerospike/peers.rb +4 -0
- data/lib/aerospike/peers/parse.rb +26 -6
- data/lib/aerospike/policy/batch_policy.rb +25 -15
- data/lib/aerospike/policy/client_policy.rb +2 -2
- data/lib/aerospike/policy/query_policy.rb +25 -12
- data/lib/aerospike/policy/scan_policy.rb +39 -16
- data/lib/aerospike/query/stream_command.rb +6 -5
- data/lib/aerospike/record.rb +4 -3
- data/lib/aerospike/socket/ssl.rb +13 -13
- data/lib/aerospike/socket/tcp.rb +8 -1
- data/lib/aerospike/utils/string_parser.rb +7 -3
- data/lib/aerospike/version.rb +1 -1
- metadata +11 -7
- data/lib/aerospike/command/batch_command_exists.rb +0 -93
- data/lib/aerospike/command/batch_command_get.rb +0 -84
- data/lib/aerospike/command/batch_node.rb +0 -82
data/lib/aerospike/cluster.rb
CHANGED
@@ -25,7 +25,7 @@ require 'aerospike/atomic/atomic'
|
|
25
25
|
module Aerospike
|
26
26
|
class Cluster
|
27
27
|
attr_reader :connection_timeout, :connection_queue_size, :user, :password
|
28
|
-
attr_reader :features, :
|
28
|
+
attr_reader :features, :tls_options
|
29
29
|
attr_reader :cluster_id, :aliases
|
30
30
|
attr_reader :cluster_name
|
31
31
|
|
@@ -36,7 +36,7 @@ module Aerospike
|
|
36
36
|
@connection_timeout = policy.timeout
|
37
37
|
@tend_interval = policy.tend_interval
|
38
38
|
@cluster_name = policy.cluster_name
|
39
|
-
@
|
39
|
+
@tls_options = policy.tls
|
40
40
|
|
41
41
|
@aliases = {}
|
42
42
|
@cluster_nodes = []
|
@@ -75,7 +75,7 @@ module Aerospike
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def tls_enabled?
|
78
|
-
!
|
78
|
+
!tls_options.nil? && tls_options[:enable] != false
|
79
79
|
end
|
80
80
|
|
81
81
|
def initialize_tls_host_names(hosts)
|
@@ -102,7 +102,9 @@ module Aerospike
|
|
102
102
|
(node_array.length > 0) && !@closed.value
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
105
|
+
def get_node_for_key(key)
|
106
|
+
partition = Partition.new_by_key(key)
|
107
|
+
|
106
108
|
# Must copy hashmap reference for copy on write semantics to work.
|
107
109
|
nmap = partitions
|
108
110
|
if node_array = nmap[partition.namespace]
|
@@ -268,6 +270,8 @@ module Aerospike
|
|
268
270
|
if peers.generation_changed?
|
269
271
|
# Refresh peers for all nodes that responded the first time even if only
|
270
272
|
# one node's peers changed.
|
273
|
+
peers.reset_refresh_count!
|
274
|
+
|
271
275
|
nodes.each do |node|
|
272
276
|
node.refresh_peers(peers)
|
273
277
|
end
|
@@ -371,7 +375,7 @@ module Aerospike
|
|
371
375
|
|
372
376
|
seed_array.each do |seed|
|
373
377
|
begin
|
374
|
-
seed_node_validator = NodeValidator.new(self, seed, @connection_timeout, @cluster_name,
|
378
|
+
seed_node_validator = NodeValidator.new(self, seed, @connection_timeout, @cluster_name, tls_options)
|
375
379
|
rescue => e
|
376
380
|
Aerospike.logger.error("Seed #{seed} failed: #{e}\n#{e.backtrace.join("\n")}")
|
377
381
|
next
|
@@ -384,7 +388,7 @@ module Aerospike
|
|
384
388
|
nv = seed_node_validator
|
385
389
|
else
|
386
390
|
begin
|
387
|
-
nv = NodeValidator.new(self, aliass, @connection_timeout, @cluster_name,
|
391
|
+
nv = NodeValidator.new(self, aliass, @connection_timeout, @cluster_name, tls_options)
|
388
392
|
rescue => e
|
389
393
|
Aerospike.logger.error("Seed #{seed} failed: #{e}")
|
390
394
|
next
|
@@ -427,50 +431,7 @@ module Aerospike
|
|
427
431
|
end
|
428
432
|
|
429
433
|
def find_nodes_to_remove(refresh_count)
|
430
|
-
|
431
|
-
|
432
|
-
remove_list = []
|
433
|
-
|
434
|
-
node_list.each do |node|
|
435
|
-
if !node.active?
|
436
|
-
# Inactive nodes must be removed.
|
437
|
-
remove_list << node
|
438
|
-
next
|
439
|
-
end
|
440
|
-
|
441
|
-
case node_list.length
|
442
|
-
when 1
|
443
|
-
# Single node clusters rely solely on node health.
|
444
|
-
remove_list << node if node.unhealthy?
|
445
|
-
|
446
|
-
when 2
|
447
|
-
# Two node clusters require at least one successful refresh before removing.
|
448
|
-
if refresh_count == 2 && node.reference_count.value == 0 && !node.responded?
|
449
|
-
# Node is not referenced nor did it respond.
|
450
|
-
remove_list << node
|
451
|
-
end
|
452
|
-
|
453
|
-
else
|
454
|
-
# Multi-node clusters require two successful node refreshes before removing.
|
455
|
-
if refresh_count >= 2 && node.reference_count.value == 0
|
456
|
-
# Node is not referenced by other nodes.
|
457
|
-
# Check if node responded to info request.
|
458
|
-
if node.responded?
|
459
|
-
# Node is alive, but not referenced by other nodes. Check if mapped.
|
460
|
-
unless find_node_in_partition_map(node)
|
461
|
-
# Node doesn't have any partitions mapped to it.
|
462
|
-
# There is not point in keeping it in the cluster.
|
463
|
-
remove_list << node
|
464
|
-
end
|
465
|
-
else
|
466
|
-
# Node not responding. Remove it.
|
467
|
-
remove_list << node
|
468
|
-
end
|
469
|
-
end
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
remove_list
|
434
|
+
FindNodesToRemove.(self, refresh_count)
|
474
435
|
end
|
475
436
|
|
476
437
|
def find_node_in_partition_map(filter)
|
@@ -28,7 +28,7 @@ module Aerospike
|
|
28
28
|
host.port,
|
29
29
|
tls_name: host.tls_name,
|
30
30
|
timeout: cluster.connection_timeout,
|
31
|
-
|
31
|
+
tls_options: cluster.tls_options
|
32
32
|
).tap do |conn|
|
33
33
|
if cluster.credentials_given?
|
34
34
|
# Authenticate will raise and close connection if invalid credentials
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Cluster
|
22
|
+
# Calculates which nodes that should be removed from the cluster
|
23
|
+
module FindNodesToRemove
|
24
|
+
class << self
|
25
|
+
def call(cluster, refresh_count)
|
26
|
+
node_list = cluster.nodes
|
27
|
+
|
28
|
+
remove_list = []
|
29
|
+
|
30
|
+
node_list.each do |node|
|
31
|
+
unless node.active?
|
32
|
+
# Inactive nodes must be removed.
|
33
|
+
remove_list << node
|
34
|
+
next
|
35
|
+
end
|
36
|
+
|
37
|
+
if refresh_count.zero? && node.failed?(5) # 5 or more failures counts as failed
|
38
|
+
# All node info requests failed and this node had 5 consecutive failures.
|
39
|
+
# Remove node. If no nodes are left, seeds will be tried in next cluster
|
40
|
+
# tend iteration.
|
41
|
+
remove_list << node
|
42
|
+
next
|
43
|
+
end
|
44
|
+
|
45
|
+
if node_list.size > 1 && refresh_count >= 1 && !node.referenced?
|
46
|
+
# Node is not referenced by other nodes.
|
47
|
+
# Check if node responded to info request.
|
48
|
+
if node.failed?
|
49
|
+
remove_list << node
|
50
|
+
else
|
51
|
+
# Node is alive, but not referenced by other nodes. Check if mapped.
|
52
|
+
unless cluster.find_node_in_partition_map(node)
|
53
|
+
# Node doesn't have any partitions mapped to it.
|
54
|
+
# There is no point in keeping it in the cluster.
|
55
|
+
remove_list << node
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
remove_list
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# Copyright 2014-2017 Aerospike, Inc.
|
3
4
|
#
|
4
5
|
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
@@ -19,6 +20,8 @@ module Aerospike
|
|
19
20
|
private
|
20
21
|
|
21
22
|
class Partition # :nodoc:
|
23
|
+
UNPACK_FORMAT = 'l<'
|
24
|
+
|
22
25
|
attr_reader :namespace, :partition_id
|
23
26
|
|
24
27
|
def initialize(namespace, partition_id)
|
@@ -31,7 +34,7 @@ module Aerospike
|
|
31
34
|
def self.new_by_key(key)
|
32
35
|
Partition.new(
|
33
36
|
key.namespace,
|
34
|
-
(key.digest[0..3].unpack(
|
37
|
+
(key.digest[0..3].unpack(UNPACK_FORMAT)[0] & 0xFFFF) % Node::PARTITIONS
|
35
38
|
)
|
36
39
|
end
|
37
40
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# Copyright 2014-2018 Aerospike, Inc.
|
2
|
+
#
|
3
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
|
+
# license agreements.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
require 'aerospike/command/multi_command'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
class BatchDirectCommand < MultiCommand #:nodoc:
|
23
|
+
|
24
|
+
attr_accessor :batch
|
25
|
+
attr_accessor :policy
|
26
|
+
attr_accessor :key_map
|
27
|
+
attr_accessor :bin_names
|
28
|
+
attr_accessor :results
|
29
|
+
attr_accessor :read_attr
|
30
|
+
|
31
|
+
def initialize(node, batch, policy, key_map, bin_names, results, read_attr)
|
32
|
+
super(node)
|
33
|
+
|
34
|
+
@batch = batch
|
35
|
+
@policy = policy
|
36
|
+
@key_map = key_map
|
37
|
+
@bin_names = bin_names
|
38
|
+
@results = results
|
39
|
+
@read_attr = read_attr
|
40
|
+
end
|
41
|
+
|
42
|
+
def write_buffer
|
43
|
+
# Estimate buffer size
|
44
|
+
begin_cmd
|
45
|
+
byte_size = batch.keys.length * DIGEST_SIZE
|
46
|
+
|
47
|
+
@data_offset += batch.namespace.bytesize +
|
48
|
+
FIELD_HEADER_SIZE + byte_size + FIELD_HEADER_SIZE
|
49
|
+
|
50
|
+
if bin_names
|
51
|
+
bin_names.each do |bin_name|
|
52
|
+
estimate_operation_size_for_bin_name(bin_name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
size_buffer
|
57
|
+
|
58
|
+
operation_count = 0
|
59
|
+
if bin_names
|
60
|
+
operation_count = bin_names.length
|
61
|
+
end
|
62
|
+
|
63
|
+
write_header(policy, read_attr, 0, 2, operation_count)
|
64
|
+
write_field_string(batch.namespace, Aerospike::FieldType::NAMESPACE)
|
65
|
+
write_field_header(byte_size, Aerospike::FieldType::DIGEST_RIPE_ARRAY)
|
66
|
+
|
67
|
+
batch.keys.each do |key|
|
68
|
+
@data_offset += @data_buffer.write_binary(key.digest, @data_offset)
|
69
|
+
end
|
70
|
+
|
71
|
+
if bin_names
|
72
|
+
bin_names.each do |bin_name|
|
73
|
+
write_operation_for_bin_name(bin_name, Aerospike::Operation::READ)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end_cmd
|
78
|
+
end
|
79
|
+
|
80
|
+
# Parse all results in the batch. Add records to shared list.
|
81
|
+
# If the record was not found, the bins will be nil.
|
82
|
+
def parse_row(result_code)
|
83
|
+
generation = @data_buffer.read_int32(6)
|
84
|
+
expiration = @data_buffer.read_int32(10)
|
85
|
+
field_count = @data_buffer.read_int16(18)
|
86
|
+
op_count = @data_buffer.read_int16(20)
|
87
|
+
|
88
|
+
key = parse_key(field_count)
|
89
|
+
|
90
|
+
item = key_map[key.digest]
|
91
|
+
if item
|
92
|
+
if result_code == 0
|
93
|
+
index = item.index
|
94
|
+
key = item.key
|
95
|
+
results[index] = parse_record(key, op_count, generation, expiration)
|
96
|
+
end
|
97
|
+
else
|
98
|
+
Aerospike.logger.warn("Unexpected batch key returned: #{key}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end # class
|
103
|
+
|
104
|
+
end # module
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# Copyright 2014-2018 Aerospike, Inc.
|
2
|
+
#
|
3
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
|
+
# license agreements.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
require 'aerospike/command/batch_direct_command'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
class BatchDirectExistsCommand < BatchDirectCommand #:nodoc:
|
23
|
+
|
24
|
+
def initialize(node, batch, policy, key_map, results)
|
25
|
+
super(node, batch, policy, key_map, nil, results, INFO1_READ | INFO1_NOBINDATA)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Parse all results in the batch. Add records to shared list.
|
29
|
+
# If the record was not found, the bins will be nil.
|
30
|
+
def parse_row(result_code)
|
31
|
+
field_count = @data_buffer.read_int16(18)
|
32
|
+
op_count = @data_buffer.read_int16(20)
|
33
|
+
|
34
|
+
if op_count > 0
|
35
|
+
raise Aerospike::Exceptions::Parse.new('Received bins that were not requested!')
|
36
|
+
end
|
37
|
+
|
38
|
+
key = parse_key(field_count)
|
39
|
+
item = key_map[key.digest]
|
40
|
+
|
41
|
+
if item
|
42
|
+
index = item.index
|
43
|
+
results[index] = (result_code == 0)
|
44
|
+
else
|
45
|
+
Aerospike::logger.debug("Unexpected batch key returned: #{key.namespace}, #{key.digest}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end # class
|
50
|
+
|
51
|
+
end # module
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright 2014-2018 Aerospike, Inc.
|
2
|
+
#
|
3
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
|
+
# license agreements.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
module Aerospike
|
19
|
+
|
20
|
+
BatchNamespace = Struct.new :namespace, :keys
|
21
|
+
|
22
|
+
class BatchDirectNode #:nodoc:
|
23
|
+
|
24
|
+
attr_accessor :node
|
25
|
+
attr_accessor :batch_namespaces
|
26
|
+
|
27
|
+
def self.generate_list(cluster, keys)
|
28
|
+
keys.group_by { |key| cluster.get_node_for_key(key) }
|
29
|
+
.map { |node, keys_for_node| BatchDirectNode.new(node, keys_for_node) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(node, keys)
|
33
|
+
@node = node
|
34
|
+
@batch_namespaces = keys.group_by(&:namespace)
|
35
|
+
.map { |ns, keys_for_ns| BatchNamespace.new(ns, keys_for_ns) }
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# Copyright 2018 Aerospike, Inc.
|
2
|
+
#
|
3
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
4
|
+
# license agreements.
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
7
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
8
|
+
# the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
14
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
15
|
+
# License for the specific language governing permissions and limitations under
|
16
|
+
# the License.
|
17
|
+
|
18
|
+
require 'aerospike/command/multi_command'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
class BatchIndexCommand < MultiCommand #:nodoc:
|
23
|
+
|
24
|
+
attr_accessor :batch
|
25
|
+
attr_accessor :policy
|
26
|
+
attr_accessor :bin_names
|
27
|
+
attr_accessor :results
|
28
|
+
attr_accessor :read_attr
|
29
|
+
|
30
|
+
def initialize(node, batch, policy, bin_names, results, read_attr)
|
31
|
+
super(node)
|
32
|
+
@batch = batch
|
33
|
+
@policy = policy
|
34
|
+
@bin_names = bin_names
|
35
|
+
@results = results
|
36
|
+
@read_attr = read_attr
|
37
|
+
end
|
38
|
+
|
39
|
+
def write_buffer
|
40
|
+
bin_name_size = 0
|
41
|
+
operation_count = 0
|
42
|
+
field_count = 1
|
43
|
+
if bin_names
|
44
|
+
bin_names.each do |bin_name|
|
45
|
+
bin_name_size += bin_name.bytesize + OPERATION_HEADER_SIZE
|
46
|
+
end
|
47
|
+
operation_count = bin_names.length
|
48
|
+
end
|
49
|
+
begin_cmd
|
50
|
+
@data_offset += FIELD_HEADER_SIZE + 4 + 1 # batch.keys.length + flags
|
51
|
+
|
52
|
+
prev = nil
|
53
|
+
batch.keys.each do |key|
|
54
|
+
@data_offset += key.digest.length + 4 # 4 byte batch offset
|
55
|
+
|
56
|
+
if prev != nil && prev.namespace == key.namespace
|
57
|
+
@data_offset += 1
|
58
|
+
else
|
59
|
+
@data_offset += key.namespace.bytesize + FIELD_HEADER_SIZE + 1 + 1 + 2 + 2 # repeat/no-repeat flag + read_attr flags + field_count + operation_count
|
60
|
+
@data_offset += bin_name_size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
size_buffer
|
64
|
+
write_header(policy,read_attr | INFO1_BATCH, 0, 1, 0)
|
65
|
+
write_field_header(0, Aerospike::FieldType::BATCH_INDEX)
|
66
|
+
@data_offset += @data_buffer.write_int32(batch.keys.length, @data_offset)
|
67
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
68
|
+
|
69
|
+
prev = nil
|
70
|
+
|
71
|
+
batch.each_key_with_index do |key, index|
|
72
|
+
@data_offset += @data_buffer.write_int32(index, @data_offset)
|
73
|
+
@data_offset += @data_buffer.write_binary(key.digest, @data_offset)
|
74
|
+
|
75
|
+
if (prev != nil && prev.namespace == key.namespace)
|
76
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
77
|
+
else
|
78
|
+
@data_offset += @data_buffer.write_byte(0, @data_offset)
|
79
|
+
@data_offset += @data_buffer.write_byte(read_attr, @data_offset)
|
80
|
+
@data_offset += @data_buffer.write_int16(field_count, @data_offset)
|
81
|
+
@data_offset += @data_buffer.write_int16(operation_count, @data_offset)
|
82
|
+
write_field_string(key.namespace, Aerospike::FieldType::NAMESPACE)
|
83
|
+
|
84
|
+
if bin_names
|
85
|
+
bin_names.each do |bin_name|
|
86
|
+
write_operation_for_bin_name(bin_name, Aerospike::Operation::READ)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
prev = key
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end_cmd
|
93
|
+
end
|
94
|
+
|
95
|
+
# Parse all results in the batch. Add records to shared list.
|
96
|
+
# If the record was not found, the bins will be nil.
|
97
|
+
def parse_row(result_code)
|
98
|
+
generation = @data_buffer.read_int32(6)
|
99
|
+
expiration = @data_buffer.read_int32(10)
|
100
|
+
batch_index = @data_buffer.read_int32(14)
|
101
|
+
field_count = @data_buffer.read_int16(18)
|
102
|
+
op_count = @data_buffer.read_int16(20)
|
103
|
+
|
104
|
+
key = parse_key(field_count)
|
105
|
+
req_key = batch.key_for_index(batch_index)
|
106
|
+
|
107
|
+
if key.digest == req_key.digest
|
108
|
+
if result_code == 0
|
109
|
+
record = parse_record(req_key, op_count, generation, expiration)
|
110
|
+
results[batch_index] = record
|
111
|
+
end
|
112
|
+
else
|
113
|
+
Aerospike.logger.warn("Unexpected batch key returned: #{key}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end # class
|
118
|
+
|
119
|
+
end # module
|