aerospike 2.23.0 → 2.25.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,8 +17,8 @@
17
17
  module Aerospike
18
18
  module CDT
19
19
  class MapPolicy
20
-
21
20
  attr_accessor :order, :write_mode, :flags
21
+ attr_accessor :item_command, :items_command, :attributes
22
22
 
23
23
  def initialize(order: nil, write_mode: nil, flags: nil)
24
24
  if write_mode && flags
@@ -28,10 +28,24 @@ module Aerospike
28
28
  @order = order || MapOrder::DEFAULT
29
29
  @write_mode = write_mode || MapWriteMode::DEFAULT
30
30
  @flags = flags || MapWriteFlags::DEFAULT
31
+ @attributes = order ? order[:attr] : 0
32
+
33
+ case @write_mode
34
+ when CDT::MapWriteMode::DEFAULT
35
+ @item_command = CDT::MapOperation::PUT
36
+ @items_command = CDT::MapOperation::PUT_ITEMS
37
+ when CDT::MapWriteMode::UPDATE_ONLY
38
+ @item_command = CDT::MapOperation::REPLACE
39
+ @items_command = CDT::MapOperation::REPLACE_ITEMS
40
+ when CDT::MapWriteMode::CREATE_ONLY
41
+ @item_command = CDT::MapOperation::ADD
42
+ @items_command = CDT::MapOperation::ADD_ITEMS
43
+ else
44
+ raise Exceptions.new(ResultCode::PARAMETER_ERROR, "invalid value for MapWriteMode #{write_mode}")
45
+ end
31
46
  end
32
47
 
33
48
  DEFAULT = MapPolicy.new
34
-
35
49
  end
36
50
  end
37
51
  end
@@ -69,10 +69,18 @@ module Aerospike
69
69
  # Return true if count > 0.
70
70
  EXISTS = 13
71
71
 
72
+ ##
73
+ # :private
74
+ #
75
+ # TODO: Should be like ListOperation and Implement InvertibleMapOperation
76
+ # Inverts meaning of map command and return values. For example:
77
+ # map_remove_by_key_range(bin_name, key_begin, key_end, MapReturnType::KEY | MapReturnType::INVERTED)
78
+ # With the INVERTED flag enabled, the keys outside of the specified key range will be removed and returned.
79
+ INVERTED = 0x10000
80
+
72
81
  ##
73
82
  # Default return type: NONE
74
83
  DEFAULT_RETURN_TYPE = NONE
75
-
76
84
  end
77
85
  end
78
86
  end
@@ -15,8 +15,8 @@
15
15
  # License for the specific language governing permissions and limitations under
16
16
  # the License.
17
17
 
18
- require 'digest'
19
- require 'base64'
18
+ require "digest"
19
+ require "base64"
20
20
 
21
21
  module Aerospike
22
22
 
@@ -36,7 +36,6 @@ module Aerospike
36
36
  # +:fail_if_not_connected+ set to true
37
37
 
38
38
  class Client
39
-
40
39
  attr_accessor :default_admin_policy
41
40
  attr_accessor :default_batch_policy
42
41
  attr_accessor :default_info_policy
@@ -48,8 +47,7 @@ module Aerospike
48
47
  attr_accessor :cluster
49
48
 
50
49
  def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
51
-
52
- hosts = ::Aerospike::Host::Parse.(hosts || ENV['AEROSPIKE_HOSTS'] || 'localhost')
50
+ hosts = ::Aerospike::Host::Parse.(hosts || ENV["AEROSPIKE_HOSTS"] || "localhost")
53
51
  policy = create_policy(policy, ClientPolicy)
54
52
  set_default_policies(policy.policies)
55
53
  @cluster = Cluster.new(policy, hosts)
@@ -249,7 +247,7 @@ module Aerospike
249
247
  end
250
248
 
251
249
  response = send_info_command(policy, str_cmd, node).upcase
252
- return if response == 'OK'
250
+ return if response == "OK"
253
251
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, "Truncate failed: #{response}")
254
252
  end
255
253
 
@@ -386,7 +384,8 @@ module Aerospike
386
384
  def operate(key, operations, options = nil)
387
385
  policy = create_policy(options, OperatePolicy, default_operate_policy)
388
386
 
389
- command = OperateCommand.new(@cluster, policy, key, operations)
387
+ args = OperateArgs.new(cluster, policy, default_write_policy, default_operate_policy, key, operations)
388
+ command = OperateCommand.new(@cluster, key, args)
390
389
  execute_command(command)
391
390
  command.record
392
391
  end
@@ -415,7 +414,7 @@ module Aerospike
415
414
  def register_udf(udf_body, server_path, language, options = nil)
