aerospike 2.26.0 → 2.27.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 569388197af73988d3965e15f8b7caf42605896f21183a0e6f7d507690dec816
4
- data.tar.gz: dfe35172403817d176aecfd83747e6155a961b92960a97f8efc713a6b7540d23
3
+ metadata.gz: 3fe67950bfa737ce26a8a0e823cd84424219c6ce41720e0202ca93d4dcab2c1d
4
+ data.tar.gz: 83976d88565599f00136967bd86fe832a88783518c51be2789c1463fa06e795e
5
5
  SHA512:
6
- metadata.gz: e4de68155586c168c75a51c71749531becdf066cb22888745f8473237cb775dd9054c6401e44a04b00bee517848859d128141692da3fc7c970df2f202e5e49b9
7
- data.tar.gz: 7c041a196f2bf45a3ff575426b9269ba45c10e16f641c82f5ce11e362ace013d2480c407b8f1e9a663a27bcf78df1988d6af46de2bd22d41c0fce5366fb2a52c
6
+ metadata.gz: e018d80b673081cdbf229aa5c48dd7ebbeb9a127492cc04c651a4e56bab92d7764aba82ffb3e3783f6a6f34755ded66be58c3bf5a9e110be61c0c21e20128932
7
+ data.tar.gz: 8e02a4d37b620f838dde53b63d4af3fe20146905dd4f3a30c14f97a83453c69f0dccfbaf1f44a777bf4ab53e89583cc7a6e4343204e6749b1d4fb888f0a7200f
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.27.0] 2023-05-18
6
+ - **New Features**
7
+ - [CLIENT-1176] Support write operations in background query
8
+
9
+
5
10
  ## [2.26.0] 2022-12-02
6
11
 
7
12
  - **New Features**
@@ -1,4 +1,4 @@
1
- # Copyright 2014-2020 Aerospike, Inc.
1
+ # Copyright 2014-2023 Aerospike, Inc.
2
2
  #
3
3
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
4
  # license agreements.
@@ -225,7 +225,6 @@ module Aerospike
225
225
  policy = create_policy(options, Policy, default_info_policy)
226
226
 
227
227
  node = @cluster.random_node
228
- conn = node.get_connection(policy.timeout)
229
228
 
230
229
  if set_name && !set_name.to_s.strip.empty?
231
230
  str_cmd = "truncate:namespace=#{namespace}"
@@ -731,6 +730,59 @@ module Aerospike
731
730
  query_partitions(Aerospike::PartitionFilter.all, statement, options)
732
731
  end
733
732
 
733
+ #----------------------------------------------------------
734
+ # Query/Execute (Supported by Aerospike 3+ servers only)
735
+ #----------------------------------------------------------
736
+
737
+ # QueryExecute applies operations on records that match the statement filter.
738
+ # Records are not returned to the client.
739
+ # This asynchronous server call will return before the command is complete.
740
+ # The user can optionally wait for command completion by using the returned
741
+ # ExecuteTask instance.
742
+ #
743
+ # This method is only supported by Aerospike 3+ servers.
744
+ # If the policy is nil, the default relevant policy will be used.
745
+ #
746
+ # @param statement [Aerospike::Statement] The query or batch read statement.
747
+ # @param operations [Array<Aerospike::Operation>] An optional list of operations.
748
+ # @param options [Hash] An optional hash of policy options.
749
+ # @return [Aerospike::ExecuteTask] An ExecuteTask instance that can be used to wait for command completion.
750
+ #
751
+ # @raise [Aerospike::Exceptions::Aerospike] if an error occurs during the operation.
752
+ def query_execute(statement, operations = [], options = nil)
753
+ policy = create_policy(options, WritePolicy, default_write_policy)
754
+
755
+ if statement.nil?
756
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_COMMAND, "Query failed of invalid statement.")
757
+ end
758
+
759
+ statement = statement.clone
760
+ unless operations.empty?
761
+ statement.operations = operations
762
+ end
763
+
764
+ task_id = statement.task_id
765
+ nodes = @cluster.nodes
766
+ if nodes.empty?
767
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Query failed because cluster is empty.")
768
+ end
769
+
770
+ # Use a thread per node
771
+ nodes.each do |node|
772
+ Thread.new do
773
+ Thread.current.abort_on_exception = true
774
+ begin
775
+ command = ServerCommand.new(@cluster, node, policy, statement, true, task_id)
776
+ execute_command(command)
777
+ rescue => e
778
+ Aerospike.logger.error(e)
779
+ raise e
780
+ end
781
+ end
782
+ end
783
+ ExecuteTask.new(@cluster, statement)
784
+ end
785
+
734
786
  #-------------------------------------------------------
