aerospike 2.16.0 → 2.20.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71a4730468bf7f38257303515a01945e1221d25f98b35f28d7aa9c0d74e06e3b
4
- data.tar.gz: 1bf1fd2c18697d5e7adda3cc5df5b5fdea7ecd2c7f6c81950c7a4f9dbba06ead
3
+ metadata.gz: bed472fc5bda556a4f67f2d6e4e0ee8a82188253b34e0bfab3a0b05be3526d2e
4
+ data.tar.gz: 4a11f36509d86792412e764ef978ec6e27753eab2a96e65353b73786ea383591
5
5
  SHA512:
6
- metadata.gz: 4aeaddd24ad85bc4178973cfe865410536b8aaa2030486715d1495c380438a7e9b5980a36f953623f9da85b4f6ef497273797baad99e0e1af259faf1a6d64c6a
7
- data.tar.gz: 899f9ff5ddf4be0085dd6783f382278948f9e466778590e939a8f097b91432745001c65b6bf7ed3494056296a1c80ce1bbba5a9a6473b982101a99c839ea1168
6
+ metadata.gz: fa02cbf6bc8e6065e80849e5dcbe71d91550eb549c77af53c761df2e969d7f3135ea3641dcc8af28bd98d5f3e46ab868e61f4e61023c70f0a400e99c93747a00
7
+ data.tar.gz: 47f9d0da4d7099b2e96992012deb79292c4de7d8bbd8fa9ca3a362dc5aa126841887d3eef8f0f0f15e176190a729dde8377f486f3c0ef357b312ab43569b31ce
data/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.20.0] - 2020-11-08
6
+
7
+ Notice: This version of the client only supports Aerospike Server v4.9 and later. Some features will work for the older server versions, but they are not tested, nor officially supported.
8
+
9
+ * **New Features**
10
+ * [CLIENT-1467] Support native Boolean type for server v5.6+.
11
+
12
+ * **Improvements**
13
+ * Add basic support for server v4.9+ scan/queries.
14
+ * Don't check for key equality in Batch command results.
15
+
16
+ ## [2.19.0] - 2020-02-09
17
+
18
+ * **Improvements**
19
+ * Remove Timeout in `wait_till_stabilized` in favor of `thread.join(timeout)` . Thanks to [Marcelo](https://github.com/MarcPer) [[#104](https://github.com/aerospike/aerospike-client-ruby/pull/104)]
20
+ * Adds `ResultCode::LOST_CONFLICT`
21
+
22
+ ## [2.18.0] - 2020-12-01
23
+
24
+ * **Bug Fixes**
25
+ * Avoid panic if `Command#get_node` fails in `Command#execute`. Resolves issue #101.
26
+ * Fix wrong method invocation inside `Client#truncate` method. Thanks to [Alexander](https://github.com/selivandex)
27
+
28
+ * **Improvements**
29
+ * Added missing server error codes.
30
+
31
+ ## [2.17.0] - 2020-10-15
32
+
33
+ * **New Features**
34
+ * [CLIENT-1246] Adds missing API for Context#list_index_create and Context#map_key_create
35
+
36
+ * **Bug Fixes**
37
+ * Fixed an issue were MsgPack extensions were not recursively cleared from the CDTs during unpacking.
38
+
5
39
  ## [2.16.0] - 2020-10-12
6
40
 
7
41
  * **New Features**
@@ -46,7 +80,7 @@ All notable changes to this project will be documented in this file.
46
80
 
47
81
  * **Improvements**
48
82
  * Optimize serialization for nested structures. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#94](https://github.com/aerospike/aerospike-client-ruby/pull/94)]
49
- * Remove `Thread#abort_on_exception` from `batch_index_command`. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#94](https://github.com/aerospike/aerospike-client-ruby/pull/92)]
83
+ * Remove `Thread#abort_on_exception` from `batch_index_command`. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#92](https://github.com/aerospike/aerospike-client-ruby/pull/92)]
50
84
  * Does not allow values other than Integer, Float, String, Symbol and nil to be used as keys in Maps.
51
85
 
52
86
  * **Bug Fixes**
@@ -34,6 +34,12 @@ module Aerospike
34
34
  @value = value
35
35
  end
36
36
 
37
+ ##
38
+ # Create list with given type at index offset, given an order and pad.
39
+ def self.list_index_create(index, order, pad)
40
+ Context.new(0x10 | ListOrder.flag(order, pad), index)
41
+ end
42
+
37
43
  ##
38
44
  # Lookup list by index offset.
39
45
  # If the index is negative, the resolved index starts backwards from end of list.
@@ -90,6 +96,12 @@ module Aerospike
90
96
  Context.new(0x22, key)
91
97
  end
92
98
 
99
+ ##
100
+ # Create map with given type at map key.
101
+ def self.map_key_create(key, order)
102
+ Context.new(0x22 | order[:flag], key)
103
+ end
104
+
93
105
  ##
94
106
  # Lookup map by value.
95
107
  def self.map_value(key)
@@ -84,18 +84,33 @@ module Aerospike
84
84
  REMOVE_BY_RANK_RANGE = 39
85
85
  REMOVE_BY_VALUE_REL_RANK_RANGE = 40
86
86
 
87
- attr_reader :list_op, :arguments, :policy, :return_type, :ctx
87
+ attr_reader :list_op, :arguments, :policy, :return_type, :ctx, :flag
88
88
 
89
- def initialize(op_type, list_op, bin_name, *arguments, return_type: nil, ctx: nil)
89
+ def initialize(op_type, list_op, bin_name, *arguments, return_type: nil, ctx: nil, flag: nil)
90
90
  @op_type = op_type
91
91
  @bin_name = bin_name
92
92
  @bin_value = nil
93
93
  @list_op = list_op
94
94
  @ctx = ctx
95
+ @flag = flag
95
96
  @arguments = arguments
96
97
  @return_type = return_type
97
98
  end
98
99
 
100
+ ##
101
+ # creates list create operation.
102
+ # Server creates list at given context level. The context is allowed to be beyond list
103
+ # boundaries only if pad is set to true. In that case, nil list entries will be inserted to
104
+ # satisfy the context position.
105
+ def self.create(bin_name, order, pad, ctx: nil)
106
+ # If context not defined, the set order for top-level bin list.
107
+ if !ctx || ctx.length == 0
108
+ self.set_order(bin_name, order)
109
+ else
110
+ ListOperation.new(Operation::CDT_MODIFY, SET_TYPE, bin_name, order, ctx: ctx, flag: ListOrder.flag(order, pad))
111
+ end
112
+ end
113
+
99
114
  ##
100
115
  # Create a set list order operation.
101
116
  # Server sets list order.
@@ -504,11 +519,7 @@ module Aerospike
504
519
  packer.write_array_header(3)
505
520
  Value.of(0xff).pack(packer)
506
521
 
507
- packer.write_array_header(@ctx.length*2)
508
- @ctx.each do |ctx|
509
- Value.of(ctx.id).pack(packer)
510
- Value.of(ctx.value).pack(packer)
511
- end
522
+ pack_context(packer)
512
523
 
513
524
  packer.write_array_header(args.length+1)
514
525
  Value.of(@list_op).pack(packer)
@@ -529,6 +540,24 @@ module Aerospike
529
540
  end
530
541
  BytesValue.new(bytes)
531
542
  end
543
+
544
+ def pack_context(packer)
545
+ packer.write_array_header(@ctx.length*2)
546
+ if @flag
547
+ (1...@ctx.length).each do |i|
548
+ Value.of(@ctx[i].id).pack(packer)
549
+ Value.of(@ctx[i].value).pack(packer)
550
+ end
551
+
552
+ Value.of(@ctx[-1].id | @flag).pack(packer)
553
+ Value.of(@ctx[-1].value).pack(packer)
554
+ else
555
+ @ctx.each do |ctx|
556
+ Value.of(ctx.id).pack(packer)
557
+ Value.of(ctx.value).pack(packer)
558
+ end
559
+ end
560
+ end
532
561
  end
533
562
 
534
563
  class InvertibleListOp < ListOperation
@@ -32,6 +32,13 @@ module Aerospike
32
32
  ##
33
33
  # Default order
34
34
  DEFAULT = UNORDERED
35
+
36
+ private
37
+
38
+ def self.flag(attributes, pad)
39
+ (attributes == 1) ? 0xc0 : (pad ? 0x80 : 0x40)
40
+ end
41
+
35
42
  end
36
43
  end
37
44
  end
@@ -96,26 +96,39 @@ module Aerospike
96
96
  GET_BY_KEY_REL_INDEX_RANGE = 109
97
97
  GET_BY_VALUE_REL_RANK_RANGE = 110
98
98
 
99
- attr_reader :map_op, :arguments, :return_type, :ctx
99
+ attr_reader :map_op, :arguments, :return_type, :ctx, :flag
100
100
 
101
- def initialize(op_type, map_op, bin_name, *arguments, ctx: nil, return_type: nil)
101
+ def initialize(op_type, map_op, bin_name, *arguments, ctx: nil, return_type: nil, flag: nil)
102
102
  @op_type = op_type
103
103
  @bin_name = bin_name
104
104
  @bin_value = nil
105
105
  @map_op = map_op
106
106
  @ctx = ctx
107
+ @flag = flag
107
108
  @arguments = arguments
108
109
  @return_type = return_type
109
110
  self
110
111
  end
111
112
 
113
+ ##
114
+ # Creates a map create operation.
115
+ # Server creates map at given context level.
116
+ def self.create(bin_name, order, ctx: nil)
117
+ if !ctx || ctx.length == 0
118
+ # If context not defined, the set order for top-level bin map.
119
+ self.set_policy(MapPolicy.new(order: order, flag: 0), bin_name)
120
+ else
121
+ MapOperation.new(Operation::CDT_MODIFY, SET_TYPE, bin_name, order[:attr], ctx: ctx, flag: order[:flag])
122
+ end
123
+ end
124
+
112
125
  ##
113
126
  # Create set map policy operation.
114
127
  # Server sets map policy attributes. Server returns null.
115
128
  #
116
129
  # The required map policy attributes can be changed after the map is created.
117
130
  def self.set_policy(bin_name, policy, ctx: nil)
118
- MapOperation.new(Operation::CDT_MODIFY, SET_TYPE, bin_name, policy.order, ctx: ctx)
131
+ MapOperation.new(Operation::CDT_MODIFY, SET_TYPE, bin_name, policy.order[:attr], ctx: ctx)
119
132
  end
120
133
 
121
134
  ##
@@ -126,16 +139,16 @@ module Aerospike
126
139
  # The map policy also specifies the flags used when writing items to the map.
127
140
  def self.put(bin_name, key, value, ctx: nil, policy: MapPolicy::DEFAULT)
128
141
  if policy.flags != MapWriteFlags::DEFAULT
129
- MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order, policy.flags, ctx: ctx)
142
+ MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order[:attr], policy.flags, ctx: ctx)
130
143
  else
