aerospike 2.23.0 → 2.25.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 +4 -4
- data/CHANGELOG.md +321 -266
- data/lib/aerospike/cdt/map_policy.rb +16 -2
- data/lib/aerospike/cdt/map_return_type.rb +9 -1
- data/lib/aerospike/client.rb +52 -56
- data/lib/aerospike/command/command.rb +105 -97
- data/lib/aerospike/command/field_type.rb +25 -28
- data/lib/aerospike/command/operate_args.rb +99 -0
- data/lib/aerospike/command/operate_command.rb +6 -11
- data/lib/aerospike/exp/exp.rb +1329 -0
- data/lib/aerospike/exp/exp_bit.rb +388 -0
- data/lib/aerospike/exp/exp_hll.rb +169 -0
- data/lib/aerospike/exp/exp_list.rb +403 -0
- data/lib/aerospike/exp/exp_map.rb +493 -0
- data/lib/aerospike/exp/operation.rb +56 -0
- data/lib/aerospike/features.rb +13 -0
- data/lib/aerospike/operation.rb +20 -22
- data/lib/aerospike/policy/policy.rb +25 -12
- data/lib/aerospike/policy/query_policy.rb +35 -2
- data/lib/aerospike/policy/scan_policy.rb +0 -2
- data/lib/aerospike/query/query_command.rb +1 -1
- data/lib/aerospike/query/query_executor.rb +71 -0
- data/lib/aerospike/query/query_partition_command.rb +269 -0
- data/lib/aerospike/query/recordset.rb +9 -9
- data/lib/aerospike/query/scan_executor.rb +7 -5
- data/lib/aerospike/query/statement.rb +7 -0
- data/lib/aerospike/query/stream_command.rb +2 -1
- data/lib/aerospike/task/execute_task.rb +17 -14
- data/lib/aerospike/utils/buffer.rb +62 -35
- data/lib/aerospike/utils/packer.rb +7 -6
- data/lib/aerospike/value/value.rb +21 -51
- data/lib/aerospike/version.rb +1 -1
- data/lib/aerospike.rb +156 -146
- metadata +12 -3
@@ -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
|
data/lib/aerospike/client.rb
CHANGED
@@ -15,8 +15,8 @@
|
|
15
15
|
# License for the specific language governing permissions and limitations under
|
16
16
|
# the License.
|
17
17
|
|
18
|
-
require
|
19
|
-
require
|
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 ==
|
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
|
-
|
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(
|
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[
|
435
|
-
raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res[
|
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 ==
|
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 =
|
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(
|
482
|
+
k, v = values.split("=", 2)
|
484
483
|
case k
|
485
|
-
when
|
484
|
+
when "filename"
|
486
485
|
udf.filename = v
|
487
|
-
when
|
486
|
+
when "hash"
|
488
487
|
udf.hash = v
|
489
|
-
when
|
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?(
|
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?(
|
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 ==
|
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?(
|
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 ==
|
608
|
+
return if response == "OK"
|
611
609
|
|
612
610
|
# Index did not previously exist. Return without error.
|
613
|
-
return if response.start_with?(
|
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
|
-
#
|
697
|
-
# The query executor puts records on
|
698
|
-
# The caller can concurrently
|
699
|
-
#
|
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
|
702
|
-
# If the policy is nil,
|
703
|
-
def
|
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, "
|
707
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Query failed because cluster is empty.")
|
710
708
|
end
|
711
709
|
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
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
|