aerospike 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02e8ccb3f64b4605bc10b58af760e35373209b7323b2c06cc04f133dd12c4b7d
4
- data.tar.gz: 2b396aec824a2057daef8a6bd054c00bb103e2afd32f2d4c30de6e97853997f3
3
+ metadata.gz: e4509fc71b11809038c6ea0a8853e92de02fcade0f8e29723e7507a029f7a5e1
4
+ data.tar.gz: 8fd24ad2f984e728c9e6137b7bf6527aaa07a1371c9d46539de7f066048b13e0
5
5
  SHA512:
6
- metadata.gz: 6eb54355ef98807e3523c93bce1b5c2b440a1340387d351da5fb310f11c513d69622f60e309129ac4ea8897d26f5f3bf38362b3c6995a8241d023e383e17a887
7
- data.tar.gz: 217f6f2a2a0b782d0309e7a487416bf47be2e9225dce5899d1d9e54b2b7578a26e9e0535d9ce5dc1a53bf3b1be87c865218482a59ba4e216a68803328c7608ba
6
+ metadata.gz: 41aaaabe27c7f9a9080fb33a10444bef59f5ba6482b775d6b812529b3cc4f4656665a4e7294d328df3048c18519fafd99ac448b333c7a0506c78305a685c579e
7
+ data.tar.gz: adf16fbcb8247ac8724d1823a1072cf5796f52477fb5a9bbe84f17a6ad71402f33b3ba2db9777a8b907737d291b7e5d9a98fa6ec7595093c5fb2d0cf24915de8
@@ -2,7 +2,20 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [Unreleased]
5
+ ## [2.12.0] - 2019-04-21
6
+
7
+ * **New Features**
8
+ * Support for predicate expressions in all transaction.
9
+ * Support for `operation.delete` in `client#operate`.
10
+
11
+ * **Improvements**
12
+ * Optimize serialization for nested structures. Thanks to [@Kacper Madej](https://github.com/madejejej)! [[#94](https://github.com/aerospike/aerospike-client-ruby/pull/94)]
13
+ * 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)]
14
+ * Does not allow values other than Integer, Float, String, Symbol and nil to be used as keys in Maps.
15
+
16
+ * **Bug Fixes**
17
+ * Fixes tests that weren't using ENV variables for connections. This will allow the tests to be run on any server.
18
+
6
19
 
7
20
  ## [2.11.0] - 2019-05-17
8
21
 
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
@@ -894,7 +894,6 @@ module Aerospike
894
894
 
895
895
  batch_nodes.each do |batch|
896
896
  threads << Thread.new do
897
- Thread.current.abort_on_exception = true
898
897
  command = yield batch.node, batch
899
898
  execute_command(command)
900
899
  end
@@ -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
 
@@ -78,13 +78,16 @@ module Aerospike
78
78
  class Command #:nodoc:
79
79
 
80
80
  def initialize(node)
81
+ @data_offset = 0
82
+ @data_buffer = nil
83
+
81
84
  @node = node
82
85
 
83
86
  self
84
87
  end
85
88
 
86
89
  # List of all bins that this command will write to - sub-classes should
87
- # overrite this as appropriate.
90
+ # override this as appropriate.
88
91
  def write_bins
89
92
  []
90
93
  end
@@ -93,6 +96,9 @@ module Aerospike
93
96
  def set_write(policy, operation, key, bins)
94
97
  begin_cmd
95
98
  field_count = estimate_key_size(key, policy)
99
+
100
+ predexp_size = estimate_predexp(policy.predexp)
101
+ field_count += 1 if predexp_size > 0
96
102
 
97
103
  bins.each do |bin|
98
104
  estimate_operation_size_for_bin(bin)
@@ -102,6 +108,7 @@ module Aerospike
102
108
 
103
109
  write_header_with_policy(policy, 0, INFO2_WRITE, field_count, bins.length)
104
110
  write_key(key, policy)
111
+ write_predexp(policy.predexp, predexp_size)
105
112
 
106
113
  bins.each do |bin|
107
114
  write_operation_for_bin(bin, operation)