131
144
  case policy.write_mode
132
145
  when MapWriteMode::UPDATE_ONLY
133
146
  # Replace doesn't allow map order because it does not create on non-existing key.
134
147
  MapOperation.new(Operation::CDT_MODIFY, REPLACE, bin_name, key, value, ctx: ctx)
135
148
  when MapWriteMode::CREATE_ONLY
136
- MapOperation.new(Operation::CDT_MODIFY, ADD, bin_name, key, value, policy.order, ctx: ctx)
149
+ MapOperation.new(Operation::CDT_MODIFY, ADD, bin_name, key, value, policy.order[:attr], ctx: ctx)
137
150
  else
138
- MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order, ctx: ctx)
151
+ MapOperation.new(Operation::CDT_MODIFY, PUT, bin_name, key, value, policy.order[:attr], ctx: ctx)
139
152
  end
140
153
  end
141
154
  end
@@ -148,16 +161,16 @@ module Aerospike
148
161
  # The map policy also specifies the flags used when writing items to the map.
149
162
  def self.put_items(bin_name, values, ctx: nil, policy: MapPolicy::DEFAULT)
150
163
  if policy.flags != MapWriteFlags::DEFAULT
151
- MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order, policy.flags, ctx: ctx)
164
+ MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order[:attr], policy.flags, ctx: ctx)
152
165
  else
