aerospike 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/README.md +13 -9
  4. data/lib/aerospike/batch_attr.rb +292 -0
  5. data/lib/aerospike/batch_delete.rb +48 -0
  6. data/lib/aerospike/batch_read.rb +97 -0
  7. data/lib/aerospike/batch_record.rb +83 -0
  8. data/lib/aerospike/batch_results.rb +38 -0
  9. data/lib/aerospike/batch_udf.rb +76 -0
  10. data/lib/aerospike/batch_write.rb +79 -0
  11. data/lib/aerospike/cdt/bit_operation.rb +4 -5
  12. data/lib/aerospike/cdt/map_return_type.rb +8 -0
  13. data/lib/aerospike/client.rb +37 -51
  14. data/lib/aerospike/cluster.rb +50 -46
  15. data/lib/aerospike/command/batch_index_command.rb +6 -10
  16. data/lib/aerospike/command/batch_index_node.rb +3 -4
  17. data/lib/aerospike/command/batch_operate_command.rb +151 -0
  18. data/lib/aerospike/command/batch_operate_node.rb +51 -0
  19. data/lib/aerospike/command/command.rb +101 -87
  20. data/lib/aerospike/command/single_command.rb +1 -1
  21. data/lib/aerospike/exp/exp.rb +39 -41
  22. data/lib/aerospike/exp/exp_bit.rb +24 -24
  23. data/lib/aerospike/exp/exp_hll.rb +12 -12
  24. data/lib/aerospike/exp/exp_list.rb +101 -92
  25. data/lib/aerospike/exp/exp_map.rb +118 -121
  26. data/lib/aerospike/exp/operation.rb +2 -2
  27. data/lib/aerospike/info.rb +2 -4
  28. data/lib/aerospike/node.rb +7 -3
  29. data/lib/aerospike/operation.rb +38 -0
  30. data/lib/aerospike/policy/batch_delete_policy.rb +71 -0
  31. data/lib/aerospike/policy/batch_policy.rb +53 -4
  32. data/lib/aerospike/{command/batch_direct_node.rb → policy/batch_read_policy.rb} +17 -19
  33. data/lib/aerospike/policy/batch_udf_policy.rb +75 -0
  34. data/lib/aerospike/policy/batch_write_policy.rb +105 -0
  35. data/lib/aerospike/policy/policy.rb +3 -40
  36. data/lib/aerospike/query/server_command.rb +1 -0
  37. data/lib/aerospike/query/statement.rb +5 -21
  38. data/lib/aerospike/utils/buffer.rb +15 -15
  39. data/lib/aerospike/version.rb +1 -1
  40. data/lib/aerospike.rb +13 -12
  41. metadata +16 -14
  42. data/lib/aerospike/command/batch_direct_command.rb +0 -105
  43. data/lib/aerospike/command/batch_direct_exists_command.rb +0 -51
  44. data/lib/aerospike/query/pred_exp/and_or.rb +0 -32
  45. data/lib/aerospike/query/pred_exp/geo_json_value.rb +0 -41
  46. data/lib/aerospike/query/pred_exp/integer_value.rb +0 -32
  47. data/lib/aerospike/query/pred_exp/op.rb +0 -27
  48. data/lib/aerospike/query/pred_exp/regex.rb +0 -32
  49. data/lib/aerospike/query/pred_exp/regex_flags.rb +0 -23
  50. data/lib/aerospike/query/pred_exp/string_value.rb +0 -29
  51. data/lib/aerospike/query/pred_exp.rb +0 -192
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014-2024 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
+ # Batch key and read only operations with default policy.
18
+ # Used in batch read commands where different bins are needed for each key.
19
+
20
+ module Aerospike
21
+
22
+ # Batch user defined functions.
23
+ class BatchUDF < BatchRecord
24
+
25
+ # Optional UDF policy.
26
+ attr_accessor :policy
27
+
28
+ # Package or lua module name.
29
+ attr_accessor :package_name
30
+
31
+ # Lua function name.
32
+ attr_accessor :function_name
33
+
34
+ # Optional arguments to lua function.
35
+ attr_accessor :function_args
36
+
37
+ # Wire protocol bytes for function args. For internal use only.
38
+ attr_reader :arg_bytes
39
+
40
+ # Constructor using default policy.
41
+ def initialize(key, package_name, function_name, function_args, opt = {})
42
+ super(key, has_write: true)
43
+ @policy = BatchRecord.create_policy(opt, BatchUDFPolicy, DEFAULT_BATCH_UDF_POLICY)
44
+ @package_name = package_name
45
+ @function_name = function_name
46
+ @function_args = ListValue.new(function_args)
47
+ # Do not set arg_bytes here because may not be necessary if batch repeat flag is used.
48
+ end
49
+
50
+ # Optimized reference equality check to determine batch wire protocol repeat flag.
51
+ # For internal use only.
52
+ def ==(other) # :nodoc:
53
+ other && other.instance_of?(self.class) &&
54
+ @function_name == other.function_name && @function_args == other.function_args &&
55
+ @package_name == other.package_name && @policy == other.policy
56
+ end
57
+
58
+ DEFAULT_BATCH_UDF_POLICY = BatchUDFPolicy.new
59
+
60
+ # Return wire protocol size. For internal use only.
61
+ def size # :nodoc:
62
+ size = 6 # gen(2) + exp(4) = 6
63
+
64
+ size += @policy&.filter_exp&.size if @policy&.filter_exp
65
+
66
+ if @policy&.send_key
67
+ size += @key.user_key.estimate_size + Aerospike::FIELD_HEADER_SIZE + 1
68
+ end
69
+ size += @package_name.bytesize + Aerospike::FIELD_HEADER_SIZE
70
+ size += @function_name.bytesize + Aerospike::FIELD_HEADER_SIZE
71
+ @arg_bytes = @function_args.to_bytes
72
+ size += @arg_bytes.bytesize + Aerospike::FIELD_HEADER_SIZE
73
+ size
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014-2024 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
+ # Batch key and read only operations with default policy.
18
+ # Used in batch read commands where different bins are needed for each key.
19
+
20
+ module Aerospike
21
+
22
+ private
23
+
24
+ # Batch key and read/write operations with write policy.
25
+ class BatchWrite < BatchRecord
26
+ # Optional write policy.
27
+ attr_accessor :policy
28
+
29
+ # Required operations for this key.
30
+ attr_accessor :ops
31
+
32
+ # Initialize batch key and read/write operations.
33
+ #
34
+ # {Operation#get()} is not allowed because it returns a variable number of bins and
35
+ # makes it difficult (sometimes impossible) to lineup operations with results. Instead,
36
+ # use {Operation#get(bin_name)} for each bin name.
37
+ def initialize(key, ops, opt = {})
38
+ super(key, has_write: true)
39
+ @policy = BatchRecord.create_policy(opt, BatchWritePolicy, DEFAULT_BATCH_WRITE_POLICY)
40
+ @ops = ops
41
+ end
42
+
43
+ # Optimized reference equality check to determine batch wire protocol repeat flag.
44
+ # For internal use only.
45
+ def ==(other) # :nodoc:
46
+ other && other.instance_of?(self.class) &&
47
+ @ops == other.ops && @policy == other.policy && (@policy.nil? || !@policy.send_key)
48
+ end
49
+
50
+ DEFAULT_BATCH_WRITE_POLICY = BatchWritePolicy.new
51
+
52
+ # Return wire protocol size. For internal use only.
53
+ def size # :nodoc:
54
+ size = 6 # gen(2) + exp(4) = 6
55
+
56
+ size += @policy&.filter_exp&.size if @policy&.filter_exp
57
+
58
+ if @policy&.send_key
59
+ size += @key.user_key.estimate_size + Aerospike::FIELD_HEADER_SIZE + 1
60
+ end
61
+
62
+ has_write = false
63
+ @ops&.each do |op|
64
+ if op.is_write?
65
+ has_write = true
66
+ end
67
+
68
+ size += op.bin_name.bytesize + Aerospike::OPERATION_HEADER_SIZE if op.bin_name
69
+ size += op.bin_value.estimate_size if op.bin_value
70
+ end
71
+
72
+ unless has_write
73
+ raise AerospikeException.new(ResultCode::PARAMETER_ERROR, "Batch write operations do not contain a write")
74
+ end
75
+
76
+ size
77
+ end
78
+ end
79
+ end
@@ -65,9 +65,8 @@ module Aerospike
65
65
  @arguments = arguments