@@ -114,9 +121,14 @@ module Aerospike
114
121
  def set_delete(policy, key)
115
122
  begin_cmd
116
123
  field_count = estimate_key_size(key)
124
+
125
+ predexp_size = estimate_predexp(policy.predexp)
126
+ field_count += 1 if predexp_size > 0
127
+
117
128
  size_buffer
118
129
  write_header_with_policy(policy, 0, INFO2_WRITE|INFO2_DELETE, field_count, 0)
119
130
  write_key(key)
131
+ write_predexp(policy.predexp, predexp_size)
120
132
  end_cmd
121
133
  end
122
134
 
@@ -124,10 +136,15 @@ module Aerospike
124
136
  def set_touch(policy, key)
125
137
  begin_cmd
126
138
  field_count = estimate_key_size(key)
139
+
140
+ predexp_size = estimate_predexp(policy.predexp)
141
+ field_count += 1 if predexp_size > 0
142
+
127
143
  estimate_operation_size
128
144
  size_buffer
129
145
  write_header_with_policy(policy, 0, INFO2_WRITE, field_count, 1)
130
146
  write_key(key)
147
+ write_predexp(policy.predexp, predexp_size)
131
148
  write_operation_for_operation_type(Aerospike::Operation::TOUCH)
132
149
  end_cmd
133
150
  end
@@ -136,9 +153,14 @@ module Aerospike
136
153
  def set_exists(policy, key)
137
154
  begin_cmd
138
155
  field_count = estimate_key_size(key)
156
+
157
+ predexp_size = estimate_predexp(policy.predexp)
158
+ field_count += 1 if predexp_size > 0
159
+
139
160
  size_buffer
140
161
  write_header(policy, INFO1_READ|INFO1_NOBINDATA, 0, field_count, 0)
141
162
  write_key(key)
163
+ write_predexp(policy.predexp, predexp_size)
142
164
  end_cmd
143
165
  end
144
166
 
@@ -146,9 +168,14 @@ module Aerospike
146
168
  def set_read_for_key_only(policy, key)
147
169
  begin_cmd
148
170
  field_count = estimate_key_size(key)
171
+
172
+ predexp_size = estimate_predexp(policy.predexp)
173
+ field_count += 1 if predexp_size > 0
174
+
149
175
  size_buffer
150
176
  write_header(policy, INFO1_READ|INFO1_GET_ALL, 0, field_count, 0)
151
177
  write_key(key)
178
+ write_predexp(policy.predexp, predexp_size)
152
179
  end_cmd
153
180
  end
154
181
 
@@ -157,6 +184,10 @@ module Aerospike
157
184
  if bin_names && bin_names.length > 0
158
185
  begin_cmd
159
186
  field_count = estimate_key_size(key)
187
+
188
+ predexp_size = estimate_predexp(policy.predexp)
189
+ field_count += 1 if predexp_size > 0
190
+
160
191
 
161
192
  bin_names.each do |bin_name|
162
193
  estimate_operation_size_for_bin_name(bin_name)
@@ -165,6 +196,7 @@ module Aerospike
165
196
  size_buffer
166
197
  write_header(policy, INFO1_READ, 0, field_count, bin_names.length)
167
198
  write_key(key)
199
+ write_predexp(policy.predexp, predexp_size)
168
200
 
169
201
  bin_names.each do |bin_name|
170
202
  write_operation_for_bin_name(bin_name, Aerospike::Operation::READ)
@@ -180,6 +212,10 @@ module Aerospike
180
212
  def set_read_header(policy, key)
181
213
  begin_cmd
182
214
  field_count = estimate_key_size(key)
215
+
216
+ predexp_size = estimate_predexp(policy.predexp)
217
+ field_count += 1 if predexp_size > 0
218
+
183
219
  estimate_operation_size_for_bin_name('')
184
220
  size_buffer
185
221
 
@@ -190,6 +226,7 @@ module Aerospike
190
226
  write_header(policy, INFO1_READ, 0, field_count, 1)
191
227
 
192
228
  write_key(key)
229
+ write_predexp(policy.predexp, predexp_size)
193
230
  write_operation_for_bin_name('', Aerospike::Operation::READ)