153
166
  case policy.write_mode
154
167
  when MapWriteMode::UPDATE_ONLY
155
168
  # Replace doesn't allow map order because it does not create on non-existing key.
156
169
  MapOperation.new(Operation::CDT_MODIFY, REPLACE_ITEMS, bin_name, values, ctx: ctx)
157
170
  when MapWriteMode::CREATE_ONLY
158
- MapOperation.new(Operation::CDT_MODIFY, ADD_ITEMS, bin_name, values, policy.order, ctx: ctx)
171
+ MapOperation.new(Operation::CDT_MODIFY, ADD_ITEMS, bin_name, values, policy.order[:attr], ctx: ctx)
159
172
  else
160
- MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order, ctx: ctx)
173
+ MapOperation.new(Operation::CDT_MODIFY, PUT_ITEMS, bin_name, values, policy.order[:attr], ctx: ctx)
161
174
  end
162
175
  end
163
176
  end
@@ -170,7 +183,7 @@ module Aerospike
170
183
  # The map policy dictates the type of map to create when it does not exist.
171
184
  # The map policy also specifies the mode used when writing items to the map.
172
185
  def self.increment(bin_name, key, incr, ctx: nil, policy: MapPolicy::DEFAULT)
173
- MapOperation.new(Operation::CDT_MODIFY, INCREMENT, bin_name, key, incr, policy.order, ctx: ctx)
186
+ MapOperation.new(Operation::CDT_MODIFY, INCREMENT, bin_name, key, incr, policy.order[:attr], ctx: ctx)
174
187
  end
175
188
 
176
189
  ##
@@ -181,7 +194,7 @@ module Aerospike
181
194
  # The map policy dictates the type of map to create when it does not exist.
182
195
  # The map policy also specifies the mode used when writing items to the map.
183
196
  def self.decrement(bin_name, key, decr, ctx: nil, policy: MapPolicy::DEFAULT)
184
- MapOperation.new(Operation::CDT_MODIFY, DECREMENT, bin_name, key, decr, policy.order, ctx: ctx)
197
+ MapOperation.new(Operation::CDT_MODIFY, DECREMENT, bin_name, key, decr, policy.order[:attr], ctx: ctx)
185
198
  end
186
199
 
187
200
  ##
@@ -626,11 +639,7 @@ module Aerospike
626
639
  packer.write_array_header(3)
627
640
  Value.of(0xff).pack(packer)
628
641
 
629
- packer.write_array_header(@ctx.length*2)
630
- @ctx.each do |ctx|
631
- Value.of(ctx.id).pack(packer)
632
- Value.of(ctx.value).pack(packer)
633
- end
642
+ pack_context(packer)
634
643
 
635
644
  packer.write_array_header(args.length+1)
636
645
  Value.of(@map_op).pack(packer)
@@ -651,6 +660,23 @@ module Aerospike
651
660
  BytesValue.new(bytes)
652
661
  end
653
662
 
663
+ def pack_context(packer)
664
+ packer.write_array_header(@ctx.length*2)
665
+ if @flag
666
+ (1...@ctx.length).each do |i|
667
+ Value.of(@ctx[i].id).pack(packer)
668
+ Value.of(@ctx[i].value).pack(packer)
669
+ end
670
+
671
+ Value.of(@ctx[-1].id | @flag).pack(packer)
672
+ Value.of(@ctx[-1].value).pack(packer)
673
+ else
674
+ @ctx.each do |ctx|
675
+ Value.of(ctx.id).pack(packer)
676
+ Value.of(ctx.value).pack(packer)
677
+ end
678
+ end
679
+ end
654
680
  end
