aerospike 2.9.0 → 2.13.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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -4
  3. data/README.md +1 -1
  4. data/lib/aerospike.rb +12 -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 +10 -11
  15. data/lib/aerospike/cluster.rb +92 -17
  16. data/lib/aerospike/cluster/partition.rb +1 -1
  17. data/lib/aerospike/cluster/partition_parser.rb +169 -0
  18. data/lib/aerospike/command/admin_command.rb +2 -3
  19. data/lib/aerospike/command/batch_direct_command.rb +1 -1
  20. data/lib/aerospike/command/batch_direct_exists_command.rb +1 -1
  21. data/lib/aerospike/command/batch_direct_node.rb +3 -3
  22. data/lib/aerospike/command/batch_index_command.rb +10 -2
  23. data/lib/aerospike/command/batch_index_node.rb +2 -2
  24. data/lib/aerospike/command/batch_item.rb +1 -1
  25. data/lib/aerospike/command/command.rb +102 -11
  26. data/lib/aerospike/command/delete_command.rb +21 -5
  27. data/lib/aerospike/command/execute_command.rb +1 -1
  28. data/lib/aerospike/command/exists_command.rb +21 -5
  29. data/lib/aerospike/command/field_type.rb +3 -1
  30. data/lib/aerospike/command/multi_command.rb +11 -4
  31. data/lib/aerospike/command/operate_command.rb +6 -1
  32. data/lib/aerospike/command/read_command.rb +29 -18
  33. data/lib/aerospike/command/read_header_command.rb +18 -6
  34. data/lib/aerospike/command/roles.rb +1 -1
  35. data/lib/aerospike/command/single_command.rb +9 -3
  36. data/lib/aerospike/command/touch_command.rb +14 -3
  37. data/lib/aerospike/command/unsupported_particle_type_validator.rb +1 -1
  38. data/lib/aerospike/command/write_command.rb +13 -4
  39. data/lib/aerospike/connection/create.rb +1 -1
  40. data/lib/aerospike/features.rb +1 -1
  41. data/lib/aerospike/geo_json.rb +70 -1
  42. data/lib/aerospike/host.rb +1 -1
  43. data/lib/aerospike/info.rb +1 -1
  44. data/lib/aerospike/key.rb +1 -1
  45. data/lib/aerospike/language.rb +1 -1
  46. data/lib/aerospike/node.rb +3 -6
  47. data/lib/aerospike/node/refresh/partitions.rb +6 -15
  48. data/lib/aerospike/node_validator.rb +45 -40
  49. data/lib/aerospike/operation.rb +6 -1
  50. data/lib/aerospike/policy/admin_policy.rb +1 -1
  51. data/lib/aerospike/policy/batch_policy.rb +1 -1
  52. data/lib/aerospike/policy/client_policy.rb +1 -1
  53. data/lib/aerospike/policy/commit_level.rb +1 -1
  54. data/lib/aerospike/policy/consistency_level.rb +1 -1
  55. data/lib/aerospike/policy/generation_policy.rb +1 -1
  56. data/lib/aerospike/policy/operate_policy.rb +1 -1
  57. data/lib/aerospike/policy/policy.rb +57 -3
  58. data/lib/aerospike/policy/priority.rb +1 -1
  59. data/lib/aerospike/policy/query_policy.rb +8 -1
  60. data/lib/aerospike/policy/record_bin_multiplicity.rb +1 -1
  61. data/lib/aerospike/policy/record_exists_action.rb +1 -1
  62. data/lib/aerospike/policy/replica.rb +38 -0
  63. data/lib/aerospike/policy/scan_policy.rb +8 -1
  64. data/lib/aerospike/policy/write_policy.rb +1 -1
  65. data/lib/aerospike/query/filter.rb +1 -1
  66. data/lib/aerospike/query/pred_exp.rb +192 -0
  67. data/lib/aerospike/query/pred_exp/and_or.rb +32 -0
  68. data/lib/aerospike/query/pred_exp/geo_json_value.rb +41 -0
  69. data/lib/aerospike/query/pred_exp/integer_value.rb +32 -0
  70. data/lib/aerospike/query/pred_exp/op.rb +27 -0
  71. data/lib/aerospike/query/pred_exp/regex.rb +32 -0
  72. data/lib/aerospike/query/pred_exp/regex_flags.rb +23 -0
  73. data/lib/aerospike/query/pred_exp/string_value.rb +29 -0
  74. data/lib/aerospike/query/query_command.rb +27 -1
  75. data/lib/aerospike/query/recordset.rb +5 -5
  76. data/lib/aerospike/query/scan_command.rb +1 -1
  77. data/lib/aerospike/query/statement.rb +12 -3
  78. data/lib/aerospike/query/stream_command.rb +9 -10
  79. data/lib/aerospike/record.rb +1 -1
  80. data/lib/aerospike/result_code.rb +13 -20
  81. data/lib/aerospike/socket/base.rb +1 -1
  82. data/lib/aerospike/task/execute_task.rb +1 -1
  83. data/lib/aerospike/task/index_task.rb +1 -1
  84. data/lib/aerospike/task/task.rb +1 -1
  85. data/lib/aerospike/task/udf_register_task.rb +1 -1
  86. data/lib/aerospike/task/udf_remove_task.rb +1 -1
  87. data/lib/aerospike/ttl.rb +1 -1
  88. data/lib/aerospike/udf.rb +1 -1
  89. data/lib/aerospike/user_role.rb +1 -1
  90. data/lib/aerospike/utils/buffer.rb +1 -1
  91. data/lib/aerospike/utils/packer.rb +1 -1
  92. data/lib/aerospike/utils/pool.rb +1 -1
  93. data/lib/aerospike/utils/unpacker.rb +7 -2
  94. data/lib/aerospike/value/particle_type.rb +1 -1
  95. data/lib/aerospike/value/value.rb +59 -29
  96. data/lib/aerospike/version.rb +1 -1
  97. metadata +15 -8
  98. data/lib/aerospike/cluster/partition_tokenizer_new.rb +0 -130
  99. data/lib/aerospike/cluster/partition_tokenizer_old.rb +0 -135
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright 2014-2017 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.
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2014-2020 Aerospike, Inc.
4
+ #
5
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
6
+ # license agreements.
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
9
+ # use this file except in compliance with the License. You may obtain a copy of
10
+ # the License at http:#www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations under
16
+ # the License.
17
+
18
+ require 'base64'
19
+
20
+ module Aerospike
21
+
22
+ class PartitionParser #:nodoc:
23
+
24
+ attr_accessor :copied, :partition_generation
25
+
26
+ PARTITION_GENERATION = "partition-generation";
27
+ REPLICAS_ALL = "replicas-all";
28
+
29
+ def initialize(node, conn)
30
+ @node = node
31
+ @conn = conn
32
+ end
33
+
34
+ def update_partitions(current_map)
35
+ # Use low-level info methods and parse byte array directly for maximum performance.
36
+ # Receive format: replicas-all\t
37
+ # <ns1>:<count>,<base 64 encoded bitmap1>,<base 64 encoded bitmap2>...;
38
+ # <ns2>:<count>,<base 64 encoded bitmap1>,<base 64 encoded bitmap2>...;\n
39
+ info_map = Info.request(@conn, PARTITION_GENERATION, REPLICAS_ALL)
40
+
41
+ @partition_generation = info_map[PARTITION_GENERATION].to_i
42
+
43
+ info = info_map[REPLICAS_ALL]
44
+ if !info || info.length == 0
45
+ raise Aerospike::Exceptions::Connection.new("#{REPLICAS_ALL} response for node #{@node.name} is empty")
46
+ end
47
+
48
+ @buffer = info
49
+ @length = info.length
50
+ @offset = 0
51
+
52
+ new_map = nil
53
+ copied = false
54
+ beginning = @offset
55
+
56
+ while @offset < @length && @buffer[@offset] != '\n'
57
+ namespace = parse_name
58
+ replica_count = parse_replica_count
59
+
60
+ replica_array = current_map[namespace]
61
+ if !replica_array
62
+ if !copied
63
+ # Make shallow copy of map.
64
+ new_map = current_map.clone
65
+ copied = true
66
+ end
67
+
68
+ replica_array = Atomic.new(Array.new(replica_count))
69
+ new_map[namespace] = replica_array
70
+ end
71
+
72
+ for replica in 0...replica_count do
73
+ node_array = (replica_array.get)[replica]
74
+
75
+ if !node_array
76
+ if !copied
77
+ # Make shallow copy of map.
78
+ new_map = current_map.clone
79
+ copied = true
80
+ end
81
+
82
+ node_array = Atomic.new(Array.new(Aerospike::Node::PARTITIONS))
83
+ new_map[namespace].update{|v| v[replica] = node_array; v}
84
+ end
85
+
86
+ restore_buffer = parse_bitmap
87
+ i = 0
88
+ while i < Aerospike::Node::PARTITIONS
89
+ if (restore_buffer[i>>3].ord & (0x80 >> (i & 7))) != 0
90
+ node_array.update{|v| v[i] = @node; v}
91
+ end
92
+ i = i.succ
93
+ end
94
+ end
95
+ end
96
+
97
+ copied ? new_map : nil
98
+ end
99
+
100
+ private
101
+
102
+ def parse_name
103
+ beginning = @offset
104
+ while @offset < @length
105
+ break if @buffer[@offset] == ':'
106
+ @offset+=1
107
+ end
108
+
109
+ # Parse namespace.
110
+ namespace = @buffer[beginning...@offset].strip
111
+
112
+ if namespace.length <= 0 || namespace.length >= 32
113
+ response = get_truncated_response
114
+ raise Aerospike::Exceptions::Parse.new(
115
+ "Invalid partition namespace #{namespace}. Response=#{response}"
116
+ )
117
+ end
118
+
119
+ @offset+=1
120
+ namespace
121
+ end
122
+
123
+ def parse_replica_count
124
+ beginning = @offset
125
+ while @offset < @length
126
+ break if @buffer[@offset] == ','
127
+ @offset+=1
128
+ end
129
+
130
+ # Parse count
131
+ count = @buffer[beginning...@offset].strip.to_i
132
+
133
+ if count < 0 || count > 4096
134
+ response = get_truncated_response
135
+ raise Aerospike::Exceptions::Parse.new(
136
+ "Invalid partition count #{count}. Response=#{response}"
137
+ )
138
+ end
139
+
140
+ @offset+=1
141
+ count
142
+ end
143
+
144
+ def parse_bitmap
145
+ beginning = @offset
146
+ while @offset < @length
147
+ break if @buffer[@offset] == ','
148
+ break if @buffer[@offset] == ';'
149
+ @offset+=1
150
+ end
151
+
152
+ bit_map_length = @offset - beginning
153
+ restore_buffer = Base64.strict_decode64(@buffer[beginning, bit_map_length])
154
+
155
+ @offset+=1
156
+ restore_buffer
157
+ end
158
+
159
+
160
+ def get_truncated_response
161
+ max = @length
162
+ @length = max if @length > 200
163
+ @buffer[0...max]
164
+ end
165
+
166
+
167
+ end # class
168
+
169
+ end # module
@@ -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.
@@ -25,7 +25,6 @@ module Aerospike
25
25
  CHANGE_PASSWORD = 4
