aerospike 2.21.1 → 2.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/lib/aerospike/atomic/atomic.rb +1 -1
  4. data/lib/aerospike/cdt/context.rb +7 -7
  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_return_type.rb +4 -0
  8. data/lib/aerospike/client.rb +34 -59
  9. data/lib/aerospike/cluster.rb +6 -3
  10. data/lib/aerospike/command/admin_command.rb +2 -2
  11. data/lib/aerospike/command/batch_index_node.rb +1 -1
  12. data/lib/aerospike/command/batch_item.rb +1 -1
  13. data/lib/aerospike/command/command.rb +62 -30
  14. data/lib/aerospike/command/field_type.rb +3 -0
  15. data/lib/aerospike/command/login_command.rb +7 -5
  16. data/lib/aerospike/command/multi_command.rb +8 -2
  17. data/lib/aerospike/command/read_command.rb +2 -2
  18. data/lib/aerospike/connection/authenticate.rb +4 -4
  19. data/lib/aerospike/features.rb +9 -9
  20. data/lib/aerospike/host/parse.rb +2 -2
  21. data/lib/aerospike/key.rb +10 -1
  22. data/lib/aerospike/node/refresh/info.rb +1 -1
  23. data/lib/aerospike/node/verify/name.rb +1 -1
  24. data/lib/aerospike/node/verify/partition_generation.rb +1 -1
  25. data/lib/aerospike/node/verify/peers_generation.rb +1 -1
  26. data/lib/aerospike/node/verify/rebalance_generation.rb +1 -1
  27. data/lib/aerospike/node_validator.rb +6 -1
  28. data/lib/aerospike/policy/policy.rb +4 -1
  29. data/lib/aerospike/policy/scan_policy.rb +20 -1
  30. data/lib/aerospike/privilege.rb +1 -1
  31. data/lib/aerospike/query/node_partitions.rb +39 -0
  32. data/lib/aerospike/query/partition_filter.rb +66 -0
  33. data/lib/aerospike/query/partition_status.rb +36 -0
  34. data/lib/aerospike/query/partition_tracker.rb +347 -0
  35. data/lib/aerospike/query/scan_command.rb +3 -3
  36. data/lib/aerospike/query/scan_executor.rb +69 -0
  37. data/lib/aerospike/query/scan_partition_command.rb +49 -0
  38. data/lib/aerospike/query/statement.rb +1 -1
  39. data/lib/aerospike/query/stream_command.rb +14 -1
  40. data/lib/aerospike/result_code.rb +79 -4
  41. data/lib/aerospike/role.rb +2 -2
  42. data/lib/aerospike/task/execute_task.rb +2 -2
  43. data/lib/aerospike/task/index_task.rb +1 -1
  44. data/lib/aerospike/user_role.rb +1 -1
  45. data/lib/aerospike/utils/buffer.rb +12 -0
  46. data/lib/aerospike/utils/pool.rb +1 -1
  47. data/lib/aerospike/value/value.rb +6 -6
  48. data/lib/aerospike/version.rb +1 -1
  49. data/lib/aerospike.rb +6 -0
  50. metadata +11 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0685f64b5853e918eca12c6ad4a64a1c7ac5c1d0370627c252e598f4686be68
4
- data.tar.gz: a342e374dc180201176018cf1e13c7764a64963fe78e505d55d93b5f2ed83b70
3
+ metadata.gz: ee4d21995440d0ab8667220405ddc187b0f9f411563fd5998d7b0b15b6da2be9
4
+ data.tar.gz: d6e101e2b87b669f7d930b83b19e472d0ddf94ea4e9a1e974425540f273b047a
5
5
  SHA512:
