aerospike 2.16.0 → 2.20.0

Sign up to get free protection for your applications and to get access to all the features.
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: []