655
681
 
656
682
  end
@@ -20,15 +20,15 @@ module Aerospike
20
20
 
21
21
  ##
22
22
  # Map is not ordered. This is the default.
23
- UNORDERED = 0
23
+ UNORDERED = {attr: 0, flag: 0x40}
24
24
 
25
25
  ##
26
26
  # Order map by key.
27
- KEY_ORDERED = 1
27
+ KEY_ORDERED = {attr: 1, flag: 0x80}
28
28
 
29
29
  ##
30
30
  # Order map by key, then value.
31
- KEY_VALUE_ORDERED = 3
31
+ KEY_VALUE_ORDERED = {attr: 3, flag: 0xc0}
32
32
 
33
33
  ##
34
34
  # Default order
@@ -233,7 +233,7 @@ module Aerospike
233
233
  str_cmd = "truncate:namespace=#{namespace}"
234
234
  str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
235
235
  else
236
- if node.supports_feature(Aerospike::Features::TRUNCATE_NAMESPACE)
236
+ if node.supports_feature?(Aerospike::Features::TRUNCATE_NAMESPACE)
237
237
  str_cmd = "truncate-namespace:namespace=#{namespace}"
238
238
  else
239
239
  str_cmd = "truncate:namespace=#{namespace}"
@@ -543,10 +543,11 @@ module Aerospike
543
543
 
544
544
  # Use a thread per node
545
545
  nodes.each do |node|
546
+ partitions = node.cluster.node_partitions(node, statement.namespace)
546
547
  Thread.new do
547
548
  Thread.current.abort_on_exception = true
548
549
  begin
549
- command = QueryCommand.new(node, policy, statement, nil)
550
+ command = QueryCommand.new(node, policy, statement, nil, partitions)
550
551
  execute_command(command)
551
552
  rescue => e
552
553
  Aerospike.logger.error(e)
@@ -644,9 +645,10 @@ module Aerospike
644
645
  if policy.concurrent_nodes
645
646
  # Use a thread per node
646
647
  nodes.each do |node|
648
+ partitions = node.cluster.node_partitions(node, namespace)
647
649
  Thread.new do
648
650
  Thread.current.abort_on_exception = true
649
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
651
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
650
652
  begin
651
653
  execute_command(command)
652
654
  rescue => e
@@ -661,7 +663,8 @@ module Aerospike
661
663
  Thread.new do
662
664
  Thread.current.abort_on_exception = true
663
665
  nodes.each do |node|
664
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
666
+ partitions = node.cluster.node_partitions(node, namespace)
667
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
665
668
  begin
666
669
  execute_command(command)
667
670
  rescue => e
@@ -694,9 +697,10 @@ module Aerospike
694
697
 
695
698
  recordset = Recordset.new(policy.record_queue_size, 1, :scan)
696
699
 
700
+ partitions = node.cluster.node_partitions(node, namespace)
697
701
  Thread.new do
698
702
  Thread.current.abort_on_exception = true
699
- command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
703
+ command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset, partitions)
700
704
  begin
701
705
  execute_command(command)
702
706
  rescue => e
@@ -734,9 +738,10 @@ module Aerospike
734
738
 
735
739
  # Use a thread per node
736
740
  nodes.each do |node|
741
+ partitions = node.cluster.node_partitions(node, statement.namespace)
737
742
  Thread.new do
738
743
  Thread.current.abort_on_exception = true
739
- command = QueryCommand.new(node, new_policy, statement, recordset)
744
+ command = QueryCommand.new(node, new_policy, statement, recordset, partitions)
740
745
  begin
741
746
  execute_command(command)
742
747
  rescue => e
@@ -18,7 +18,6 @@
18
18
  # the License.
19
19
 
20
20
  require 'set'
21
- require 'timeout'
22
21
 
23
22
  require 'aerospike/atomic/atomic'
24
23
 
@@ -231,6 +230,27 @@ module Aerospike
231
230
  batch_read_node(partition, replica_policy)
232
231
  end
233
232
 
233
+ # Returns partitions pertaining to a node
234
+ def node_partitions(node, namespace)
235
+ res = []
236
+
237
+ partition_map = partitions
238
+ replica_array = partition_map[namespace]
239
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
240
+
241
+ node_array = (replica_array.get)[0]
242
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !node_array
243
+
244
+
245
+ pid = 0
246
+ for tnode in node_array.get
247
+ res << pid if node == tnode
248
+ pid+=1
249
+ end
250
+
251
+ res
252
+ end
253
+
234
254
  # Returns a random node on the cluster
235
255
  def random_node
236
256
  # Must copy array reference for copy on write semantics to work.
@@ -428,6 +448,7 @@ module Aerospike
428
448
 
429
449
  def wait_till_stablized
430
450
  count = -1
451
+ done = false
431
452
 
432
453
  # will run until the cluster is stablized
433
454
  thr = Thread.new do
@@ -438,20 +459,20 @@ module Aerospike
438
459
  # If not, assume cluster has stabilized and return.
439
460
  break if count == nodes.length
440
461
 
441
- sleep(0.001) # sleep for a miliseconds
462
+ # Break if timed out
463
+ break if done
464
+
465
+ sleep(0.001) # sleep for a milisecond
442
466
 