6
- metadata.gz: 4151a866e0ff1c36e924aa1a6123411499f7c1bcf48b01177028db5d7a7a72ac2cfde2febb398a42774c4b490c5e0f78839a14a52d5d0c19c9850f5e34dd7141
7
- data.tar.gz: babd62c5d0307153073c51bfa879e0700a9ad56875da37eb711965da82ddc09b765cbbd770ec60c6973d818318200708ba27a4c4ee4a7b598076324ef9093176
6
+ metadata.gz: d2619ef3fa2d999a0b27211f0859b8b3d62b35ea4dd0f64b76fef6606c1f3ef026aa8cc89bffb63af688b0056e4add4ea189ebcc288c07ad05c18e0cc1445470
7
+ data.tar.gz: 3461927918426fcc829a81728938db3e5a61788b7c2d22f674f3f5ca011f7e4f71dc87f4953818dbbaa9d1d9bafbffc115d9238401180f00b560a989438bfb63
data/CHANGELOG.md CHANGED
@@ -2,8 +2,23 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.23.0] 2022-10-25
6
+
7
+ * **New Features**
8
+ * [CLIENT-1752] Add 'EXISTS' return type for CDT read operations.
9
+ * [CLIENT-1195] Support partition scans.
10
+ * [CLIENT-1238] Support max_records on partition scans.
11
+ * [CLIENT-1940] Lint and Clean up using Rubocop.
12
+
13
+ ## [2.22.0] 2022-07-14
14
+
15
+ * **Fixes**
16
+ * [CLIENT-1785] Fix Client#read_users to avoid error. PR #112 Thanks to [Dotan Mor](https://github.com/dotan-mor)
17
+ * [CLIENT-1787] Support multiple DNS IPs during connection.
18
+ * [CLIENT-1789] Authentication Retry fails in certain conditions.
19
+
5
20
  ## [2.21.1] - 2022-06-21
6
-
21
+
7
22
  This s hotfix release. It is recommended to upgrade your client if you use authentication.
8
23
 
9
24
  * **Bug Fixes**
@@ -48,7 +48,7 @@ module Aerospike
48
48
  @value = value
49
49
  end
50
50
  end
51
- alias_method 'value='.to_sym, :set
51
+ alias_method :value=, :set
52
52
 
53
53
  end # class
54
54
 
@@ -52,7 +52,7 @@ module Aerospike
52
52
  def self.list_index(index)
53
53
  Context.new(0x10, index)
54
54
  end
55
-
55
+
56
56
  ##
57
57
  # Lookup list by rank.
58
58
  # 0 = smallest value
@@ -61,13 +61,13 @@ module Aerospike
61
61
  def self.list_rank(rank)
62
62
  Context.new(0x11, rank)
63
63
  end
64
-
64
+
65
65
  ##
66
66
  # Lookup list by value.
67
67
  def self.list_value(key)
68
68
  Context.new(0x13, key)
69
69
  end
70
-
70
+
71
71
  ##
72
72
  # Lookup map by index offset.
73
73
  # If the index is negative, the resolved index starts backwards from end of list.
@@ -80,7 +80,7 @@ module Aerospike
80
80
  def self.map_index(index)
81
81
  Context.new(0x20, index)
82
82
  end
83
-
83
+
84
84
  ##
85
85
  # Lookup map by rank.
86
86
  # 0 = smallest value
@@ -89,13 +89,13 @@ module Aerospike
89
89
  def self.map_rank(rank)
90
90
  Context.new(0x21, rank)
91
91
  end
92
-
92
+
93
93
  ##
94
94
  # Lookup map by key.
95
95
  def self.map_key(key)
96
96
  Context.new(0x22, key)
97
97
  end
98
-
98
+
99
99
  ##
100
100
  # Create map with given type at map key.
101
101
  def self.map_key_create(key, order)
@@ -106,7 +106,7 @@ module Aerospike
106
106
  # Lookup map by value.
107
107
  def self.map_value(key)
108
108
  Context.new(0x23, key)
109
- end
109
+ end
110
110
 
111
111
  end
112
112
  end
@@ -60,6 +60,10 @@ module Aerospike
60
60
  # Return value for single key read and value list for range read.
61
61
  VALUE = 7
62
62
 
