aerospike 0.1.6 → 1.0.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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/lib/aerospike.rb +5 -0
  4. data/lib/aerospike/atomic/atomic.rb +3 -1
  5. data/lib/aerospike/client.rb +98 -32
  6. data/lib/aerospike/cluster/cluster.rb +25 -8
  7. data/lib/aerospike/cluster/connection.rb +1 -1
  8. data/lib/aerospike/cluster/node.rb +16 -3
  9. data/lib/aerospike/cluster/node_validator.rb +16 -4
  10. data/lib/aerospike/cluster/partition.rb +1 -1
  11. data/lib/aerospike/cluster/partition_tokenizer_new.rb +4 -2
  12. data/lib/aerospike/cluster/partition_tokenizer_old.rb +1 -1
  13. data/lib/aerospike/command/admin_command.rb +353 -0
  14. data/lib/aerospike/command/batch_command.rb +12 -42
  15. data/lib/aerospike/command/batch_command_exists.rb +1 -1
  16. data/lib/aerospike/command/batch_command_get.rb +1 -1
  17. data/lib/aerospike/command/batch_item.rb +1 -1
  18. data/lib/aerospike/command/batch_node.rb +1 -1
  19. data/lib/aerospike/command/command.rb +9 -14
  20. data/lib/aerospike/command/delete_command.rb +1 -1
  21. data/lib/aerospike/command/execute_command.rb +1 -1
  22. data/lib/aerospike/command/exists_command.rb +1 -1
  23. data/lib/aerospike/command/operate_command.rb +1 -1
  24. data/lib/aerospike/command/read_command.rb +12 -38
  25. data/lib/aerospike/command/read_header_command.rb +2 -2
  26. data/lib/aerospike/command/roles.rb +36 -0
  27. data/lib/aerospike/command/single_command.rb +1 -1
  28. data/lib/aerospike/command/touch_command.rb +1 -1
  29. data/lib/aerospike/command/write_command.rb +1 -1
  30. data/lib/aerospike/info.rb +1 -1
  31. data/lib/aerospike/loggable.rb +1 -1
  32. data/lib/aerospike/policy/admin_policy.rb +33 -0
  33. data/lib/aerospike/policy/batch_policy.rb +5 -5
  34. data/lib/aerospike/policy/client_policy.rb +15 -4
  35. data/lib/aerospike/policy/generation_policy.rb +0 -5
  36. data/lib/aerospike/policy/policy.rb +6 -6
  37. data/lib/aerospike/policy/query_policy.rb +2 -2
  38. data/lib/aerospike/policy/scan_policy.rb +6 -6
  39. data/lib/aerospike/policy/write_policy.rb +8 -8
  40. data/lib/aerospike/query/query_command.rb +1 -1
  41. data/lib/aerospike/query/scan_command.rb +1 -1
  42. data/lib/aerospike/query/stream_command.rb +1 -1
  43. data/lib/aerospike/record.rb +2 -3
  44. data/lib/aerospike/result_code.rb +11 -1
  45. data/lib/aerospike/user_role.rb +30 -0
  46. data/lib/aerospike/utils/buffer.rb +22 -2
  47. data/lib/aerospike/utils/epoc.rb +3 -1
  48. data/lib/aerospike/utils/pool.rb +1 -1
  49. data/lib/aerospike/value/value.rb +12 -13
  50. data/lib/aerospike/version.rb +1 -1
  51. metadata +6 -2
@@ -18,11 +18,12 @@ module Aerospike
18
18
 
19
19
  private
20
20
 
21
- class NodeValidator
21
+ class NodeValidator # :nodoc:
22
22
 
23
23
  attr_reader :host, :aliases, :name, :use_new_info
24
24
 
25
- def initialize(host, timeout)
25
+ def initialize(cluster, host, timeout)
26
+ @cluster = cluster
26
27
  @use_new_info = true
27
28
  @host = host
28
29
 
@@ -47,8 +48,19 @@ module Aerospike
47
48
  def set_address(timeout)
48
49
  @aliases.each do |aliass|
49
50
  begin
50
- conn = Connection.new(aliass.name, aliass.port, 1)
51
- conn.timeout = timeout
51
+ conn = Connection.new(aliass.name, aliass.port, timeout)
52
+
53
+ # need to authenticate
54
+ if @cluster.user && @cluster.user != ''
55
+ begin
56
+ command = AdminCommand.new
57
+ command.authenticate(conn, @cluster.user, @cluster.password)
58
+ rescue => e
59
+ # Socket not authenticated. Do not put back into pool.
60
+ conn.close if conn
61
+ raise e
62
+ end
63
+ end
52
64
 