443
467
  count = nodes.length
444
468
  end
445
469
  end
446
470
 
447
471
  # wait for the thread to finish or timeout
448
- begin
449
- Timeout.timeout(@connection_timeout) do
450
- thr.join
451
- end
452
- rescue Timeout::Error
453
- thr.kill if thr.alive?
454
- end
472
+ thr.join(@connection_timeout)
473
+ done = true
474
+ sleep(0.001)
475
+ thr.kill if thr.alive?
455
476
 
456
477
  @closed.value = false if @cluster_nodes.length > 0
457
478
  end
@@ -110,16 +110,12 @@ module Aerospike
110
110
  field_count = @data_buffer.read_int16(18)
111
111
  op_count = @data_buffer.read_int16(20)
112
112
 
113
- key = parse_key(field_count)
113
+ skip_key(field_count)
114
114
  req_key = batch.key_for_index(batch_index)
115
115
 
116
- if key.digest == req_key.digest
117
- if result_code == 0
118
- record = parse_record(req_key, op_count, generation, expiration)
119
- results[batch_index] = record
120
- end
121
- else
122
- Aerospike.logger.warn("Unexpected batch key returned: #{key}")
116
+ if result_code == 0
117
+ record = parse_record(req_key, op_count, generation, expiration)
118
+ results[batch_index] = record
123
119
  end
124
120
  end
125
121
 
@@ -36,7 +36,7 @@ module Aerospike
36
36
  raise Aerospike::Exceptions::Parse.new('Received bins that were not requested!')
37
37
  end
38
38
 
39
- parse_key(field_count)
39
+ skip_key(field_count)
40
40
  results[batch_index] = (result_code == 0)
41
41
  end
42
42
 
@@ -66,6 +66,8 @@ module Aerospike
66
66
  INFO3_LAST = Integer(1 << 0)
67
67
  # Commit to master only before declaring success.
68
68
  INFO3_COMMIT_MASTER = Integer(1 << 1)
69
+ # Partition is complete response in scan.
70
+ INFO3_PARTITION_DONE = Integer(1 << 2)
69
71
  # Update only. Merge bins.
70
72
  INFO3_UPDATE_ONLY = Integer(1 << 3)
71
73
 
@@ -333,7 +335,7 @@ module Aerospike
333
335
  mark_compressed(policy)
334
336
  end
335
337
 
336
- def set_scan(policy, namespace, set_name, bin_names)
338
+ def set_scan(policy, namespace, set_name, bin_names, partitions)
337
339
  # Estimate buffer size
338
340
  begin_cmd
339
341
  field_count = 0
@@ -357,7 +359,10 @@ module Aerospike
357
359
  field_count += 1 if predexp_size > 0
358
360
 
359
361
  # Estimate scan options size.
360
- @data_offset += 2 + FIELD_HEADER_SIZE
362
+ # @data_offset += 2 + FIELD_HEADER_SIZE
363
+ # field_count += 1
364
+
365
+ @data_offset += partitions.length * 2 + FIELD_HEADER_SIZE
361
366
  field_count += 1
362
367
 
363
368
  # Estimate scan timeout size.
@@ -392,24 +397,30 @@ module Aerospike
392
397
  write_field_string(set_name, Aerospike::FieldType::TABLE)
393
398
  end
394
399
 
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
404
+ end
405
+
395
406
  if policy.records_per_second > 0
396
407
  write_field_int(policy.records_per_second, Aerospike::FieldType::RECORDS_PER_SECOND)
397
408
  end
398
409
 
399
410
  write_predexp(policy.predexp, predexp_size)
400
411
 
401
- write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
412
+ # write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
402
413
 
403
- priority = policy.priority & 0xFF
404
- priority <<= 4
405
- if policy.fail_on_cluster_change
406
- priority |= 0x08
407
- end
414
+ # priority = policy.priority & 0xFF
415
+ # priority <<= 4
416
+ # if policy.fail_on_cluster_change
417
+ # priority |= 0x08
418
+ # end
408
419
 
409
- @data_buffer.write_byte(priority, @data_offset)
410
- @data_offset += 1
411
- @data_buffer.write_byte(policy.scan_percent.to_i.ord, @data_offset)
412
- @data_offset += 1
420
+ # @data_buffer.write_byte(priority, @data_offset)
421
+ # @data_offset += 1
422
+ # @data_buffer.write_byte(policy.scan_percent.to_i.ord, @data_offset)
423
+ # @data_offset += 1
413
424
 
414
425
  write_field_header(4, Aerospike::FieldType::SCAN_TIMEOUT)
415
426
  @data_buffer.write_uint32(policy.socket_timeout.to_i, @data_offset)
@@ -446,10 +457,14 @@ module Aerospike
446
457
  @node = get_node
447
458
  @conn = @node.get_connection(@policy.timeout)
448
459
  rescue => e
449
- # Socket connection error has occurred. Decrease health and retry.
450
- @node.decrease_health
460
+ if @node
461
+ # Socket connection error has occurred. Decrease health and retry.
462
+ @node.decrease_health
451
463
 
452
- Aerospike.logger.error("Node #{@node.to_s}: #{e}")
464
+ Aerospike.logger.error("Node #{@node.to_s}: #{e}")
465
+ else
466
+ Aerospike.logger.error("No node available for transaction: #{e}")
467
+ end
453
468
  next