735
787
  # User administration
736
788
  #-------------------------------------------------------
@@ -1,4 +1,4 @@
1
- # Copyright 2014-2020 Aerospike, Inc.
1
+ # Copyright 2014-2024 Aerospike, Inc.
2
2
  #
3
3
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
4
  # license agreements.
@@ -465,6 +465,254 @@ module Aerospike
465
465
  end_cmd
466
466
  end
467
467
 
468
+ def set_query(policy, statement, background, node_partitions)
469
+ function_arg_buffer = nil
470
+ field_count = 0
471
+ filter_size = 0
472
+
473
+ begin_cmd
474
+
475
+ if statement.namespace
476
+ @data_offset += statement.namespace.bytesize + FIELD_HEADER_SIZE
477
+ field_count += 1
478
+ end
479
+
480
+ if statement.set_name
481
+ @data_offset += statement.set_name.bytesize + FIELD_HEADER_SIZE
482
+ field_count += 1
483
+ end
484
+
485
+ # Estimate recordsPerSecond field size. This field is used in new servers and not used
486
+ # (but harmless to add) in old servers.
487
+ if statement.records_per_second > 0
488
+ @data_offset += 4 + FIELD_HEADER_SIZE
489
+ field_count += 1
490
+ end
491
+
492
+ # Estimate socket timeout field size. This field is used in new servers and not used
493
+ # (but harmless to add) in old servers.
494
+ @data_offset += 4 + FIELD_HEADER_SIZE
495
+ field_count += 1
496
+
497
+ # Estimate task_id field.
498
+ @data_offset += 8 + FIELD_HEADER_SIZE
499
+ field_count += 1
500
+
501
+ filter = statement.filters[0]
502
+ bin_names = statement.bin_names
503
+ packed_ctx = nil
504
+
505
+ if filter
506
+ col_type = filter.collection_type
507
+
508
+ # Estimate INDEX_TYPE field.
509
+ if col_type > 0
510
+ @data_offset += FIELD_HEADER_SIZE + 1
511
+ field_count += 1
512
+ end
513
+
514
+ # Estimate INDEX_RANGE field.
515
+ @data_offset += FIELD_HEADER_SIZE
516
+ filter_size += 1 # num filters
517
+ filter_size += filter.estimate_size
518
+
519
+ @data_offset += filter_size
520
+ field_count += 1
521
+
522
+ packed_ctx = filter.packed_ctx
523
+ if packed_ctx
524
+ @data_offset += FIELD_HEADER_SIZE + packed_ctx.length
525
+ field_count += 1
526
+ end
527
+ end
528
+
529
+ statement.set_task_id
530
+ predexp = policy.predexp || statement.predexp
531
+
532
+ if predexp
533
+ @data_offset += FIELD_HEADER_SIZE
534
+ pred_size = Aerospike::PredExp.estimate_size(predexp)
535
+ @data_offset += pred_size
536
+ field_count += 1
537
+ end
538
+
539
+ unless policy.filter_exp.nil?
540
+ exp_size = estimate_expression_size(policy.filter_exp)
541
+ field_count += 1 if exp_size > 0
542
+ end
543
+
544
+ # Estimate aggregation/background function size.
545
+ if statement.function_name
546
+ @data_offset += FIELD_HEADER_SIZE + 1 # udf type
547
+ @data_offset += statement.package_name.bytesize + FIELD_HEADER_SIZE
548
+ @data_offset += statement.function_name.bytesize + FIELD_HEADER_SIZE
549
+
550
+ function_arg_buffer = ""
551
+ if statement.function_args && statement.function_args.length > 0
552
+ function_arg_buffer = Value.of(statement.function_args).to_bytes
553
+ end
554
+ @data_offset += FIELD_HEADER_SIZE + function_arg_buffer.bytesize
555
+ field_count += 4
556
+ end
557
+
558
+ max_records = 0
559
+ parts_full_size = 0
560
+ parts_partial_digest_size = 0
561
+ parts_partial_bval_size = 0
562
+
563
+ unless node_partitions.nil?
564
+ parts_full_size = node_partitions.parts_full.length * 2
565
+ parts_partial_digest_size = node_partitions.parts_partial.length * 20
566
+
567
+ unless filter.nil?
568
+ parts_partial_bval_size = node_partitions.parts_partial.length * 8
569
+ end
570
+ max_records = node_partitions.record_max
571
+ end
572
+
573
+ if parts_full_size > 0
574
+ @data_offset += parts_full_size + FIELD_HEADER_SIZE
575
+ field_count += 1
576
+ end
577
+
578
+ if parts_partial_digest_size > 0
579
+ @data_offset += parts_partial_digest_size + FIELD_HEADER_SIZE
580
+ field_count += 1
581
+ end
582
+
583
+ if parts_partial_bval_size > 0
584
+ @data_offset += parts_partial_bval_size + FIELD_HEADER_SIZE
585
+ field_count += 1
586
+ end
587
+
588
+ # Estimate max records field size. This field is used in new servers and not used
589
+ # (but harmless to add) in old servers.
590
+ if max_records > 0
591
+ @data_offset += 8 + FIELD_HEADER_SIZE
592
+ field_count += 1
593
+ end
594
+
595
+ operations = statement.operations
596
+ operation_count = 0
597
+
598
+ if !operations.empty?
599
+
600
+ unless background
601
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR)
602
+ end
603
+
604
+ operations.each do |operation|
605
+ estimate_operation_size_for_operation(operation)
606
+ end
607
+ operation_count = operations.size
608
+ elsif !bin_names.empty?
609
+ bin_names.each do |bin_name|
610
+ estimate_operation_size_for_bin_name(bin_name)
611
+ end
612
+ operation_count = bin_names.length
613
+ # Estimate size for selected bin names (query bin names already handled for old servers).
614
+ end
615
+
616
+ size_buffer
617
+
618
+ if background
619
+ write_header_with_policy(policy, 0, INFO2_WRITE, field_count, operation_count)
620
+ else
621
+ read_attr = INFO1_READ
622
+ read_attr |= INFO1_NOBINDATA unless policy.include_bin_data
623
+ read_attr |= INFO1_SHORT_QUERY if policy.short_query
624
+ write_header(policy, read_attr, 0, field_count, operation_count)
625
+ end
626
+
627
+ write_field_string(statement.namespace, FieldType::NAMESPACE) if statement.namespace
628
+ write_field_string(statement.set_name, FieldType::TABLE) if statement.set_name
629
+
630
+ # Write records per second.
631
+ write_field_int(statement.records_per_second, FieldType::RECORDS_PER_SECOND) if statement.records_per_second > 0
632
+
633
+ write_filter_exp(policy.filter_exp, exp_size)
634
+
635
+ # Write socket idle timeout.
636
+ write_field_int(policy.socket_timeout, FieldType::SOCKET_TIMEOUT)
637
+
638
+ # Write task_id field
639
+ write_field_int64(statement.task_id, FieldType::TRAN_ID)
640
+
641
+ unless predexp.nil?
642
+ write_field_header(pred_size, Aerospike::FieldType::PREDEXP)
643
+ @data_offset = Aerospike::PredExp.write(
644
+ predexp, @data_buffer, @data_offset
645
+ )
646
+ end
647
+
648
+ if filter
649
+ type = filter.collection_type
650
+
651
+ if type > 0
652
+ write_field_header(1, FieldType::INDEX_TYPE)
653
+ @data_offset += @data_buffer.write_byte(type, @data_offset)
654
+ end
655
+
656
+ write_field_header(filter_size, FieldType::INDEX_RANGE)
657
+ @data_offset += @data_buffer.write_byte(1, @data_offset)
658
+ @data_offset = filter.write(@data_buffer, @data_offset)
659
+
660
+ if packed_ctx
661
+ write_field_header(packed_ctx.length, FieldType::INDEX_CONTEXT)
662
+ @data_offset += @data_buffer.write_binary(packed_ctx, @data_offset)
663
+ end
664
+ end
665
+
666
+ if statement.function_name
667
+ write_field_header(1, FieldType::UDF_OP)
668
+ @data_offset += @data_buffer.write_byte(1, @data_offset)
669
+ write_field_string(statement.package_name, FieldType::UDF_PACKAGE_NAME)
670
+ write_field_string(statement.function_name, FieldType::UDF_FUNCTION)
671
+ write_field_string(function_arg_buffer, FieldType::UDF_ARGLIST)
672
+ end
673
+
674
+ if parts_full_size > 0
675
+ write_field_header(parts_full_size, FieldType::PID_ARRAY)
676
+ node_partitions.parts_full.each do |part|
677
+ @data_offset += @data_buffer.write_uint16_little_endian(part.id, @data_offset)
678
+ end
679
+ end
680
+
681
+ if parts_partial_digest_size > 0
682
+ write_field_header(parts_partial_digest_size, FieldType::DIGEST_ARRAY)
683
+ node_partitions.parts_partial.each do |part|
684
+ @data_offset += @data_buffer.write_binary(part.digest, @data_offset)
685
+ end
686
+ end
687
+
688
+ if parts_partial_bval_size > 0
689
+ write_field_header(parts_partial_bval_size, FieldType::BVAL_ARRAY)
690
+ @node_partitions.parts_partial.each do |part|
691
+ @data_offset += @data_buffer.write_uint64_little_endian(part.bval, @data_offset)
692
+ end
693
+ end
694
+
695
+ if max_records > 0
696
+ write_field(max_records, FieldType::MAX_RECORDS)
697
+ end
698
+
699
+ if operations.empty?
700
+ if bin_names.empty?
701
+ bin_names.each do |bin_name|
702
+ write_operation_for_bin_name(bin_name, Operation::READ)
703
+ end
704
+ end
705
+ else
706
+ operations.each do |operation|
707
+ write_operation_for_operation(operation)
708
+ end
709
+ end
710
+
711
+ end_cmd
712
+
713
+ nil
714
+ end
715
+
468
716
  def execute
