aerospike 2.14.0 → 2.19.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.
@@ -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
@@ -44,6 +44,7 @@ module Aerospike
44
44
  attr_accessor :default_read_policy
45
45
  attr_accessor :default_scan_policy
46
46
  attr_accessor :default_write_policy
47
+ attr_accessor :default_operate_policy
47
48
  attr_accessor :cluster
48
49
 
49
50
  def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
@@ -232,7 +233,7 @@ module Aerospike
232
233
  str_cmd = "truncate:namespace=#{namespace}"
233
234
  str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
234
235
  else
235
- if node.supports_feature(Aerospike::Features::TRUNCATE_NAMESPACE)
236
+ if node.supports_feature?(Aerospike::Features::TRUNCATE_NAMESPACE)
236
237
  str_cmd = "truncate-namespace:namespace=#{namespace}"
237
238
  else
238
239
  str_cmd = "truncate:namespace=#{namespace}"
@@ -383,7 +384,7 @@ module Aerospike
383
384
  # read the result, all in one database call. Operations are executed in
384
385
  # the order they are specified.
385
386
  def operate(key, operations, options = nil)
386
- policy = create_policy(options, WritePolicy, default_write_policy)
387
+ policy = create_policy(options, OperatePolicy, default_operate_policy)
387
388
 
388
389
  command = OperateCommand.new(@cluster, policy, key, operations)
389
390
  execute_command(command)
@@ -827,6 +828,7 @@ module Aerospike
827
828
  self.default_query_policy = create_policy(policies[:query], QueryPolicy)
828
829
  self.default_scan_policy = create_policy(policies[:scan], ScanPolicy)
829
830
  self.default_write_policy = create_policy(policies[:write], WritePolicy)
831
+ self.default_operate_policy = create_policy(policies[:operate], OperatePolicy)
830
832
  end
831
833
 
832
834
  def send_info_command(policy, command, node = nil)
@@ -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
 
@@ -428,6 +427,7 @@ module Aerospike
428
427
 
429
428
  def wait_till_stablized
430
429
  count = -1
430
+ done = false
431
431
 
432
432
  # will run until the cluster is stablized
433
433
  thr = Thread.new do
@@ -438,20 +438,20 @@ module Aerospike
438
438
  # If not, assume cluster has stabilized and return.
439
439
  break if count == nodes.length
440
440
 
441
- sleep(0.001) # sleep for a miliseconds
441
+ # Break if timed out
442
+ break if done
443
+
444
+ sleep(0.001) # sleep for a milisecond
442
445
 
443
446
  count = nodes.length
444
447
  end
445
448
  end
446
449
 
447
450
  # 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
451
+ thr.join(@connection_timeout)
452
+ done = true
453
+ sleep(0.001)
454
+ thr.kill if thr.alive?
455
455
 
456
456
  @closed.value = false if @cluster_nodes.length > 0
457
457
  end
@@ -59,6 +59,9 @@ module Aerospike
59
59
  # Create only. Fail if record already exists.
60
60
  INFO2_CREATE_ONLY = Integer(1 << 5)
61
61
 
62
+ # Return a result for every operation.
63
+ INFO2_RESPOND_ALL_OPS = Integer(1 << 7)
64
+
62
65
  # This is the last of a multi-part message.
63
66
  INFO3_LAST = Integer(1 << 0)
64
67
  # Commit to master only before declaring success.
@@ -254,10 +257,12 @@ module Aerospike
254
257
  read_attr = 0
255
258
  write_attr = 0
256
259
  read_header = false
260
+ record_bin_multiplicity = policy.record_bin_multiplicity == RecordBinMultiplicity::ARRAY
257
261
 
258
262
  operations.each do |operation|
259
263
  case operation.op_type
260
- when Aerospike::Operation::READ
264
+ when Aerospike::Operation::READ, Aerospike::Operation::CDT_READ,
265
+ Aerospike::Operation::HLL_READ, Aerospike::Operation::BIT_READ
261
266
  read_attr |= INFO1_READ
262
267
 
263
268
  # Read all bins if no bin is specified.
@@ -271,17 +276,22 @@ module Aerospike
271
276
  read_attr |= INFO1_READ
272
277
  read_header = true
273
278
 
274
- when Aerospike::Operation::CDT_READ
275
- read_attr |= INFO1_READ
276
-
277
279
  else
278
280
  write_attr = INFO2_WRITE
279
281
  end
280
282
 
