aerospike 2.5.1 → 2.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +3 -3
- data/lib/aerospike.rb +33 -6
- data/lib/aerospike/aerospike_exception.rb +9 -26
- data/lib/aerospike/client.rb +7 -22
- data/lib/aerospike/{cluster/cluster.rb → cluster.rb} +122 -161
- data/lib/aerospike/cluster/create_connection.rb +42 -0
- data/lib/aerospike/cluster/find_node.rb +35 -0
- data/lib/aerospike/connection/authenticate.rb +35 -0
- data/lib/aerospike/connection/create.rb +36 -0
- data/lib/aerospike/host.rb +7 -4
- data/lib/aerospike/host/parse.rb +50 -0
- data/lib/aerospike/node.rb +232 -0
- data/lib/aerospike/node/generation.rb +50 -0
- data/lib/aerospike/node/refresh/failed.rb +34 -0
- data/lib/aerospike/node/refresh/friends.rb +100 -0
- data/lib/aerospike/node/refresh/info.rb +60 -0
- data/lib/aerospike/node/refresh/partitions.rb +60 -0
- data/lib/aerospike/node/refresh/peers.rb +83 -0
- data/lib/aerospike/node/refresh/reset.rb +36 -0
- data/lib/aerospike/node/verify/cluster_name.rb +35 -0
- data/lib/aerospike/node/verify/name.rb +43 -0
- data/lib/aerospike/node/verify/partition_generation.rb +43 -0
- data/lib/aerospike/node/verify/peers_generation.rb +41 -0
- data/lib/aerospike/{cluster/node_validator.rb → node_validator.rb} +29 -47
- data/lib/aerospike/peer.rb +24 -0
- data/lib/aerospike/peers.rb +44 -0
- data/lib/aerospike/peers/fetch.rb +36 -0
- data/lib/aerospike/peers/parse.rb +88 -0
- data/lib/aerospike/policy/client_policy.rb +16 -9
- data/lib/aerospike/socket/base.rb +86 -0
- data/lib/aerospike/socket/ssl.rb +70 -0
- data/lib/aerospike/socket/tcp.rb +57 -0
- data/lib/aerospike/utils/buffer.rb +7 -6
- data/lib/aerospike/utils/string_parser.rb +53 -0
- data/lib/aerospike/value/value.rb +7 -8
- data/lib/aerospike/version.rb +1 -1
- metadata +30 -7
- data/lib/aerospike/cluster/connection.rb +0 -124
- data/lib/aerospike/cluster/node.rb +0 -274
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
# generic class for representing changes in eg. peer and partition generation
|
23
|
+
class Generation
|
24
|
+
attr_reader :number
|
25
|
+
|
26
|
+
def initialize(number = -1)
|
27
|
+
@number = ::Aerospike::Atomic.new(number)
|
28
|
+
@changed = ::Aerospike::Atomic.new(false)
|
29
|
+
end
|
30
|
+
|
31
|
+
def changed?
|
32
|
+
@changed.value == true
|
33
|
+
end
|
34
|
+
|
35
|
+
def eql?(number)
|
36
|
+
@number.value == number
|
37
|
+
end
|
38
|
+
|
39
|
+
def reset_changed!
|
40
|
+
@changed.value = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def update(new_number)
|
44
|
+
return if @number.value == new_number
|
45
|
+
@number.value = new_number
|
46
|
+
@changed.value = true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
module Failed
|
24
|
+
class << self
|
25
|
+
def call(node, e)
|
26
|
+
Aerospike.logger.info("Node #{node.name} refresh failed: #{e.inspect}")
|
27
|
+
Aerospike.logger.debug { e.backtrace.join("\n") }
|
28
|
+
node.failed!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
# Refresh peers/friends based on old service protocol
|
24
|
+
module Friends
|
25
|
+
class << self
|
26
|
+
def call(node, peers, info_map)
|
27
|
+
friend_string = info_map['services']
|
28
|
+
cluster = node.cluster
|
29
|
+
|
30
|
+
Aerospike.logger.debug("Refreshing friends for node #{node.name}: services=#{friend_string}")
|
31
|
+
|
32
|
+
if friend_string.to_s.empty?
|
33
|
+
node.peers_count.value = 0
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
friend_names = friend_string.split(';')
|
38
|
+
node.peers_count.value = friend_names.size
|
39
|
+
|
40
|
+
friend_names.each do |friend|
|
41
|
+
hostname, port = friend.split(':')
|
42
|
+
host = Host.new(hostname, port.to_i)
|
43
|
+
found_node = cluster.find_alias(host)
|
44
|
+
|
45
|
+
if found_node
|
46
|
+
found_node.increase_reference_count!
|
47
|
+
Aerospike.logger.debug("Found existing node #{found_node.name} for host #{host}: Increased ref count to #{found_node.reference_count.value}")
|
48
|
+
else
|
49
|
+
unless peers.hosts.include?(host)
|
50
|
+
prepare(cluster, peers, host)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def prepare(cluster, peers, host)
|
57
|
+
Aerospike.logger.debug("Preparing to add new node for host #{host}")
|
58
|
+
nv = NodeValidator.new(
|
59
|
+
cluster,
|
60
|
+
host,
|
61
|
+
cluster.connection_timeout,
|
62
|
+
cluster.cluster_name,
|
63
|
+
cluster.ssl_options
|
64
|
+
)
|
65
|
+
|
66
|
+
node = peers.find_node_by_name(nv.name)
|
67
|
+
|
68
|
+
unless node.nil?
|
69
|
+
Aerospike.logger.debug("Found existing node #{node.name} among peers for host #{host}")
|
70
|
+
peers.hosts << host
|
71
|
+
node.aliases << host
|
72
|
+
return true
|
73
|
+
end
|
74
|
+
|
75
|
+
node = cluster.find_node_by_name(nv.name)
|
76
|
+
|
77
|
+
unless node.nil?
|
78
|
+
Aerospike.logger.debug("Found existing node #{node.name} in cluster for host #{host}")
|
79
|
+
peers.hosts << host
|
80
|
+
node.aliases << host
|
81
|
+
# Only increase reference count if found in cluster
|
82
|
+
node.increase_reference_count!
|
83
|
+
cluster.add_alias(host, node)
|
84
|
+
return true
|
85
|
+
end
|
86
|
+
|
87
|
+
Aerospike.logger.debug("No existing node found - creating new node #{nv.name} for host #{host}")
|
88
|
+
node = cluster.create_node(nv)
|
89
|
+
peers.hosts << host
|
90
|
+
peers.nodes[nv.name] = node
|
91
|
+
true
|
92
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
93
|
+
::Aerospike.logger.warn("Add node for host #{host} failed: #{e}")
|
94
|
+
false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
module Info
|
24
|
+
CMDS_BASE = %w[node partition-generation cluster-name].freeze
|
25
|
+
CMDS_PEERS = (CMDS_BASE + ['peers-generation']).freeze
|
26
|
+
CMDS_SERVICES = (CMDS_BASE + ['services']).freeze
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def call(node, peers)
|
30
|
+
conn = node.tend_connection
|
31
|
+
if peers.use_peers?
|
32
|
+
info_map = ::Aerospike::Info.request(conn, *CMDS_PEERS)
|
33
|
+
Verify::PeersGeneration.(node, info_map, peers)
|
34
|
+
Verify::PartitionGeneration.(node, info_map)
|
35
|
+
Verify::Name.(node, info_map)
|
36
|
+
Verify::ClusterName.(node, info_map)
|
37
|
+
else
|
38
|
+
info_map = ::Aerospike::Info.request(conn, *CMDS_SERVICES)
|
39
|
+
Verify::PartitionGeneration.(node, info_map)
|
40
|
+
Verify::Name.(node, info_map)
|
41
|
+
Verify::ClusterName.(node, info_map)
|
42
|
+
Refresh::Friends.(node, peers, info_map)
|
43
|
+
end
|
44
|
+
|
45
|
+
node.restore_health
|
46
|
+
node.responded!
|
47
|
+
|
48
|
+
peers.refresh_count += 1
|
49
|
+
node.reset_failures!
|
50
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
51
|
+
conn.close if conn
|
52
|
+
node.decrease_health
|
53
|
+
peers.generation_changed = true if peers.use_peers?
|
54
|
+
Refresh::Failed.(node, e)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
module Partitions
|
24
|
+
class << self
|
25
|
+
def call(node, peers)
|
26
|
+
return unless should_refresh?(node, peers)
|
27
|
+
|
28
|
+
node.cluster.update_partitions(tokenizer(node), node)
|
29
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
30
|
+
node.tend_connection.close
|
31
|
+
Refresh::Failed.(node, e)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return correct tokenizer depending on version
|
35
|
+
def tokenizer(node)
|
36
|
+
conn = node.tend_connection
|
37
|
+
if node.use_new_info?
|
38
|
+
Aerospike.logger.info("Updating partitions for node #{node.name} using new protocol")
|
39
|
+
PartitionTokenizerNew.new(conn)
|
40
|
+
else
|
41
|
+
Aerospike.logger.info("Updating partitions for node #{node.name} using old protocol")
|
42
|
+
PartitionTokenizerOld.new(conn)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Do not refresh partitions when node connection has already failed
|
47
|
+
# during this cluster tend iteration. Also, avoid "split cluster"
|
48
|
+
# case where this node thinks it's a 1-node cluster. Unchecked, such
|
49
|
+
# a node can dominate the partition map and cause all other nodes to
|
50
|
+
# be dropped.
|
51
|
+
def should_refresh?(node, peers)
|
52
|
+
return false if node.failed? || !node.active?
|
53
|
+
return false if !node.has_peers? && peers.refresh_count > 1
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Refresh
|
23
|
+
module Peers
|
24
|
+
class << self
|
25
|
+
def call(node, peers)
|
26
|
+
return unless should_refresh?(node)
|
27
|
+
|
28
|
+
::Aerospike.logger.debug("Update peers for node #{node.name}")
|
29
|
+
|
30
|
+
cluster = node.cluster
|
31
|
+
|
32
|
+
collection = ::Aerospike::Peers::Fetch.(cluster, node.tend_connection)
|
33
|
+
peers.peers = collection.peers
|
34
|
+
node.peers_count.value = peers.peers.size
|
35
|
+
peers_validated = true
|
36
|
+
|
37
|
+
peers.peers.each do |peer|
|
38
|
+
next if ::Aerospike::Cluster::FindNode.(cluster, peers, peer.node_name)
|
39
|
+
|
40
|
+
node_validated = false
|
41
|
+
|
42
|
+
peer.hosts.each do |host|
|
43
|
+
begin
|
44
|
+
nv = NodeValidator.new(cluster, host, cluster.connection_timeout, cluster.cluster_name, cluster.ssl_options)
|
45
|
+
|
46
|
+
if nv.name != peer.node_name
|
47
|
+
::Aerospike.logger.warn("Peer node #{peer.node_name} is different than actual node #{nv.name} for host #{host}");
|
48
|
+
# Must look for new node name in the unlikely event that node names do not agree.
|
49
|
+
# Node already exists. Do not even try to connect to hosts.
|
50
|
+
if Cluster::FindNode.(cluster, peers, nv.name)
|
51
|
+
node_validated = true
|
52
|
+
break;
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
new_node = cluster.create_node(nv)
|
57
|
+
peers.nodes[nv.name] = new_node
|
58
|
+
node_validated = true
|
59
|
+
break;
|
60
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
61
|
+
Aerospike.logger.warn("Add node #{host} failed: #{e.inspect}")
|
62
|
+
end
|
63
|
+
|
64
|
+
peers_validated = false unless node_validated
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Only set new peers generation if all referenced peers are added to
|
69
|
+
# the cluster.
|
70
|
+
node.peers_generation.update(collection.generation) if peers_validated
|
71
|
+
peers.refresh_count += 1
|
72
|
+
rescue ::Aerospike::Exceptions::Aerospike => e
|
73
|
+
Refresh::Failed.(node, e)
|
74
|
+
end
|
75
|
+
|
76
|
+
def should_refresh?(node)
|
77
|
+
node.failures.value == 0 && node.active?
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
|
21
|
+
module Aerospike
|
22
|
+
class Node
|
23
|
+
module Refresh
|
24
|
+
# Reset a node before running a refresh cycle
|
25
|
+
module Reset
|
26
|
+
class << self
|
27
|
+
def call(node)
|
28
|
+
node.reset_reference_count!
|
29
|
+
node.reset_responded!
|
30
|
+
node.partition_generation.reset_changed!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2018 Aerospike, Inc.
|
4
|
+
#
|
5
|
+
# Portions may be licensed to Aerospike, Inc. under one or more contributor
|
6
|
+
# license agreements.
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
9
|
+
# use this file except in compliance with the License. You may obtain a copy of
|
10
|
+
# the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
16
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
17
|
+
# License for the specific language governing permissions and limitations under
|
18
|
+
# the License.
|
19
|
+
|
20
|
+
module Aerospike
|
21
|
+
class Node
|
22
|
+
module Verify
|
23
|
+
module ClusterName
|
24
|
+
class << self
|
25
|
+
def call(node, info_map)
|
26
|
+
if node.cluster_name && node.cluster_name != info_map['cluster-name']
|
27
|
+
node.inactive!
|
28
|
+
raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Cluster name does not match. expected: #{node.cluster_name}, got: #{info_map['cluster-name']}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|