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.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -4
  3. data/README.md +1 -1
  4. data/lib/aerospike.rb +17 -4
  5. data/lib/aerospike/aerospike_exception.rb +7 -1
  6. data/lib/aerospike/atomic/atomic.rb +1 -1
  7. data/lib/aerospike/bin.rb +1 -1
  8. data/lib/aerospike/cdt/list_operation.rb +1 -1
  9. data/lib/aerospike/cdt/map_operation.rb +1 -1
  10. data/lib/aerospike/cdt/map_order.rb +1 -1
  11. data/lib/aerospike/cdt/map_policy.rb +1 -1
  12. data/lib/aerospike/cdt/map_return_type.rb +1 -1
  13. data/lib/aerospike/cdt/map_write_mode.rb +1 -1
  14. data/lib/aerospike/client.rb +31 -17
  15. data/lib/aerospike/cluster.rb +139 -17
  16. data/lib/aerospike/cluster/partition.rb +1 -1
  17. data/lib/aerospike/cluster/partition_parser.rb +169 -0
  18. data/lib/aerospike/cluster/rack_parser.rb +117 -0
  19. data/lib/aerospike/command/admin_command.rb +1 -1
  20. data/lib/aerospike/command/batch_direct_command.rb +2 -1
  21. data/lib/aerospike/command/batch_direct_exists_command.rb +1 -1
  22. data/lib/aerospike/command/batch_direct_node.rb +3 -3
  23. data/lib/aerospike/command/batch_index_command.rb +11 -2
  24. data/lib/aerospike/command/batch_index_node.rb +2 -2
  25. data/lib/aerospike/command/batch_item.rb +1 -1
  26. data/lib/aerospike/command/command.rb +157 -11
  27. data/lib/aerospike/command/delete_command.rb +21 -5
  28. data/lib/aerospike/command/execute_command.rb +1 -1
  29. data/lib/aerospike/command/exists_command.rb +21 -5
  30. data/lib/aerospike/command/field_type.rb +3 -1
  31. data/lib/aerospike/command/multi_command.rb +55 -5
  32. data/lib/aerospike/command/operate_command.rb +6 -1
  33. data/lib/aerospike/command/read_command.rb +63 -20
  34. data/lib/aerospike/command/read_header_command.rb +18 -6
  35. data/lib/aerospike/command/roles.rb +1 -1
  36. data/lib/aerospike/command/single_command.rb +9 -3
  37. data/lib/aerospike/command/touch_command.rb +48 -4
  38. data/lib/aerospike/command/unsupported_particle_type_validator.rb +1 -1
  39. data/lib/aerospike/command/write_command.rb +13 -4
  40. data/lib/aerospike/connection/create.rb +1 -1
  41. data/lib/aerospike/features.rb +3 -1
  42. data/lib/aerospike/geo_json.rb +70 -1
  43. data/lib/aerospike/host.rb +1 -1
  44. data/lib/aerospike/info.rb +1 -1
  45. data/lib/aerospike/key.rb +1 -1
  46. data/lib/aerospike/language.rb +1 -1
  47. data/lib/aerospike/node.rb +21 -7
  48. data/lib/aerospike/node/rebalance.rb +50 -0
  49. data/lib/aerospike/node/refresh/info.rb +4 -1
  50. data/lib/aerospike/node/refresh/partitions.rb +6 -15
  51. data/lib/aerospike/node/refresh/racks.rb +47 -0
  52. data/lib/aerospike/node/refresh/reset.rb +1 -0
  53. data/lib/aerospike/node/verify/rebalance_generation.rb +43 -0
  54. data/lib/aerospike/node_validator.rb +45 -40
  55. data/lib/aerospike/operation.rb +6 -1
  56. data/lib/aerospike/policy/admin_policy.rb +1 -1
  57. data/lib/aerospike/policy/batch_policy.rb +1 -1
  58. data/lib/aerospike/policy/client_policy.rb +16 -1
  59. data/lib/aerospike/policy/commit_level.rb +1 -1
  60. data/lib/aerospike/policy/consistency_level.rb +1 -1
  61. data/lib/aerospike/policy/generation_policy.rb +1 -1
  62. data/lib/aerospike/policy/operate_policy.rb +1 -1
  63. data/lib/aerospike/policy/policy.rb +64 -2
  64. data/lib/aerospike/policy/priority.rb +1 -1
  65. data/lib/aerospike/policy/query_policy.rb +8 -1
  66. data/lib/aerospike/policy/record_bin_multiplicity.rb +1 -1
  67. data/lib/aerospike/policy/record_exists_action.rb +1 -1
  68. data/lib/aerospike/policy/replica.rb +45 -0
  69. data/lib/aerospike/policy/scan_policy.rb +8 -1
  70. data/lib/aerospike/policy/write_policy.rb +1 -1
  71. data/lib/aerospike/query/filter.rb +1 -1
  72. data/lib/aerospike/query/pred_exp.rb +192 -0
  73. data/lib/aerospike/query/pred_exp/and_or.rb +32 -0
  74. data/lib/aerospike/query/pred_exp/geo_json_value.rb +41 -0
  75. data/lib/aerospike/query/pred_exp/integer_value.rb +32 -0
  76. data/lib/aerospike/query/pred_exp/op.rb +27 -0
  77. data/lib/aerospike/query/pred_exp/regex.rb +32 -0
  78. data/lib/aerospike/query/pred_exp/regex_flags.rb +23 -0
  79. data/lib/aerospike/query/pred_exp/string_value.rb +29 -0
  80. data/lib/aerospike/query/query_command.rb +27 -1
  81. data/lib/aerospike/query/recordset.rb +5 -5
  82. data/lib/aerospike/query/scan_command.rb +1 -1
  83. data/lib/aerospike/query/statement.rb +12 -3
  84. data/lib/aerospike/query/stream_command.rb +1 -1
  85. data/lib/aerospike/record.rb +1 -1
  86. data/lib/aerospike/result_code.rb +13 -7
  87. data/lib/aerospike/socket/base.rb +4 -3
  88. data/lib/aerospike/task/execute_task.rb +1 -1
  89. data/lib/aerospike/task/index_task.rb +1 -1
  90. data/lib/aerospike/task/task.rb +1 -1
  91. data/lib/aerospike/task/udf_register_task.rb +1 -1
  92. data/lib/aerospike/task/udf_remove_task.rb +1 -1
  93. data/lib/aerospike/ttl.rb +1 -1
  94. data/lib/aerospike/udf.rb +1 -1
  95. data/lib/aerospike/user_role.rb +1 -1
  96. data/lib/aerospike/utils/buffer.rb +14 -4
  97. data/lib/aerospike/utils/packer.rb +1 -1
  98. data/lib/aerospike/utils/pool.rb +1 -1
  99. data/lib/aerospike/utils/unpacker.rb +7 -2
  100. data/lib/aerospike/value/particle_type.rb +1 -1
  101. data/lib/aerospike/value/value.rb +59 -29
  102. data/lib/aerospike/version.rb +1 -1
  103. metadata +19 -8
  104. data/lib/aerospike/cluster/partition_tokenizer_new.rb +0 -130
  105. 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: 5ec864bf7ffd197e9badf516904193eb4e6260ac257335facc8e3df058307384