283
+ if [Aerospike::Operation::HLL_MODIFY, Aerospike::Operation::HLL_READ,
284
+ Aerospike::Operation::BIT_MODIFY, Aerospike::Operation::BIT_READ].include?(operation.op_type)
285
+ record_bin_multiplicity = true
286
+ end
287
+
281
288
  estimate_operation_size_for_operation(operation)
282
289
  end
283
290
  size_buffer
284
291
 
292
+
293
+ write_attr |= INFO2_RESPOND_ALL_OPS if write_attr != 0 && record_bin_multiplicity
294
+
285
295
  if write_attr != 0
286
296
  write_header_with_policy(policy, read_attr, write_attr, field_count, operations.length)
287
297
  else
@@ -436,10 +446,14 @@ module Aerospike
436
446
  @node = get_node
437
447
  @conn = @node.get_connection(@policy.timeout)
438
448
  rescue => e
439
- # Socket connection error has occurred. Decrease health and retry.
440
- @node.decrease_health
449
+ if @node
450
+ # Socket connection error has occurred. Decrease health and retry.
451
+ @node.decrease_health
441
452
 
442
- Aerospike.logger.error("Node #{@node.to_s}: #{e}")
453
+ Aerospike.logger.error("Node #{@node.to_s}: #{e}")
454
+ else
455
+ Aerospike.logger.error("No node available for transaction: #{e}")
456
+ end
443
457
  next
444
458
  end
445
459
 
@@ -42,5 +42,8 @@ module Aerospike
42
42
 
43
43
  # Server supports the "truncate-namespace" command
44
44
  TRUNCATE_NAMESPACE = :"truncate-namespace"
45
+
46
+ # Server supports the "blob-bits" command
47
+ BLOB_BITS = :"blob-bits"
45
48
  end
46
49
  end
@@ -20,7 +20,7 @@ module Aerospike
20
20
 
21
21
  class Operation
22
22
 
23
- attr_reader :op_type, :bin_name, :bin_value
23
+ attr_reader :op_type, :bin_name, :bin_value, :ctx
24
24
 
25
25
  READ = 1
26
26
  READ_HEADER = 1
@@ -31,12 +31,17 @@ module Aerospike
31
31
  APPEND = 9
32
32
  PREPEND = 10
33
33
  TOUCH = 11
34
+ BIT_READ = 12
35
+ BIT_MODIFY = 13
34
36
  DELETE = 14
37
+ HLL_READ = 15
38
+ HLL_MODIFY = 16
35
39
 
36
- def initialize(op_type, bin_name=nil, bin_value=NullValue.new)
40
+ def initialize(op_type, bin_name=nil, bin_value=NullValue.new, ctx = nil)
37
41
  @op_type = op_type
38
42
  @bin_name = bin_name
39
43
  @bin_value = Value.of(bin_value)
44
+ @ctx = ctx
40
45
  self
41
46
  end
42
47
 
@@ -31,7 +31,7 @@ module Aerospike
31
31
  # Try node on the same rack as the client first. If there are no nodes on the
32
32
  # same rack, use SEQUENCE instead.
33
33
  #
34
- # ClientPolicy#rack_aware}, ClientPolicy#rack_id, and server rack
34
+ # ClientPolicy#rack_aware, ClientPolicy#rack_id, and server rack
35
35
  # configuration must also be set to enable this functionality.
36
36
  PREFER_RACK = 3
37
37
 
@@ -60,6 +60,10 @@ module Aerospike
60
60
  # exists.
61
61
  KEY_EXISTS_ERROR = 5
62
62
 
63
+ # Bin already exists on a create-only operation.
64
+ BIN_EXISTS_ERROR = 6
65
+
66
+
63
67
  # Expected cluster ID was not received.
64
68
  CLUSTER_KEY_MISMATCH = 7
65
69
 
@@ -91,6 +95,9 @@ module Aerospike
91
95
  # Unsupported Server Feature (e.g. Scan + UDF)
92
96
  UNSUPPORTED_FEATURE = 16
93
97
 
98
+ # Bin not found on update-only operation.
99
+ BIN_NOT_FOUND = 17
100
+
94
101
  # Specified bin name does not exist in record.
95
102
  DEVICE_OVERLOAD = 18
96
103
 
@@ -122,11 +129,19 @@ module Aerospike
122
129
  # The transaction was not performed because the predexp was false.
123
130
  FILTERED_OUT = 27
124
131
 
132
+ # Write command loses conflict to XDR.
133
+ LOST_CONFLICT = 28
134
+
125
135
  # There are no more records left for query.
126
136
  QUERY_END = 50
127
137
 