66
66
  end
67
67
 
68
-
69
68
  # BitResizeOp creates byte "resize" operation.
70
- # Server resizes byte[] to byte_size according to resize_flags (See {@link BitResizeFlags}).
69
+ # Server resizes byte[] to byte_size according to resize_flags (See {BitResizeFlags}).
71
70
  # Server does not return a value.
72
71
  # Example:
73
72
  # bin = [0b00000001, 0b01000010]
@@ -195,7 +194,7 @@ module Aerospike
195
194
  # BitAddOp creates bit "add" operation.
196
195
  # Server adds value to byte[] bin starting at bit_offset for bit_size. Bit_size must be <= 64.
197
196
  # Signed indicates if bits should be treated as a signed number.
198
- # If add overflows/underflows, {@link BitOverflowAction} is used.
197
+ # If add overflows/underflows, {BitOverflowAction} is used.
199
198
  # Server does not return a value.
200
199
  # Example:
201
200
  # bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
@@ -223,7 +222,7 @@ module Aerospike
223
222
  # BitSubtractOp creates bit "subtract" operation.
224
223
  # Server subtracts value from byte[] bin starting at bit_offset for bit_size. Bit_size must be <= 64.
225
224
  # Signed indicates if bits should be treated as a signed number.
226
- # If add overflows/underflows, {@link BitOverflowAction} is used.
225
+ # If add overflows/underflows, {BitOverflowAction} is used.
227
226
  # Server does not return a value.
