aerospike 2.9.1 → 2.14.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 +50 -4
- data/README.md +1 -1
- data/lib/aerospike.rb +17 -4
- data/lib/aerospike/aerospike_exception.rb +7 -1
- data/lib/aerospike/atomic/atomic.rb +1 -1
- data/lib/aerospike/bin.rb +1 -1
- data/lib/aerospike/cdt/list_operation.rb +1 -1
- data/lib/aerospike/cdt/map_operation.rb +1 -1
- data/lib/aerospike/cdt/map_order.rb +1 -1
- data/lib/aerospike/cdt/map_policy.rb +1 -1
- data/lib/aerospike/cdt/map_return_type.rb +1 -1
- data/lib/aerospike/cdt/map_write_mode.rb +1 -1
- data/lib/aerospike/client.rb +31 -17
- data/lib/aerospike/cluster.rb +139 -17
- data/lib/aerospike/cluster/partition.rb +1 -1
- data/lib/aerospike/cluster/partition_parser.rb +169 -0
- data/lib/aerospike/cluster/rack_parser.rb +117 -0
- data/lib/aerospike/command/admin_command.rb +1 -1
- data/lib/aerospike/command/batch_direct_command.rb +2 -1
- data/lib/aerospike/command/batch_direct_exists_command.rb +1 -1
- data/lib/aerospike/command/batch_direct_node.rb +3 -3
- data/lib/aerospike/command/batch_index_command.rb +11 -2
- data/lib/aerospike/command/batch_index_node.rb +2 -2
- data/lib/aerospike/command/batch_item.rb +1 -1
- data/lib/aerospike/command/command.rb +157 -11
- data/lib/aerospike/command/delete_command.rb +21 -5
- data/lib/aerospike/command/execute_command.rb +1 -1
- data/lib/aerospike/command/exists_command.rb +21 -5
- data/lib/aerospike/command/field_type.rb +3 -1
- data/lib/aerospike/command/multi_command.rb +55 -5
- data/lib/aerospike/command/operate_command.rb +6 -1
- data/lib/aerospike/command/read_command.rb +63 -20
- data/lib/aerospike/command/read_header_command.rb +18 -6
- data/lib/aerospike/command/roles.rb +1 -1
- data/lib/aerospike/command/single_command.rb +9 -3
- data/lib/aerospike/command/touch_command.rb +48 -4
- data/lib/aerospike/command/unsupported_particle_type_validator.rb +1 -1
- data/lib/aerospike/command/write_command.rb +13 -4
- data/lib/aerospike/connection/create.rb +1 -1
- data/lib/aerospike/features.rb +3 -1
- data/lib/aerospike/geo_json.rb +70 -1
- data/lib/aerospike/host.rb +1 -1
- data/lib/aerospike/info.rb +1 -1
- data/lib/aerospike/key.rb +1 -1
- data/lib/aerospike/language.rb +1 -1
- data/lib/aerospike/node.rb +21 -7
- data/lib/aerospike/node/rebalance.rb +50 -0
- data/lib/aerospike/node/refresh/info.rb +4 -1
- data/lib/aerospike/node/refresh/partitions.rb +6 -15
- data/lib/aerospike/node/refresh/racks.rb +47 -0
- data/lib/aerospike/node/refresh/reset.rb +1 -0
- data/lib/aerospike/node/verify/rebalance_generation.rb +43 -0
- data/lib/aerospike/node_validator.rb +45 -40
- data/lib/aerospike/operation.rb +6 -1
- data/lib/aerospike/policy/admin_policy.rb +1 -1
- data/lib/aerospike/policy/batch_policy.rb +1 -1
- data/lib/aerospike/policy/client_policy.rb +16 -1
- data/lib/aerospike/policy/commit_level.rb +1 -1
- data/lib/aerospike/policy/consistency_level.rb +1 -1
- data/lib/aerospike/policy/generation_policy.rb +1 -1
- data/lib/aerospike/policy/operate_policy.rb +1 -1
- data/lib/aerospike/policy/policy.rb +64 -2
- data/lib/aerospike/policy/priority.rb +1 -1
- data/lib/aerospike/policy/query_policy.rb +8 -1
- data/lib/aerospike/policy/record_bin_multiplicity.rb +1 -1
- data/lib/aerospike/policy/record_exists_action.rb +1 -1
- data/lib/aerospike/policy/replica.rb +45 -0
- data/lib/aerospike/policy/scan_policy.rb +8 -1
- data/lib/aerospike/policy/write_policy.rb +1 -1
- data/lib/aerospike/query/filter.rb +1 -1
- data/lib/aerospike/query/pred_exp.rb +192 -0
- data/lib/aerospike/query/pred_exp/and_or.rb +32 -0
- data/lib/aerospike/query/pred_exp/geo_json_value.rb +41 -0
- data/lib/aerospike/query/pred_exp/integer_value.rb +32 -0
- data/lib/aerospike/query/pred_exp/op.rb +27 -0
- data/lib/aerospike/query/pred_exp/regex.rb +32 -0
- data/lib/aerospike/query/pred_exp/regex_flags.rb +23 -0
- data/lib/aerospike/query/pred_exp/string_value.rb +29 -0
- data/lib/aerospike/query/query_command.rb +27 -1
- data/lib/aerospike/query/recordset.rb +5 -5
- data/lib/aerospike/query/scan_command.rb +1 -1
- data/lib/aerospike/query/statement.rb +12 -3
- data/lib/aerospike/query/stream_command.rb +1 -1
- data/lib/aerospike/record.rb +1 -1
- data/lib/aerospike/result_code.rb +13 -7
- data/lib/aerospike/socket/base.rb +4 -3
- data/lib/aerospike/task/execute_task.rb +1 -1
- data/lib/aerospike/task/index_task.rb +1 -1
- data/lib/aerospike/task/task.rb +1 -1
- data/lib/aerospike/task/udf_register_task.rb +1 -1
- data/lib/aerospike/task/udf_remove_task.rb +1 -1
- data/lib/aerospike/ttl.rb +1 -1
- data/lib/aerospike/udf.rb +1 -1
- data/lib/aerospike/user_role.rb +1 -1
- data/lib/aerospike/utils/buffer.rb +14 -4
- data/lib/aerospike/utils/packer.rb +1 -1
- data/lib/aerospike/utils/pool.rb +1 -1
- data/lib/aerospike/utils/unpacker.rb +7 -2
- data/lib/aerospike/value/particle_type.rb +1 -1
- data/lib/aerospike/value/value.rb +59 -29
- data/lib/aerospike/version.rb +1 -1
- metadata +19 -8
- data/lib/aerospike/cluster/partition_tokenizer_new.rb +0 -130
- data/lib/aerospike/cluster/partition_tokenizer_old.rb +0 -135
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d0452d4d35ee6d5ce56586cc99b3a68c7e1b4a6c4f6334c6794414a483e2ef01
         | 