469
717
  iterations = 0
470
718
 
@@ -537,7 +785,7 @@ module Aerospike
537
785
  parse_result
538
786
  rescue => e
539
787
  case e
540
- # do not log the following exceptions
788
+ # do not log the following exceptions
541
789
  when Aerospike::Exceptions::ScanTerminated
542
790
  when Aerospike::Exceptions::QueryTerminated
543
791
  else
@@ -703,9 +951,8 @@ module Aerospike
703
951
  read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
704
952
  write_attr |= INFO2_DURABLE_DELETE if policy.durable_delete
705
953
  read_attr |= INFO1_COMPRESS_RESPONSE if policy.use_compression
706
-
707
954
  # Write all header data except total size which must be written last.
708
- @data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message heade.length.
955
+ @data_buffer.write_byte(MSG_REMAINING_HEADER_SIZE, 8) # Message header.length.
709
956
  @data_buffer.write_byte(read_attr, 9)
710
957
  @data_buffer.write_byte(write_attr, 10)
711
958
  @data_buffer.write_byte(info_attr, 11)
@@ -22,7 +22,7 @@ module Aerospike
22
22
  # Container object for client policy command.
23
23
  class Policy
24
24
  attr_accessor :filter_exp, :priority, :timeout, :max_retries, :sleep_between_retries, :consistency_level,
