aerospike 2.19.0 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +354 -244
- data/lib/aerospike/atomic/atomic.rb +1 -1
- data/lib/aerospike/cdt/context.rb +137 -70
- data/lib/aerospike/cdt/list_return_type.rb +4 -0
- data/lib/aerospike/cdt/map_operation.rb +6 -6
- data/lib/aerospike/cdt/map_policy.rb +16 -2
- data/lib/aerospike/cdt/map_return_type.rb +13 -1
- data/lib/aerospike/client.rb +137 -115
- data/lib/aerospike/cluster/create_connection.rb +1 -1
- data/lib/aerospike/cluster.rb +41 -4
- data/lib/aerospike/command/admin_command.rb +368 -52
- data/lib/aerospike/command/batch_index_command.rb +4 -8
- data/lib/aerospike/command/batch_index_exists_command.rb +1 -1
- data/lib/aerospike/command/batch_index_node.rb +1 -1
- data/lib/aerospike/command/batch_item.rb +1 -1
- data/lib/aerospike/command/command.rb +180 -123
- data/lib/aerospike/command/field_type.rb +25 -24
- data/lib/aerospike/command/login_command.rb +164 -0
- data/lib/aerospike/command/multi_command.rb +25 -2
- data/lib/aerospike/command/operate_args.rb +99 -0
- data/lib/aerospike/command/operate_command.rb +6 -11
- data/lib/aerospike/command/read_command.rb +2 -2
- data/lib/aerospike/connection/authenticate.rb +36 -3
- data/lib/aerospike/exp/exp.rb +1329 -0
- data/lib/aerospike/exp/exp_bit.rb +388 -0
- data/lib/aerospike/exp/exp_hll.rb +169 -0
- data/lib/aerospike/exp/exp_list.rb +403 -0
- data/lib/aerospike/exp/exp_map.rb +493 -0
- data/lib/aerospike/exp/operation.rb +56 -0
- data/lib/aerospike/features.rb +22 -9
- data/lib/aerospike/host/parse.rb +2 -2
- data/lib/aerospike/key.rb +10 -1
- data/lib/aerospike/node/refresh/info.rb +1 -1
- data/lib/aerospike/node/verify/name.rb +1 -1
- data/lib/aerospike/node/verify/partition_generation.rb +1 -1
- data/lib/aerospike/node/verify/peers_generation.rb +1 -1
- data/lib/aerospike/node/verify/rebalance_generation.rb +1 -1
- data/lib/aerospike/node_validator.rb +6 -1
- data/lib/aerospike/operation.rb +20 -22
- data/lib/aerospike/policy/auth_mode.rb +36 -0
- data/lib/aerospike/policy/client_policy.rb +4 -1
- data/lib/aerospike/policy/policy.rb +29 -13
- data/lib/aerospike/policy/query_policy.rb +35 -2
- data/lib/aerospike/policy/scan_policy.rb +19 -2
- data/lib/aerospike/privilege.rb +133 -0
- data/lib/aerospike/query/filter.rb +44 -32
- data/lib/aerospike/query/node_partitions.rb +39 -0
- data/lib/aerospike/query/partition_filter.rb +66 -0
- data/lib/aerospike/{command/roles.rb → query/partition_status.rb} +16 -19
- data/lib/aerospike/query/partition_tracker.rb +347 -0
- data/lib/aerospike/query/query_command.rb +20 -10
- data/lib/aerospike/query/query_executor.rb +71 -0
- data/lib/aerospike/query/query_partition_command.rb +267 -0
- data/lib/aerospike/query/recordset.rb +9 -9
- data/lib/aerospike/query/scan_command.rb +3 -2
- data/lib/aerospike/query/scan_executor.rb +71 -0
- data/lib/aerospike/query/scan_partition_command.rb +49 -0
- data/lib/aerospike/query/statement.rb +8 -1
- data/lib/aerospike/query/stream_command.rb +17 -0
- data/lib/aerospike/result_code.rb +83 -8
- data/lib/aerospike/role.rb +55 -0
- data/lib/aerospike/task/execute_task.rb +19 -16
- data/lib/aerospike/task/index_task.rb +1 -1
- data/lib/aerospike/user_role.rb +26 -1
- data/lib/aerospike/utils/buffer.rb +93 -29
- data/lib/aerospike/utils/packer.rb +7 -6
- data/lib/aerospike/utils/pool.rb +1 -1
- data/lib/aerospike/value/particle_type.rb +1 -12
- data/lib/aerospike/value/value.rb +35 -60
- data/lib/aerospike/version.rb +1 -1
- data/lib/aerospike.rb +156 -136
- metadata +24 -6
@@ -0,0 +1,267 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2020 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 "aerospike/query/stream_command"
|
18
|
+
require "aerospike/query/recordset"
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
private
|
22
|
+
|
23
|
+
class QueryPartitionCommand < QueryCommand #:nodoc:
|
24
|
+
def initialize(node, tracker, policy, statement, recordset, node_partitions)
|
25
|
+
super(node, policy, statement, recordset, @node_partitions)
|
26
|
+
@node_partitions = node_partitions
|
27
|
+
@tracker = tracker
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_buffer
|
31
|
+
function_arg_buffer = nil
|
32
|
+
field_count = 0
|
33
|
+
filter_size = 0
|
34
|
+
bin_name_size = 0
|
35
|
+
|
36
|
+
begin_cmd
|
37
|
+
|
38
|
+
if @statement.namespace
|
39
|
+
@data_offset += @statement.namespace.bytesize + FIELD_HEADER_SIZE
|
40
|
+
field_count += 1
|
41
|
+
end
|
42
|
+
|
43
|
+
if @statement.set_name
|
44
|
+
@data_offset += @statement.set_name.bytesize + FIELD_HEADER_SIZE
|
45
|
+
field_count += 1
|
46
|
+
end
|
47
|
+
|
48
|
+
# Estimate recordsPerSecond field size. This field is used in new servers and not used
|
49
|
+
# (but harmless to add) in old servers.
|
50
|
+
if @policy.records_per_second > 0
|
51
|
+
@data_offset += 4 + FIELD_HEADER_SIZE
|
52
|
+
field_count += 1
|
53
|
+
end
|
54
|
+
|
55
|
+
# Estimate socket timeout field size. This field is used in new servers and not used
|
56
|
+
# (but harmless to add) in old servers.
|
57
|
+
@data_offset += 4 + FIELD_HEADER_SIZE
|
58
|
+
field_count += 1
|
59
|
+
|
60
|
+
# Estimate task_id field.
|
61
|
+
@data_offset += 8 + FIELD_HEADER_SIZE
|
62
|
+
field_count += 1
|
63
|
+
|
64
|
+
filter = @statement.filters[0]
|
65
|
+
bin_names = @statement.bin_names
|
66
|
+
packed_ctx = nil
|
67
|
+
|
68
|
+
if filter
|
69
|
+
col_type = filter.collection_type
|
70
|
+
|
71
|
+
# Estimate INDEX_TYPE field.
|
72
|
+
if col_type > 0
|
73
|
+
@data_offset += FIELD_HEADER_SIZE + 1
|
74
|
+
field_count += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
# Estimate INDEX_RANGE field.
|
78
|
+
@data_offset += FIELD_HEADER_SIZE
|
79
|
+
filter_size += 1 # num filters
|
80
|
+
filter_size += filter.estimate_size
|
81
|
+
|
82
|
+
@data_offset += filter_size
|
83
|
+
field_count += 1
|
84
|
+
|
85
|
+
packed_ctx = filter.packed_ctx
|
86
|
+
if packed_ctx
|
87
|
+
@data_offset += FIELD_HEADER_SIZE + packed_ctx.length
|
88
|
+
field_count += 1
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@statement.set_task_id
|
93
|
+
predexp = @policy.predexp || @statement.predexp
|
94
|
+
|
95
|
+
if predexp
|
96
|
+
@data_offset += FIELD_HEADER_SIZE
|
97
|
+
pred_size = Aerospike::PredExp.estimate_size(predexp)
|
98
|
+
@data_offset += pred_size
|
99
|
+
field_count += 1
|
100
|
+
end
|
101
|
+
|
102
|
+
unless @policy.filter_exp.nil?
|
103
|
+
exp_size = estimate_expression_size(@policy.filter_exp)
|
104
|
+
field_count += 1 if exp_size > 0
|
105
|
+
end
|
106
|
+
|
107
|
+
# Estimate aggregation/background function size.
|
108
|
+
if @statement.function_name
|
109
|
+
@data_offset += FIELD_HEADER_SIZE + 1 # udf type
|
110
|
+
@data_offset += @statement.package_name.bytesize + FIELD_HEADER_SIZE
|
111
|
+
@data_offset += @statement.function_name.bytesize + FIELD_HEADER_SIZE
|
112
|
+
|
113
|
+
function_arg_buffer = ""
|
114
|
+
if @statement.function_args && @statement.function_args.length > 0
|
115
|
+
function_arg_buffer = Value.of(@statement.function_args).to_bytes
|
116
|
+
end
|
117
|
+
@data_offset += FIELD_HEADER_SIZE + function_arg_buffer.bytesize
|
118
|
+
field_count += 4
|
119
|
+
end
|
120
|
+
|
121
|
+
max_records = 0
|
122
|
+
parts_full_size = 0
|
123
|
+
parts_partial_digest_size = 0
|
124
|
+
parts_partial_bval_size = 0
|
125
|
+
|
126
|
+
unless @node_partitions.nil?
|
127
|
+
parts_full_size = @node_partitions.parts_full.length * 2
|
128
|
+
parts_partial_digest_size = @node_partitions.parts_partial.length * 20
|
129
|
+
|
130
|
+
unless filter.nil?
|
131
|
+
parts_partial_bval_size = @node_partitions.parts_partial.length * 8
|
132
|
+
end
|
133
|
+
max_records = @node_partitions.record_max
|
134
|
+
end
|
135
|
+
|
136
|
+
if parts_full_size > 0
|
137
|
+
@data_offset += parts_full_size + FIELD_HEADER_SIZE
|
138
|
+
field_count += 1
|
139
|
+
end
|
140
|
+
|
141
|
+
if parts_partial_digest_size > 0
|
142
|
+
@data_offset += parts_partial_digest_size + FIELD_HEADER_SIZE
|
143
|
+
field_count += 1
|
144
|
+
end
|
145
|
+
|
146
|
+
if parts_partial_bval_size > 0
|
147
|
+
@data_offset += parts_partial_bval_size + FIELD_HEADER_SIZE
|
148
|
+
field_count += 1
|
149
|
+
end
|
150
|
+
|
151
|
+
# Estimate max records field size. This field is used in new servers and not used
|
152
|
+
# (but harmless to add) in old servers.
|
153
|
+
if max_records > 0
|
154
|
+
@data_offset += 8 + FIELD_HEADER_SIZE
|
155
|
+
field_count += 1
|
156
|
+
end
|
157
|
+
|
158
|
+
operation_count = 0
|
159
|
+
unless bin_names.empty?
|
160
|
+
# Estimate size for selected bin names (query bin names already handled for old servers).
|
161
|
+
bin_names.each do |bin_name|
|
162
|
+
estimate_operation_size_for_bin_name(bin_name)
|
163
|
+
end
|
164
|
+
operation_count = bin_names.length
|
165
|
+
end
|
166
|
+
|
167
|
+
projected_offset = @data_offset
|
168
|
+
|
169
|
+
size_buffer
|
170
|
+
|
171
|
+
read_attr = INFO1_READ
|
172
|
+
read_attr |= INFO1_NOBINDATA if !@policy.include_bin_data
|
173
|
+
read_attr |= INFO1_SHORT_QUERY if @policy.short_query
|
174
|
+
|
175
|
+
infoAttr = INFO3_PARTITION_DONE
|
176
|
+
|
177
|
+
write_header(@policy, read_attr, 0, field_count, operation_count)
|
178
|
+
|
179
|
+
write_field_string(@statement.namespace, FieldType::NAMESPACE) if @statement.namespace
|
180
|
+
write_field_string(@statement.set_name, FieldType::TABLE) if @statement.set_name
|
181
|
+
|
182
|
+
# Write records per second.
|
183
|
+
write_field_int(@policy.records_per_second, FieldType::RECORDS_PER_SECOND) if @policy.records_per_second > 0
|
184
|
+
|
185
|
+
write_filter_exp(@policy.filter_exp, exp_size)
|
186
|
+
|
187
|
+
# Write socket idle timeout.
|
188
|
+
write_field_int(@policy.socket_timeout, FieldType::SOCKET_TIMEOUT)
|
189
|
+
|
190
|
+
# Write task_id field
|
191
|
+
write_field_int64(@statement.task_id, FieldType::TRAN_ID)
|
192
|
+
|
193
|
+
unless predexp.nil?
|
194
|
+
write_field_header(pred_size, Aerospike::FieldType::PREDEXP)
|
195
|
+
@data_offset = Aerospike::PredExp.write(
|
196
|
+
predexp, @data_buffer, @data_offset
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
if filter
|
201
|
+
type = filter.collection_type
|
202
|
+
|
203
|
+
if type > 0
|
204
|
+
write_field_header(1, FieldType::INDEX_TYPE)
|
205
|
+
@data_offset += @data_buffer.write_byte(type, @data_offset)
|
206
|
+
end
|
207
|
+
|
208
|
+
write_field_header(filter_size, FieldType::INDEX_RANGE)
|
209
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
210
|
+
@data_offset = filter.write(@data_buffer, @data_offset)
|
211
|
+
|
212
|
+
if packed_ctx
|
213
|
+
write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
|
214
|
+
@data_offset += @data_buffer.write_binary(packed_ctx, @data_offset)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
if @statement.function_name
|
219
|
+
write_field_header(1, FieldType::UDF_OP)
|
220
|
+
@data_offset += @data_buffer.write_byte(1, @data_offset)
|
221
|
+
write_field_string(@statement.package_name, FieldType::UDF_PACKAGE_NAME)
|
222
|
+
write_field_string(@statement.function_name, FieldType::UDF_FUNCTION)
|
223
|
+
write_field_string(function_arg_buffer, FieldType::UDF_ARGLIST)
|
224
|
+
end
|
225
|
+
|
226
|
+
if parts_full_size > 0
|
227
|
+
write_field_header(parts_full_size, FieldType::PID_ARRAY)
|
228
|
+
@node_partitions.parts_full.each do |part|
|
229
|
+
@data_offset += @data_buffer.write_uint16_little_endian(part.id, @data_offset)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
if parts_partial_digest_size > 0
|
234
|
+
write_field_header(parts_partial_digest_size, FieldType::DIGEST_ARRAY)
|
235
|
+
@node_partitions.parts_partial.each do |part|
|
236
|
+
@data_offset += @data_buffer.write_binary(part.digest, @data_offset)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
if parts_partial_bval_size > 0
|
241
|
+
write_field_header(parts_partial_bval_size, FieldType::BVAL_ARRAY)
|
242
|
+
@node_partitions.parts_partial.each do |part|
|
243
|
+
@data_offset += @data_buffer.write_uint64_little_endian(part.bval, @data_offset)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
if max_records > 0
|
248
|
+
write_field(max_records, FieldType::MAX_RECORDS)
|
249
|
+
end
|
250
|
+
|
251
|
+
unless bin_names.empty?
|
252
|
+
bin_names.each do |bin_name|
|
253
|
+
write_operation_for_bin_name(bin_name, Operation::READ)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
end_cmd
|
258
|
+
|
259
|
+
nil
|
260
|
+
end
|
261
|
+
|
262
|
+
def should_retry(e)
|
263
|
+
# !! converts nil to false
|
264
|
+
!!@tracker&.should_retry(@node_partitions, e)
|
265
|
+
end
|
266
|
+
end # class
|
267
|
+
end # module
|
@@ -22,7 +22,6 @@ module Aerospike
|
|
22
22
|
# so the production and the consumptoin are decoupled
|
23
23
|
# there can be an unlimited count of producer threads and consumer threads
|
24
24
|
class Recordset
|
25
|
-
|
26
25
|
attr_reader :records
|
27
26
|
|
28
27
|
def initialize(queue_size = 5000, thread_count = 1, type)
|
@@ -66,18 +65,21 @@ module Aerospike
|
|
66
65
|
|
67
66
|
# this is called by working threads to signal their job is finished
|
68
67
|
# it decreases the count of active threads and puts an EOF on queue when all threads are finished
|
69
|
-
|
68
|
+
# e is an exception that has happened in the exceutor, and outside of the threads themselves
|
69
|
+
def thread_finished(expn = nil)
|
70
70
|
@active_threads.update do |v|
|
71
71
|
v -= 1
|
72
72
|
@records.enq(nil) if v == 0
|
73
73
|
v
|
74
74
|
end
|
75
|
+
|
76
|
+
raise expn unless expn.nil?
|
75
77
|
end
|
76
78
|
|
77
79
|
# this is called by a thread who faced an exception to singnal to terminate the whole operation
|
78
80
|
# it also may be called by the user to terminate the command in the middle of fetching records from server nodes
|
79
81
|
# it clears the queue so that if any threads are waiting for the queue get unblocked and find out about the cancellation
|
80
|
-
def cancel(expn=nil)
|
82
|
+
def cancel(expn = nil)
|
81
83
|
set_exception(expn)
|
82
84
|
@cancelled.set(true)
|
83
85
|
@records.clear
|
@@ -104,18 +106,16 @@ module Aerospike
|
|
104
106
|
@filters.nil? || @filters.empty?
|
105
107
|
end
|
106
108
|
|
107
|
-
|
109
|
+
private
|
108
110
|
|
109
|
-
def set_exception(expn=nil)
|
111
|
+
def set_exception(expn = nil)
|
110
112
|
expn ||= (@type == :scan ? SCAN_TERMINATED_EXCEPTION : QUERY_TERMINATED_EXCEPTION)
|
111
113
|
@thread_exception.set(expn)
|
112
114
|
end
|
113
|
-
|
114
115
|
end
|
115
116
|
|
116
117
|
private
|
117
118
|
|
118
|
-
|
119
|
-
|
120
|
-
|
119
|
+
SCAN_TERMINATED_EXCEPTION = Aerospike::Exceptions::ScanTerminated.new()
|
120
|
+
QUERY_TERMINATED_EXCEPTION = Aerospike::Exceptions::QueryTerminated.new()
|
121
121
|
end
|
@@ -23,7 +23,7 @@ module Aerospike
|
|
23
23
|
|
24
24
|
class ScanCommand < StreamCommand #:nodoc:
|
25
25
|
|
26
|
-
def initialize(node, policy, namespace, set_name, bin_names, recordset)
|
26
|
+
def initialize(node, policy, namespace, set_name, bin_names, recordset, node_partitions)
|
27
27
|
super(node)
|
28
28
|
|
29
29
|
@policy = policy
|
@@ -31,10 +31,11 @@ module Aerospike
|
|
31
31
|
@set_name = set_name
|
32
32
|
@bin_names = bin_names
|
33
33
|
@recordset = recordset
|
34
|
+
@node_partitions = node_partitions
|
34
35
|
end
|
35
36
|
|
36
37
|
def write_buffer
|
37
|
-
set_scan(@policy, @namespace, @set_name, @bin_names)
|
38
|
+
set_scan(@policy, @namespace, @set_name, @bin_names, @node_partitions)
|
38
39
|
end
|
39
40
|
|
40
41
|
end # class
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2014-2020 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 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
|
+
class ScanExecutor # :nodoc:
|
20
|
+
def self.scan_partitions(policy, cluster, tracker, namespace, set_name, recordset, bin_names = nil)
|
21
|
+
interval = policy.sleep_between_retries
|
22
|
+
|
23
|
+
should_retry = false
|
24
|
+
|
25
|
+
loop do
|
26
|
+
# reset last_expn
|
27
|
+
@last_expn = nil
|
28
|
+
|
29
|
+
list = tracker.assign_partitions_to_nodes(cluster, namespace)
|
30
|
+
|
31
|
+
if policy.concurrent_nodes
|
32
|
+
threads = []
|
33
|
+
# Use a thread per node
|
34
|
+
list.each do |node_partition|
|
35
|
+
threads << Thread.new do
|
36
|
+
Thread.current.abort_on_exception = true
|
37
|
+
command = ScanPartitionCommand.new(policy, tracker, node_partition, namespace, set_name, bin_names, recordset)
|
38
|
+
begin
|
39
|
+
command.execute
|
40
|
+
rescue => e
|
41
|
+
@last_expn = e unless e == SCAN_TERMINATED_EXCEPTION
|
42
|
+
should_retry ||= command.should_retry(e)
|
43
|
+
Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
threads.each(&:join)
|
48
|
+
else
|
49
|
+
# Use a single thread for all nodes for all node
|
50
|
+
list.each do |node_partition|
|
51
|
+
command = ScanPartitionCommand.new(policy, tracker, node_partition, namespace, set_name, bin_names, recordset)
|
52
|
+
begin
|
53
|
+
command.execute
|
54
|
+
rescue => e
|
55
|
+
@last_expn = e unless e == SCAN_TERMINATED_EXCEPTION
|
56
|
+
should_retry ||= command.should_retry(e)
|
57
|
+
Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if tracker.complete?(@cluster, policy) || !should_retry
|
63
|
+
recordset.thread_finished(@last_expn)
|
64
|
+
return
|
65
|
+
end
|
66
|
+
sleep(interval) if policy.sleep_between_retries > 0
|
67
|
+
statement.reset_task_id
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2014-2020 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 'aerospike/query/stream_command'
|
18
|
+
require 'aerospike/query/recordset'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
class ScanPartitionCommand < StreamCommand #:nodoc:
|
25
|
+
|
26
|
+
def initialize(policy, tracker, node_partitions, namespace, set_name, bin_names, recordset)
|
27
|
+
super(node_partitions.node)
|
28
|
+
|
29
|
+
@policy = policy
|
30
|
+
@namespace = namespace
|
31
|
+
@set_name = set_name
|
32
|
+
@bin_names = bin_names
|
33
|
+
@recordset = recordset
|
34
|
+
@node_partitions = node_partitions
|
35
|
+
@tracker = tracker
|
36
|
+
end
|
37
|
+
|
38
|
+
def write_buffer
|
39
|
+
set_scan(@policy, @namespace, @set_name, @bin_names, @node_partitions)
|
40
|
+
end
|
41
|
+
|
42
|
+
def should_retry(e)
|
43
|
+
# !! converts nil to false
|
44
|
+
!!@tracker&.should_retry(@node_partitions, e)
|
45
|
+
end
|
46
|
+
|
47
|
+
end # class
|
48
|
+
|
49
|
+
end # module
|
@@ -49,7 +49,7 @@ module Aerospike
|
|
49
49
|
# This method is redundant because PredExp can now be set in the base Policy for
|
50
50
|
# any transaction (including queries).
|
51
51
|
#
|
52
|
-
# NOTE : Policy.predexp takes precedence to this value. This value will be
|
52
|
+
# NOTE : Policy.predexp takes precedence to this value. This value will be
|
53
53
|
# deprecated in the future.
|
54
54
|
@predexp = nil
|
55
55
|
|
@@ -81,6 +81,13 @@ module Aerospike
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
def reset_task_id
|
85
|
+
@task_id = rand(RAND_MAX)
|
86
|
+
while @task_id == 0
|
87
|
+
@task_id = rand(RAND_MAX)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
84
91
|
private
|
85
92
|
|
86
93
|
RAND_MAX = 2**63
|
@@ -39,6 +39,8 @@ module Aerospike
|
|
39
39
|
case result_code
|
40
40
|
when Aerospike::ResultCode::OK
|
41
41
|
# noop
|
42
|
+
when Aerospike::ResultCode::PARTITION_UNAVAILABLE
|
43
|
+
# noop
|
42
44
|
when Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
|
43
45
|
# consume the rest of the input buffer from the socket
|
44
46
|
read_bytes(receive_size - @data_offset) if @data_offset < receive_size
|
@@ -58,6 +60,18 @@ module Aerospike
|
|
58
60
|
op_count = @data_buffer.read_int16(20)
|
59
61
|
key = parse_key(field_count)
|
60
62
|
|
63
|
+
# If cmd is the end marker of the response, do not proceed further
|
64
|
+
if (info3 & INFO3_PARTITION_DONE) != 0
|
65
|
+
# When an error code is received, mark partition as unavailable
|
66
|
+
# for the current round. Unavailable partitions will be retried
|
67
|
+
# in the next round. Generation is overloaded as partitionId.
|
68
|
+
if result_code != 0
|
69
|
+
@tracker&.partition_unavailable(@node_partitions, generation)
|
70
|
+
end
|
71
|
+
|
72
|
+
next
|
73
|
+
end
|
74
|
+
|
61
75
|
if result_code == 0
|
62
76
|
if @recordset.active?
|
63
77
|
@recordset.records.enq(parse_record(key, op_count, generation, expiration))
|
@@ -65,6 +79,9 @@ module Aerospike
|
|
65
79
|
expn = @recordset.is_scan? ? SCAN_TERMINATED_EXCEPTION : QUERY_TERMINATED_EXCEPTION
|
66
80
|
raise expn
|
67
81
|
end
|
82
|
+
|
83
|
+
# UDF results do not return a key
|
84
|
+
@tracker&.set_last(@node_partitions, key, key.bval) if key
|
68
85
|
end
|
69
86
|
end # while
|
70
87
|
|
@@ -20,6 +20,42 @@ module Aerospike
|
|
20
20
|
|
21
21
|
attr_reader :code
|
22
22
|
|
23
|
+
# One or more keys failed in a batch.
|
24
|
+
BATCH_FAILED = -20
|
25
|
+
|
26
|
+
# No response was received from the server.
|
27
|
+
NO_RESPONSE = -19
|
28
|
+
|
29
|
+
# A network error. Checked the wrapped error for detail.
|
30
|
+
NETWORK_ERROR = -18
|
31
|
+
|
32
|
+
# A common, none-aerospike error. Checked the wrapped error for detail.
|
33
|
+
COMMON_ERROR = -17
|
34
|
+
|
35
|
+
# Max retries limit reached.
|
36
|
+
MAX_RETRIES_EXCEEDED = -16
|
37
|
+
|
38
|
+
# Max errors limit reached.
|
39
|
+
MAX_ERROR_RATE = -15
|
40
|
+
|
41
|
+
# Requested Rack for node/namespace was not defined in the cluster.
|
42
|
+
RACK_NOT_DEFINED = -13
|
43
|
+
|
44
|
+
# Cluster has an invalid partition map, usually due to bad configuration.
|
45
|
+
INVALID_CLUSTER_PARTITION_MAP = -12
|
46
|
+
|
47
|
+
# Server is not accepting requests.
|
48
|
+
SERVER_NOT_AVAILABLE = -11
|
49
|
+
|
50
|
+
# Cluster Name does not match the ClientPolicy.ClusterName value.
|
51
|
+
CLUSTER_NAME_MISMATCH_ERROR = -10
|
52
|
+
|
53
|
+
# Recordset has already been closed or cancelled
|
54
|
+
RECORDSET_CLOSED = -9
|
55
|
+
|
56
|
+
# There were no connections available to the node in the pool, and the pool was limited
|
57
|
+
NO_AVAILABLE_CONNECTIONS_TO_NODE = -8
|
58
|
+
|
23
59
|
# Value type not supported by Aerospike server
|
24
60
|
TYPE_NOT_SUPPORTED = -7
|
25
61
|
|
@@ -76,8 +112,8 @@ module Aerospike
|
|
76
112
|
# XDS product is not available.
|
77
113
|
NO_XDS = 10
|
78
114
|
|
79
|
-
#
|
80
|
-
|
115
|
+
# Partition is unavailable.
|
116
|
+
PARTITION_UNAVAILABLE = 11
|
81
117
|
|
82
118
|
# Operation is not supported with configured bin type (single-bin or
|
83
119
|
# multi-bin).
|
@@ -182,7 +218,7 @@ module Aerospike
|
|
182
218
|
# Privilege is invalid.
|
183
219
|
INVALID_PRIVILEGE = 72
|
184
220
|
|
185
|
-
# Specified IP
|
221
|
+
# Specified IP allowlist is invalid.
|
186
222
|
INVALID_WHITELIST = 73
|
187
223
|
|
188
224
|
# User must be authentication before performing database operations.
|
@@ -191,7 +227,7 @@ module Aerospike
|
|
191
227
|
# User does not posses the required role to perform the database operation.
|
192
228
|
ROLE_VIOLATION = 81
|
193
229
|
|
194
|
-
# Client IP address is not on the IP
|
230
|
+
# Client IP address is not on the IP allowlist.
|
195
231
|
NOT_WHITELISTED = 82
|
196
232
|
|
197
233
|
# LDAP feature not enabled on server.
|
@@ -265,6 +301,45 @@ module Aerospike
|
|
265
301
|
|
266
302
|
def self.message(code)
|
267
303
|
case code
|
304
|
+
when BATCH_FAILED
|
305
|
+
"one or more keys failed in a batch"
|
306
|
+
|
307
|
+
when NO_RESPONSE
|
308
|
+
"no response was received from the server"
|
309
|
+
|
310
|
+
when NETWORK_ERROR
|
311
|
+
"network error. Checked the wrapped error for detail"
|
312
|
+
|
313
|
+
when COMMON_ERROR
|
314
|
+
"common, none-aerospike error. Checked the wrapped error for detail"
|
315
|
+
|
316
|
+
when MAX_RETRIES_EXCEEDED
|
317
|
+
"Max retries exceeded"
|
318
|
+
|
319
|
+
when MAX_ERROR_RATE
|
320
|
+
"Max errors limit reached for node"
|
321
|
+
|
322
|
+
when RACK_NOT_DEFINED
|
323
|
+
"Requested Rack for node/namespace was not defined in the cluster."
|
324
|
+
|
325
|
+
when INVALID_CLUSTER_PARTITION_MAP
|
326
|
+
"Cluster has an invalid partition map, usually due to bad configuration."
|
327
|
+
|
328
|
+
when SERVER_NOT_AVAILABLE
|
329
|
+
"Server is not accepting requests."
|
330
|
+
|
331
|
+
when CLUSTER_NAME_MISMATCH_ERROR
|
332
|
+
"Cluster Name does not match the ClientPolicy.ClusterName value"
|
333
|
+
|
334
|
+
when RECORDSET_CLOSED
|
335
|
+
"Recordset has already been closed or cancelled."
|
336
|
+
|
337
|
+
when NO_AVAILABLE_CONNECTIONS_TO_NODE
|
338
|
+
"No available connections to the node. Connection Pool was empty, and limited to certain number of connections."
|
339
|
+
|
340
|
+
when TYPE_NOT_SUPPORTED
|
341
|
+
"Type cannot be converted to Value Type."
|
342
|
+
|
268
343
|
when COMMAND_REJECTED
|
269
344
|
"Command rejected"
|
270
345
|
|
@@ -316,8 +391,8 @@ module Aerospike
|
|
316
391
|
when NO_XDS
|
317
392
|
"XDS not available"
|
318
393
|
|
319
|
-
when
|
320
|
-
|
394
|
+
when PARTITION_UNAVAILABLE
|
395
|
+
"Partition not available"
|
321
396
|
|
322
397
|
when BIN_TYPE_ERROR
|
323
398
|
"Bin type error"
|
@@ -422,7 +497,7 @@ module Aerospike
|
|
422
497
|
"Invalid privilege"
|
423
498
|
|
424
499
|
when INVALID_WHITELIST
|
425
|
-
"Specified IP
|
500
|
+
"Specified IP allowlist is invalid"
|
426
501
|
|
427
502
|
when NOT_AUTHENTICATED
|
428
503
|
"Not authenticated"
|
@@ -431,7 +506,7 @@ module Aerospike
|
|
431
506
|
"Role violation"
|
432
507
|
|
433
508
|
when NOT_WHITELISTED
|
434
|
-
"Client IP address is not on the IP
|
509
|
+
"Client IP address is not on the IP allowlist"
|
435
510
|
|
436
511
|
when LDAP_NOT_ENABLED
|
437
512
|
"LDAP feature not enabled on server"
|