26
26
  GRANT_ROLES = 5
27
27
  REVOKE_ROLES = 6
28
- REPLACE_ROLES = 7
29
28
  #CREATE_ROLE = 8
30
29
  QUERY_USERS = 9
31
30
  #QUERY_ROLES = 10
@@ -39,7 +38,7 @@ module Aerospike
39
38
  #PRIVILEGES = 11
40
39
 
41
40
  # Misc
42
- MSG_VERSION = 0
41
+ MSG_VERSION = 2
43
42
  MSG_TYPE = 2
44
43
 
45
44
  HEADER_SIZE = 24
@@ -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.
@@ -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.
@@ -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.
@@ -24,8 +24,8 @@ module Aerospike
24
24
  attr_accessor :node
25
25
  attr_accessor :batch_namespaces
26
26
 
27
- def self.generate_list(cluster, keys)
28
- keys.group_by { |key| cluster.get_node_for_key(key) }
27
+ def self.generate_list(cluster, replica_policy, keys)
28
+ keys.group_by { |key| cluster.get_node_for_key(replica_policy, key) }
29
29
  .map { |node, keys_for_node| BatchDirectNode.new(node, keys_for_node) }
30
30
  end
31
31
 
@@ -39,7 +39,12 @@ module Aerospike
39
39
  def write_buffer