25
- :predexp, :fail_on_filtered_out, :replica, :use_compression
25
+ :predexp, :fail_on_filtered_out, :replica, :use_compression, :socket_timeout
26
26
 
27
27
  alias total_timeout timeout
28
28
  alias total_timeout= timeout=
@@ -133,6 +133,16 @@ module Aerospike
133
133
  # Duration to sleep between retries if a transaction fails and the
134
134
  # timeout was not exceeded. Enter zero to skip sleep.
135
135
  @sleep_between_retries = opt[:sleep_between_retries] || 0.5
136
+
137
+ # Determines network timeout for each attempt.
138
+ #
139
+ # If socket_timeout is not zero and socket_timeout is reached before an attempt completes,
140
+ # the Timeout above is checked. If Timeout is not exceeded, the transaction
141
+ # is retried. If both socket_timeout and Timeout are non-zero, socket_timeout must be less
142
+ # than or equal to Timeout, otherwise Timeout will also be used for socket_timeout.
143
+ #
144
+ # Default: 30s
145
+ @socket_timeout = opt[:socket_timeout] || 30000
136
146
  end
137
147
  end # class
138
148
  end # module
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2014-2020 Aerospike, Inc.
2
+ # Copyright 2014-2023 Aerospike, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@ module Aerospike
24
24
  class WritePolicy < Policy