4
- data.tar.gz: '09fe60ac38789318a8739439d99490810129056614a479cafcecce01803c1bff'
3
+ metadata.gz: d0452d4d35ee6d5ce56586cc99b3a68c7e1b4a6c4f6334c6794414a483e2ef01
4
+ data.tar.gz: 328a5672510bb68e044a92c39fc1f04059daa53b4332eaa5a64dda04f5b3de78
5
5
  SHA512:
6
- metadata.gz: 0cf87d41d1b4b04121bbf8589974bfa931dea4ec96f17bdf94db737797afb60dc05932f6f56eed0b8f138bb6684a45eb4974c489e878ed5a949209734bf2dae7
7
- data.tar.gz: 65bccc5b55db802415541ae4b5307020477344bb2d771d7cc84b9554192fa97f76874c7538d2c62dbd0025780d91bd91c8dfc1e0143c2bd3753f092d1c391885
6
+ metadata.gz: 44c883336f3993d532c7989e1c6bf737deca2773cb444a4cfa6021bca35311c9d4fe5c74ddb73fa1274661435a127892f9a368bd1d94120e6965bee38b870216
7
+ data.tar.gz: ebac442b5b2ddc345b7d7713b0e8d7f0aaaba9da24aabe811e1a10a26555c2a85ba1d2bad0a0266674fdcc1c3deb573ed1839ffe98294dc979ccc69e42eab187
@@ -2,12 +2,58 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [Unreleased]
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/issue/77)]
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/issue/74)]
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/issue/73)]
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
@@ -1,4 +1,4 @@
1
- # Copyright 2014-2018 Aerospike, Inc.
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/partition_tokenizer_new'
108
- require 'aerospike/cluster/partition_tokenizer_old'
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-2018 Aerospike, Inc.
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
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
2
+ # Copyright 2014-2020 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.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright 2016-2018 Aerospike, Inc.
3
+ # Copyright 2016-2020 Aerospike, Inc.
4
4
  #
5
5
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
6
6
  # license agreements.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2016-2018 Aerospike, Inc.
2
+ # Copyright 2016-2020 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2016-2017 Aerospike, Inc.
2
+ # Copyright 2016-2020 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2016-2018 Aerospike, Inc.
2
+ # Copyright 2016-2020 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2016-2017 Aerospike, Inc.
2
+ # Copyright 2016-2020 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- # Copyright 2016-2018 Aerospike, Inc.
2
+ # Copyright 2016-2020 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
@@ -1,4 +1,4 @@
1
- # Copyright 2014-2018 Aerospike, Inc.
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
- str_cmd = "truncate:namespace=#{namespace}"
228
- str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
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
- # Send index command to one node. That node will distribute the command to other nodes.
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
- # TODO: wait until all migrations are finished
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
- _, response = @cluster.request_info(policy, command).first
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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright 2014-2018 Aerospike, Inc.
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
- def get_node_for_key(key)
106
- partition = Partition.new_by_key(key)
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
- # Must copy hashmap reference for copy on write semantics to work.
109
- nmap = partitions
110
- if node_array = nmap[partition.namespace]
111
- node = node_array.value[partition.partition_id]
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
- random_node
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
- index = (@node_index.update{ |v| v+1 } % node_array.length).abs
128
- node = node_array[index]
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(tokens, node)
171
- nmap = tokens.update_partition(partitions, node)
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 |node_array|
445
- return true if node_array.value.any? { |node| node == filter }
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