63
+ ##
64
+ # Return true if count > 0.
65
+ EXISTS = 13
66
+
63
67
  ##
64
68
  # :private
65
69
  #
@@ -138,9 +138,7 @@ module Aerospike
138
138
  # The map policy dictates the type of map to create when it does not exist.
139
139
  # The map policy also specifies the flags used when writing items to the map.
140
140
  def self.put(bin_name, key, value, ctx: nil, policy: MapPolicy::DEFAULT)
141
- if policy.flags != MapWriteFlags::DEFAULT
142
- MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order[:attr], policy.flags, ctx: ctx)
143
- else
141
+ if policy.flags == MapWriteFlags::DEFAULT
144
142
  case policy.write_mode
145
143
  when MapWriteMode::UPDATE_ONLY
146
144
  # Replace doesn't allow map order because it does not create on non-existing key.
@@ -150,6 +148,8 @@ module Aerospike
150
148
  else
151
149
  MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order[:attr], ctx: ctx)
152
150
  end
151
+ else
152
+ MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order[:attr], policy.flags, ctx: ctx)
153
153
  end
154
154
  end
155
155
 
@@ -160,9 +160,7 @@ module Aerospike
160
160
  # The map policy dictates the type of map to create when it does not exist.
161
161
  # The map policy also specifies the flags used when writing items to the map.
162
162
  def self.put_items(bin_name, values, ctx: nil, policy: MapPolicy::DEFAULT)
163
- if policy.flags != MapWriteFlags::DEFAULT
164
- MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order[:attr], policy.flags, ctx: ctx)
165
- else
163
+ if policy.flags == MapWriteFlags::DEFAULT
166
164
  case policy.write_mode
167
165
  when MapWriteMode::UPDATE_ONLY
168
166
  # Replace doesn't allow map order because it does not create on non-existing key.
@@ -172,6 +170,8 @@ module Aerospike
172
170
  else
173
171
  MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order[:attr], ctx: ctx)
174
172
  end
173
+ else
174
+ MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order[:attr], policy.flags, ctx: ctx)
175
175
  end
176
176
  end
177
177
 
@@ -65,6 +65,10 @@ module Aerospike
65
65
  # Return key/value items.
66
66
  KEY_VALUE = 8
67
67
 
68
+ ##
69
+ # Return true if count > 0.
70
+ EXISTS = 13
71
+
68
72
  ##
69
73
  # Default return type: NONE
70
74
  DEFAULT_RETURN_TYPE = NONE
@@ -624,13 +624,15 @@ module Aerospike
624
624
  # Scan Operations
625
625
  #-------------------------------------------------------
626
626
 
627
- def scan_all(namespace, set_name, bin_names = nil, options = nil)
627
+ # Reads records in specified namespace and set using partition filter.
628
+ # If the policy's concurrent_nodes is specified, each server node will be read in
629
+ # parallel. Otherwise, server nodes are read sequentially.
630
+ # If partition_filter is nil, all partitions will be scanned.
631
+ # If the policy is nil, the default relevant policy will be used.
632
+ # This method is only supported by Aerospike 4.9+ servers.
633
+ def scan_partitions(partition_filter, namespace, set_name, bin_names = nil, options = nil)
628
634
  policy = create_policy(options, ScanPolicy, default_scan_policy)
629
635
 
630
- # wait until all migrations are finished
631
- # TODO: implement
632
- # @cluster.WaitUntillMigrationIsFinished(policy.timeout)
633
-
634
636
  # Retry policy must be one-shot for scans.
635
637
  # copy on write for policy
636
638
  new_policy = policy.clone
@@ -640,80 +642,53 @@ module Aerospike
640
642
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
641
643
  end
642
644
 