40
40
  bin_name_size = 0
41
41
  operation_count = 0
42
+ field_count_row = 1
42
43
  field_count = 1
44
+
45
+ predexp_size = estimate_predexp(@policy.predexp)
46
+ field_count += 1 if predexp_size > 0
47
+
43
48
  if bin_names
44
49
  bin_names.each do |bin_name|
45
50
  bin_name_size += bin_name.bytesize + OPERATION_HEADER_SIZE
@@ -61,7 +66,10 @@ module Aerospike
61
66
  end
62
67
  end
63
68
  size_buffer
64
- write_header(policy,read_attr | INFO1_BATCH, 0, 1, 0)
69
+ write_header(policy,read_attr | INFO1_BATCH, 0, field_count, 0)
70
+
71
+ write_predexp(@policy.predexp, predexp_size)
72
+
65
73
  write_field_header(0, Aerospike::FieldType::BATCH_INDEX)
66
74
  @data_offset += @data_buffer.write_int32(batch.keys.length, @data_offset)
67
75
  @data_offset += @data_buffer.write_byte(1, @data_offset)
@@ -77,7 +85,7 @@ module Aerospike
77
85
  else
78
86
  @data_offset += @data_buffer.write_byte(0, @data_offset)
79
87
  @data_offset += @data_buffer.write_byte(read_attr, @data_offset)