138
+ # Security functionality not supported by connected server.
128
139
  SECURITY_NOT_SUPPORTED = 51
140
+
141
+ # Security functionality not enabled by connected server.
129
142
  SECURITY_NOT_ENABLED = 52
143
+
144
+ # Security scheme not supported.
130
145
  SECURITY_SCHEME_NOT_SUPPORTED = 53
131
146
 
132
147
  # Administration command is invalid.
@@ -155,6 +170,9 @@ module Aerospike
155
170
  # Security credential is invalid.
156
171
  INVALID_CREDENTIAL = 65
157
172
 
173
+ # Expired session token.
174
+ EXPIRED_SESSION = 66
175
+
158
176
  # Role name is invalid.
159
177
  INVALID_ROLE = 70
160
178
 
@@ -164,15 +182,48 @@ module Aerospike
164
182
  # Privilege is invalid.
165
183
  INVALID_PRIVILEGE = 72
166
184
 
185
+ # Specified IP whitelist is invalid.
186
+ INVALID_WHITELIST = 73
187
+
167
188
  # User must be authentication before performing database operations.
168
189
  NOT_AUTHENTICATED = 80
169
190
 
170
191
  # User does not posses the required role to perform the database operation.
171
192
  ROLE_VIOLATION = 81
172
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
+
173
212
  # A user defined function returned an error code.
174
213
  UDF_BAD_RESPONSE = 100
175
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
+
176
227
  # Secondary index already exists.
177
228
  INDEX_FOUND = 200
178
229
 
@@ -206,6 +257,12 @@ module Aerospike
206
257
  # Generic query error.
207
258
  QUERY_GENERIC = 213
208
259
 
260
+ # Network error. Query is aborted.
261
+ QUERY_NET_IO = 214
262
+
263
+ # Internal error.
264
+ QUERY_DUPLICATE = 215
265
+
209
266
  def self.message(code)
210
267
  case code
211
268
  when COMMAND_REJECTED
@@ -244,6 +301,9 @@ module Aerospike
244
301
  when KEY_EXISTS_ERROR
245
302
  "Key already exists"
246
303
 
304
+ when BIN_EXISTS_ERROR
305
+ "Bin already exists on a create-only operation"
306
+
247
307
  when CLUSTER_KEY_MISMATCH
248
308
  "Cluster key mismatch"
249
309
 
@@ -274,6 +334,9 @@ module Aerospike
274
334
  when UNSUPPORTED_FEATURE
275
335
  "Unsupported Server Feature"
276
336
 
337
+ when BIN_NOT_FOUND
338
+ "Bin not found on update-only operation"
339
+
277
340
  when DEVICE_OVERLOAD
278
341
  "Device overload"
279
342
 
@@ -304,6 +367,9 @@ module Aerospike
304
367
  when FILTERED_OUT
305
368
  "The transaction was not performed because the predexp was false."
306
369
 
370
+ when LOST_CONFLICT
371
+ "Write command loses conflict to XDR."
372
+
307
373
  when QUERY_END
308
374
  "Query end"
309
375
 
@@ -343,6 +409,9 @@ module Aerospike
343
409
  when INVALID_CREDENTIAL
344
410
  "Invalid credential"
345
411
 
412
+ when EXPIRED_SESSION
413
+ "Expired session token"
414
+
346
415
  when INVALID_ROLE
347
416
  "Invalid role"
348
417
 
@@ -352,15 +421,48 @@ module Aerospike
352
421
  when INVALID_PRIVILEGE
353
422
  "Invalid privilege"
354
423
 
424
+ when INVALID_WHITELIST
425
+ "Specified IP whitelist is invalid"
426
+
355
427
  when NOT_AUTHENTICATED
356
428
  "Not authenticated"
357
429
 
358
430
  when ROLE_VIOLATION
359
431
  "Role violation"
360
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
+
361
451
  when UDF_BAD_RESPONSE
362
452
  "UDF d error"
363
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
+
364
466
  when INDEX_FOUND
365
467
  "Index already exists"
366
468
 
@@ -394,6 +496,12 @@ module Aerospike
394
496
  when QUERY_GENERIC
395
497
  "Query error"
396
498
 
499
+ when QUERY_NET_IO
500
+ "Network error. Query is aborted"
501
+
502
+ when QUERY_DUPLICATE
503
+ "Internal query error"
504
+
397
505
  else
398
506
  "ResultCode #{code} unknown in the client. Please file a github issue."
399
507
  end # case
@@ -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
@@ -36,7 +36,7 @@ module Aerospike
36
36
  #RTA_DICT = 15