228
227
  # Example:
229
228
  # bin = [0b00000001, 0b01000010, 0b00000011, 0b00000100, 0b00000101]
@@ -351,7 +350,7 @@ module Aerospike
351
350
  bytes = nil
352
351
  args = arguments.dup
353
352
  Packer.use do |packer|
354
- if @ctx != nil && @ctx.length > 0
353
+ if !@ctx.nil? && @ctx.length > 0
355
354
  packer.write_array_header(3)
356
355
  Value.of(0xff).pack(packer)
357
356
 
@@ -69,6 +69,14 @@ module Aerospike
69
69
  # Return true if count > 0.
70
70
  EXISTS = 13
71
71
 
72
+ ##
73
+ # Return an unordered map.
74
+ UNORDERED_MAP = 16
75
+
76
+ ##
77
+ # Return an ordered map.
78
+ ORDERED_MAP = 17
79
+
72
80
  ##
73
81
  # :private
74
82
  #
@@ -36,15 +36,7 @@ module Aerospike
36
36
  # +:fail_if_not_connected+ set to true
37
37
 
38
38
  class Client
39
- attr_accessor :default_admin_policy
40
- attr_accessor :default_batch_policy
41
- attr_accessor :default_info_policy
42
- attr_accessor :default_query_policy
43
- attr_accessor :default_read_policy
44
- attr_accessor :default_scan_policy
45
- attr_accessor :default_write_policy
46
- attr_accessor :default_operate_policy
47
- attr_accessor :cluster
39
+ attr_accessor :default_admin_policy, :default_batch_policy, :default_info_policy, :default_query_policy, :default_read_policy, :default_scan_policy, :default_write_policy, :default_operate_policy, :cluster
48
40
 
49
41
  def initialize(hosts = nil, policy: ClientPolicy.new, connect: true)
50
42
  hosts = ::Aerospike::Host::Parse.(hosts || ENV["AEROSPIKE_HOSTS"] || "localhost")
@@ -230,11 +222,11 @@ module Aerospike
230
222
  str_cmd = "truncate:namespace=#{namespace}"
231
223
  str_cmd << ";set=#{set_name}" unless set_name.to_s.strip.empty?
232
224
  else
233
- if node.supports_feature?(Aerospike::Features::TRUNCATE_NAMESPACE)
234
- str_cmd = "truncate-namespace:namespace=#{namespace}"
235
- else
236
- str_cmd = "truncate:namespace=#{namespace}"
237
- end
225
+ str_cmd = if node.supports_feature?(Aerospike::Features::TRUNCATE_NAMESPACE)
226
+ "truncate-namespace:namespace=#{namespace}"
227
+ else
228
+ "truncate:namespace=#{namespace}"
229
+ end
238
230
  end
239
231
 
240
232
  if before_last_update
@@ -329,15 +321,8 @@ module Aerospike
329
321
  bin_names = nil
330
322
  end
331
323
 