80
- @data_offset += @data_buffer.write_int16(field_count, @data_offset)
88
+ @data_offset += @data_buffer.write_int16(field_count_row, @data_offset)
81
89
  @data_offset += @data_buffer.write_int16(operation_count, @data_offset)
82
90
  write_field_string(key.namespace, Aerospike::FieldType::NAMESPACE)
83
91
 
@@ -22,9 +22,9 @@ module Aerospike
22
22
  attr_accessor :node
23
23
  attr_accessor :keys_by_idx
24
24
 
25
- def self.generate_list(cluster, keys)
25
+ def self.generate_list(cluster, replica_policy, keys)
26
26
  keys.each_with_index
27
- .group_by { |key, _| cluster.get_node_for_key(key) }
27
+ .group_by { |key, _| cluster.get_node_for_key(replica_policy, key) }
28
28
  .map { |node, keys_with_idx| BatchIndexNode.new(node, keys_with_idx) }
29
29
  end
30
30
 
@@ -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.
@@ -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.
@@ -77,14 +77,20 @@ module Aerospike
77
77
 
78
78
  class Command #:nodoc:
79
79
 
80
- def initialize(node)
80
+ def initialize(node=nil)
81
+ @data_offset = 0
82
+ @data_buffer = nil
83
+
81
84
  @node = node
82
85
 
86
+ # will add before use
87
+ @sequence = Atomic.new(-1)
88
+
83
89
  self
84
90
  end
85
91
 
86
92
  # List of all bins that this command will write to - sub-classes should
87
- # overrite this as appropriate.
93
+ # override this as appropriate.
88
94
  def write_bins
89
95
  []
90
96
  end