37
37
  #RTA_APPEND_DICT = 16
38
38
  #RTA_APPEND_LIST = 17
39
- #LUA_BLOB = 18
39
+ HLL = 18
40
40
  MAP = 19
41
41
  LIST = 20
42
42
  GEOJSON = 23
@@ -23,14 +23,24 @@ module Aerospike
23
23
  # Polymorphic value classes used to efficiently serialize objects into the wire protocol.
24
24
  class Value #:nodoc:
25
25
 
26
- def self.of(value)
26
+ def self.of(value, allow_64bits = false)
27
27
  case value
28
28
  when Integer
29
- if value.bit_length < 64
30
- res = IntegerValue.new(value)
29
+ if !allow_64bits
30
+ if value.bit_length < 64
31
+ res = IntegerValue.new(value)
32
+ else
33
+ # big nums > 2**63 are not supported
34
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported with more than 64 bits.")
35
+ end
31
36
  else
32
- # big nums > 2**63 are not supported
33
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported.")
37
+ # used in bitwise operations
38
+ if value.bit_length <= 64
39
+ res = IntegerValue.new(value)
40
+ else
41
+ # nums with more than 64 bits are not supported
42
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported with more than 64 bits.")
43
+ end
34
44
  end
35
45
  when Float
36
46
  res = FloatValue.new(value)
@@ -48,6 +58,8 @@ module Aerospike
48
58
  res = GeoJSONValue.new(value)
49
59
  when nil
50
60
  res = NULL
61
+ when TrueClass, FalseClass
62
+ res = BoolValue.new(value)
51
63
  else
52
64
  # throw an exception for anything that is not supported.
53
65
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported.")
@@ -526,6 +538,49 @@ module Aerospike
526
538
 
527
539
  end
528
540
 
541
+ # #######################################/
542
+
543
+ # HLLValue value. Encapsulates a HyperLogLog value.
544
+ # Supported by Aerospike server version 4.9 and later.
545
+ class HLLValue < Value #:nodoc:
546
+
547
+ def initialize(value)
548
+ @bytes = value
549
+ @bytes.force_encoding('binary')
550
+
551
+ self
552
+ end
553
+
554
+ def type
555
+ Aerospike::ParticleType::HLL
556
+ end
557
+
558
+ def get
559
+ self
560
+ end
561
+
562
+ def to_s
563
+ @bytes.to_s
564
+ end
565
+
566
+ def to_bytes
567
+ @bytes
568
+ end
569
+
570
+ def estimate_size
571
+ @bytes.bytesize
572
+ end
573
+
574
+ def write(buffer, offset)
575
+ buffer.write_binary(@bytes, offset)
576
+ end
577
+
578
+ def pack(packer)
579
+ packer.write(Aerospike::ParticleType::BLOB.chr + @bytes)
580
+ end
581
+
582
+ end
583
+
529
584
  #######################################
530
585
 
531
586
  def self.encoding
@@ -572,6 +627,10 @@ module Aerospike
572
627
  hdrsz = 1 + 2 + (ncells * 8)
573
628
  Aerospike::GeoJSON.new(buf.read(offset + hdrsz, length - hdrsz))
574
629
 
630
+ when Aerospike::ParticleType::HLL
631
+ bytes = buf.read(offset,length)
632
+ Aerospike::HLLValue.new(bytes)
633
+
575
634
  else
576
635
  nil
577
636
  end
@@ -593,4 +652,47 @@ module Aerospike
593
652
  nil
594
653
  end
595
654
  end
655
+
656
+ private
657
+
658
+ #######################################
659
+
660
+ # Boolean value.
661
+ # This is private, and only used internally for bitwise CDTs
662
+ class BoolValue < Value #:nodoc:
663
+
664
+ def initialize(val)
665
+ @value = val || false
666
+ self
667
+ end
668
+
669
+ def estimate_size
670
+ 1
671
+ end
672
+
673
+ def write(buffer, offset)
674
+ raise Exception.new("Unreachable")
675
+ end
676
+
677
+ def pack(packer)
678
+ packer.write(@value)
679
+ end
680
+
681
+ def type
682
+ raise Exception.new("Unreachable")
683
+ end
684
+
685
+ def get
686
+ @value
687
+ end
688
+
689
+ def to_bytes
690
+ raise Exception.new("Unreachable")
691
+ end
692
+
693
+ def to_s
694
+ @value.to_s
695
+ end
696
+
697
+ end # BoolValue
596
698
  end # module