aerospike 1.0.12 → 2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -18
- data/README.md +7 -2
- data/lib/aerospike.rb +8 -0
- data/lib/aerospike/cdt/list_operation.rb +199 -0
- data/lib/aerospike/cdt/map_operation.rb +352 -0
- data/lib/aerospike/cdt/map_order.rb +38 -0
- data/lib/aerospike/cdt/map_policy.rb +37 -0
- data/lib/aerospike/cdt/map_return_type.rb +74 -0
- data/lib/aerospike/cdt/map_write_mode.rb +41 -0
- data/lib/aerospike/client.rb +84 -119
- data/lib/aerospike/cluster/cluster.rb +4 -4
- data/lib/aerospike/command/admin_command.rb +325 -325
- data/lib/aerospike/command/command.rb +2 -2
- data/lib/aerospike/command/roles.rb +13 -13
- data/lib/aerospike/key.rb +24 -5
- data/lib/aerospike/operation.rb +2 -0
- data/lib/aerospike/policy/admin_policy.rb +10 -10
- data/lib/aerospike/policy/consistency_level.rb +4 -4
- data/lib/aerospike/query/stream_command.rb +1 -1
- data/lib/aerospike/result_code.rb +1 -1
- data/lib/aerospike/task/execute_task.rb +68 -68
- data/lib/aerospike/task/task.rb +2 -6
- data/lib/aerospike/utils/packer.rb +47 -0
- data/lib/aerospike/utils/unpacker.rb +106 -0
- data/lib/aerospike/value/value.rb +19 -51
- data/lib/aerospike/version.rb +1 -1
- metadata +17 -7
@@ -56,7 +56,7 @@ module Aerospike
|
|
56
56
|
# This is the last of a multi-part message.
|
57
57
|
INFO3_LAST = Integer(1 << 0)
|
58
58
|
# Commit to master only before declaring success.
|
59
|
-
INFO3_COMMIT_MASTER = Integer(1 << 1)
|
59
|
+
INFO3_COMMIT_MASTER = Integer(1 << 1)
|
60
60
|
# Update only. Merge bins.
|
61
61
|
INFO3_UPDATE_ONLY = Integer(1 << 3)
|
62
62
|
|
@@ -460,7 +460,7 @@ module Aerospike
|
|
460
460
|
else
|
461
461
|
Aerospike.logger.error(e)
|
462
462
|
end
|
463
|
-
|
463
|
+
|
464
464
|
# close the connection
|
465
465
|
# cancelling/closing the batch/multi commands will return an error, which will
|
466
466
|
# close the connection to throw away its data and signal the server about the
|
@@ -16,24 +16,24 @@
|
|
16
16
|
|
17
17
|
module Aerospike
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# Pre-defined user roles.
|
20
|
+
module Role
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
# Manage users and their roles.
|
23
|
+
USER_ADMIN = 'user-admin'
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
# Manage indicies, user-defined functions and server configuration.
|
26
|
+
SYS_ADMIN = 'sys-admin'
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# Allow read, write and UDF transactions with the database.
|
29
|
+
READ_WRITE_UDF = "read-write-udf"
|
30
30
|
|
31
|
-
|
32
|
-
|
31
|
+
# Allow read and write transactions with the database.
|
32
|
+
READ_WRITE = 'read-write'
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
# Allow read transactions with the database.
|
35
|
+
READ = 'read'
|
36
36
|
|
37
|
-
|
37
|
+
end # module
|
38
38
|
|
39
39
|
end # module
|
data/lib/aerospike/key.rb
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
require 'digest'
|
18
18
|
|
19
19
|
require 'aerospike/value/value'
|
20
|
+
require 'aerospike/utils/pool'
|
20
21
|
|
21
22
|
module Aerospike
|
22
23
|
|
@@ -24,20 +25,31 @@ module Aerospike
|
|
24
25
|
|
25
26
|
@@digest_pool = Pool.new
|
26
27
|
@@digest_pool.create_block = Proc.new do
|
27
|
-
|
28
|
-
Digest::
|
28
|
+
if RUBY_PLATFORM == 'java'
|
29
|
+
OpenSSL::Digest::RIPEMD160.new
|
29
30
|
else
|
30
|
-
|
31
|
+
Digest::RMD160.new
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
# enable backwards compatibility with v1 client for integer keys
|
36
|
+
# ref. https://github.com/aerospike/aerospike-client-ruby/pull/34
|
37
|
+
def self.enable_v1_compatibility!(comp = true)
|
38
|
+
@v1_compatibility = !!comp
|
39
|
+
end
|
40
|
+
def self.v1_compatible?
|
41
|
+
@v1_compatibility
|
42
|
+
end
|
34
43
|
|
35
44
|
attr_reader :namespace, :set_name, :digest
|
45
|
+
attr_reader :v1_compatible
|
46
|
+
alias_method :v1_compatible?, :v1_compatible
|
36
47
|
|
37
|
-
def initialize(ns, set, val, digest=nil)
|
48
|
+
def initialize(ns, set, val, digest=nil, v1_compatible: self.class.v1_compatible?)
|
38
49
|
@namespace = ns
|
39
50
|
@set_name = set
|
40
51
|
@user_key = Value.of(val)
|
52
|
+
@v1_compatible = v1_compatible
|
41
53
|
|
42
54
|
unless digest
|
43
55
|
compute_digest
|
@@ -48,6 +60,7 @@ module Aerospike
|
|
48
60
|
self
|
49
61
|
end
|
50
62
|
|
63
|
+
|
51
64
|
def to_s
|
52
65
|
"#{@namespace}:#{@set_name}:#{@user_key}:#{@digest.nil? ? '' : @digest.bytes}"
|
53
66
|
end
|
@@ -75,11 +88,17 @@ module Aerospike
|
|
75
88
|
|
76
89
|
def compute_digest
|
77
90
|
key_type = @user_key.type
|
91
|
+
key_bytes = @user_key.to_bytes
|
78
92
|
|
79
93
|
if key_type == Aerospike::ParticleType::NULL
|
80
94
|
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::PARAMETER_ERROR, "Invalid key: nil")
|
81
95
|
end
|
82
96
|
|
97
|
+
# v1.0.12 and prior computed integer key digest using little endian byte order
|
98
|
+
if key_type == Aerospike::ParticleType::INTEGER && v1_compatible?
|
99
|
+
key_bytes.reverse!
|
100
|
+
end
|
101
|
+
|
83
102
|
# get a hash from pool and make it ready for work
|
84
103
|
h = @@digest_pool.poll
|
85
104
|
h.reset
|
@@ -87,7 +106,7 @@ module Aerospike
|
|
87
106
|
# Compute a complete digest
|
88
107
|
h.update(@set_name)
|
89
108
|
h.update(key_type.chr)
|
90
|
-
h.update(
|
109
|
+
h.update(key_bytes)
|
91
110
|
@digest = h.digest
|
92
111
|
|
93
112
|
# put the hash object back to the pool
|
data/lib/aerospike/operation.rb
CHANGED
@@ -16,18 +16,18 @@
|
|
16
16
|
|
17
17
|
module Aerospike
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
# Policy attributes used for user administration commands.
|
20
|
+
class AdminPolicy
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
# User administration command socket timeout in milliseconds.
|
23
|
+
# Default is one second timeout.
|
24
|
+
attr_accessor :timeout
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
# NewAdminPolicy generates a new AdminPolicy with default values.
|
27
|
+
def initialize(opt={})
|
28
|
+
@timeout = opt[:timeout] || 1
|
29
|
+
end
|
30
30
|
|
31
|
-
|
31
|
+
end # class
|
32
32
|
|
33
33
|
end # module
|
@@ -17,11 +17,11 @@ module Aerospike
|
|
17
17
|
|
18
18
|
module ConsistencyLevel
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
# Involve a single replica in the operation.
|
21
|
+
CONSISTENCY_ONE = 0
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
# Involve all replicas in the operation.
|
24
|
+
CONSISTENCY_ALL = 1
|
25
25
|
|
26
26
|
end # module
|
27
27
|
|
@@ -40,7 +40,7 @@ module Aerospike
|
|
40
40
|
# return successfully
|
41
41
|
if (@recordset == nil) && (result_code == Aerospike::ResultCode::KEY_NOT_FOUND_ERROR)
|
42
42
|
# consume the rest of the input buffer from the socket
|
43
|
-
read_bytes(receive_size - data_offset) if @data_offset < receive_size
|
43
|
+
read_bytes(receive_size - @data_offset) if @data_offset < receive_size
|
44
44
|
|
45
45
|
return nil
|
46
46
|
end
|
@@ -14,72 +14,72 @@
|
|
14
14
|
|
15
15
|
module Aerospike
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
17
|
+
private
|
18
|
+
|
19
|
+
# ExecuteTask is used to poll for long running server execute job completion.
|
20
|
+
class ExecuteTask < Task
|
21
|
+
|
22
|
+
# NewExecuteTask initializes task with fields needed to query server nodes.
|
23
|
+
def initialize(cluster, statement)
|
24
|
+
super(cluster, false)
|
25
|
+
|
26
|
+
@task_id = statement.task_id
|
27
|
+
@scan = statement.is_scan?
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# IsDone queries all nodes for task completion status.
|
33
|
+
def all_nodes_done?
|
34
|
+
|
35
|
+
if @scan
|
36
|
+
command = 'scan-list'
|
37
|
+
else
|
38
|
+
command = 'query-list'
|
39
|
+
end
|
40
|
+
|
41
|
+
nodes = @cluster.nodes
|
42
|
+
done = false
|
43
|
+
|
44
|
+
nodes.each do |node|
|
45
|
+
conn = node.get_connection(0)
|
46
|
+
responseMap, _ = Info.request(conn, command)
|
47
|
+
node.put_connection(conn)
|
48
|
+
|
49
|
+
response = responseMap[command]
|
50
|
+
find = "job_id=#{@task_id}:"
|
51
|
+
index = response.index(find)
|
52
|
+
|
53
|
+
unless index
|
54
|
+
# don't return on first check
|
55
|
+
done = true
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
59
|
+
b = index + find.length
|
60
|
+
response = response[b, response.length]
|
61
|
+
find = 'job_status='
|
62
|
+
index = response.index(find)
|
63
|
+
|
64
|
+
next unless index
|
65
|
+
|
66
|
+
b = index + find.length
|
67
|
+
response = response[b, response.length]
|
68
|
+
e = response.index(':')
|
69
|
+
status = response[0, e]
|
70
|
+
|
71
|
+
case status
|
72
|
+
when 'ABORTED'
|
73
|
+
raise raise Aerospike::Exceptions::QueryTerminated
|
74
|
+
when 'IN PROGRESS'
|
75
|
+
return false
|
76
|
+
when 'DONE'
|
77
|
+
done = true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
done
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
85
|
end
|
data/lib/aerospike/task/task.rb
CHANGED
@@ -38,7 +38,7 @@ module Aerospike
|
|
38
38
|
# make sure there will be only ONE thread polling for completetion status
|
39
39
|
@done_thread.update do |dt|
|
40
40
|
dt ? dt : Thread.new do
|
41
|
-
abort_on_exception=true
|
41
|
+
Thread.current.abort_on_exception = true
|
42
42
|
failures = 0
|
43
43
|
while true
|
44
44
|
begin
|
@@ -60,11 +60,7 @@ module Aerospike
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def completed?
|
63
|
-
|
64
|
-
true
|
65
|
-
else
|
66
|
-
@done.value = all_nodes_done?
|
67
|
-
end
|
63
|
+
@done.value ||= all_nodes_done?
|
68
64
|
end
|
69
65
|
|
70
66
|
end # class
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2016 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
|
+
require 'msgpack'
|
18
|
+
require 'aerospike/utils/pool'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
class Packer < MessagePack::Packer #:nodoc:
|
25
|
+
|
26
|
+
@@pool = Pool.new
|
27
|
+
@@pool.create_block = Proc.new { Packer.new }
|
28
|
+
|
29
|
+
def self.use
|
30
|
+
packer = @@pool.poll
|
31
|
+
packer.clear
|
32
|
+
yield packer
|
33
|
+
ensure
|
34
|
+
@@pool.offer(packer)
|
35
|
+
end
|
36
|
+
|
37
|
+
# WARNING: This method is not compatible with message pack standard.
|
38
|
+
def write_raw_short(val)
|
39
|
+
buffer << [val].pack("S>")
|
40
|
+
end
|
41
|
+
|
42
|
+
def bytes
|
43
|
+
self.to_s.force_encoding('binary')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright 2016 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
|
+
require 'msgpack'
|
18
|
+
require 'aerospike/utils/pool'
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
class Unpacker
|
25
|
+
|
26
|
+
@@pool = Pool.new
|
27
|
+
@@pool.create_block = Proc.new { Unpacker.new }
|
28
|
+
|
29
|
+
def self.use
|
30
|
+
unpacker = @@pool.poll
|
31
|
+
unpacker.reset
|
32
|
+
yield unpacker
|
33
|
+
ensure
|
34
|
+
@@pool.offer(unpacker)
|
35
|
+
end
|
36
|
+
|
37
|
+
MsgPackExt = Struct.new(:type, :data)
|
38
|
+
MsgPackExt::TYPES = [
|
39
|
+
# Map Create Flags:
|
40
|
+
0x00, # UNORDERED
|
41
|
+
0x01, # K_ORDERED
|
42
|
+
0x03, # KV_ORDERED
|
43
|
+
0x08, # PRESERVE_ORDER
|
44
|
+
]
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@unpacker = MessagePack::Unpacker.new
|
48
|
+
MsgPackExt::TYPES.each do |type|
|
49
|
+
@unpacker.register_type(type) { |data| MsgPackExt.new(type, data) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def unpack(bytes)
|
54
|
+
obj = @unpacker.feed(bytes).read
|
55
|
+
case obj
|
56
|
+
when Array then unpack_list(obj)
|
57
|
+
when Hash then unpack_map(obj)
|
58
|
+
else obj
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def reset
|
63
|
+
@unpacker.reset
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def unpack_list(array)
|
69
|
+
normalize_strings_in_array(array)
|
70
|
+
end
|
71
|
+
|
72
|
+
def unpack_map(hash)
|
73
|
+
hash = normalize_strings_in_map(hash)
|
74
|
+
if hash.any?
|
75
|
+
(key, _) = hash.first
|
76
|
+
hash.shift if MsgPackExt === key
|
77
|
+
end
|
78
|
+
hash
|
79
|
+
end
|
80
|
+
|
81
|
+
def normalize_elem(elem)
|
82
|
+
case elem
|
83
|
+
when String
|
84
|
+
elem[1..-1].encode(Aerospike.encoding)
|
85
|
+
when Array
|
86
|
+
normalize_strings_in_array(elem)
|
87
|
+
when Hash
|
88
|
+
normalize_strings_in_map(elem)
|
89
|
+
else
|
90
|
+
elem
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def normalize_strings_in_array(arr)
|
95
|
+
arr.map! { |elem| normalize_elem(elem) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def normalize_strings_in_map(hash)
|
99
|
+
hash.inject({}) do |h, (k,v)|
|
100
|
+
h.update({ normalize_elem(k) => normalize_elem(v) })
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|