332
- if policy.use_batch_direct
333
- key_map = BatchItem.generate_map(keys)
334
- execute_batch_direct_commands(policy, keys) do |node, batch|
335
- BatchDirectCommand.new(node, batch, policy, key_map, bin_names, results, info_flags)
336
- end
337
- else
338
- execute_batch_index_commands(policy, keys) do |node, batch|
339
- BatchIndexCommand.new(node, batch, policy, bin_names, results, info_flags)
340
- end
324
+ execute_batch_index_commands(policy, keys) do |node, batch|
325
+ BatchIndexCommand.new(node, batch, policy, bin_names, results, info_flags)
341
326
  end
342
327
 
343
328
  results
@@ -351,6 +336,21 @@ module Aerospike
351
336
  batch_get(keys, :none, options)
352
337
  end
353
338
 
339
+ # Operate on multiple records for specified batch keys in one batch call.
340
+ # This method allows different namespaces/bins for each key in the batch.
341
+ # The returned records are located in the same list.
342
+ #
343
+ # records can be BatchRead, BatchWrite, BatchDelete or BatchUDF.
344
+ #
345
+ # Requires server version 6.0+
346
+ def batch_operate(records, options = nil)
347
+ policy = create_policy(options, BatchPolicy, default_batch_policy)
348
+
349
+ execute_batch_operate_commands(policy, records) do |node, batch|
350
+ BatchOperateCommand.new(node, batch, policy, records)
351
+ end
352
+ end
353
+
354
354
  # Check if multiple record keys exist in one batch call.
355
355
  # The returned boolean array is in positional order with the original key array order.
356
356
  # The policy can be used to specify timeouts and protocol type.
@@ -358,15 +358,8 @@ module Aerospike
358
358
  policy = create_policy(options, BatchPolicy, default_batch_policy)
359
359
  results = Array.new(keys.length)
360
360
 
361
- if policy.use_batch_direct
362
- key_map = BatchItem.generate_map(keys)
363
- execute_batch_direct_commands(policy, keys) do |node, batch|
364
- BatchDirectExistsCommand.new(node, batch, policy, key_map, results)
365
- end
366
- else
367
- execute_batch_index_commands(policy, keys) do |node, batch|
368
- BatchIndexExistsCommand.new(node, batch, policy, results)
369
- end
361
+ execute_batch_index_commands(policy, keys) do |node, batch|
362
+ BatchIndexExistsCommand.new(node, batch, policy, results)
370
363
  end
371
364
 
372
365
  results
@@ -430,7 +423,7 @@ module Aerospike
430
423
  end
431
424
 
432
425
  if res["error"]
433
- raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res["error"]}\nFile: #{res["file"]}\nLine: #{res["line"]}\nMessage: #{res["message"]}")
426
+ raise Aerospike::Exceptions::CommandRejected.new("Registration failed: #{res['error']}\nFile: #{res['file']}\nLine: #{res['line']}\nMessage: #{res['message']}")
434
427
  end
435
428
 
436
429
  UdfRegisterTask.new(@cluster, server_path)
@@ -566,7 +559,8 @@ module Aerospike
566
559
  # ctx is an optional list of context. Supported on server v6.1+.
567
560
  def create_index(namespace, set_name, index_name, bin_name, index_type, collection_type = nil, options = nil, ctx: nil)
568
561
  if options.nil? && collection_type.is_a?(Hash)
569
- options, collection_type = collection_type, nil
562
+ options = collection_type
563
+ collection_type = nil
570
564
  end
571
565
  policy = create_policy(options, Policy, default_info_policy)
572
566
 
@@ -943,13 +937,11 @@ module Aerospike
943
937
  when Hash
944
938
  policy_klass.new(policy)
945
939
  else
946
- fail TypeError, "policy should be a #{policy_klass.name} instance or a Hash"
940
+ raise TypeError, "policy should be a #{policy_klass.name} instance or a Hash"
947
941
  end
948
942
  end
949
943
 
950
- def cluster=(cluster)
951
- @cluster = cluster
952
- end
944
+ attr_writer :cluster
953
945
 
954
946
  def cluster_config_changed(cluster)
955
947
  Aerospike.logger.debug { "Cluster config change detected; active nodes: #{cluster.nodes.map(&:name)}" }
@@ -999,24 +991,18 @@ module Aerospike
999
991
  threads.each(&:join)
1000
992
  end
1001
993
 
1002
- def execute_batch_direct_commands(policy, keys)
994
+ def execute_batch_operate_commands(policy, records)
1003
995
  if @cluster.nodes.empty?