454
469
  end
455
470
 
@@ -782,6 +797,12 @@ module Aerospike
782
797
  @data_offset += len
783
798
  end
784
799
 
800
+ def write_u16_little_endian(i, ftype)
801
+ @data_buffer.write_uint16_little_endian(i, @data_offset+FIELD_HEADER_SIZE)
802
+ write_field_header(2, ftype)
803
+ @data_offset += 2
804
+ end
805
+
785
806
  def write_field_int(i, ftype)
786
807
  @data_buffer.write_int32(i, @data_offset+FIELD_HEADER_SIZE)
787
808
  write_field_header(4, ftype)
@@ -32,6 +32,7 @@ module Aerospike
32
32
  SCAN_OPTIONS = 8
33
33
  SCAN_TIMEOUT = 9
34
34
  RECORDS_PER_SECOND = 10
35
+ PID_ARRAY = 11
35
36
  INDEX_NAME = 21
36
37
  INDEX_RANGE = 22
37
38
  INDEX_FILTER = 23
@@ -150,6 +150,23 @@ module Aerospike
150
150
  Aerospike::Key.new(namespace, set_name, user_key, digest)
151
151
  end
152
152
 
153
+ def skip_key(field_count)
154
+ # in Stream queries, there are no keys
155
+ return unless field_count > 0
156
+
157
+ i = 0
158
+ while i < field_count
159
+ read_bytes(4)
160
+
161
+ fieldlen = @data_buffer.read_int32(0)
162
+ read_bytes(fieldlen)
163
+
164
+ i = i.succ
165
+ end
166
+
167
+ nil
168
+ end
169
+
153
170
  # Parses the given byte buffer and populate the result object.
154
171
  # Returns the number of bytes that were parsed from the given buffer.
155
172
  def parse_record(key, op_count, generation, expiration)
@@ -23,12 +23,13 @@ module Aerospike
23
23
 
24
24
  class QueryCommand < StreamCommand #:nodoc:
25
25
 
26
- def initialize(node, policy, statement, recordset)
26
+ def initialize(node, policy, statement, recordset, partitions)
27
27
  super(node)
28
28
 
29
29
  @policy = policy
30
30
  @statement = statement
31
31
  @recordset = recordset
32
+ @partitions = partitions
32
33
  end
33
34
 
34
35
  def write_buffer
@@ -81,7 +82,10 @@ module Aerospike
81
82
  @data_offset += binNameSize
82
83
  fieldCount+=1
83
84
  end
84
- else
85
+ else
86
+ @data_offset += @partitions.length * 2 + FIELD_HEADER_SIZE
87
+ fieldCount += 1
88
+
85
89
  if @policy.records_per_second > 0
86
90
  @data_offset += 4 + FIELD_HEADER_SIZE
87
91
  fieldCount += 1
@@ -89,8 +93,8 @@ module Aerospike
89
93
 
90
94
  # Calling query with no filters is more efficiently handled by a primary index scan.
91
95
  # Estimate scan options size.
92
- @data_offset += (2 + FIELD_HEADER_SIZE)
93
- fieldCount+=1
96
+ # @data_offset += (2 + FIELD_HEADER_SIZE)
97
+ # fieldCount+=1
94
98
  end
95
99
 
96
100
  @statement.set_task_id
@@ -177,18 +181,24 @@ module Aerospike
177
181
  end
178
182
  end
179
183
  else
184
+ write_field_header(@partitions.length * 2, Aerospike::FieldType::PID_ARRAY)
185
+ for pid in @partitions
186
+ @data_buffer.write_uint16_little_endian(pid, @data_offset)
187
+ @data_offset += 2
188
+ end
189
+
180
190
  if @policy.records_per_second > 0
181
191
  write_field_int(@policy.records_per_second, Aerospike::FieldType::RECORDS_PER_SECOND)
182
192
  end
183
193
 
184
194
  # Calling query with no filters is more efficiently handled by a primary index scan.
185
- write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
186
- priority = @policy.priority.ord
187
- priority = priority << 4
188
- @data_buffer.write_byte(priority, @data_offset)
189
- @data_offset+=1
190
- @data_buffer.write_byte(100.ord, @data_offset)
191
- @data_offset+=1
195
+ # write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
196
+ # priority = @policy.priority.ord
197
+ # priority = priority << 4
198
+ # @data_buffer.write_byte(priority, @data_offset)
199
+ # @data_offset+=1
200
+ # @data_buffer.write_byte(100.ord, @data_offset)
201
+ # @data_offset+=1
192
202
  end
193
203
 
194
204
  write_field_header(8, Aerospike::FieldType::TRAN_ID)
@@ -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, 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
+ @partitions = 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, @partitions)
38
39
  end
39
40
 
40
41
  end # class
@@ -58,6 +58,9 @@ module Aerospike
58
58
  op_count = @data_buffer.read_int16(20)
59
59
  key = parse_key(field_count)
60
60
 
61
+ # If cmd is the end marker of the response, do not proceed further
62
+ return true if (info3 & INFO3_PARTITION_DONE) != 0
63
+
61
64
  if result_code == 0
62
65
  if @recordset.active?
63
66
  @recordset.records.enq(parse_record(key, op_count, generation, expiration))
@@ -129,11 +129,19 @@ module Aerospike
129
129
  # The transaction was not performed because the predexp was false.
