aerospike 2.11.0 → 2.12.0

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