1004
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing Batch Direct command failed because cluster is empty.")
996
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Executing Batch Index command failed because cluster is empty.")
1005
997
  end
1006
998
 
1007
- batch_nodes = BatchDirectNode.generate_list(@cluster, policy.replica, keys)
999
+ batch_nodes = BatchOperateNode.generate_list(@cluster, policy.replica, records)
1008
1000
  threads = []
1009
1001
 
1010
- # Use a thread per namespace per node
1011
- batch_nodes.each do |batch_node|
1012
- # copy to avoid race condition
1013
- bn = batch_node
1014
- bn.batch_namespaces.each do |batch|
1015
- threads << Thread.new do
1016
- Thread.current.abort_on_exception = true
1017
- command = yield batch_node.node, batch
1018
- execute_command(command)
1019
- end
1002
+ batch_nodes.each do |batch|
1003
+ threads << Thread.new do
1004
+ command = yield batch.node, batch
1005
+ execute_command(command)
1020
1006
  end
1021
1007
  end
1022
1008
 
@@ -120,15 +120,15 @@ module Aerospike
120
120
  # Returns a node on the cluster for read operations
121
121
  def batch_read_node(partition, replica_policy)
122
122
  case replica_policy
123
- when Aerospike::Replica::MASTER, Aerospike::Replica::SEQUENCE
124
- return master_node(partition)
125
- when Aerospike::Replica::MASTER_PROLES
126
- return master_proles_node(partition)
127
- when Aerospike::Replica::PREFER_RACK
128
- return rack_node(partition, seq)
129
- when Aerospike::Replica::RANDOM
130
- return random_node
131
- else
123
+ when Aerospike::Replica::MASTER, Aerospike::Replica::SEQUENCE
124
+ master_node(partition)
125
+ when Aerospike::Replica::MASTER_PROLES
126
+ master_proles_node(partition)
127
+ when Aerospike::Replica::PREFER_RACK
128
+ rack_node(partition, seq)
129
+ when Aerospike::Replica::RANDOM
130
+ random_node
131
+ else
132
132
  raise Aerospike::Exceptions::InvalidNode("invalid policy.replica value")
133
133
  end
134
134
  end
@@ -136,17 +136,17 @@ module Aerospike
136
136
  # Returns a node on the cluster for read operations
137
137
  def read_node(partition, replica_policy, seq)
138
138
  case replica_policy
139
- when Aerospike::Replica::MASTER
140
- return master_node(partition)
141
- when Aerospike::Replica::MASTER_PROLES
142
- return master_proles_node(partition)
143
- when Aerospike::Replica::PREFER_RACK
144
- return rack_node(partition, seq)
145
- when Aerospike::Replica::SEQUENCE
146
- return sequence_node(partition, seq)
147
- when Aerospike::Replica::RANDOM
148
- return random_node
149
- else
139
+ when Aerospike::Replica::MASTER
140
+ master_node(partition)
141
+ when Aerospike::Replica::MASTER_PROLES
142
+ master_proles_node(partition)
143
+ when Aerospike::Replica::PREFER_RACK
144
+ rack_node(partition, seq)
145
+ when Aerospike::Replica::SEQUENCE
146
+ sequence_node(partition, seq)
147
+ when Aerospike::Replica::RANDOM
148
+ random_node
149
+ else
150
150
  raise Aerospike::Exceptions::InvalidNode("invalid policy.replica value")
151
151
  end
152
152
  end
@@ -155,12 +155,12 @@ module Aerospike
155
155
  def master_node(partition)
156
156
  partition_map = partitions
157
157
  replica_array = partition_map[partition.namespace]
158
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
158
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless replica_array
159
159
 
160
- node_array = (replica_array.get)[0]
161
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !node_array
160
+ node_array = replica_array.get[0]
161
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless node_array
162
162
 
163
- node = (node_array.get)[partition.partition_id]
163
+ node = node_array.get[partition.partition_id]
164
164
  raise Aerospike::Exceptions::InvalidNode if !node || !node.active?
165
165
 
166
166
  node
@@ -170,7 +170,7 @@ module Aerospike
170
170
  def rack_node(partition, seq)
171
171
  partition_map = partitions
172
172
  replica_array = partition_map[partition.namespace]
173
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
173
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless replica_array
174
174
 
175
175
  replica_array = replica_array.get
176
176
 
@@ -179,10 +179,10 @@ module Aerospike
179
179
  node = nil