130
130
  FILTERED_OUT = 27
131
131
 
132
+ # Write command loses conflict to XDR.
133
+ LOST_CONFLICT = 28
134
+
132
135
  # There are no more records left for query.
133
136
  QUERY_END = 50
134
137
 
138
+ # Security functionality not supported by connected server.
135
139
  SECURITY_NOT_SUPPORTED = 51
140
+
141
+ # Security functionality not enabled by connected server.
136
142
  SECURITY_NOT_ENABLED = 52
143
+
144
+ # Security scheme not supported.
137
145
  SECURITY_SCHEME_NOT_SUPPORTED = 53
138
146
 
139
147
  # Administration command is invalid.
@@ -162,6 +170,9 @@ module Aerospike
162
170
  # Security credential is invalid.
163
171
  INVALID_CREDENTIAL = 65
164
172
 
173
+ # Expired session token.
174
+ EXPIRED_SESSION = 66
175
+
165
176
  # Role name is invalid.
166
177
  INVALID_ROLE = 70
167
178
 
@@ -171,15 +182,48 @@ module Aerospike
171
182
  # Privilege is invalid.
172
183
  INVALID_PRIVILEGE = 72
173
184
 
185
+ # Specified IP whitelist is invalid.
186
+ INVALID_WHITELIST = 73
187
+
174
188
  # User must be authentication before performing database operations.
175
189
  NOT_AUTHENTICATED = 80
176
190
 
177
191
  # User does not posses the required role to perform the database operation.
178
192
  ROLE_VIOLATION = 81
179
193
 
194
+ # Client IP address is not on the IP whitelist.
195
+ NOT_WHITELISTED = 82
196
+
197
+ # LDAP feature not enabled on server.
198
+ LDAP_NOT_ENABLED = 90
199
+
200
+ # Error in LDAP setup.
201
+ LDAP_SETUP = 91
202
+
203
+ # Error in LDAP TLS setup.
204
+ LDAP_TLS_SETUP = 92
205
+
206
+ # Error authenticating LDAP user.
207
+ LDAP_AUTHENTICATION = 93
208
+
209
+ # Error querying LDAP server.
210
+ LDAP_QUERY = 94
211
+
180
212
  # A user defined function returned an error code.
181
213
  UDF_BAD_RESPONSE = 100
182
214
 
215
+ # Batch functionality has been disabled by configuring the batch-index-thread=0.
216
+ BATCH_DISABLED = 150
217
+
218
+ # Batch max requests has been exceeded.
219
+ BATCH_MAX_REQUESTS = 151
220
+
221
+ # All batch queues are full.
222
+ BATCH_QUEUES_FULL = 152
223
+
224
+ # GeoJSON is malformed or not supported.
225
+ INVALID_GEOJSON = 160
226
+
183
227
  # Secondary index already exists.
184
228
  INDEX_FOUND = 200
185
229
 
@@ -213,6 +257,12 @@ module Aerospike
213
257
  # Generic query error.
214
258
  QUERY_GENERIC = 213
215
259
 
260
+ # Network error. Query is aborted.
261
+ QUERY_NET_IO = 214
262
+
263
+ # Internal error.
264
+ QUERY_DUPLICATE = 215
265
+
216
266
  def self.message(code)
217
267
  case code
218
268
  when COMMAND_REJECTED
@@ -317,6 +367,9 @@ module Aerospike
317
367
  when FILTERED_OUT
318
368
  "The transaction was not performed because the predexp was false."
319
369
 
370
+ when LOST_CONFLICT
371
+ "Write command loses conflict to XDR."
372
+
320
373
  when QUERY_END
321
374
  "Query end"
322
375
 
@@ -356,6 +409,9 @@ module Aerospike
356
409
  when INVALID_CREDENTIAL
357
410
  "Invalid credential"
358
411
 
412
+ when EXPIRED_SESSION
413
+ "Expired session token"
414
+
359
415
  when INVALID_ROLE
360
416
  "Invalid role"
361
417
 
@@ -365,15 +421,48 @@ module Aerospike
365
421
  when INVALID_PRIVILEGE
366
422
  "Invalid privilege"
367
423
 
424
+ when INVALID_WHITELIST
425
+ "Specified IP whitelist is invalid"
426
+
368
427
  when NOT_AUTHENTICATED
369
428
  "Not authenticated"
370
429
 
371
430
  when ROLE_VIOLATION
372
431
  "Role violation"
373
432
 
433
+ when NOT_WHITELISTED
434
+ "Client IP address is not on the IP whitelist"
435
+
436
+ when LDAP_NOT_ENABLED
437
+ "LDAP feature not enabled on server"
438
+
439
+ when LDAP_SETUP
440
+ "Error in LDAP setup"
441
+
442
+ when LDAP_TLS_SETUP
443
+ "Error in LDAP TLS setup"
444
+
445
+ when LDAP_AUTHENTICATION
446
+ "Error authenticating LDAP user"
447
+
448
+ when LDAP_QUERY
449
+ "Error querying LDAP server"
450
+
374
451
  when UDF_BAD_RESPONSE
375
452
  "UDF d error"
376
453
 