194
231
  end_cmd
195
232
  end
@@ -198,6 +235,10 @@ module Aerospike
198
235
  def set_operate(policy, key, operations)
199
236
  begin_cmd
200
237
  field_count = estimate_key_size(key, policy)
238
+
239
+ predexp_size = estimate_predexp(policy.predexp)
240
+ field_count += 1 if predexp_size > 0
241
+
201
242
  read_attr = 0
202
243
  write_attr = 0
203
244
  read_header = false
@@ -205,19 +246,22 @@ module Aerospike
205
246
  operations.each do |operation|
206
247
  case operation.op_type
207
248
  when Aerospike::Operation::READ
208
- read_attr |= INFO1_READ
249
+ read_attr |= INFO1_READ
209
250
 
210
251
  # Read all bins if no bin is specified.
211
252
  read_attr |= INFO1_GET_ALL unless operation.bin_name
212
253
 
213
254
  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
255
+ # The server does not currently return record header data with _INFO1_NOBINDATA attribute set.
256
+ # The workaround is to request a non-existent bin.
257
+ # TODO: Fix this on server.
258
+ # read_attr |= _INFO1_READ | _INFO1_NOBINDATA
259
+ read_attr |= INFO1_READ
219
260
  read_header = true
220
261
 
262
+ when Aerospike::Operation::CDT_READ
263
+ read_attr |= INFO1_READ
264
+
221
265
  else
222
266
  write_attr = INFO2_WRITE
223
267
  end
@@ -232,6 +276,7 @@ module Aerospike
232
276
  write_header(policy, read_attr, write_attr, field_count, operations.length)
233
277
  end
234
278
  write_key(key, policy)
279
+ write_predexp(policy.predexp, predexp_size)
235
280
 
236
281
  operations.each do |operation|
237
282
  write_operation_for_operation(operation)
@@ -245,6 +290,10 @@ module Aerospike
245
290
  def set_udf(policy, key, package_name, function_name, args)
246
291
  begin_cmd
247
292
  field_count = estimate_key_size(key, policy)
293
+
294
+ predexp_size = estimate_predexp(policy.predexp)
295
+ field_count += 1 if predexp_size > 0
296
+
248
297
  arg_bytes = args.to_bytes
249
298
 
250
299
  field_count += estimate_udf_size(package_name, function_name, arg_bytes)
@@ -252,6 +301,7 @@ module Aerospike
252
301
 
253
302
  write_header(policy, 0, INFO2_WRITE, field_count, 0)
254
303
  write_key(key, policy)
304
+ write_predexp(policy.predexp, predexp_size)
255
305
  write_field_string(package_name, Aerospike::FieldType::UDF_PACKAGE_NAME)
256
306
  write_field_string(function_name, Aerospike::FieldType::UDF_FUNCTION)
257
307
  write_field_bytes(arg_bytes, Aerospike::FieldType::UDF_ARGLIST)
@@ -273,6 +323,9 @@ module Aerospike
273
323
  @data_offset += set_name.bytesize + FIELD_HEADER_SIZE
274
324
  field_count += 1
275
325
  end
326
+
327
+ predexp_size = estimate_predexp(policy.predexp)
328
+ field_count += 1 if predexp_size > 0
276
329
 
277
330
  # Estimate scan options size.
278
331
  @data_offset += 2 + FIELD_HEADER_SIZE
@@ -310,6 +363,8 @@ module Aerospike
310
363
  write_field_string(set_name, Aerospike::FieldType::TABLE)
311
364
  end
312
365
 
366
+ write_predexp(policy.predexp, predexp_size)
367
+
313
368
  write_field_header(2, Aerospike::FieldType::SCAN_OPTIONS)
314
369
 
315
370
  priority = policy.priority & 0xFF
@@ -498,6 +553,16 @@ module Aerospike
498
553
  @data_offset += OPERATION_HEADER_SIZE
499
554
  end
500
555
 