416
415
  policy = create_policy(options, Policy, default_info_policy)
417
416
 
418
- content = Base64.strict_encode64(udf_body).force_encoding('binary')
417
+ content = Base64.strict_encode64(udf_body).force_encoding("binary")
419
418
  str_cmd = "udf-put:filename=#{server_path};content=#{content};"
420
419
  str_cmd << "content-len=#{content.length};udf-type=#{language};"
421
420
 
@@ -424,15 +423,15 @@ module Aerospike
424
423
 
425
424
  res = {}
426
425
  response_map.each do |k, response|
427
- vals = response.to_s.split(';')
426
+ vals = response.to_s.split(";")
428
427
  vals.each do |pair|
429
428
  k, v = pair.split("=", 2)
430
429
  res[k] = v
431
430
  end
432
431
  end
433
432
 
434
- if res['error']
435
- raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res['error']}\nFile: #{res['file']}\nLine: #{res['line']}\nMessage: #{res['message']}")
433
+ if res["error"]
434
+ raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res["error"]}\nFile: #{res["file"]}\nLine: #{res["line"]}\nMessage: #{res["message"]}")
436
435
  end
437
436
 
438
437
  UdfRegisterTask.new(@cluster, server_path)
@@ -454,7 +453,7 @@ module Aerospike
454
453
  response_map = @cluster.request_info(policy, str_cmd)
455
454
  _, response = response_map.first
456
455
 
457
- if response == 'ok'
456
+ if response == "ok"
458
457
  UdfRemoveTask.new(@cluster, udf_name)
459
458
  else
460
459
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, response)
@@ -466,27 +465,27 @@ module Aerospike
466
465
  def list_udf(options = nil)
467
466
  policy = create_policy(options, Policy, default_info_policy)
468
467
 
469
- str_cmd = 'udf-list'
468
+ str_cmd = "udf-list"
470
469
 
471
470
  # Send command to one node. That node will distribute it to other nodes.
472
471
  response_map = @cluster.request_info(policy, str_cmd)
473
472
  _, response = response_map.first
474
473
 
475
- vals = response.split(';')
474
+ vals = response.split(";")
476
475
 
477
476
  vals.map do |udf_info|
478
- next if udf_info.strip! == ''
477
+ next if udf_info.strip! == ""
479
478
 
480
- udf_parts = udf_info.split(',')
479
+ udf_parts = udf_info.split(",")
481
480
  udf = UDF.new
482
481
  udf_parts.each do |values|
483
- k, v = values.split('=', 2)
482
+ k, v = values.split("=", 2)
484
483
  case k
485
- when 'filename'
484
+ when "filename"
486
485
  udf.filename = v
487
- when 'hash'
486
+ when "hash"
488
487
  udf.hash = v
489
- when 'type'
488
+ when "type"
490
489
  udf.language = v
491
490
  end
492
491
  end
@@ -501,7 +500,7 @@ module Aerospike
501
500
  # udf file = <server udf dir>/<package name>.lua
502
501
  #
503
502
  # This method is only supported by Aerospike 3 servers.
504
- def execute_udf(key, package_name, function_name, args=[], options = nil)
503
+ def execute_udf(key, package_name, function_name, args = [], options = nil)
505
504
  policy = create_policy(options, WritePolicy, default_write_policy)
506
505
 
507
506
  command = ExecuteCommand.new(@cluster, policy, key, package_name, function_name, args)
@@ -514,10 +513,10 @@ module Aerospike
514
513
  result_map = record.bins
515
514
 
516
515
  # User defined functions don't have to return a value.
517
- key, obj = result_map.detect{ |k, _| k.include?('SUCCESS') }
516
+ key, obj = result_map.detect { |k, _| k.include?("SUCCESS") }
518
517
  return obj if key
519
518
 
520
- key, obj = result_map.detect{ |k, _| k.include?('FAILURE') }
519
+ key, obj = result_map.detect { |k, _| k.include?("FAILURE") }
521
520
  message = key ? obj.to_s : "Invalid UDF return value"
522
521
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::UDF_BAD_RESPONSE, message)
523
522
  end
@@ -530,7 +529,7 @@ module Aerospike
530
529
  #
531
530
  # This method is only supported by Aerospike 3 servers.
532
531
  # If the policy is nil, the default relevant policy will be used.
533
- def execute_udf_on_query(statement, package_name, function_name, function_args=[], options = nil)
532
+ def execute_udf_on_query(statement, package_name, function_name, function_args = [], options = nil)
534
533
  policy = create_policy(options, QueryPolicy, default_query_policy)
535
534
 
536
535
  nodes = @cluster.nodes