454
+ when BATCH_DISABLED
455
+ "Batch functionality has been disabled by configuring the batch-index-thread=0"
456
+
457
+ when BATCH_MAX_REQUESTS
458
+ "Batch max requests has been exceeded"
459
+
460
+ when BATCH_QUEUES_FULL
461
+ "All batch queues are full"
462
+
463
+ when INVALID_GEOJSON
464
+ "GeoJSON is malformed or not supported"
465
+
377
466
  when INDEX_FOUND
378
467
  "Index already exists"
379
468
 
@@ -407,6 +496,12 @@ module Aerospike
407
496
  when QUERY_GENERIC
408
497
  "Query error"
409
498
 
499
+ when QUERY_NET_IO
500
+ "Network error. Query is aborted"
501
+
502
+ when QUERY_DUPLICATE
503
+ "Internal query error"
504
+
410
505
  else
411
506
  "ResultCode #{code} unknown in the client. Please file a github issue."
412
507
  end # case
@@ -33,6 +33,7 @@ module Aerospike
33
33
 
34
34
  INT16 = 's>'
35
35
  UINT16 = 'n'
36
+ UINT16LE = 'v'
36
37
  INT32 = 'l>'
37
38
  UINT32 = 'N'
38
39
  INT64 = 'q>'
@@ -92,6 +93,11 @@ module Aerospike
92
93
  2
93
94
  end
94
95
 
96
+ def write_uint16_little_endian(i, offset)
97
+ @buf[offset, 2] = [i].pack(UINT16LE)
98
+ 2
99
+ end
100
+
95
101
  def write_int32(i, offset)
96
102
  @buf[offset, 4] = [i].pack(INT32)
97
103
  4
@@ -156,6 +162,10 @@ module Aerospike
156
162
  vals.unpack(DOUBLE)[0]
157
163
  end
158
164
 
165
+ def read_bool(offset, length)
166
+ length <= 0 ? false : @buf[offset].ord != 0
167
+ end
168
+
159
169
  def to_s
160
170
  @buf[0..@slice_end-1]
161
171
  end
@@ -92,9 +92,9 @@ module Aerospike
92
92
  end
93
93
  value
94
94
  when Array
95
- normalize_strings_in_array(elem)
95
+ unpack_list(elem)
96
96
  when Hash
97
- normalize_strings_in_map(elem)
97
+ unpack_map(elem)
98
98
  else
99
99
  elem
100
100
  end
@@ -23,19 +23,8 @@ module Aerospike
23
23
  DOUBLE = 2
24
24
  STRING = 3
25
25
  BLOB = 4
26
- #TIMESTAMP = 5
27
- #DIGEST = 6
28
- #JBLOB = 7
29
- #CSHARP_BLOB = 8
30
- #PYTHON_BLOB = 9
31
26
  RUBY_BLOB = 10
32
- #PHP_BLOB = 11
33
- #ERLANG_BLOB = 12
34
- #SEGMENT_POINTER = 13
35
- #RTA_LIST = 14
36
- #RTA_DICT = 15
37
- #RTA_APPEND_DICT = 16
38
- #RTA_APPEND_LIST = 17
27
+ BOOL = 17
39
28
  HLL = 18
40
29
  MAP = 19
41
30
  LIST = 20
@@ -606,6 +606,9 @@ module Aerospike
606
606
  when Aerospike::ParticleType::DOUBLE
607
607
  buf.read_double(offset)
608
608
 
609
+ when Aerospike::ParticleType::BOOL
610
+ buf.read_bool(offset, length)
611
+
609
612
  when Aerospike::ParticleType::BLOB
610
613
  buf.read(offset,length)
611
614
 
@@ -658,7 +661,7 @@ module Aerospike
658
661
  #######################################
659
662
 
660
663
  # Boolean value.
661
- # This is private, and only used internally for bitwise CDTs
664
+ # Supported by Aerospike server 5.6+ only.
662
665
  class BoolValue < Value #:nodoc:
663
666
 
664
667
  def initialize(val)
@@ -671,7 +674,9 @@ module Aerospike
671
674
  end
672
675
 
673
676
  def write(buffer, offset)
674
- raise Exception.new("Unreachable")
677
+ val = @value ? 1 : 0
678
+ buffer.write_byte(val.ord, offset)
679
+ 1
675
680
  end
676
681
 
677
682
  def pack(packer)
@@ -679,7 +684,7 @@ module Aerospike
679
684
  end
680
685
 
681
686
  def type
682
- raise Exception.new("Unreachable")
687
+ Aerospike::ParticleType::BOOL
683
688
  end
684
689
 
685
690
  def get
@@ -687,7 +692,7 @@ module Aerospike
687
692
  end
688
693
 
689
694
  def to_bytes
690
- raise Exception.new("Unreachable")
695
+ @value.ord
691
696
  end
692
697
 
693
698
  def to_s
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Aerospike
3
- VERSION = "2.16.0"
3
+ VERSION = "2.20.0"
4
4
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aerospike
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.16.0
4
+ version: 2.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Khosrow Afroozeh
8
8
  - Jan Hecking
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-10-12 00:00:00.000000000 Z
12
+ date: 2021-11-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack
@@ -210,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
210
210
  version: '0'
211
211
  requirements: []
212
212
  rubygems_version: 3.1.2
213
- signing_key:
213
+ signing_key:
214
214
  specification_version: 4
215
215
  summary: An Aerospike driver for Ruby.
216
216
  test_files: []