| 4 | 
            +
              data.tar.gz: 328a5672510bb68e044a92c39fc1f04059daa53b4332eaa5a64dda04f5b3de78
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 44c883336f3993d532c7989e1c6bf737deca2773cb444a4cfa6021bca35311c9d4fe5c74ddb73fa1274661435a127892f9a368bd1d94120e6965bee38b870216
         | 
| 7 | 
            +
              data.tar.gz: ebac442b5b2ddc345b7d7713b0e8d7f0aaaba9da24aabe811e1a10a26555c2a85ba1d2bad0a0266674fdcc1c3deb573ed1839ffe98294dc979ccc69e42eab187
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -2,12 +2,58 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            All notable changes to this project will be documented in this file.
         | 
| 4 4 |  | 
| 5 | 
            -
            ## [ | 
| 5 | 
            +
            ## [2.14.0] - 2019-08-06
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            * **New Features**
         | 
| 8 | 
            +
              * Adds support for rake-aware reads.
         | 
| 9 | 
            +
              * Adds support for client-server compression.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            * **Improvements**
         | 
| 12 | 
            +
              * Adds support for `truncate-namespace` command.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            ## [2.13.0] - 2019-07-17
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            * **New Features**
         | 
| 17 | 
            +
              * Adds support for replica policies.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            * **Improvements**
         | 
| 20 | 
            +
              * Remove support for "old" partition tokenizer.
         | 
| 21 | 
            +
              * Refactor how partition parser is initialized and called.
         | 
| 22 | 
            +
              * Adds support for 'replicas' and remove the old partition table queries from the server.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            ## [2.12.0] - 2019-04-21
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            * **New Features**
         | 
| 27 | 
            +
              * Support for predicate expressions in all transaction.
         | 
| 28 | 
            +
              * Support for `operation.delete` in `client#operate`.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            * **Improvements**
         | 
| 31 | 
            +
              * Optimize serialization for nested structures. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#94](https://github.com/aerospike/aerospike-client-ruby/pull/94)]
         | 
| 32 | 
            +
              * Remove `Thread#abort_on_exception` from `batch_index_command`. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#94](https://github.com/aerospike/aerospike-client-ruby/pull/92)]
         | 
| 33 | 
            +
              * Does not allow values other than Integer, Float, String, Symbol and nil to be used as keys in Maps.
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            * **Bug Fixes**
         | 
| 36 | 
            +
              * Fixes tests that weren't using ENV variables for connections. This will allow the tests to be run on any server.
         | 
| 37 | 
            +
             | 
| 38 | 
            +
             | 
| 39 | 
            +
            ## [2.11.0] - 2019-05-17
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            * **New Features**
         | 