53
65
  info_map= Info.request(conn, 'node', 'build')
54
66
  if node_name = info_map['node']
@@ -18,7 +18,7 @@ module Aerospike
18
18
 
19
19
  private
20
20
 
21
- class Partition
21
+ class Partition # :nodoc:
22
22
  attr_reader :namespace, :partition_id
23
23
 
24
24
  def initialize(namespace, partition_id)
@@ -22,7 +22,7 @@ module Aerospike
22
22
 
23
23
  REPLICAS_NAME = 'replicas-master'
24
24
 
25
- class PartitionTokenizerNew
25
+ class PartitionTokenizerNew #:nodoc:
26
26
 
27
27
  def initialize(conn)
28
28
  # Use low-level info methods and parse byte array directly for maximum performance.
@@ -97,11 +97,13 @@ module Aerospike
97
97
 
98
98
  bit_map_length = @offset - beginning
99
99
  restore_buffer = Base64.strict_decode64(@buffer[beginning, bit_map_length])
100
- for i in 0...Aerospike::Node::PARTITIONS
100
+ i = 0
101
+ while i < Aerospike::Node::PARTITIONS
101
102
  if (restore_buffer[i>>3].ord & (0x80 >> (i & 7))) != 0
102
103
  # Logger.Info("Map: `" + namespace + "`," + strconv.Itoa(i) + "," + node.String)
103
104
  node_array.update{|v| v[i] = node; v}
104
105
  end
106
+ i = i.succ
105
107
  end
106
108
 
107
109
  @offset+=1
@@ -20,7 +20,7 @@ module Aerospike
20
20
 
21
21
  private
22
22
 
23
- class PartitionTokenizerOld
23
+ class PartitionTokenizerOld #:nodoc:
24
24
 
25
25
  def initialize(conn)
26
26
  # Use low-level info methods and parse byte array directly for maximum performance.
