aerospike 2.19.0 → 2.26.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +354 -244
  3. data/lib/aerospike/atomic/atomic.rb +1 -1
  4. data/lib/aerospike/cdt/context.rb +137 -70
  5. data/lib/aerospike/cdt/list_return_type.rb +4 -0
  6. data/lib/aerospike/cdt/map_operation.rb +6 -6
  7. data/lib/aerospike/cdt/map_policy.rb +16 -2
  8. data/lib/aerospike/cdt/map_return_type.rb +13 -1
  9. data/lib/aerospike/client.rb +137 -115
  10. data/lib/aerospike/cluster/create_connection.rb +1 -1
  11. data/lib/aerospike/cluster.rb +41 -4
  12. data/lib/aerospike/command/admin_command.rb +368 -52
  13. data/lib/aerospike/command/batch_index_command.rb +4 -8
  14. data/lib/aerospike/command/batch_index_exists_command.rb +1 -1
  15. data/lib/aerospike/command/batch_index_node.rb +1 -1
  16. data/lib/aerospike/command/batch_item.rb +1 -1
  17. data/lib/aerospike/command/command.rb +180 -123
  18. data/lib/aerospike/command/field_type.rb +25 -24
  19. data/lib/aerospike/command/login_command.rb +164 -0
  20. data/lib/aerospike/command/multi_command.rb +25 -2
  21. data/lib/aerospike/command/operate_args.rb +99 -0
  22. data/lib/aerospike/command/operate_command.rb +6 -11
  23. data/lib/aerospike/command/read_command.rb +2 -2
  24. data/lib/aerospike/connection/authenticate.rb +36 -3
  25. data/lib/aerospike/exp/exp.rb +1329 -0
  26. data/lib/aerospike/exp/exp_bit.rb +388 -0
  27. data/lib/aerospike/exp/exp_hll.rb +169 -0
  28. data/lib/aerospike/exp/exp_list.rb +403 -0
  29. data/lib/aerospike/exp/exp_map.rb +493 -0
  30. data/lib/aerospike/exp/operation.rb +56 -0
  31. data/lib/aerospike/features.rb +22 -9
  32. data/lib/aerospike/host/parse.rb +2 -2
  33. data/lib/aerospike/key.rb +10 -1
  34. data/lib/aerospike/node/refresh/info.rb +1 -1
  35. data/lib/aerospike/node/verify/name.rb +1 -1
  36. data/lib/aerospike/node/verify/partition_generation.rb +1 -1
  37. data/lib/aerospike/node/verify/peers_generation.rb +1 -1
  38. data/lib/aerospike/node/verify/rebalance_generation.rb +1 -1
  39. data/lib/aerospike/node_validator.rb +6 -1
  40. data/lib/aerospike/operation.rb +20 -22
  41. data/lib/aerospike/policy/auth_mode.rb +36 -0
  42. data/lib/aerospike/policy/client_policy.rb +4 -1
  43. data/lib/aerospike/policy/policy.rb +29 -13
  44. data/lib/aerospike/policy/query_policy.rb +35 -2
  45. data/lib/aerospike/policy/scan_policy.rb +19 -2
  46. data/lib/aerospike/privilege.rb +133 -0
  47. data/lib/aerospike/query/filter.rb +44 -32
  48. data/lib/aerospike/query/node_partitions.rb +39 -0
  49. data/lib/aerospike/query/partition_filter.rb +66 -0
  50. data/lib/aerospike/{command/roles.rb → query/partition_status.rb} +16 -19
  51. data/lib/aerospike/query/partition_tracker.rb +347 -0
  52. data/lib/aerospike/query/query_command.rb +20 -10
  53. data/lib/aerospike/query/query_executor.rb +71 -0
  54. data/lib/aerospike/query/query_partition_command.rb +267 -0
  55. data/lib/aerospike/query/recordset.rb +9 -9
  56. data/lib/aerospike/query/scan_command.rb +3 -2
  57. data/lib/aerospike/query/scan_executor.rb +71 -0
  58. data/lib/aerospike/query/scan_partition_command.rb +49 -0
  59. data/lib/aerospike/query/statement.rb +8 -1
  60. data/lib/aerospike/query/stream_command.rb +17 -0
  61. data/lib/aerospike/result_code.rb +83 -8
  62. data/lib/aerospike/role.rb +55 -0
  63. data/lib/aerospike/task/execute_task.rb +19 -16
  64. data/lib/aerospike/task/index_task.rb +1 -1
  65. data/lib/aerospike/user_role.rb +26 -1
  66. data/lib/aerospike/utils/buffer.rb +93 -29
  67. data/lib/aerospike/utils/packer.rb +7 -6
  68. data/lib/aerospike/utils/pool.rb +1 -1
  69. data/lib/aerospike/value/particle_type.rb +1 -12
  70. data/lib/aerospike/value/value.rb +35 -60
  71. data/lib/aerospike/version.rb +1 -1
  72. data/lib/aerospike.rb +156 -136
  73. 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
- def thread_finished
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
- private
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
- SCAN_TERMINATED_EXCEPTION = Aerospike::Exceptions::ScanTerminated.new()
119
- QUERY_TERMINATED_EXCEPTION = Aerospike::Exceptions::QueryTerminated.new()
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
- # Server is not accepting requests.
80
- SERVER_NOT_AVAILABLE = 11
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 whitelist is invalid.
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 whitelist.
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 SERVER_NOT_AVAILABLE
320
- "Server not available"
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 whitelist is invalid"
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 whitelist"
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"