556
+ def estimate_predexp(predexp)
557
+ if predexp && predexp.size > 0
558
+ @data_offset += FIELD_HEADER_SIZE
559
+ sz = Aerospike::PredExp.estimate_size(predexp)
560
+ @data_offset += sz
561
+ return sz
562
+ end
563
+ return 0
564
+ end
565
+
501
566
  # Generic header write.
502
567
  def write_header(policy, read_attr, write_attr, field_count, operation_count)
503
568
  read_attr |= INFO1_CONSISTENCY_ALL if policy.consistency_level == Aerospike::ConsistencyLevel::CONSISTENCY_ALL
@@ -696,6 +761,15 @@ module Aerospike
696
761
  @data_offset += 1
697
762
  end
698
763
 
764
+ def write_predexp(predexp, predexp_size)
765
+ if predexp && predexp.size > 0
766
+ write_field_header(predexp_size, Aerospike::FieldType::PREDEXP)
767
+ @data_offset = Aerospike::PredExp.write(
768
+ predexp, @data_buffer, @data_offset
769
+ )
770
+ end
771
+ end
772
+
699
773
  def begin_cmd
700
774
  @data_offset = MSG_TOTAL_HEADER_SIZE
701
775
  end
@@ -43,13 +43,25 @@ module Aerospike
43
43
 
44
44
  result_code = @data_buffer.read(13).ord & 0xFF
45
45
 
46
- if (result_code != 0) && (result_code != Aerospike::ResultCode::KEY_NOT_FOUND_ERROR)
47
- raise Aerospike::Exceptions::Aerospike.new(result_code)
46
+ if result_code == 0
47
+ @existed = true
48
+ return
48
49
  end
49
50
 
50
- @existed = (result_code == 0)
51
+ if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
52
+ @existed = false
53
+ return
54
+ end
55
+
56
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
57
+ if @policy.fail_on_filtered_out
58
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
59
+ end
60
+ @existed = true
61
+ return
62
+ end
51
63
 
52
- empty_socket
64
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
53
65
  end
54
66
 
55
67
  end # class
@@ -43,13 +43,25 @@ module Aerospike
43
43
 
44
44
  result_code = @data_buffer.read(13).ord & 0xFF
45
45
 
46
- if (result_code != 0) && (result_code != Aerospike::ResultCode::KEY_NOT_FOUND_ERROR)
47
- raise Aerospike::Exceptions::Aerospike.new(result_code)
46
+ if result_code == 0
47
+ @exists = true
48
+ return
48
49
  end
49
50
 
50
- @exists = (result_code == 0)
51
+ if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
52
+ @exists = false
53
+ return
54
+ end
55
+
56
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
57
+ if @policy.fail_on_filtered_out
58
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
59
+ end
60
+ @exists = true
61
+ return
62
+ end
51
63
 
52
- empty_socket
64
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
53
65
  end
54
66
 
55
67
  end # class
@@ -59,10 +59,13 @@ module Aerospike
59
59
  read_bytes(MSG_REMAINING_HEADER_SIZE)
60
60
  result_code = @data_buffer.read(5).ord & 0xFF
61
61
 
62
- # The only valid server return codes are "ok" and "not found".
62
+ # The only valid server return codes are "ok", "not found" and "filtered out".
63
63
  # If other return codes are received, then abort the batch.
64
- if result_code != 0 && result_code != Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
65
- raise Aerospike::Exceptions::Aerospike.new(result_code)
64
+ if result_code != 0
65
+ if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR || result_code == Aerospike::ResultCode::FILTERED_OUT
66
+ else
67
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
68
+ end
66
69
  end
67
70
 
68
71
  # If cmd is the end marker of the response, do not proceed further
@@ -76,29 +76,36 @@ module Aerospike
76
76
 
77
77
  end
78
78
 
79
- if result_code != 0
80
- return nil if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
81
- return nil if result_code == Aerospike::ResultCode::LARGE_ITEM_NOT_FOUND
82
- if result_code == Aerospike::ResultCode::UDF_BAD_RESPONSE
83
- begin
84
- @record = parse_record(op_count, field_count, generation, expiration)
85
- handle_udf_error(result_code)
86
- rescue => e
87
- Aerospike.logger.error("UDF execution error: #{e}")
88
- raise e
89
- end
90
-
79
+ if result_code == 0
80
+ if op_count == 0
81
+ @record = Record.new(@node, @key, nil, generation, expiration)
82
+ return
91
83
  end