@@ -0,0 +1,353 @@
1
+ # encoding: utf-8
2
+ # Copyright 2014 Aerospike, Inc.
3
+ #
4
+ # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
+ # license agreements.
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
+ # use this file except in compliance with the License. You may obtain a copy of
9
+ # the License at http:#www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations under
15
+ # the License.
16
+
17
+ module Aerospike
18
+
19
+ private
20
+ # Commands
21
+ AUTHENTICATE = 0
22
+ CREATE_USER = 1
23
+ DROP_USER = 2
24
+ SET_PASSWORD = 3
25
+ CHANGE_PASSWORD = 4
26
+ GRANT_ROLES = 5
27
+ REVOKE_ROLES = 6
28
+ REPLACE_ROLES = 7
29
+ #CREATE_ROLE = 8
30
+ QUERY_USERS = 9
31
+ #QUERY_ROLES = 10
32
+
33
+ # Field IDs
34
+ USER = 0
35
+ PASSWORD = 1
36
+ OLD_PASSWORD = 2
37
+ CREDENTIAL = 3
38
+ ROLES = 10
39
+ #PRIVILEGES = 11
40
+
41
+ # Misc
42
+ MSG_VERSION = 0
43
+ MSG_TYPE = 2
44
+
45
+ HEADER_SIZE = 24
46
+ HEADER_REMAINING = 16
47
+ RESULT_CODE = 9
48
+ QUERY_END = 50
49
+
50
+ class AdminCommand #:nodoc:
51
+
52
+ def initialize
53
+ @data_buffer = Buffer.get
54
+ @data_offset = 8
55
+ end
56
+
57
+ def authenticate(conn, user, password)
58
+ begin
59
+ set_authenticate(user, password)
60
+ conn.write(@data_buffer, @data_offset)
61
+ conn.read(@data_buffer, HEADER_SIZE)
62
+
63
+ result = @data_buffer.read(RESULT_CODE)
64
+ raise Exceptions::Aerospike.new(result, "Authentication failed") if result != 0
65
+ ensure
66
+ Buffer.put(@data_buffer)
67
+ end
68
+ end
69
+
70
+ def set_authenticate(user, password)
71
+ write_header(AUTHENTICATE, 2)
72
+ write_field_str(USER, user)
73
+ write_field_bytes(CREDENTIAL, password)
74
+ write_size
75
+
76
+ return @data_offset
77
+ end
78
+
79
+ def create_user(cluster, policy, user, password, roles)
80
+ write_header(CREATE_USER, 3)
81
+ write_field_str(USER, user)
82
+ write_field_bytes(PASSWORD, password)
83
+ write_roles(roles)
84
+ execute_command(cluster, policy)
85
+ end
86
+
87
+ def drop_user(cluster, policy, user)
88
+ write_header(DROP_USER, 1)
89
+ write_field_str(USER, user)
90
+ execute_command(cluster, policy)
91
+ end
92
+
93
+ def set_password(cluster, policy, user, password)
94
+ write_header(SET_PASSWORD, 2)
95
+ write_field_str(USER, user)
96
+ write_field_bytes(PASSWORD, password)
97
+ execute_command(cluster, policy)
98
+ end
99
+
100
+ def change_password(cluster, policy, user, password)
101
+ write_header(CHANGE_PASSWORD, 3)
102
+ write_field_str(USER, user)
103
+ write_field_bytes(OLD_PASSWORD, cluster.password)
104
+ write_field_bytes(PASSWORD, password)
105
+ execute_command(cluster, policy)
106
+ end
107
+
108
+ def grant_roles(cluster, policy, user, roles)
109
+ write_header(GRANT_ROLES, 2)
110
+ write_field_str(USER, user)
111
+ write_roles(roles)
112
+ execute_command(cluster, policy)
113
+ end
114
+
115
+ def revoke_roles(cluster, policy, user, roles)
116
+ write_header(REVOKE_ROLES, 2)
117
+ write_field_str(USER, user)
118
+ write_roles(roles)
119
+ execute_command(cluster, policy)
120
+ end
121
+
122
+ def replace_roles(cluster, policy, user, roles)
123
+ write_header(REPLACE_ROLES, 2)
124
+ write_field_str(USER, user)
125
+ write_roles(roles)
126
+ execute_command(cluster, policy)
127
+ end
128
+
129
+ def query_user(cluster, policy, user)
130
+ # TODO: Remove the workaround in the future
131
+ sleep(0.010)
132
+
133
+ list = []
134
+ begin
135
+ write_header(QUERY_USERS, 1)
136
+ write_field_str(USER, user)
137
+ list = read_users(cluster, policy)
138
+ return (list.is_a?(Array) && list.length > 0 ? list.first : nil)
139
+ ensure
140
+ Buffer.put(@data_buffer)
141
+ end
142
+ end
143
+
144
+ def query_users(cluster, policy)
145
+ # TODO: Remove the workaround in the future
146
+ sleep(0.010)
147
+ begin
148
+ write_header(QUERY_USERS, 0)
149
+ return read_users(cluster, policy)
150
+ ensure
151
+ Buffer.put(@data_buffer)
152
+ end
153
+ end
154
+
155
+ def write_roles(roles)
156
+ offset = @data_offset + FIELD_HEADER_SIZE
157
+ @data_buffer.write_byte(roles.length.ord, offset)
158
+ offset += 1
159
+
160
+ roles.each do |role|
161
+ len = @data_buffer.write_binary(role, offset+1)
162
+ @data_buffer.write_byte(len, offset)
163
+ offset += len + 1
164
+ end
165
+
166
+ size = offset - @data_offset - FIELD_HEADER_SIZE
167
+ write_field_header(ROLES, size)
168
+ @data_offset = offset
169
+ end
170
+
171
+ def write_size
172
+ # Write total size of message which is the current offset.
173
+ size = Integer(@data_offset-8) | Integer(MSG_VERSION << 56) | Integer(MSG_TYPE << 48)
174
+ @data_buffer.write_int64(size, 0)
175
+ end
176
+
177
+ def write_header(command, field_count)
178
+ # Authenticate header is almost all zeros
179
+ i = @data_offset
180
+ while i < @data_offset+16
181
+ @data_buffer.write_byte(0, i)
182
+ i = i.succ
183
+ end
184
+ @data_buffer.write_byte(command, @data_offset+2)
185
+ @data_buffer.write_byte(field_count, @data_offset+3)
186
+ @data_offset += 16
187
+ end
188
+
189
+ def write_field_str(id, str)
190
+ len = @data_buffer.write_binary(str, @data_offset+FIELD_HEADER_SIZE)
191
+ write_field_header(id, len)
192
+ @data_offset += len
193
+ end
194
+
195
+ def write_field_bytes(id, bytes)
196
+ @data_buffer.write_binary(bytes, @data_offset+FIELD_HEADER_SIZE)
197
+ write_field_header(id, bytes.bytesize)
198
+ @data_offset += bytes.bytesize
199
+ end
200
+
201
+ def write_field_header(id, size)
202
+ @data_buffer.write_int32(size+1, @data_offset)
203
+ @data_offset += 4
204
+ @data_buffer.write_byte(id, @data_offset)
205
+ @data_offset += 1
206
+ end
207
+
208
+ def execute_command(cluster, policy)
209
+ # TODO: Remove the workaround in the future
210
+ sleep(0.010)
211
+
212
+ write_size
213
+ node = cluster.random_node
214
+
215
+ timeout = 1
216
+ timeout = policy.timeout if policy && policy.timeout > 0
217
+
218
+ conn = node.get_connection(timeout)
219
+
220
+ begin
221
+ conn.write(@data_buffer, @data_offset)
222
+ conn.read(@data_buffer, HEADER_SIZE)
223
+ node.put_connection(conn)
224
+ rescue => e
225
+ conn.close if conn
226
+ raise e
227
+ end
228
+
229
+ result = @data_buffer.read(RESULT_CODE)
230
+ raise Exceptions::Aerospike.new(result) if result != 0
231
+
232
+ Buffer.put(@data_buffer)
233
+ end
234
+
235
+ def read_users(cluster, policy)
236
+ write_size
237
+ node = cluster.random_node
238
+
239
+ timeout = 1
240
+ timeout = policy.timeout if policy != nil && policy.timeout > 0
241
+
242
+ status = -1
243
+ list = []
244
+ begin
245
+ conn = node.get_connection(timeout)
246
+ conn.write(@data_buffer, @data_offset)
247
+ status, list = read_user_blocks(conn)
248
+ node.put_connection(conn)
249
+ rescue => e
250
+ conn.close if conn
251
+ raise e
252
+ end
253
+
254
+ raise Exceptions::Aerospike.new(result) if status > 0
255
+
256
+ return list
257
+ end
258
+
259
+ def read_user_blocks(conn)
260
+ rlist = []
261
+ status = 0
262
+ begin
263
+ while status == 0
264
+ conn.read(@data_buffer, 8)
265
+ size = @data_buffer.read_int64(0)
266
+ receive_size = (size & 0xFFFFFFFFFFFF)
267
+
268
+ if receive_size > 0
269
+ @data_buffer.resize(receive_size) if receive_size > @data_buffer.size
270
+
271
+ conn.read(@data_buffer, receive_size)
272
+ status, list = parse_users(receive_size)
273
+ rlist.concat(list.to_a)
274
+ else
275
+ break
276
+ end
277
+ end
278
+ return status, rlist
279
+ rescue => e
280
+ return -1, []
281
+ end
282
+ end
283
+
284
+ def parse_users(receive_size)
285
+ @data_offset = 0
286
+ list = []
287
+
288
+ while @data_offset < receive_size
289
+ result_code = @data_buffer.read(@data_offset+1)
290
+
291
+ if result_code != 0
292
+ return (result_code == QUERY_END ? -1 : result_code)
293
+ end
294
+
295
+ userRoles = UserRoles.new
296
+ field_count = @data_buffer.read(@data_offset+3)
297
+ @data_offset += HEADER_REMAINING
298
+
299
+ i = 0
300
+ while i < field_count
301
+ len = @data_buffer.read_int32(@data_offset)
302
+ @data_offset += 4
303
+ id = @data_buffer.read(@data_offset)
304
+ @data_offset += 1
305
+ len -= 1
306
+
307
+ case id
308
+ when USER
309
+ userRoles.user = @data_buffer.read(@data_offset, len)
310
+ @data_offset += len
311
+ when ROLES
312
+ parse_roles(userRoles)
313
+ else
314
+ @data_offset += len
315
+ end
316
+
317
+ i = i.succ
318
+ end
319
+
320
+ next if userRoles.user == "" && userRoles.roles == nil
321
+
322
+ userRoles.roles = [] if userRoles.roles == nil
323
+ list << userRoles
324
+ end
325
+
326
+ return 0, list
327
+ end
328
+
329
+ def parse_roles(userRoles)
330
+ size = @data_buffer.read(@data_offset)
331
+ @data_offset += 1
332
+ userRoles.roles = []
333
+
334
+ i = 0
335
+ while i < size
336
+ len = @data_buffer.read(@data_offset)
337
+ @data_offset += 1
338
+ role = @data_buffer.read(@data_offset, len)
339
+ @data_offset += len
340
+ userRoles.roles << role
341
+
342
+ i = i.succ
343
+ end
344
+ end
345
+
346
+ SALT = '$2a$10$7EqJtq98hPqEX7fNZaFWoO'
347
+ def self.hash_password(password)
348
+ # Hashing the password with the cost of 10, with a static salt
349
+ return BCrypt::Engine.hash_secret(password, SALT, :cost => 10)
350
+ end
351
+ end
352
+ end
353
+
@@ -24,7 +24,7 @@ module Aerospike
24
24
 