180
180
  fallback = nil
181
181
  for i in 1..replica_array.length
182
- idx = (seq.update{|v| v.succ} % replica_array.size).abs
183
- node = (replica_array[idx].get)[partition.partition_id]
182
+ idx = (seq.update { |v| v.succ } % replica_array.size).abs
183
+ node = replica_array[idx].get[partition.partition_id]
184
184
 
185
- next if !node
185
+ next unless node
186
186
 
187
187
  fallback = node
188
188
 
@@ -202,14 +202,14 @@ module Aerospike
202
202
  def master_proles_node(partition)
203
203
  partition_map = partitions
204
204
  replica_array = partition_map[partition.namespace]
205
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
205
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless replica_array
206
206
 
207
207
  replica_array = replica_array.get
208
208
 
209
209
  node = nil
210
210
  for replica in replica_array
211
- idx = (@replica_index.update{|v| v.succ} % replica_array.size).abs
212
- node = (replica_array[idx].get)[partition.partition_id]
211
+ idx = (@replica_index.update { |v| v.succ } % replica_array.size).abs
212
+ node = replica_array[idx].get[partition.partition_id]
213
213
 
214
214
  return node if node && node.active?
215
215
  end
@@ -221,14 +221,14 @@ module Aerospike
221
221
  def sequence_node(partition, seq)
222
222
  partition_map = partitions
223
223
  replica_array = partition_map[partition.namespace]
224
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
224
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless replica_array
225
225
 
226
226
  replica_array = replica_array.get
227
227
 
228
228
  node = nil
229
229
  for replica in replica_array
230
- idx = (seq.update{|v| v.succ} % replica_array.size).abs
231
- node = (replica_array[idx].get)[partition.partition_id]
230
+ idx = (seq.update { |v| v.succ } % replica_array.size).abs
231
+ node = replica_array[idx].get[partition.partition_id]
232
232
 
233
233
  return node if node && node.active?
234
234
  end
@@ -236,9 +236,13 @@ module Aerospike
236
236
  raise Aerospike::Exceptions::InvalidNode
237
237
  end
238
238
 
239
- def get_node_for_key(replica_policy, key)
239
+ def get_node_for_key(replica_policy, key, is_write: false)
240
240
  partition = Partition.new_by_key(key)
241
- batch_read_node(partition, replica_policy)
241
+ if is_write
242
+ master_node(partition)
243
+ else
244
+ batch_read_node(partition, replica_policy)
245
+ end
242
246
  end
243
247
 
244
248
  # Returns partitions pertaining to a node
@@ -247,10 +251,10 @@ module Aerospike
247
251
 
248
252
  partition_map = partitions
249
253
  replica_array = partition_map[namespace]
250
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !replica_array
254
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless replica_array
251
255
 
252
- node_array = (replica_array.get)[0]
253
- raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") if !node_array
256
+ node_array = replica_array.get[0]
257
+ raise Aerospike::Exceptions::InvalidNamespace("namespace not found in the partition map") unless node_array
254
258
 
255
259
 
256
260
  pid = 0
@@ -270,7 +274,7 @@ module Aerospike
270
274
  i = 0
271
275
  while i < length
272
276
  # Must handle concurrency with other non-tending threads, so node_index is consistent.
273
- idx = (@node_index.update{ |v| v.succ } % node_array.length).abs
277
+ idx = (@node_index.update { |v| v.succ } % node_array.length).abs
274
278
  node = node_array[idx]
275
279
 
276
280
  return node if node.active?
@@ -366,13 +370,13 @@ module Aerospike
366
370
  @tend_thread = Thread.new do
367
371
  Thread.current.abort_on_exception = false
368
372
  loop do
369
- begin
373
+
370
374
  tend
371
375
  sleep(@tend_interval / 1000.0)
372
- rescue => e
376
+ rescue => e
373
377
  Aerospike.logger.error("Exception occured during tend: #{e}")
374
378
  Aerospike.logger.debug { e.backtrace.join("\n") }
375
- end
379
+
376
380
  end
377
381
  end
378
382
  end
@@ -453,7 +457,7 @@ module Aerospike
453
457
 
454
458
  def log_tend_stats(nodes)
455
459
  diff = nodes.size - @old_node_count