25
25
 
26
26
  attr_accessor :record_exists_action, :generation_policy,
27
- :generation, :ttl, :send_key, :commit_level,
28
- :durable_delete
27
+ :generation, :ttl, :send_key, :commit_level,
28
+ :durable_delete
29
29
 
30
30
  alias expiration ttl
31
31
  alias expiration= ttl=
@@ -74,6 +74,11 @@ module Aerospike
74
74
  # Valid for Aerospike Server Enterprise Edition 3.10+ only.
75
75
  @durable_delete = opt.fetch(:durable_delete, false)
76
76
 
77
+ # Transaction timeout.
78
+ # This timeout is used to set the socket timeout and is also sent to the
79
+ # server along with the transaction in the wire protocol.
80
+ # Default for write policy is 1.
81
+ @timeout = opt[:timeout] || 1
77
82
  self
78
83
  end
79
84
 
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014-2023 Aerospike, Inc.
3
+ #
4
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
+ # license agreements.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
+ # use this file except in compliance with the License. You may obtain a copy of
9
+ # the License at http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+
18
+ module Aerospike
19
+ class ServerCommand < MultiCommand
20
+ attr_accessor :statement, :task_id, :cluster, :write_policy, :background
21
+
22
+ def initialize(cluster, node, policy, statement, background, task_id)
23
+ super(node)
24
+ @statement = statement
25
+ @task_id = task_id
26
+ @cluster = cluster
27
+ @policy = policy
28
+ @background = background
29
+ end
30
+
31
+ def write?
32
+ true
33
+ end
34
+
35
+ def write_buffer
36
+ set_query(@policy, @statement, background, nil)
37
+ end
38
+
39
+ def parse_row
40
+ field_count = @data_buffer.read_int16(18)
41
+ result_code = @data_buffer.read(5).ord & 0xFF
42
+ skip_key(field_count)
43
+
44
+ if result_code != 0
45
+ if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
46
+ return false
47
+ end
48
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
49
+ end
50
+ op_count = @data_buffer.read_int16(20)
51
+ if op_count <= 0
52
+ return Record.new(@node, key, bins, generation, expiration)
53
+ end
54
+
55
+ unless valid?
56
+ raise Aerospike::Exceptions::QueryTerminated
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2014-2020 Aerospike, Inc.
2
+ # Copyright 2014-2023 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -16,11 +16,14 @@
16
16
 
17
17
  module Aerospike
18
18
 
19
+ # The Aerospike::Statement class represents a query or scan statement to be executed on the database.
20
+ # It provides a set of properties that define the query or scan, including namespace, set name, bin names,
21
+ # index name, filters, and operations.
19
22
  class Statement
20
23
 
21
24
  attr_accessor :namespace, :set_name, :index_name, :bin_names, :task_id
22
- attr_accessor :filters, :package_name, :function_name, :function_args
23
- attr_accessor :predexp, :return_data
25
+ attr_accessor :filters, :package_name, :function_name, :function_args, :operations
26
+ attr_accessor :predexp, :return_data, :records_per_second
24
27
 
25
28
  def initialize(namespace, set_name, bin_names=[])
26
29
  # Namespace determines query Namespace
@@ -56,6 +59,14 @@ module Aerospike
56
59
  @package_name = nil
57
60
  @function_name = nil
58
61
  @function_args = nil
62
+ @operations = nil
63
+
64
+
65
+ # Limit returned records per second (rps) rate for each server.
66
+ # Will not apply rps limit if records_per_second is zero.
67
+ # Currently only applicable to a query without a defined filter (scan).
68
+ # Default is 0
69
+ @records_per_second = 0
59
70
 
60
71
  # TaskId determines query task id. (Optional)
61
72
  @task_id = rand(RAND_MAX)
@@ -64,33 +75,35 @@ module Aerospike
64
75
  @return_data = true
65
76
  end
66
77
 
67
- def set_aggregate_function(package_name, function_name, function_args=[], return_data=true)
78
+ def set_aggregate_function(package_name, function_name, function_args=[], return_data=true)
68
79
  @package_name = package_name
69
80
  @function_name = function_name
70
81
  @function_args = function_args
71
82
  @return_data = return_data
72
- end
83
+ end
73
84
 