25
25
  private
26
26
 
27
- class BatchCommand < Command
27
+ class BatchCommand < Command #:nodoc:
28
28
 
29
29
  def initialize(node)
30
30
  super(node)
@@ -61,7 +61,8 @@ module Aerospike
61
61
  set_name = nil
62
62
  user_key = nil
63
63
 
64
- for i in 0...field_count
64
+ i = 0
65
+ while i < field_count
65
66
  read_bytes(4)
66
67
 
67
68
  fieldlen = @data_buffer.read_int32(0)
@@ -80,6 +81,8 @@ module Aerospike
80
81
  when Aerospike::FieldType::KEY
81
82
  user_key = Aerospike::bytes_to_key_value(@data_buffer.read(1).ord, @data_buffer, 2, size-1)
82
83
  end
84
+
85
+ i = i.succ
83
86
  end
84
87
 
85
88
  Aerospike::Key.new(namespace, set_name, user_key, digest)
@@ -88,17 +91,15 @@ module Aerospike
88
91
  # Parses the given byte buffer and populate the result object.
89
92
  # Returns the number of bytes that were parsed from the given buffer.
90
93
  def parse_record(key, op_count, generation, expiration)
91
- bins = nil
92
- duplicates = nil
93
-
94
- for i in 0...op_count
94
+ bins = op_count > 0 ? {} : nil
95
+ i = 0
96
+ while i < op_count
95
97
  raise Aerospike::Exceptions::QueryTerminated.new unless valid?