92
-
93
- raise Aerospike::Exceptions::Aerospike.new(result_code)
84
+
85
+ @record = parse_record(op_count, field_count, generation, expiration)
86
+ return
94
87
  end
95
88
 
96
- if op_count == 0
97
- @record = Record.new(@node, @key, nil, generation, expiration)
89
+ return nil if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
90
+
91
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
92
+ if @policy.fail_on_filtered_out
93
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
94
+ end
98
95
  return
99
96
  end
100
97
 
101
- @record = parse_record(op_count, field_count, generation, expiration)
98
+ if result_code == Aerospike::ResultCode::UDF_BAD_RESPONSE
99
+ begin
100
+ @record = parse_record(op_count, field_count, generation, expiration)
101
+ handle_udf_error(result_code)
102
+ rescue => e
103
+ Aerospike.logger.error("UDF execution error: #{e}")
104
+ raise e
105
+ end
106
+ end
107
+
108
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
102
109
  end
103
110
 
104
111
  def handle_udf_error(result_code)
@@ -47,15 +47,23 @@ module Aerospike
47
47
  generation = @data_buffer.read_int32(14)
48
48
  expiration = @data_buffer.read_int32(18)
49
49
  @record = Record.new(@node, @key, nil, generation, expiration)
50
- else
51
- if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
52
- @record = nil
53
- else
50
+ return
51
+ end
52
+
53
+ if result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR
54
+ @record = nil
55
+ return
56
+ end
57
+
58
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
59
+ @record = nil
60
+ if @policy.fail_on_filtered_out
54
61
  raise Aerospike::Exceptions::Aerospike.new(result_code)
55
62
  end
63
+ return
56
64
  end
57
65
 
58
- empty_socket
66
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
59
67
  end
60
68
 
61
69
  end # class
@@ -40,9 +40,16 @@ module Aerospike
40
40
 
41
41
  result_code = @data_buffer.read(13).ord & 0xFF
42
42
 
43
- raise Aerospike::Exceptions::Aerospike.new(result_code) if result_code != 0
43
+ return if result_code == 0
44
44
 
45
- empty_socket
45
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
46
+ if @policy.fail_on_filtered_out
47
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
48
+ end
49
+ return
50
+ end
51
+
52
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
46
53
  end
47
54
 
48
55
  end # class
@@ -52,11 +52,16 @@ module Aerospike
52
52
 
53
53
  result_code = @data_buffer.read(13).ord & 0xFF
54
54
 
55
- if result_code != 0
56
- raise Aerospike::Exceptions::Aerospike.new(result_code)
55
+ return if result_code == 0
56
+
57
+ if result_code == Aerospike::ResultCode::FILTERED_OUT
58
+ if @policy.fail_on_filtered_out
59
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
60
+ end
61
+ return
57
62
  end
58
63
 
59
- empty_socket
64
+ raise Aerospike::Exceptions::Aerospike.new(result_code)
60
65
  end
61
66
 
62
67
  end # class
@@ -31,6 +31,7 @@ module Aerospike
31
31
  APPEND = 9
32
32
  PREPEND = 10
33
33
  TOUCH = 11
34
+ DELETE = 14
34
35
 
35
36
  def initialize(op_type, bin_name=nil, bin_value=NullValue.new)
36
37
  @op_type = op_type
@@ -71,6 +72,10 @@ module Aerospike
71
72
  Operation.new(TOUCH)
72
73
  end
73
74
 
75
+ def self.delete
76
+ Operation.new(DELETE)
77
+ end
78
+
74
79
  end
75
80
 
76
81
  end # module
@@ -22,7 +22,8 @@ module Aerospike
22
22
  # Container object for client policy command.
23
23
  class Policy
24
24
 
25
- attr_accessor :priority, :timeout, :max_retries, :sleep_between_retries, :consistency_level
25
+ attr_accessor :priority, :timeout, :max_retries, :sleep_between_retries, :consistency_level,
26
+ :predexp, :fail_on_filtered_out
26
27
 