74
- def is_scan?
75
- return (filters.nil? || (filters.empty?))
76
- end
85
+ def is_scan?
86
+ return (filters.nil? || (filters.empty?))
87
+ end
77
88
 
78
- def set_task_id
79
- while @task_id == 0
80
- @task_id = rand(RAND_MAX)
89
+ def set_task_id
90
+ while @task_id == 0
91
+ @task_id = rand(RAND_MAX)
92
+ end
81
93
  end
82
- end
83
94
 
84
- def reset_task_id
85
- @task_id = rand(RAND_MAX)
86
- while @task_id == 0
95
+ def reset_task_id
87
96
  @task_id = rand(RAND_MAX)
97
+ while @task_id == 0
98
+ @task_id = rand(RAND_MAX)
99
+ end
88
100
  end
89
- end
90
101
 
91
- private
92
102
 
93
- RAND_MAX = 2**63
103
+
104
+ private
105
+
106
+ RAND_MAX = 2**63 - 1
94
107
 
95
108
  end # class
96
109
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2014-2020 Aerospike, Inc.
1
+ # Copyright 2014-2023 Aerospike, Inc.
2
2
  #
3
3
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
4
4
  # license agreements.
@@ -33,6 +33,8 @@ module Aerospike
33
33
  @node = node
34
34
  end
35
35
 
36
+
37
+
36
38
  def to_s
37
39
  "key: `#{key}` bins: `#{bins}` generation: `#{generation}`, ttl: `#{ttl}`"
38
40
  end
@@ -41,6 +43,18 @@ module Aerospike
41
43
 
42
44
  CITRUSLEAF_EPOCH = 1262304000
43
45
 
46
+ # Arguments:
47
+ # value: the key to retrieve the value for
48
+ #
49
+ # Returns:
50
+ # the value of the specified key, or `nil` if `@bins` is `nil`
51
+ def get_value(value)
52
+ unless @bins.nil?
53
+ return @bins[value]
54
+ end
55
+ nil
56
+ end
57
+
44
58
  # Converts an absolute expiration time (in seconds from citrusleaf epoch)
45
59
  # to relative time-to-live (TTL) in seconds
46
60
  def expiration_to_ttl(secs_from_epoc)
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Aerospike
3
- VERSION = "2.26.0"
3
+ VERSION = "2.27.0"
4
4
  end
data/lib/aerospike.rb CHANGED
@@ -169,6 +169,7 @@ require "aerospike/query/scan_executor"
169
169
  require "aerospike/query/scan_partition_command"
170
170
  require "aerospike/query/query_executor"
171
171
  require "aerospike/query/query_partition_command"
172
+ require "aerospike/query/server_command"
172
173
 
173
174
  require "aerospike/exp/exp"
174
175
  require "aerospike/exp/exp_map"
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aerospike
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.26.0
4
+ version: 2.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Khosrow Afroozeh
8
8
  - Jan Hecking
9
- autorequire:
9
+ - Sachin Venkatesha Murthy
10
+ autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2022-12-02 00:00:00.000000000 Z
13
+ date: 2023-05-18 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: msgpack
@@ -44,6 +45,7 @@ description: Official Aerospike Client for ruby. Access your Aerospike cluster w
44
45
  email:
45
46
  - khosrow@aerospike.com
46
47
  - jhecking@aerospike.com
48
+ - smurthy@aerospike.com
47
49
  executables: []
48
50
  extensions: []
49
51
  extra_rdoc_files: []
@@ -181,6 +183,7 @@ files:
181
183
  - lib/aerospike/query/scan_command.rb
182
184
  - lib/aerospike/query/scan_executor.rb
183
185
  - lib/aerospike/query/scan_partition_command.rb
186
+ - lib/aerospike/query/server_command.rb
184
187
  - lib/aerospike/query/statement.rb
185
188
  - lib/aerospike/query/stream_command.rb
186
189
  - lib/aerospike/record.rb
@@ -227,8 +230,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
230
  - !ruby/object:Gem::Version
228
231
  version: '0'
229
232
  requirements: []
230
- rubygems_version: 3.3.5
231
- signing_key:
233
+ rubygems_version: 3.3.3
234
+ signing_key:
232
235
  specification_version: 4
233
236
  summary: An Aerospike driver for Ruby.
234
237
  test_files: []