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.
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"