| 42 | 
            +
              * Support for predicate expressions in queries. Thanks to [@Minus10Degrees](https://github.com/Minus10Degrees)! [[#78](https://github.com/aerospike/aerospike-client-ruby/issues/78)]
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            * **Bug Fixes**
         | 
| 45 | 
            +
              * Client#execute\_udf\_on\_query should not modify the statement argument. [[#79](https://github.com/aerospike/aerospike-client-ruby/issues/79)]
         | 
| 46 | 
            +
              * Encoding::UndefinedConversionError when reading blob data from CDT list/map bin. [[#84](https://github.com/aerospike/aerospike-client-ruby/issues/84)]
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            ## [2.10.0] - 2019-05-10
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            * **New Features**
         | 
| 51 | 
            +
              * Add support for LB discovery / seeding. Thanks to [@filiptepper](https://github.com/filiptepper)! [[#80](https://github.com/aerospike/aerospike-client-ruby/issues/80)]
         | 
| 6 52 |  | 
| 7 53 | 
             
            ## [2.9.1] - 2019-04-03
         | 
| 8 54 |  | 
| 9 55 | 
             
            * **Bug Fixes**
         | 
| 10 | 
            -
              * Query fails if one or more cluster nodes do not have records in the set [[#77](https://github.com/aerospike/aerospike-client-ruby/ | 
| 56 | 
            +
              * Query fails if one or more cluster nodes do not have records in the set [[#77](https://github.com/aerospike/aerospike-client-ruby/issues/77)]
         | 
| 11 57 |  | 
| 12 58 | 
             
            * **Updates**
         | 
| 13 59 | 
             
              * Change admin message version to 2 (from 0)
         | 
| @@ -20,10 +66,10 @@ All notable changes to this project will be documented in this file. | |
| 20 66 | 
             
              * Add INFINITY and WILDCARD values for use in CDT map/list comparators. [AER-5945]
         | 
| 21 67 |  | 
| 22 68 | 
             
            * **Bug Fixes**
         | 
| 23 | 
            -
              * Default policies set on Client instance do not get applied [[#74](https://github.com/aerospike/aerospike-client-ruby/ | 
| 69 | 
            +
              * Default policies set on Client instance do not get applied [[#74](https://github.com/aerospike/aerospike-client-ruby/issues/74)]
         | 
| 24 70 |  | 
| 25 71 | 
             
            * **Updates**
         | 
| 26 | 
            -
              * *BREAKING CHANGE*: Change default for send_key write policy to false [[#73](https://github.com/aerospike/aerospike-client-ruby/ | 
| 72 | 
            +
              * *BREAKING CHANGE*: Change default for send_key write policy to false [[#73](https://github.com/aerospike/aerospike-client-ruby/issues/73)]
         | 
| 27 73 | 
             
              * Support truncate info command argument "lut=now" for servers that require it. [AER-5955]
         | 
| 28 74 |  | 
| 29 75 | 
             
            ## [2.8.0] - 2018-08-06
         | 
    
        data/README.md
    CHANGED
    
    | @@ -97,7 +97,7 @@ This library is packaged with a number of tests. | |
| 97 97 |  | 
| 98 98 | 
             
            To run all the test cases:
         | 
| 99 99 |  | 
| 100 | 
            -
                $ bundle exec rspec
         | 
| 100 | 
            +
                $ AEROSPIKE_HOSTS="<host:port>[,<hoist:port>]" AEROSPIKE_USER="<user>" AEROSPIKE_PASSWORD="<pass>" bundle exec rspec
         | 
| 101 101 |  | 
| 102 102 | 
             
            <a name="Examples"></a>
         | 
| 103 103 | 
             
            ## Examples
         | 
    
        data/lib/aerospike.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Copyright 2014- | 
| 1 | 
            +
            # Copyright 2014-2020 Aerospike, Inc.
         | 
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            # Portions may be licensed to Aerospike, Inc. under one or more contributor
         | 
| 4 4 | 
             
            # license agreements.
         | 
| @@ -22,6 +22,7 @@ require "timeout" | |
| 22 22 | 
             
            require 'resolv'
         | 
| 23 23 | 
             
            require 'msgpack'
         | 
| 24 24 | 
             
            require 'bcrypt'
         | 
| 25 | 
            +
            require 'zlib'
         | 
| 25 26 |  | 
| 26 27 | 
             
            require 'aerospike/atomic/atomic'
         | 
| 27 28 |  | 
| @@ -101,22 +102,25 @@ require 'aerospike/connection/create' | |
| 101 102 |  | 
| 102 103 | 
             
            require 'aerospike/cluster'
         | 
| 103 104 | 
             
            require 'aerospike/cluster/create_connection'
         | 
| 104 | 
            -
            require 'aerospike/cluster/partition'
         | 
| 105 105 | 
             
            require 'aerospike/cluster/find_nodes_to_remove'
         | 
| 106 106 | 
             
            require 'aerospike/cluster/find_node'
         | 
| 107 | 
            -
            require 'aerospike/cluster/ | 
| 108 | 
            -
            require 'aerospike/cluster/ | 
| 107 | 
            +
            require 'aerospike/cluster/partition'
         | 
| 108 | 
            +
            require 'aerospike/cluster/partition_parser'
         | 
| 109 | 
            +
            require 'aerospike/cluster/rack_parser'
         | 
| 109 110 | 
             
            require 'aerospike/node'
         | 
| 110 111 | 
             
            require 'aerospike/node/generation'
         | 
| 112 | 
            +
            require 'aerospike/node/rebalance'
         | 
| 111 113 | 
             
            require 'aerospike/node/refresh/failed'
         | 
| 112 114 | 
             
            require 'aerospike/node/refresh/friends'
         | 
| 113 115 | 
             
            require 'aerospike/node/refresh/info'
         | 
| 114 116 | 
             
            require 'aerospike/node/refresh/partitions'
         | 
| 117 | 
            +
            require 'aerospike/node/refresh/racks'
         | 
| 115 118 | 
             
            require 'aerospike/node/refresh/peers'
         | 
| 116 119 | 
             
            require 'aerospike/node/refresh/reset'
         | 
| 117 120 | 
             
            require 'aerospike/node/verify/cluster_name'
         | 
| 118 121 | 
             
            require 'aerospike/node/verify/name'
         | 
| 119 122 | 
             
            require 'aerospike/node/verify/partition_generation'
         | 
| 123 | 
            +
            require 'aerospike/node/verify/rebalance_generation'
         | 
| 120 124 | 
             
            require 'aerospike/node/verify/peers_generation'
         | 
| 121 125 | 
             
            require 'aerospike/node_validator'
         | 
| 122 126 | 
             
            require 'aerospike/peer'
         | 
| @@ -142,6 +146,15 @@ require 'aerospike/query/stream_command' | |
| 142 146 | 
             
            require 'aerospike/query/query_command'
         | 
| 143 147 | 
             
            require 'aerospike/query/scan_command'
         | 
| 144 148 | 
             
            require 'aerospike/query/statement'
         | 
| 149 | 
            +
            require 'aerospike/query/pred_exp'
         | 
| 150 | 
            +
             | 
| 151 | 
            +
            require 'aerospike/query/pred_exp/and_or'
         | 
| 152 | 
            +
            require 'aerospike/query/pred_exp/geo_json_value'
         | 
| 153 | 
            +
            require 'aerospike/query/pred_exp/integer_value'
         | 
| 154 | 
            +
            require 'aerospike/query/pred_exp/op'
         | 
| 155 | 
            +
            require 'aerospike/query/pred_exp/regex'
         | 
| 156 | 
            +
            require 'aerospike/query/pred_exp/regex_flags'
         | 
| 157 | 
            +
            require 'aerospike/query/pred_exp/string_value'
         | 
| 145 158 |  | 
| 146 159 | 
             
            module Aerospike
         | 
| 147 160 | 
             
              extend Loggable
         | 
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 | 
            -
            # Copyright 2014- | 
| 2 | 
            +
            # Copyright 2014-2020 Aerospike, Inc.
         | 
| 3 3 | 
             
            #
         | 
| 4 4 | 
             
            # Portions may be licensed to Aerospike, Inc. under one or more contributor
         | 
| 5 5 | 
             
            # license agreements.
         | 
| @@ -90,5 +90,11 @@ module Aerospike | |
| 90 90 | 
             
                    super(ResultCode::COMMAND_REJECTED, msg)
         | 
| 91 91 | 
             
                  end
         | 
| 92 92 | 
             
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                class InvalidNamespace < Aerospike
         | 
| 95 | 
            +
                  def initialize(msg=nil)
         | 
| 96 | 
            +
                    super(ResultCode::INVALID_NAMESPACE, msg)
         | 
| 97 | 
            +
                  end
         | 
| 98 | 
            +
                end
         | 
| 93 99 | 
             
              end
         | 
| 94 100 | 
             
            end
         | 
    
        data/lib/aerospike/bin.rb
    CHANGED
    
    
    
        data/lib/aerospike/client.rb
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Copyright 2014- | 
| 1 | 
            +
            # Copyright 2014-2020 Aerospike, Inc.
         | 
| 2 2 | 
             
            #
         | 
| 3 3 | 
             
            # Portions may be licensed to Aerospike, Inc. under one or more contributor
         | 
| 4 4 | 
             
            # license agreements.
         | 
| @@ -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 :cluster
         | 
| 47 48 |  | 
| 48 49 | 
             
                def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
         | 
| 49 50 |  | 
| @@ -224,8 +225,19 @@ module Aerospike | |
| 224 225 | 
             
                def truncate(namespace, set_name = nil, before_last_update = nil, options = {})
         | 
| 225 226 | 
             
                  policy = create_policy(options, Policy, default_info_policy)
         | 
| 226 227 |  | 
| 227 | 
            -
                   | 
| 228 | 
            -
                   | 
| 228 | 
            +
                  node = @cluster.random_node
         | 
| 229 | 
            +
                  conn = node.get_connection(policy.timeout)
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                  if set_name && !set_name.to_s.strip.empty?
         | 
| 232 | 
            +
                    str_cmd = "truncate:namespace=#{namespace}"
         | 
| 233 | 
            +
                    str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
         | 
| 234 | 
            +
                  else
         | 
| 235 | 
            +
                    if node.supports_feature(Aerospike::Features::TRUNCATE_NAMESPACE)
         | 
| 236 | 
            +
                      str_cmd = "truncate-namespace:namespace=#{namespace}"
         | 
| 237 | 
            +
                    else
         | 
| 238 | 
            +
                      str_cmd = "truncate:namespace=#{namespace}"
         | 
| 239 | 
            +
                    end
         | 
| 240 | 
            +
                  end
         | 
| 229 241 |  | 
| 230 242 | 
             
                  if before_last_update
         | 
| 231 243 | 
             
                    lut_nanos = (before_last_update.to_f * 1_000_000_000.0).round
         | 
| @@ -235,8 +247,7 @@ module Aerospike | |
| 235 247 | 
             
                    str_cmd << ";lut=now"
         | 
| 236 248 | 
             
                  end
         | 
| 237 249 |  | 
| 238 | 
            -
                   | 
| 239 | 
            -
                  response = send_info_command(policy, str_cmd).upcase
         | 
| 250 | 
            +
                  response = send_info_command(policy, str_cmd, node).upcase
         | 
| 240 251 | 
             
                  return if response == 'OK'
         | 
| 241 252 | 
             
                  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_ERROR, "Truncate failed: #{response}")
         | 
| 242 253 | 
             
                end
         | 
| @@ -322,11 +333,11 @@ module Aerospike | |
| 322 333 |  | 
| 323 334 | 
             
                  if policy.use_batch_direct
         | 
| 324 335 | 
             
                    key_map = BatchItem.generate_map(keys)
         | 
| 325 | 
            -
                    execute_batch_direct_commands(keys) do |node, batch|
         | 
| 336 | 
            +
                    execute_batch_direct_commands(policy, keys) do |node, batch|
         | 
| 326 337 | 
             
                      BatchDirectCommand.new(node, batch, policy, key_map, bin_names, results, info_flags)
         | 
| 327 338 | 
             
                    end
         | 
| 328 339 | 
             
                  else
         | 
| 329 | 
            -
                    execute_batch_index_commands(keys) do |node, batch|
         | 
| 340 | 
            +
                    execute_batch_index_commands(policy, keys) do |node, batch|
         | 
| 330 341 | 
             
                      BatchIndexCommand.new(node, batch, policy, bin_names, results, info_flags)
         | 
| 331 342 | 
             
                    end
         | 
| 332 343 | 
             
                  end
         | 
| @@ -351,11 +362,11 @@ module Aerospike | |
| 351 362 |  | 
| 352 363 | 
             
                  if policy.use_batch_direct
         | 
| 353 364 | 
             
                    key_map = BatchItem.generate_map(keys)
         | 
| 354 | 
            -
                    execute_batch_direct_commands(keys) do |node, batch|
         | 
| 365 | 
            +
                    execute_batch_direct_commands(policy, keys) do |node, batch|
         | 
| 355 366 | 
             
                      BatchDirectExistsCommand.new(node, batch, policy, key_map, results)
         | 
| 356 367 | 
             
                    end
         | 
| 357 368 | 
             
                  else
         | 
| 358 | 
            -
                    execute_batch_index_commands(keys) do |node, batch|
         | 
| 369 | 
            +
                    execute_batch_index_commands(policy, keys) do |node, batch|
         | 
| 359 370 | 
             
                      BatchIndexExistsCommand.new(node, batch, policy, results)
         | 
| 360 371 | 
             
                    end
         | 
| 361 372 | 
             
                  end
         | 
| @@ -526,7 +537,7 @@ module Aerospike | |
| 526 537 | 
             
                    raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing UDF failed because cluster is empty.")
         | 
| 527 538 | 
             
                  end
         | 
| 528 539 |  | 
| 529 | 
            -
                   | 
| 540 | 
            +
                  statement = statement.clone
         | 
| 530 541 | 
             
                  statement.set_aggregate_function(package_name, function_name, function_args, false)
         | 
| 531 542 |  | 
| 532 543 | 
             
                  # Use a thread per node
         | 
| @@ -818,9 +829,13 @@ module Aerospike | |
| 818 829 | 
             
                  self.default_write_policy = create_policy(policies[:write], WritePolicy)
         | 
| 819 830 | 
             
                end
         | 
| 820 831 |  | 
| 821 | 
            -
                def send_info_command(policy, command)
         | 
| 832 | 
            +
                def send_info_command(policy, command, node = nil)
         | 
| 822 833 | 
             
                  Aerospike.logger.debug { "Sending info command: #{command}" }
         | 
| 823 | 
            -
                   | 
| 834 | 
            +
                  if node
         | 
| 835 | 
            +
                    _, response = @cluster.request_node_info(node, policy, command).first
         | 
| 836 | 
            +
                  else
         | 
| 837 | 
            +
                    _, response = @cluster.request_info(policy, command).first
         | 
| 838 | 
            +
                  end
         | 
| 824 839 | 
             
                  response.to_s
         | 
| 825 840 | 
             
                end
         | 
| 826 841 |  | 
| @@ -884,17 +899,16 @@ module Aerospike | |
| 884 899 | 
             
                  command.execute
         | 
| 885 900 | 
             
                end
         | 
| 886 901 |  | 
| 887 | 
            -
                def execute_batch_index_commands(keys)
         | 
| 902 | 
            +
                def execute_batch_index_commands(policy, keys)
         | 
| 888 903 | 
             
                  if @cluster.nodes.empty?
         | 
| 889 904 | 
             
                    raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing Batch Index command failed because cluster is empty.")
         | 
| 890 905 | 
             
                  end
         | 
| 891 906 |  | 
| 892 | 
            -
                  batch_nodes = BatchIndexNode.generate_list(@cluster, keys)
         | 
| 907 | 
            +
                  batch_nodes = BatchIndexNode.generate_list(@cluster, policy.replica, keys)
         | 
| 893 908 | 
             
                  threads = []
         | 
| 894 909 |  | 
| 895 910 | 
             
                  batch_nodes.each do |batch|
         | 
| 896 911 | 
             
                    threads << Thread.new do
         | 
| 897 | 
            -
                      Thread.current.abort_on_exception = true
         | 
| 898 912 | 
             
                      command = yield batch.node, batch
         | 
| 899 913 | 
             
                      execute_command(command)
         | 
| 900 914 | 
             
                    end
         | 
| @@ -903,12 +917,12 @@ module Aerospike | |
| 903 917 | 
             
                  threads.each(&:join)
         | 
| 904 918 | 
             
                end
         | 
| 905 919 |  | 
| 906 | 
            -
                def execute_batch_direct_commands(keys)
         | 
| 920 | 
            +
                def execute_batch_direct_commands(policy, keys)
         | 
| 907 921 | 
             
                  if @cluster.nodes.empty?
         | 
| 908 922 | 
             
                    raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing Batch Direct command failed because cluster is empty.")
         | 
| 909 923 | 
             
                  end
         | 
| 910 924 |  | 
| 911 | 
            -
                  batch_nodes = BatchDirectNode.generate_list(@cluster, keys)
         | 
| 925 | 
            +
                  batch_nodes = BatchDirectNode.generate_list(@cluster, policy.replica, keys)
         | 
| 912 926 | 
             
                  threads = []
         | 
| 913 927 |  | 
| 914 928 | 
             
                  # Use a thread per namespace per node
         | 
    
        data/lib/aerospike/cluster.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            # Copyright 2014- | 
| 3 | 
            +
            # Copyright 2014-2020 Aerospike, Inc.
         | 
| 4 4 | 
             
            #
         | 
| 5 5 | 
             
            # Portions may be licensed to Aerospike, Inc. under one or more contributor
         | 
| 6 6 | 
             
            # license agreements.
         | 
| @@ -28,6 +28,7 @@ module Aerospike | |
| 28 28 | 
             
                attr_reader :features, :tls_options
         | 
| 29 29 | 
             
                attr_reader :cluster_id, :aliases
         | 
| 30 30 | 
             
                attr_reader :cluster_name
         | 
| 31 | 
            +
                attr_accessor :rack_aware, :rack_id
         | 
| 31 32 |  | 
| 32 33 | 
             
                def initialize(policy, hosts)
         | 
| 33 34 | 
             
                  @cluster_seeds = hosts
         | 
| @@ -37,6 +38,10 @@ module Aerospike | |
| 37 38 | 
             
                  @tend_interval = policy.tend_interval
         | 
| 38 39 | 
             
                  @cluster_name = policy.cluster_name
         | 
| 39 40 | 
             
                  @tls_options = policy.tls
         | 
| 41 | 
            +
                  @rack_aware = policy.rack_aware
         | 
| 42 | 
            +
                  @rack_id = policy.rack_id
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  @replica_index = Atomic.new(0)
         | 
| 40 45 |  | 
| 41 46 | 
             
                  @aliases = {}
         | 
| 42 47 | 
             
                  @cluster_nodes = []
         | 
| @@ -102,18 +107,128 @@ module Aerospike | |
| 102 107 | 
             
                  (node_array.length > 0) && !@closed.value
         | 
| 103 108 | 
             
                end
         | 
| 104 109 |  | 
| 105 | 
            -
                 | 
| 106 | 
            -
             | 
| 110 | 
            +
                # Returns a node on the cluster for read operations
         | 
| 111 | 
            +
                def batch_read_node(partition, replica_policy)
         | 
| 112 | 
            +
                  case replica_policy
         | 
| 113 | 
            +
                    when Aerospike::Replica::MASTER, Aerospike::Replica::SEQUENCE
         | 
| 114 | 
            +
                      return master_node(partition)
         | 
| 115 | 
            +
                    when Aerospike::Replica::MASTER_PROLES
         | 
| 116 | 
            +
                      return master_proles_node(partition)
         | 
| 117 | 
            +
                    when Aerospike::Replica::PREFER_RACK
         | 
| 118 | 
            +
                      return rack_node(partition, seq)
         | 
| 119 | 
            +
                    when Aerospike::Replica::RANDOM
         | 
| 120 | 
            +
                      return random_node
         | 
| 121 | 
            +
                    else
         | 
| 122 | 
            +
                      raise Aerospike::Exceptions::InvalidNode("invalid policy.replica value")
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                # Returns a node on the cluster for read operations
         | 
| 127 | 
            +
                def read_node(partition, replica_policy, seq)
         | 
| 128 | 
            +
                  case replica_policy
         | 
| 129 | 
            +
                    when Aerospike::Replica::MASTER
         | 
| 130 | 
            +
                      return master_node(partition)
         | 
| 131 | 
            +
                    when Aerospike::Replica::MASTER_PROLES
         | 
| 132 | 
            +
                      return master_proles_node(partition)
         | 
| 133 | 
            +
                    when Aerospike::Replica::PREFER_RACK
         | 
| 134 | 
            +
                      return rack_node(partition, seq)
         | 
| 135 | 
            +
                    when Aerospike::Replica::SEQUENCE
         | 
| 136 | 
            +
                      return sequence_node(partition, seq)
         | 
| 137 | 
            +
                    when Aerospike::Replica::RANDOM
         | 
| 138 | 
            +
                      return random_node
         | 
| 139 | 
            +
                    else
         | 
| 140 | 
            +
                      raise Aerospike::Exceptions::InvalidNode("invalid policy.replica value")
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                # Returns a node on the cluster for read operations
         | 
| 145 | 
            +
                def master_node(partition)
         | 
| 146 | 
            +
                  partition_map = partitions
         | 
| 147 | 
            +
                  replica_array = partition_map[partition.namespace]
         | 
| 148 | 
            +
                  raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  node_array = (replica_array.get)[0]
         | 
| 151 | 
            +
                  raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !node_array
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  node = (node_array.get)[partition.partition_id]
         | 
| 154 | 
            +
                  raise Aerospike::Exceptions::InvalidNode if !node || !node.active?
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  node
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # Returns a node on the cluster
         | 
| 160 | 
            +
                def rack_node(partition, seq)
         | 
| 161 | 
            +
                  partition_map = partitions
         | 
| 162 | 
            +
                  replica_array = partition_map[partition.namespace]
         | 
| 163 | 
            +
                  raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  replica_array = replica_array.get
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                  is_retry = seq.value > -1
         | 
| 168 | 
            +
             | 
| 169 | 
            +
                  node = nil
         | 
| 170 | 
            +
                  fallback = nil
         | 
| 171 | 
            +
                  for i in 1..replica_array.length
         | 
| 172 | 
            +
                    idx = (seq.update{|v| v.succ} % replica_array.size).abs
         | 
| 173 | 
            +
                    node = (replica_array[idx].get)[partition.partition_id]
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                    next if !node
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                    fallback = node
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                    # If fallback exists, do not retry on node where command failed,
         | 
| 180 | 
            +
                    # even if fallback is not on the same rack.
         | 
| 181 | 
            +
                    return fallback if is_retry && fallback && i == replica_array.length
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                    return node if node && node.active? && node.has_rack(partition.namespace, @rack_id)
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  return fallback if fallback
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                  raise Aerospike::Exceptions::InvalidNode
         | 
| 189 | 
            +
                end
         | 
| 107 190 |  | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
                   | 
| 111 | 
            -
             | 
| 191 | 
            +
                # Returns a node on the cluster for read operations
         | 
| 192 | 
            +
                def master_proles_node(partition)
         | 
| 193 | 
            +
                  partition_map = partitions
         | 
| 194 | 
            +
                  replica_array = partition_map[partition.namespace]
         | 
| 195 | 
            +
                  raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                  replica_array = replica_array.get
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  node = nil
         | 
| 200 | 
            +
                  for replica in replica_array
         | 
| 201 | 
            +
                    idx = (@replica_index.update{|v| v.succ} % replica_array.size).abs
         | 
| 202 | 
            +
                    node = (replica_array[idx].get)[partition.partition_id]
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    return node if node && node.active?
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  raise Aerospike::Exceptions::InvalidNode
         | 
| 208 | 
            +
                end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                # Returns a random node on the cluster
         | 
| 211 | 
            +
                def sequence_node(partition, seq)
         | 
| 212 | 
            +
                  partition_map = partitions
         | 
| 213 | 
            +
                  replica_array = partition_map[partition.namespace]
         | 
| 214 | 
            +
                  raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                  replica_array = replica_array.get
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                  node = nil
         | 
| 219 | 
            +
                  for replica in replica_array
         | 
| 220 | 
            +
                    idx = (seq.update{|v| v.succ} % replica_array.size).abs
         | 
| 221 | 
            +
                    node = (replica_array[idx].get)[partition.partition_id]
         | 
| 112 222 |  | 
| 113 223 | 
             
                    return node if node && node.active?
         | 
| 114 224 | 
             
                  end
         | 
| 115 225 |  | 
| 116 | 
            -
                   | 
| 226 | 
            +
                  raise Aerospike::Exceptions::InvalidNode
         | 
| 227 | 
            +
                end
         | 
| 228 | 
            +
             | 
| 229 | 
            +
                def get_node_for_key(replica_policy, key)
         | 
| 230 | 
            +
                  partition = Partition.new_by_key(key)
         | 
| 231 | 
            +
                  batch_read_node(partition, replica_policy)
         | 
| 117 232 | 
             
                end
         | 
| 118 233 |  | 
| 119 234 | 
             
                # Returns a random node on the cluster
         | 
| @@ -124,8 +239,8 @@ module Aerospike | |
| 124 239 | 
             
                  i = 0
         | 
| 125 240 | 
             
                  while i < length
         | 
| 126 241 | 
             
                    # Must handle concurrency with other non-tending threads, so node_index is consistent.
         | 
| 127 | 
            -
                     | 
| 128 | 
            -
                    node = node_array[ | 
| 242 | 
            +
                    idx = (@node_index.update{ |v| v.succ } % node_array.length).abs
         | 
| 243 | 
            +
                    node = node_array[idx]
         | 
| 129 244 |  | 
| 130 245 | 
             
                    return node if node.active?
         | 
| 131 246 |  | 
| @@ -167,12 +282,9 @@ module Aerospike | |
| 167 282 | 
             
                  end
         | 
| 168 283 | 
             
                end
         | 
| 169 284 |  | 
| 170 | 
            -
                def update_partitions( | 
| 171 | 
            -
                  nmap =  | 
| 172 | 
            -
                  # update partition write map
         | 
| 285 | 
            +
                def update_partitions(parser)
         | 
| 286 | 
            +
                  nmap = parser.update_partitions(partitions)
         | 
| 173 287 | 
             
                  set_partitions(nmap) if nmap
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                  Aerospike.logger.info("Partitions for node #{node.name} updated")
         | 
| 176 288 | 
             
                end
         | 
| 177 289 |  | 
| 178 290 | 
             
                def request_info(policy, *commands)
         | 
| @@ -183,6 +295,13 @@ module Aerospike | |
| 183 295 | 
             
                  end
         | 
| 184 296 | 
             
                end
         | 
| 185 297 |  | 
| 298 | 
            +
                def request_node_info(node, policy, *commands)
         | 
| 299 | 
            +
                  conn = node.get_connection(policy.timeout)
         | 
| 300 | 
            +
                  Info.request(conn, *commands).tap do
         | 
| 301 | 
            +
                    node.put_connection(conn)
         | 
| 302 | 
            +
                  end
         | 
| 303 | 
            +
                end
         | 
| 304 | 
            +
             | 
| 186 305 | 
             
                def supports_feature?(feature)
         | 
| 187 306 | 
             
                  @features.get.include?(feature.to_s)
         | 
| 188 307 | 
             
                end
         | 
| @@ -279,6 +398,7 @@ module Aerospike | |
| 279 398 |  | 
| 280 399 | 
             
                  nodes.each do |node|
         | 
| 281 400 | 
             
                    node.refresh_partitions(peers) if node.partition_generation.changed?
         | 
| 401 | 
            +
                    node.refresh_racks if node.rebalance_generation.changed?
         | 
| 282 402 | 
             
                  end
         | 
| 283 403 |  | 
| 284 404 | 
             
                  if peers.generation_changed? || !peers.use_peers?
         | 
| @@ -441,8 +561,10 @@ module Aerospike | |
| 441 561 | 
             
                def find_node_in_partition_map(filter)
         | 
| 442 562 | 
             
                  partitions_list = partitions
         | 
| 443 563 |  | 
| 444 | 
            -
                  partitions_list.values.each do | | 
| 445 | 
            -
                     | 
| 564 | 
            +
                  partitions_list.values.each do |replica_array|
         | 
| 565 | 
            +
                    replica_array.get.each do |node_array|
         | 
| 566 | 
            +
                      return true if node_array.value.any? { |node| node == filter }
         | 
| 567 | 
            +
                    end
         | 
| 446 568 | 
             
                  end
         | 
| 447 569 | 
             
                  false
         | 
| 448 570 | 
             
                end
         |