aerospike 2.14.0 → 2.19.0

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