@@ -93,6 +99,9 @@ module Aerospike
93
99
  def set_write(policy, operation, key, bins)
94
100
  begin_cmd
95
101
  field_count = estimate_key_size(key, policy)
102
+
103
+ predexp_size = estimate_predexp(policy.predexp)
104
+ field_count += 1 if predexp_size > 0
96
105
 
97
106
  bins.each do |bin|
98
107
  estimate_operation_size_for_bin(bin)
@@ -102,6 +111,7 @@ module Aerospike
102
111
 
103
112
  write_header_with_policy(policy, 0, INFO2_WRITE, field_count, bins.length)
104
113
  write_key(key, policy)
114
+ write_predexp(policy.predexp, predexp_size)
105
115
 
106
116
  bins.each do |bin|
107
117
  write_operation_for_bin(bin, operation)
@@ -114,9 +124,14 @@ module Aerospike
114
124
  def set_delete(policy, key)
115
125
  begin_cmd
116
126
  field_count = estimate_key_size(key)
127
+
128
+ predexp_size = estimate_predexp(policy.predexp)
129
+ field_count += 1 if predexp_size > 0
130
+
117
131
  size_buffer
118
132
  write_header_with_policy(policy, 0, INFO2_WRITE|INFO2_DELETE, field_count, 0)
119
133
  write_key(key)
134
+ write_predexp(policy.predexp, predexp_size)
120
135
  end_cmd
121
136
  end
122
137
 
@@ -124,10 +139,15 @@ module Aerospike
124
139
  def set_touch(policy, key)
125
140
  begin_cmd
126
141
  field_count = estimate_key_size(key)
142
+
143
+ predexp_size = estimate_predexp(policy.predexp)
144
+ field_count += 1 if predexp_size > 0
145
+
127
146
  estimate_operation_size
128
147
  size_buffer
129
148
  write_header_with_policy(policy, 0, INFO2_WRITE, field_count, 1)
130
149
  write_key(key)
150
+ write_predexp(policy.predexp, predexp_size)
131
151
  write_operation_for_operation_type(Aerospike::Operation::TOUCH)
132
152
  end_cmd
133
153
  end
@@ -136,9 +156,14 @@ module Aerospike
136
156
  def set_exists(policy, key)
137
157
  begin_cmd
138
158
  field_count = estimate_key_size(key)
159
+
160
+ predexp_size = estimate_predexp(policy.predexp)
161
+ field_count += 1 if predexp_size > 0
162
+
139
163
  size_buffer
140
164
  write_header(policy, INFO1_READ|INFO1_NOBINDATA, 0, field_count, 0)
141
165
  write_key(key)
166
+ write_predexp(policy.predexp, predexp_size)
142
167
  end_cmd
143
168
  end
144
169
 
@@ -146,9 +171,14 @@ module Aerospike
146
171
  def set_read_for_key_only(policy, key)
147
172
  begin_cmd
148
173
  field_count = estimate_key_size(key)
174
+
175
+ predexp_size = estimate_predexp(policy.predexp)
176
+ field_count += 1 if predexp_size > 0
177
+
149
178
  size_buffer
150
179
  write_header(policy, INFO1_READ|INFO1_GET_ALL, 0, field_count, 0)
151
180
  write_key(key)
181
+ write_predexp(policy.predexp, predexp_size)
152
182
  end_cmd
153
183
  end
154
184
 
@@ -157,6 +187,10 @@ module Aerospike
157
187
  if bin_names && bin_names.length > 0
158
188
  begin_cmd
159
189
  field_count = estimate_key_size(key)
190
+
191
+ predexp_size = estimate_predexp(policy.predexp)
192
+ field_count += 1 if predexp_size > 0
193
+
160
194
 
161
195
  bin_names.each do |bin_name|
162
196
  estimate_operation_size_for_bin_name(bin_name)
@@ -165,6 +199,7 @@ module Aerospike
165
199
  size_buffer
166
200
  write_header(policy, INFO1_READ, 0, field_count, bin_names.length)