643
- recordset = Recordset.new(policy.record_queue_size, nodes.length, :scan)
644
-
645
- if policy.concurrent_nodes
646
- # Use a thread per node
647
- nodes.each do |node|
648
- partitions = node.cluster.node_partitions(node, namespace)
649
- Thread.new do
650
- Thread.current.abort_on_exception = true
651
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
652
- begin
653
- execute_command(command)
654
- rescue => e
655
- Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
656
- recordset.cancel(e)
657
- ensure
658
- recordset.thread_finished
659
- end
660
- end
661
- end
662
- else
663
- Thread.new do
664
- Thread.current.abort_on_exception = true
665
- nodes.each do |node|
666
- partitions = node.cluster.node_partitions(node, namespace)
667
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
668
- begin
669
- execute_command(command)
670
- rescue => e
671
- Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
672
- recordset.cancel(e)
673
- ensure
674
- recordset.thread_finished
675
- end
676
- end
677
- end
645
+ tracker = Aerospike::PartitionTracker.new(policy, nodes, partition_filter)
646
+ recordset = Recordset.new(policy.record_queue_size, 1, :scan)
647
+ Thread.new do
648
+ Thread.current.abort_on_exception = true
649
+ ScanExecutor.scan_partitions(policy, @cluster, tracker, namespace, set_name, recordset, bin_names)
678
650
  end
679
651
 
680
652
  recordset
681
653
  end
682
654
 
683
- # ScanNode reads all records in specified namespace and set, from one node only.
684
- # The policy can be used to specify timeouts.
685
- def scan_node(node, namespace, set_name, bin_names = nil, options = nil)
655
+ # Reads all records in specified namespace and set for one node only.
656
+ # If the policy is nil, the default relevant policy will be used.
657
+ def scan_node_partitions(node, namespace, set_name, bin_names = nil, options = nil)
686
658
  policy = create_policy(options, ScanPolicy, default_scan_policy)
687
- # wait until all migrations are finished
688
- # TODO: implement
689
- # @cluster.WaitUntillMigrationIsFinished(policy.timeout)
690
659
 
691
660
  # Retry policy must be one-shot for scans.
692
661
  # copy on write for policy
693
662
  new_policy = policy.clone
694
- new_policy.max_retries = 0
695
663
 
696
- node = @cluster.get_node_by_name(node) unless node.is_a?(Aerospike::Node)
664
+ unless node.active?
665
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
666
+ end
697
667
 
668
+ tracker = Aerospike::PartitionTracker.new(policy, [node])
698
669
  recordset = Recordset.new(policy.record_queue_size, 1, :scan)
699
-
700
- partitions = node.cluster.node_partitions(node, namespace)
701
670
  Thread.new do
702
671
  Thread.current.abort_on_exception = true
703
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
704
- begin
705
- execute_command(command)
706
- rescue => e
707
- Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
708
- recordset.cancel(e)
709
- ensure
710
- recordset.thread_finished
711
- end
672
+ ScanExecutor.scan_partitions(policy, @cluster, tracker, namespace, set_name, recordset, bin_names)
712
673
  end
713
674
 
714
675
  recordset
715
676
  end
716
677
 
678
+ # Reads all records in specified namespace and set from all nodes.
679
+ # If the policy's concurrent_nodes is specified, each server node will be read in
680
+ # parallel. Otherwise, server nodes are read sequentially.
681
+ # If the policy is nil, the default relevant policy will be used.
682
+ def scan_all(namespace, set_name, bin_names = nil, options = nil)
683
+ scan_partitions(Aerospike::PartitionFilter.all, namespace, set_name, bin_names, options)
684
+ end
685
+
686
+ # ScanNode reads all records in specified namespace and set, from one node only.
687
+ # The policy can be used to specify timeouts.
688
+ def scan_node(node, namespace, set_name, bin_names = nil, options = nil)
689
+ scan_node_partitions(node, namespace, set_name, bin_names, options)
690
+ end
691
+
717
692
  #--------------------------------------------------------
718
693
  # Query functions (Supported by Aerospike 3 servers only)
719
694
  #--------------------------------------------------------
@@ -463,7 +463,7 @@ module Aerospike
463
463
  count = -1
464
464
  done = false
465
465
 