27
28
  def initialize(opt={})
28
29
  # Container object for transaction policy attributes used in all database
@@ -32,6 +33,50 @@ module Aerospike
32
33
  # Currently, only used for scans.
33
34
  @priority = opt[:priority] || Priority::DEFAULT
34
35
 
36
+ # Set optional predicate expression filters in postfix notation.
37
+ # Predicate expression filters are applied on the query results on the server.
38
+ # Predicate expression filters may occur on any bin in the record.
39
+ # Requires Aerospike Server versions >= 3.12
40
+ #
41
+ # Postfix notation is described here: http://wiki.c2.com/?PostfixNotation
42
+ #
43
+ # Example:
44
+ #
45
+ # (c >= 11 and c <= 20) or (d > 3 and (d < 5)
46
+ # policy.predexp = [
47
+ # PredExp.integer_bin("c"),
48
+ # PredExp.integer_value(11),
49
+ # PredExp.integer_greater_eq(),
50
+ # PredExp.integer_bin("c"),
51
+ # PredExp.integer_value(20),
52
+ # PredExp.integer_less_eq(),
53
+ # PredExp.and(2),
54
+ # PredExp.integer_bin("d"),
55
+ # PredExp.integer_value(3),
56
+ # PredExp.integer_greater(),
57
+ # PredExp.integer_bin("d"),
58
+ # PredExp.integer_value(5),
59
+ # PredExp.integer_less(),
60
+ # PredExp.and(2),
61
+ # PredExp.or(2)
62
+ # ]
63
+ #
64
+ # # Record last update time > 2017-01-15
65
+ # policy.predexp = [
66
+ # PredExp.rec_last_update(),
67
+ # PredExp.integer_value(Time.new(2017, 1, 15).to_i),
68
+ # PredExp.integer_greater(),
69
+ # PredExp.integer_greater()
70
+ # ]
71
+ @predexp = opt[:predexp] || nil
72
+
73
+
74
+ # Throw exception if @predexp is defined and that filter evaluates
75
+ # to false (transaction ignored). The Aerospike::Exceptions::Aerospike
76
+ # will contain result code Aerospike::ResultCode::FILTERED_OUT.
77
+ # This field is not applicable to batch, scan or query commands.
78
+ @fail_on_filtered_out = opt[:fail_on_filtered_out] || false
79
+
35
80
  # How replicas should be consulted in a read operation to provide the desired
36
81
  # consistency guarantee. Default to allowing one replica to be used in the
37
82
  # read operation.
@@ -93,9 +93,11 @@ module Aerospike
93
93
  @data_offset += 8 + FIELD_HEADER_SIZE
94
94
  fieldCount+=1
95
95
 
96
- if @statement.predexp
96
+ predexp = @policy.predexp || @statement.predexp
97
+
98
+ if predexp
97
99
  @data_offset += FIELD_HEADER_SIZE
98
- predSize = Aerospike::PredExp.estimate_size(@statement.predexp)
100
+ predSize = Aerospike::PredExp.estimate_size(predexp)
99
101
  @data_offset += predSize
100
102
  fieldCount += 1
101
103
  end
@@ -184,10 +186,10 @@ module Aerospike
184
186
  @data_buffer.write_int64(@statement.task_id, @data_offset)
185
187
  @data_offset += 8
186
188
 
187
- if @statement.predexp
189
+ if predexp
188
190
  write_field_header(predSize, Aerospike::FieldType::PREDEXP)
189
191
  @data_offset = Aerospike::PredExp.write(
190
- @statement.predexp, @data_buffer, @data_offset
192
+ predexp, @data_buffer, @data_offset
191
193
  )
192
194
  end
193
195
 
@@ -43,7 +43,14 @@ module Aerospike
43
43
  # aggregation function.
44
44
  @filters = []
45
45
 
