aerospike 2.19.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: 85cdd4e1a2cbb3572cf4c84715a6a43e768e5b8b4b3adc583d45dd41280b9c31
4
- data.tar.gz: faa4ae8908d9fca3798b59053a0753bf9df740ff006d6bdccaf39b45fd4b11d7
3
+ metadata.gz: bed472fc5bda556a4f67f2d6e4e0ee8a82188253b34e0bfab3a0b05be3526d2e
4
+ data.tar.gz: 4a11f36509d86792412e764ef978ec6e27753eab2a96e65353b73786ea383591
5
5
  SHA512:
6
- metadata.gz: 1137414c6f8d465650d88d3169710f4c860ce1938acc24998cbdcd33abed486b238f4ce8a3aee92158a610df99db756311d5aba6617bc464db81268e41529cf6
7
- data.tar.gz: 7f9e276d0d4aab9843312cb3054305a82b4b59691473e869ad1fcefb1eaacb6ee19c46c2bdacd0cc081650b474a426a0dea845c1e678e23967b66ab34294a5ff
6
+ metadata.gz: fa02cbf6bc8e6065e80849e5dcbe71d91550eb549c77af53c761df2e969d7f3135ea3641dcc8af28bd98d5f3e46ab868e61f4e61023c70f0a400e99c93747a00
7
+ data.tar.gz: 47f9d0da4d7099b2e96992012deb79292c4de7d8bbd8fa9ca3a362dc5aa126841887d3eef8f0f0f15e176190a729dde8377f486f3c0ef357b312ab43569b31ce
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
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
+
5
16
  ## [2.19.0] - 2020-02-09
6
17
 
7
18
  * **Improvements**
@@ -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
@@ -230,6 +230,27 @@ module Aerospike
230
230
  batch_read_node(partition, replica_policy)
231
231
  end
232
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
+
233
254
  # Returns a random node on the cluster
234
255
  def random_node
235
256
  # Must copy array reference for copy on write semantics to work.
@@ -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)
@@ -786,6 +797,12 @@ module Aerospike
786
797
  @data_offset += len
787
798
  end
788
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
+
789
806
  def write_field_int(i, ftype)
790
807
  @data_buffer.write_int32(i, @data_offset+FIELD_HEADER_SIZE)
791
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))
@@ -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
@@ -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.19.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.19.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: 2021-02-09 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: []