466
- # will run until the cluster is stablized
466
+ # will run until the cluster is stabilized
467
467
  thr = Thread.new do
468
468
  loop do
469
469
  tend
@@ -475,14 +475,17 @@ module Aerospike
475
475
  # Break if timed out
476
476
  break if done
477
477
 
478
- sleep(0.001) # sleep for a milisecond
478
+ sleep(0.001) # sleep for a millisecond
479
479
 
480
480
  count = nodes.length
481
481
  end
482
482
  end
483
483
 
484
484
  # wait for the thread to finish or timeout
485
- thr.join(@connection_timeout)
485
+ # This will give the client up to 10 times the timeout duration to find
486
+ # a host and connect successfully eventually, in case the DNS
487
+ # returns multiple IPs and some of them are not reachable.
488
+ thr.join(@connection_timeout * 10)
486
489
  done = true
487
490
  sleep(0.001)
488
491
  thr.kill if thr.alive?
@@ -381,7 +381,7 @@ module Aerospike
381
381
  raise e
382
382
  end
383
383
 
384
- raise Exceptions::Aerospike.new(result) if status > 0
384
+ raise Exceptions::Aerospike.new(status) if status > 0
385
385
 
386
386
  return list
387
387
  end
@@ -653,7 +653,7 @@ module Aerospike
653
653
  list << s
654
654
  end
655
655
 
656
- list
656
+ list
657
657
  end
658
658
 
659
659
  end
@@ -30,7 +30,7 @@ module Aerospike
30
30
 
31
31
  def initialize(node, keys_with_idx)
32
32
  @node = node
33
- @keys_by_idx = Hash[keys_with_idx.map(&:reverse)]
33
+ @keys_by_idx = keys_with_idx.map(&:reverse).to_h
34
34
  end
35
35
 
36
36
  def keys
@@ -28,7 +28,7 @@ module Aerospike
28
28
  .map { |key, keys_with_idx|
29
29
  [key.digest, BatchItem.new(key, keys_with_idx.map(&:last))]
30
30
  }
31
- Hash[map]
31
+ map.to_h
32
32
  end
33
33
 
34
34
  def initialize(key, indexes)
@@ -112,7 +112,7 @@ module Aerospike
112
112
  def set_write(policy, operation, key, bins)
113
113
  begin_cmd
114
114
  field_count = estimate_key_size(key, policy)
115
-
115
+
116
116
  predexp_size = estimate_predexp(policy.predexp)
117
117
  field_count += 1 if predexp_size > 0
118
118
 
@@ -138,7 +138,7 @@ module Aerospike
138
138
  def set_delete(policy, key)
139
139
  begin_cmd
140
140
  field_count = estimate_key_size(key)
141
-
141
+
142
142
  predexp_size = estimate_predexp(policy.predexp)
143
143
  field_count += 1 if predexp_size > 0
144
144
 
@@ -153,7 +153,7 @@ module Aerospike
153
153
  def set_touch(policy, key)
154
154
  begin_cmd
155
155
  field_count = estimate_key_size(key)
156
-
156
+
157
157
  predexp_size = estimate_predexp(policy.predexp)
158
158
  field_count += 1 if predexp_size > 0
159
159
 
@@ -170,7 +170,7 @@ module Aerospike
170
170
  def set_exists(policy, key)
171
171
  begin_cmd
172
172
  field_count = estimate_key_size(key)
173
-
173
+
174
174
  predexp_size = estimate_predexp(policy.predexp)
175
175
  field_count += 1 if predexp_size > 0
176
176
 
@@ -185,7 +185,7 @@ module Aerospike
185
185
  def set_read_for_key_only(policy, key)
186
186
  begin_cmd
187
187
  field_count = estimate_key_size(key)
188
-
188
+
189
189
  predexp_size = estimate_predexp(policy.predexp)
190
190
  field_count += 1 if predexp_size > 0
191
191
 
@@ -201,7 +201,7 @@ module Aerospike
201
201
  if bin_names && bin_names.length > 0