@@ -559,7 +558,6 @@ module Aerospike
559
558
  ExecuteTask.new(@cluster, statement)
560
559
  end
561
560
 
562
-
563
561
  # Create secondary index.
564
562
  # This asynchronous server call will return before command is complete.
565
563
  # The user can optionally wait for command completion by using the returned
@@ -583,12 +581,12 @@ module Aerospike
583
581
 
584
582
  # Send index command to one node. That node will distribute the command to other nodes.
585
583
  response = send_info_command(policy, str_cmd).upcase
586
- if response == 'OK'
584
+ if response == "OK"
587
585
  # Return task that could optionally be polled for completion.
588
586
  return IndexTask.new(@cluster, namespace, index_name)
589
587
  end
590
588
 
591
- if response.start_with?('FAIL:200')
589
+ if response.start_with?("FAIL:200")
592
590
  # Index has already been created. Do not need to poll for completion.
593
591
  return IndexTask.new(@cluster, namespace, index_name, true)
594
592
  end
@@ -607,10 +605,10 @@ module Aerospike
607
605
 
608
606
  # Send index command to one node. That node will distribute the command to other nodes.
609
607
  response = send_info_command(policy, str_cmd).upcase
610
- return if response == 'OK'
608
+ return if response == "OK"
611
609
 
612
610
  # Index did not previously exist. Return without error.
613
- return if response.start_with?('FAIL:201')
611
+ return if response.start_with?("FAIL:201")
614
612
 
615
613
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INDEX_GENERIC, "Drop index failed: #{response}")
616
614
  end
@@ -693,44 +691,44 @@ module Aerospike
693
691
  # Query functions (Supported by Aerospike 3 servers only)
694
692
  #--------------------------------------------------------
695
693
 
696
- # Query executes a query and returns a recordset.
697
- # The query executor puts records on a channel from separate goroutines.
698
- # The caller can concurrently pops records off the channel through the
699
- # record channel.
694
+ # Executes a query for specified partitions and returns a recordset.
695
+ # The query executor puts records on the queue from separate threads.
696
+ # The caller can concurrently pop records off the queue through the
697
+ # recordset.records API.
700
698
  #
701
- # This method is only supported by Aerospike 3 servers.
702
- # If the policy is nil, a default policy will be generated.
703
- def query(statement, options = nil)
699
+ # This method is only supported by Aerospike 4.9+ servers.
700
+ # If the policy is nil, the default relevant policy will be used.
701
+ def query_partitions(partition_filter, statement, options = nil)
704
702
  policy = create_policy(options, QueryPolicy, default_query_policy)
705
703
  new_policy = policy.clone
706
704
 
707
705
  nodes = @cluster.nodes
708
706
  if nodes.empty?
709
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
707
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Query failed because cluster is empty.")
710
708
  end
711
709
 
712
- recordset = Recordset.new(policy.record_queue_size, nodes.length, :query)
713
-
714
- # Use a thread per node
715
- nodes.each do |node|
716
- partitions = node.cluster.node_partitions(node, statement.namespace)
717
- Thread.new do
718
- Thread.current.abort_on_exception = true
719
- command = QueryCommand.new(node, new_policy, statement, recordset, partitions)
720
- begin
721
- execute_command(command)
722
- rescue => e
723
- Aerospike.logger.error(e.backtrace.join("\n")) unless e == QUERY_TERMINATED_EXCEPTION
724
- recordset.cancel(e)
725
- ensure
726
- recordset.thread_finished
727
- end
728
- end
710
+ # result recordset
711
+ recordset = Recordset.new(policy.record_queue_size, 1, :query)
712
+ tracker = PartitionTracker.new(policy, nodes, partition_filter)
713
+ Thread.new do
714
+ Thread.current.abort_on_exception = true
715
+ QueryExecutor.query_partitions(@cluster, policy, tracker, statement, recordset)
729
716
  end
730
717
 
731
718
  recordset
732
719
  end
733
720
 
721
+ # Query executes a query and returns a recordset.
722
+ # The query executor puts records on a channel from separate threads.
723
+ # The caller can concurrently pops records off the channel through the
724
+ # record channel.
725
+ #
726
+ # This method is only supported by Aerospike 3 servers.
727
+ # If the policy is nil, a default policy will be generated.
728
+ def query(statement, options = nil)
729
+ query_partitions(Aerospike::PartitionFilter.all, statement, options)
730
+ end
731
+
734
732
  #-------------------------------------------------------
735
733
  # User administration
736
734
  #-------------------------------------------------------
@@ -966,7 +964,5 @@ module Aerospike
966
964
 
967
965
  threads.each(&:join)
968
966
  end
969
-
970
967
  end # class
971
-
972
968
  end # module