96
98
 
97
99
  read_bytes(8)
98
100
 
99
101
  op_size = @data_buffer.read_int32(0).ord
100
102
  particle_type = @data_buffer.read(5).ord
101
- version = @data_buffer.read(6).ord
102
103
  name_size = @data_buffer.read(7).ord
103
104
 
104
105
  read_bytes(name_size)
@@ -114,44 +115,13 @@ module Aerospike
114
115
  # if !@bin_names || @bin_names.any?{|bn| bn == name}
115
116
  # if !@bin_names || (@bin_names == []) || @bin_names.any?{|bn| bn == name}
116
117
  if !@bin_names || (@bin_names.empty?) || @bin_names.any?{|bn| bn == name}
117
-
118
- vmap = nil
119
-
120
- if version > 0 || duplicates
121
- unless duplicates
122
- duplicates = []
123
- duplicates << bins
124
- bins = nil
125
-
126
- for j in 0...version
127
- duplicates << nil
128
- end
129
- else
130
- for j in duplicates.length..version
131
- duplicates << nil
132
- end
133
- end
134
-
135
- vmap = duplicates[version]
136
- unless vmap
137
- vmap = {}
138
- duplicates[version] = vmap
139
- end
140
- else
141
- unless bins
142
- bins = {}
143
- end
144
- vmap = bins
145
- end
146
- vmap[name] = value
118
+ bins[name] = value
147
119
  end
148
- end
149
120
 
150
- # Remove nil duplicates just in case there were holes in the version number space.
151
- # TODO: this seems to be a bad idea; O(n) algorithm after another O(n) algorithm
152
- duplicates.compact! if duplicates
121
+ i = i.succ
122
+ end
153
123
 
154
- Record.new(@node, key, bins, duplicates, generation, expiration)
124
+ Record.new(@node, key, bins, generation, expiration)
155
125
  end
156
126
 
157
127
  def read_bytes(length)