202
202
  begin_cmd
203
203
  field_count = estimate_key_size(key)
204
-
204
+
205
205
  predexp_size = estimate_predexp(policy.predexp)
206
206
  field_count += 1 if predexp_size > 0
207
207
 
@@ -229,7 +229,7 @@ module Aerospike
229
229
  def set_read_header(policy, key)
230
230
  begin_cmd
231
231
  field_count = estimate_key_size(key)
232
-
232
+
233
233
  predexp_size = estimate_predexp(policy.predexp)
234
234
  field_count += 1 if predexp_size > 0
235
235
 
@@ -252,7 +252,7 @@ module Aerospike
252
252
  def set_operate(policy, key, operations)
253
253
  begin_cmd
254
254
  field_count = estimate_key_size(key, policy)
255
-
255
+
256
256
  predexp_size = estimate_predexp(policy.predexp)
257
257
  field_count += 1 if predexp_size > 0
258
258
 
@@ -263,7 +263,7 @@ module Aerospike
263
263
 
264
264
  operations.each do |operation|
265
265
  case operation.op_type
266
- when Aerospike::Operation::READ, Aerospike::Operation::CDT_READ,
266
+ when Aerospike::Operation::READ, Aerospike::Operation::CDT_READ,
267
267
  Aerospike::Operation::HLL_READ, Aerospike::Operation::BIT_READ
268
268
  read_attr |= INFO1_READ
269
269
 
@@ -282,7 +282,7 @@ module Aerospike
282
282
  write_attr = INFO2_WRITE
283
283
  end
284
284
 
