aerospike 2.9.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
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