46
- # Predicate expressions
46
+ # Predicate expressions in postfix notation. If the expression is evaluated to false,
47
+ # the record will be ommited in the results.
48
+ #
49
+ # This method is redundant because PredExp can now be set in the base Policy for
50
+ # any transaction (including queries).
51
+ #
52
+ # NOTE : Policy.predexp takes precedence to this value. This value will be
53
+ # deprecated in the future.
47
54
  @predexp = nil
48
55
 
49
56
  @package_name = nil
@@ -116,6 +116,12 @@ module Aerospike
116
116
  # Enterprise-only feature not supported by the community edition
117
117
  ENTERPRISE_ONLY = 25
118
118
 
119
+ # The operation cannot be applied to the current bin value on the server.
120
+ OP_NOT_APPLICABLE = 26
121
+
122
+ # The transaction was not performed because the predexp was false.
123
+ FILTERED_OUT = 27
124
+
119
125
  # There are no more records left for query.
120
126
  QUERY_END = 50
121
127
 
@@ -167,9 +173,6 @@ module Aerospike
167
173
  # A user defined function returned an error code.
168
174
  UDF_BAD_RESPONSE = 100
169
175
 
170
- # The requested item in a large collection was not found.
171
- LARGE_ITEM_NOT_FOUND = 125
172
-
173
176
  # Secondary index already exists.
174
177
  INDEX_FOUND = 200
175
178
 
@@ -295,6 +298,12 @@ module Aerospike
295
298
  when ENTERPRISE_ONLY
296
299
  "Enterprise-only feature not supported by community edition"
297
300
 
301
+ when OP_NOT_APPLICABLE
302
+ "The operation cannot be applied to the current bin value on the server."
303
+
304
+ when FILTERED_OUT
305
+ "The transaction was not performed because the predexp was false."
306
+
298
307
  when QUERY_END
299
308
  "Query end"
300
309
 
@@ -352,9 +361,6 @@ module Aerospike
352
361
  when UDF_BAD_RESPONSE
353
362
  "UDF d error"
354
363
 
355
- when LARGE_ITEM_NOT_FOUND
356
- "Large collection item not found"
357
-
358
364
  when INDEX_FOUND
359
365
  "Index already exists"
360
366
 
@@ -22,14 +22,11 @@ require 'aerospike/aerospike_exception'
22
22
  module Aerospike
23
23
  # Polymorphic value classes used to efficiently serialize objects into the wire protocol.
24
24
  class Value #:nodoc:
25
- INTEGER_RANGE = Range.new(-2**63, 2**63 - 1).freeze
26
25
 
27
26
  def self.of(value)
28
27
  case value
29
- when nil
30
- res = NULL
31
28
  when Integer
32
- if INTEGER_RANGE.cover?(value)
29
+ if value.bit_length < 64
33
30
  res = IntegerValue.new(value)
34
31
  else
35
32
  # big nums > 2**63 are not supported
@@ -49,6 +46,8 @@ module Aerospike
49
46
  res = ListValue.new(value)
50
47
  when GeoJSON
51
48
  res = GeoJSONValue.new(value)
49
+ when nil
50
+ res = NULL
52
51
  else
53
52
  # throw an exception for anything that is not supported.
54
53
  raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported.")
@@ -57,6 +56,22 @@ module Aerospike
57
56
  res
58
57
  end
59
58
 
59
+ def self.validate_hash_key(value)
60
+ case value
61
+ when Integer
62
+ if value.bit_length >= 64
63
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported as hash key.")
64
+ end
65
+ when Float
66
+ when String
67
+ when Symbol
68
+ when nil
69
+ else
70
+ # throw an exception for anything that is not supported.
71
+ raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::TYPE_NOT_SUPPORTED, "Value type #{value.class} not supported as hash key.")
72
+ end
73
+ end
74
+
60
75
  end # Value
61
76
 
62
77
  # Empty value.
@@ -137,7 +152,7 @@ module Aerospike
137
152
  end
138
153
  end
139
154
 
140
- INFINITY = InfinityValue.new.freeze
155
+ INFINITY = Value::INFINITY = InfinityValue.new.freeze
141
156
 
142
157
  # Wildcard value.
143
158
  class WildcardValue < Value #:nodoc:
@@ -178,7 +193,7 @@ module Aerospike
178
193
  end