456
- action = "#{diff.abs} #{diff.abs == 1 ? "node has" : "nodes have"} #{diff > 0 ? "joined" : "left"} the cluster."
460
+ action = "#{diff.abs} #{diff.abs == 1 ? 'node has' : 'nodes have'} #{diff > 0 ? 'joined' : 'left'} the cluster."
457
461
  Aerospike.logger.info("Tend finished. #{action} Old node count: #{@old_node_count}, New node count: #{nodes.size}")
458
462
  @old_node_count = nodes.size
459
463
  end
@@ -689,11 +693,11 @@ module Aerospike
689
693
  end
690
694
 
691
695
  def node_exists(search, node_list)
692
- node_list.any? {|node| node == search }
696
+ node_list.any? { |node| node == search }
693
697
  end
694
698
 
695
699
  def find_node_by_name(node_name)
696
- nodes.detect{|node| node.name == node_name }
700
+ nodes.detect { |node| node.name == node_name }
697
701
  end
698
702
  end
699
703
  end
@@ -21,11 +21,7 @@ module Aerospike
21
21
 
22
22
  class BatchIndexCommand < MultiCommand #:nodoc:
23
23
 
24
- attr_accessor :batch
25
- attr_accessor :policy
26
- attr_accessor :bin_names
27
- attr_accessor :results
28
- attr_accessor :read_attr
24
+ attr_accessor :batch, :policy, :bin_names, :results, :read_attr
29
25
 
30
26
  def initialize(node, batch, policy, bin_names, results, read_attr)
31
27
  super(node)
@@ -42,8 +38,8 @@ module Aerospike
42
38
  field_count_row = 1
43
39
  field_count = 1
44
40
 
45
- predexp_size = estimate_predexp(@policy.predexp)
46
- field_count += 1 if predexp_size > 0
41
+ exp_size = estimate_expression_size(@policy.filter_exp)
42
+ field_count += 1 if exp_size > 0
47
43
 
48
44
  if bin_names
49
45
  bin_names.each do |bin_name|
@@ -58,7 +54,7 @@ module Aerospike
58
54
  batch.keys.each do |key|
59
55
  @data_offset += key.digest.length + 4 # 4 byte batch offset
60
56
 
61
- if prev != nil && prev.namespace == key.namespace
57
+ if !prev.nil? && prev.namespace == key.namespace
62
58
  @data_offset += 1
63
59
  else
64
60
  @data_offset += key.namespace.bytesize + FIELD_HEADER_SIZE + 1 + 1 + 2 + 2 # repeat/no-repeat flag + read_attr flags + field_count + operation_count
@@ -68,7 +64,7 @@ module Aerospike
68
64
  size_buffer
69
65
  write_header_read(policy, read_attr | INFO1_BATCH, 0, field_count, 0)
70
66
 
71
- write_predexp(@policy.predexp, predexp_size)
67
+ write_filter_exp(@policy.filter_exp, exp_size)
72
68
 
73
69
  write_field_header(0, Aerospike::FieldType::BATCH_INDEX)
74
70
  @data_offset += @data_buffer.write_int32(batch.keys.length, @data_offset)
@@ -80,7 +76,7 @@ module Aerospike
80
76
  @data_offset += @data_buffer.write_int32(index, @data_offset)
81
77
  @data_offset += @data_buffer.write_binary(key.digest, @data_offset)
82
78
 
83
- if (prev != nil && prev.namespace == key.namespace)
79
+ if !prev.nil? && prev.namespace == key.namespace
84
80
  @data_offset += @data_buffer.write_byte(1, @data_offset)
85
81
  else
86
82
  @data_offset += @data_buffer.write_byte(0, @data_offset)
@@ -19,13 +19,12 @@ module Aerospike
19
19
 
20
20
  class BatchIndexNode #:nodoc:
21
21
 
22
- attr_accessor :node
23
- attr_accessor :keys_by_idx
22
+ attr_accessor :node, :keys_by_idx
24
23
 
25
24
  def self.generate_list(cluster, replica_policy, keys)
26
25
  keys.each_with_index
27
- .group_by { |key, _| cluster.get_node_for_key(replica_policy, key) }
28
- .map { |node, keys_with_idx| BatchIndexNode.new(node, keys_with_idx) }
26
+ .group_by { |key, _| cluster.get_node_for_key(replica_policy, key) }
27
+ .map { |node, keys_with_idx| BatchIndexNode.new(node, keys_with_idx) }
29
28
  end
30
29
 
31
30
  def initialize(node, keys_with_idx)