285
- if [Aerospike::Operation::HLL_MODIFY, Aerospike::Operation::HLL_READ,
285
+ if [Aerospike::Operation::HLL_MODIFY, Aerospike::Operation::HLL_READ,
286
286
  Aerospike::Operation::BIT_MODIFY, Aerospike::Operation::BIT_READ].include?(operation.op_type)
287
287
  record_bin_multiplicity = true
288
288
  end
@@ -294,10 +294,10 @@ module Aerospike
294
294
 
295
295
  write_attr |= INFO2_RESPOND_ALL_OPS if write_attr != 0 && record_bin_multiplicity
296
296
 
297
- if write_attr != 0
298
- write_header_with_policy(policy, read_attr, write_attr, field_count, operations.length)
299
- else
297
+ if write_attr == 0
300
298
  write_header(policy, read_attr, write_attr, field_count, operations.length)
299
+ else
300
+ write_header_with_policy(policy, read_attr, write_attr, field_count, operations.length)
301
301
  end
302
302
  write_key(key, policy)
303
303
  write_predexp(policy.predexp, predexp_size)
@@ -315,7 +315,7 @@ module Aerospike
315
315
  def set_udf(policy, key, package_name, function_name, args)
316
316
  begin_cmd
317
317
  field_count = estimate_key_size(key, policy)
318
-
318
+
319
319
  predexp_size = estimate_predexp(policy.predexp)
320
320
  field_count += 1 if predexp_size > 0
321
321
 
@@ -335,11 +335,15 @@ module Aerospike
335
335
  mark_compressed(policy)
336
336
  end
337
337
 
338
- def set_scan(policy, namespace, set_name, bin_names, partitions)
338
+ def set_scan(policy, namespace, set_name, bin_names, node_partitions)
339
339
  # Estimate buffer size
340
340
  begin_cmd
341
341
  field_count = 0
342
342
 
343
+ parts_full_size = node_partitions.parts_full.length * 2
344
+ parts_partial_size = node_partitions.parts_partial.length * 20
345
+ max_records = node_partitions.record_max
346
+
343
347
  if namespace
344
348
  @data_offset += namespace.bytesize + FIELD_HEADER_SIZE
345
349
  field_count += 1
@@ -349,7 +353,22 @@ module Aerospike
349
353
  @data_offset += set_name.bytesize + FIELD_HEADER_SIZE
350
354
  field_count += 1
351
355
  end
352
-
356
+
357
+ if parts_full_size > 0
358
+ @data_offset += parts_full_size + FIELD_HEADER_SIZE
359
+ field_count += 1
360
+ end
361
+
362
+ if parts_partial_size > 0
363
+ @data_offset += parts_partial_size + FIELD_HEADER_SIZE
364
+ field_count += 1
365
+ end
366
+
367
+ if max_records > 0
368
+ @data_offset += 8 + FIELD_HEADER_SIZE
369
+ field_count += 1
370
+ end
371
+
353
372
  if policy.records_per_second > 0
354
373
  @data_offset += 4 + FIELD_HEADER_SIZE
355
374
  field_count += 1
@@ -362,9 +381,6 @@ module Aerospike
362
381
  # @data_offset += 2 + FIELD_HEADER_SIZE
363
382
  # field_count += 1
364
383
 
365
- @data_offset += partitions.length * 2 + FIELD_HEADER_SIZE
366
- field_count += 1
367
-
368
384
  # Estimate scan timeout size.
369
385
  @data_offset += 4 + FIELD_HEADER_SIZE
370
386
  field_count += 1
@@ -378,7 +394,7 @@ module Aerospike
378
394
  size_buffer
379
395
  read_attr = INFO1_READ
380
396
 
381
- if !policy.include_bin_data
397
+ unless policy.include_bin_data
382
398
  read_attr |= INFO1_NOBINDATA
383
399
  end
384
400
 
@@ -397,10 +413,26 @@ module Aerospike
397
413
  write_field_string(set_name, Aerospike::FieldType::TABLE)
398
414
  end
399
415
 
400
- write_field_header(partitions.length * 2, Aerospike::FieldType::PID_ARRAY)
401
- for pid in partitions
402
- @data_buffer.write_uint16_little_endian(pid, @data_offset)
403
- @data_offset += 2
416
+ if parts_full_size > 0
417
+ write_field_header(parts_full_size, Aerospike::FieldType::PID_ARRAY)
418
+
419
+ node_partitions.parts_full.each do |part|
420
+ @data_buffer.write_uint16_little_endian(part.id, @data_offset)
421
+ @data_offset+=2
422
+ end
423
+ end
424
+
425
+ if parts_partial_size > 0
426
+ write_field_header(parts_partial_size, Aerospike::FieldType::DIGEST_ARRAY)
427
+
428
+ node_partitions.parts_partial.each do |part|
429
+ @data_buffer.write_binary(part.digest, @data_offset)
430
+ @data_offset+=part.digest.length
431
+ end
432
+ end
433
+
434
+ if max_records > 0
435
+ write_field_int64(max_records, Aerospike::FieldType::MAX_RECORDS)
404
436
  end
405
437
 
406
438
  if policy.records_per_second > 0
@@ -809,6 +841,12 @@ module Aerospike
809
841
  @data_offset += 4
810
842
  end
811
843
 
844
+ def write_field_int64(i, ftype)
845
+ @data_buffer.write_int64(i, @data_offset+FIELD_HEADER_SIZE)
846
+ write_field_header(8, ftype)
847
+ @data_offset += 8
848
+ end
849
+
812
850
  def write_field_bytes(bytes, ftype)
813
851
  @data_buffer.write_binary(bytes, @data_offset+FIELD_HEADER_SIZE)
814
852
  write_field_header(bytes.bytesize, ftype)
@@ -840,12 +878,6 @@ module Aerospike
840
878
  end
841
879
 
842
880
  def size_buffer_sz(size)
843
- # Corrupted data streams can result in a hug.length.
844
- # Do a sanity check here.
845
- if size > Buffer::MAX_BUFFER_SIZE
846
- raise Aerospike::Exceptions::Parse.new("Invalid size for buffer: #{size}")
847
- end
848
-
849
881
  @data_buffer.resize(size)
850
882
  end
851
883
 
@@ -33,6 +33,9 @@ module Aerospike
33
33
  SCAN_TIMEOUT = 9
34
34
  RECORDS_PER_SECOND = 10
35
35
  PID_ARRAY = 11
36
+ DIGEST_ARRAY = 12
37
+ MAX_RECORDS = 13
38
+ BVAL_ARRAY = 15
36
39
  INDEX_NAME = 21
37
40
  INDEX_RANGE = 22
38
41
  INDEX_FILTER = 23
@@ -38,6 +38,7 @@ module Aerospike
38
38
  end
39
39
 
40
40
  def authenticate_new(conn, cluster)
41
+ @data_offset = 8
41
42
  policy = cluster.client_policy
42
43
  case policy.auth_mode
43
44
  when Aerospike::AuthMode::EXTERNAL
@@ -68,7 +69,7 @@ module Aerospike
68
69
 
69
70
  result = @data_buffer.read(RESULT_CODE)
70
71
 
71
- if result != 0
72
+ if result != 0
72
73
  return if result == Aerospike::ResultCode::SECURITY_NOT_ENABLED
73
74
  raise Exceptions::Aerospike.new(result, "Authentication failed")
74
75
  end
@@ -125,12 +126,13 @@ module Aerospike
125
126
  end
126
127
 
127
128
  def authenticate_via_token(conn, cluster)
129
+ @data_offset = 8
128
130
  policy = cluster.client_policy
129
- if policy.auth_mode != Aerospike::AuthMode::PKI
131
+ if policy.auth_mode == Aerospike::AuthMode::PKI
132
+ write_header(AUTHENTICATE, 1)
133
+ else
130
134
  write_header(AUTHENTICATE, 2)
131
135
  write_field_str(USER, policy.user)
132
- else
133
- write_header(AUTHENTICATE, 1)
134
136
  end
135
137
 
136
138
  write_field_bytes(SESSION_TOKEN, cluster.session_token) if cluster.session_token
@@ -144,7 +146,7 @@ module Aerospike
144
146
  receive_size = (size & 0xFFFFFFFFFFFF) - HEADER_REMAINING
145
147
  conn.read(@data_buffer, receive_size)
146
148
 
147
- if result != 0
149
+ if result != 0
148
150
  return if result == Aerospike::ResultCode::SECURITY_NOT_ENABLED
149
151
  raise Exceptions::Aerospike.new(result, "Authentication failed")
150
152
  end
@@ -32,6 +32,9 @@ module Aerospike
32
32
  @compressed_data_buffer = nil
33
33
  @compressed_data_offset = nil
34
34
 
35
+ @node_partitions = nil
36
+ @tracker = nil
37
+
35
38
  self
36
39
  end
37
40
 
@@ -97,8 +100,9 @@ module Aerospike
97
100
 
98
101
  # The only valid server return codes are "ok", "not found" and "filtered out".
99
102
  # If other return codes are received, then abort the batch.
100
- if result_code != 0
103
+ if result_code != 0
101
104
  if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR || result_code == Aerospike::ResultCode::FILTERED_OUT
105
+ # NOOP
102
106
  else
103
107
  raise Aerospike::Exceptions::Aerospike.new(result_code)
104
108
  end
@@ -142,12 +146,14 @@ module Aerospike
142
146
  set_name = @data_buffer.read(1, size).force_encoding('utf-8')
143
147
  when Aerospike::FieldType::KEY
144
148
  user_key = Aerospike::bytes_to_key_value(@data_buffer.read(1).ord, @data_buffer, 2, size-1)
149
+ when Aerospike::FieldType::BVAL_ARRAY
150
+ bval = @data_buffer.read_uint64_little_endian(1)
145
151
  end
146
152
 
147
153
  i = i.succ
148
154
  end
149
155
 
150
- Aerospike::Key.new(namespace, set_name, user_key, digest)
156
+ Aerospike::Key.new(namespace, set_name, user_key, digest, bval: bval)
151
157
  end
152
158
 
153
159
  def skip_key(field_count)