179
194
  end
180
195
 
181
- WILDCARD = WildcardValue.new.freeze
196
+ WILDCARD = Value::WILDCARD = WildcardValue.new.freeze
182
197
 
183
198
  # Byte array value.
184
199
  class BytesValue < Value #:nodoc:
@@ -356,21 +371,16 @@ module Aerospike
356
371
  class ListValue < Value #:nodoc:
357
372
 
358
373
  def initialize(list)
359
- @list = list || nil
360
- Packer.use do |packer|
361
- pack(packer)
362
- @bytes = packer.bytes
363
- end
364
- self
374
+ @list = list || []
365
375
  end
366
376
 
367
377
  def estimate_size
368
- @bytes.bytesize
378
+ bytes.bytesize
369
379
  end
370
380
 
371
381
  def write(buffer, offset)
372
- buffer.write_binary(@bytes, offset)
373
- @bytes.bytesize
382
+ buffer.write_binary(bytes, offset)
383
+ bytes.bytesize
374
384
  end
375
385
 
376
386
  def pack(packer)
@@ -389,13 +399,26 @@ module Aerospike
389
399
  end
390
400
 
391
401
  def to_bytes
392
- @bytes
402
+ bytes
393
403
  end
394
404
 
395
405
  def to_s
396
406
  @list.map{|v| v.to_s}.to_s
397
407
  end
398
408
 
409
+ private
410
+
411
+ def bytes
412
+ return @bytes if @bytes
413
+
414
+ Packer.use do |packer|
415
+ pack(packer)
416
+ @bytes = packer.bytes
417
+ end
418
+
419
+ @bytes
420
+ end
421
+
399
422
  end
400
423
 
401
424
  # #######################################/
@@ -406,28 +429,22 @@ module Aerospike
406
429
 
407
430
  def initialize(vmap)
408
431
  @vmap = vmap || {}
409
-
410
- Packer.use do |packer|
411
- pack(packer)
412
- @bytes = packer.bytes
413
- end
414
-
415
- self
416
432
  end
417
433
 
418
434
  def estimate_size
419
- @bytes.bytesize
435
+ bytes.bytesize
420
436
  end
421
437
 
422
438
  def write(buffer, offset)
423
- buffer.write_binary(@bytes, offset)
424
- @bytes.bytesize
439
+ buffer.write_binary(bytes, offset)
440
+ bytes.bytesize
425
441
  end
426
442
 
427
443
  def pack(packer)
428
444
  packer.write_map_header(@vmap.length)
429
- # @vmap.each do |key, val|
430
445
  for key, val in @vmap
446
+ Value.validate_hash_key(key)
447
+
431
448
  Value.of(key).pack(packer)
432
449
  Value.of(val).pack(packer)
433
450
  end
@@ -442,13 +459,26 @@ module Aerospike
442
459
  end
443
460
 
444
461
  def to_bytes
445
- @bytes
462
+ bytes
446
463
  end
447
464
 
448
465
  def to_s
449
466
  @vmap.map{|k, v| "#{k.to_s} => #{v.to_s}" }.to_s
450
467
  end
451
468
 
469
+ private
470
+
471
+ def bytes
472
+ return @bytes if @bytes
473
+
474
+ Packer.use do |packer|
475
+ pack(packer)
476
+ @bytes = packer.bytes
477
+ end
478
+
479
+ @bytes
480
+ end
481
+
452
482
  end
453
483
 
454
484
  # #######################################/
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Aerospike
3
- VERSION = "2.11.0"
3
+ VERSION = "2.12.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aerospike
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.0
4
+ version: 2.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Khosrow Afroozeh
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-05-17 00:00:00.000000000 Z
12
+ date: 2020-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: msgpack
@@ -196,8 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
196
  - !ruby/object:Gem::Version
197
197
  version: '0'
198
198
  requirements: []
199
- rubyforge_project:
200
- rubygems_version: 2.7.9
199
+ rubygems_version: 3.1.2
201
200
  signing_key:
202
201
  specification_version: 4
203
202
  summary: An Aerospike driver for Ruby.