167
201
  write_key(key)
202
+ write_predexp(policy.predexp, predexp_size)
168
203
 
169
204
  bin_names.each do |bin_name|
170
205
  write_operation_for_bin_name(bin_name, Aerospike::Operation::READ)
@@ -180,6 +215,10 @@ module Aerospike
180
215
  def set_read_header(policy, key)
181
216
  begin_cmd
182
217
  field_count = estimate_key_size(key)
218
+
219
+ predexp_size = estimate_predexp(policy.predexp)
220
+ field_count += 1 if predexp_size > 0
221
+
183
222
  estimate_operation_size_for_bin_name('')
184
223
  size_buffer
185
224
 
@@ -190,6 +229,7 @@ module Aerospike
190
229
  write_header(policy, INFO1_READ, 0, field_count, 1)
191
230
 
192
231
  write_key(key)
232
+ write_predexp(policy.predexp, predexp_size)
193
233
  write_operation_for_bin_name('', Aerospike::Operation::READ)
194
234
  end_cmd
195
235
  end
@@ -198,6 +238,10 @@ module Aerospike
198
238
  def set_operate(policy, key, operations)
199
239
  begin_cmd
200
240
  field_count = estimate_key_size(key, policy)
241
+
242
+ predexp_size = estimate_predexp(policy.predexp)
243
+ field_count += 1 if predexp_size > 0
244
+
201
245
  read_attr = 0
202
246
  write_attr = 0
203
247
  read_header = false
@@ -205,19 +249,22 @@ module Aerospike
205
249
  operations.each do |operation|
206
250
  case operation.op_type
207
251
  when Aerospike::Operation::READ
208
- read_attr |= INFO1_READ
252
+ read_attr |= INFO1_READ
209
253
 
210
254
  # Read all bins if no bin is specified.
211
255
  read_attr |= INFO1_GET_ALL unless operation.bin_name
212
256
 
213
257
  when Aerospike::Operation::READ_HEADER
214
- # The server does not currently return record header data with _INFO1_NOBINDATA attribute set.
215
- # The workaround is to request a non-existent bin.
216
- # TODO: Fix this on server.
217
- # read_attr |= _INFO1_READ | _INFO1_NOBINDATA
218
- read_attr |= INFO1_READ
258
+ # The server does not currently return record header data with _INFO1_NOBINDATA attribute set.
259
+ # The workaround is to request a non-existent bin.
260
+ # TODO: Fix this on server.
261
+ # read_attr |= _INFO1_READ | _INFO1_NOBINDATA
262
+ read_attr |= INFO1_READ
219
263
  read_header = true
220
264
 
265
+ when Aerospike::Operation::CDT_READ
266
+ read_attr |= INFO1_READ
267
+
221
268
  else
222
269
  write_attr = INFO2_WRITE
223
270
  end
@@ -232,6 +279,7 @@ module Aerospike
232
279
  write_header(policy, read_attr, write_attr, field_count, operations.length)
233
280
  end
234
281
  write_key(key, policy)
282
+ write_predexp(policy.predexp, predexp_size)
235
283
 
236
284
  operations.each do |operation|
237
285
  write_operation_for_operation(operation)
@@ -245,6 +293,10 @@ module Aerospike
245
293
  def set_udf(policy, key, package_name, function_name, args)
246
294
  begin_cmd
247
295
  field_count = estimate_key_size(key, policy)
296
+
297
+ predexp_size = estimate_predexp(policy.predexp)
298
+ field_count += 1 if predexp_size > 0
299
+
248
300
  arg_bytes = args.to_bytes
249
301
 
250
302
  field_count += estimate_udf_size(package_name, function_name, arg_bytes)
@@ -252,6 +304,7 @@ module Aerospike
252
304
 
253
305
  write_header(policy, 0, INFO2_WRITE, field_count, 0)
254
306
  write_key(key, policy)
307
+ write_predexp(policy.predexp, predexp_size)
255
308
  write_field_string(package_name, Aerospike::FieldType::UDF_PACKAGE_NAME)
