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