256
309
  write_field_string(function_name, Aerospike::FieldType::UDF_FUNCTION)
257
310
  write_field_bytes(arg_bytes, Aerospike::FieldType::UDF_ARGLIST)
@@ -273,6 +326,14 @@ module Aerospike
273
326
  @data_offset += set_name.bytesize + FIELD_HEADER_SIZE
274
327
  field_count += 1
275
328
  end
329
+
330
+ if policy.records_per_second > 0
331
+ @data_offset += 4 + FIELD_HEADER_SIZE
332
+ field_count += 1
333
+ end
334
+
335
+ predexp_size = estimate_predexp(policy.predexp)
336
+ field_count += 1 if predexp_size > 0
276
337
 
277
338
  # Estimate scan options size.
278
339
  @data_offset += 2 + FIELD_HEADER_SIZE
@@ -310,6 +371,12 @@ module Aerospike
310
371
  write_field_string(set_name, Aerospike::FieldType::TABLE)
311
372
  end
312
373
 
374
+ if policy.records_per_second > 0
375
+ write_field_int(policy.records_per_second, Aerospike::FieldType::RECORDS_PER_SECOND)
376
+ end
377
+
378
+ write_predexp(policy.predexp, predexp_size)
379
+
313
380
  write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
314
381
 
315
382
  priority = policy.priority & 0xFF
@@ -355,6 +422,7 @@ module Aerospike
355
422
  break if @policy.timeout > 0 && Time.now > limit
356
423
 
357
424
  begin
425
+ @node = get_node
358
426
  @conn = @node.get_connection(@policy.timeout)
359
427
  rescue => e
360
428
  # Socket connection error has occurred. Decrease health and retry.
@@ -498,6 +566,16 @@ module Aerospike
498
566
  @data_offset += OPERATION_HEADER_SIZE
499
567
  end
500
568
 
569
+ def estimate_predexp(predexp)
570
+ if predexp && predexp.size > 0
571
+ @data_offset += FIELD_HEADER_SIZE
572
+ sz = Aerospike::PredExp.estimate_size(predexp)
573
+ @data_offset += sz
574
+ return sz
575
+ end
576
+ return 0
577
+ end
578
+
501
579
  # Generic header write.
502
580
  def write_header(policy, read_attr, write_attr, field_count, operation_count)
503
581
  read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
@@ -681,21 +759,34 @@ module Aerospike
681
759
  @data_offset += len
682
760
  end
683
761
 
762
+ def write_field_int(i, ftype)
763
+ @data_buffer.write_int32(i, @data_offset+FIELD_HEADER_SIZE)
764
+ write_field_header(4, ftype)
765
+ @data_offset += 4
766
+ end
767
+
684
768
  def write_field_bytes(bytes, ftype)
685
769
  @data_buffer.write_binary(bytes, @data_offset+FIELD_HEADER_SIZE)
686
-
687
770
  write_field_header(bytes.bytesize, ftype)
688
771
  @data_offset += bytes.bytesize
689
772
  end
690
773
 
691
774
  def write_field_header(size, ftype)
692
- # Buffer.Int32ToBytes(size+1), @data_buffer, @data_offset
693
775
  @data_buffer.write_int32(size+1, @data_offset)
694
776
  @data_offset += 4
695
777
  @data_buffer.write_byte(ftype, @data_offset)
696
778
  @data_offset += 1
697
779
  end
698
780
 
781
+ def write_predexp(predexp, predexp_size)
782
+ if predexp && predexp.size > 0
783
+ write_field_header(predexp_size, Aerospike::FieldType::PREDEXP)
784
+ @data_offset = Aerospike::PredExp.write(
785
+ predexp, @data_buffer, @data_offset
786
+ )
787
+ end
788
+ end
789
+
699
790
  def begin_cmd
700
791
  @data_offset = MSG_TOTAL_HEADER_SIZE
701
792
  end