aerospike 2.5.1 → 2.6.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +3 -3
  4. data/lib/aerospike.rb +33 -6
  5. data/lib/aerospike/aerospike_exception.rb +9 -26
  6. data/lib/aerospike/client.rb +7 -22
  7. data/lib/aerospike/{cluster/cluster.rb → cluster.rb} +122 -161
  8. data/lib/aerospike/cluster/create_connection.rb +42 -0
  9. data/lib/aerospike/cluster/find_node.rb +35 -0
  10. data/lib/aerospike/connection/authenticate.rb +35 -0
  11. data/lib/aerospike/connection/create.rb +36 -0
  12. data/lib/aerospike/host.rb +7 -4
  13. data/lib/aerospike/host/parse.rb +50 -0
  14. data/lib/aerospike/node.rb +232 -0
  15. data/lib/aerospike/node/generation.rb +50 -0
  16. data/lib/aerospike/node/refresh/failed.rb +34 -0
  17. data/lib/aerospike/node/refresh/friends.rb +100 -0
  18. data/lib/aerospike/node/refresh/info.rb +60 -0
  19. data/lib/aerospike/node/refresh/partitions.rb +60 -0
  20. data/lib/aerospike/node/refresh/peers.rb +83 -0
  21. data/lib/aerospike/node/refresh/reset.rb +36 -0
  22. data/lib/aerospike/node/verify/cluster_name.rb +35 -0
  23. data/lib/aerospike/node/verify/name.rb +43 -0
  24. data/lib/aerospike/node/verify/partition_generation.rb +43 -0
  25. data/lib/aerospike/node/verify/peers_generation.rb +41 -0
  26. data/lib/aerospike/{cluster/node_validator.rb → node_validator.rb} +29 -47
  27. data/lib/aerospike/peer.rb +24 -0
  28. data/lib/aerospike/peers.rb +44 -0
  29. data/lib/aerospike/peers/fetch.rb +36 -0
  30. data/lib/aerospike/peers/parse.rb +88 -0
  31. data/lib/aerospike/policy/client_policy.rb +16 -9
  32. data/lib/aerospike/socket/base.rb +86 -0
  33. data/lib/aerospike/socket/ssl.rb +70 -0
  34. data/lib/aerospike/socket/tcp.rb +57 -0
  35. data/lib/aerospike/utils/buffer.rb +7 -6
  36. data/lib/aerospike/utils/string_parser.rb +53 -0
  37. data/lib/aerospike/value/value.rb +7 -8
  38. data/lib/aerospike/version.rb +1 -1
  39. metadata +30 -7
  40. data/lib/aerospike/cluster/connection.rb +0 -124
  41. data/lib/aerospike/cluster/node.rb +0 -274
@@ -0,0 +1,42 @@
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 Cluster
22
+ # Create connection based on cluster config and authenticate if needed
23
+ module CreateConnection
24
+ class << self
25
+ def call(cluster, host)
26
+ ::Aerospike::Connection::Create.(
27
+ host.name,
28
+ host.port,
29
+ tls_name: host.tls_name,
30
+ timeout: cluster.connection_timeout,
31
+ ssl_options: cluster.ssl_options
32
+ ).tap do |conn|
33
+ if cluster.credentials_given?
34
+ # Authenticate will raise and close connection if invalid credentials
35
+ Connection::Authenticate.(conn, cluster.user, cluster.password)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ 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 Cluster
22
+ # Find node in cluster by name
23
+ module FindNode
24
+ class << self
25
+ def call(cluster, peers, node_name)
26
+ node = cluster.find_node_by_name(node_name) || peers.find_node_by_name(node_name)
27
+ return if node.nil?
28
+ node.tap do |n|
29
+ n.increase_reference_count!
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ 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
+ module Connection # :nodoc:
22
+ module Authenticate
23
+ class << self
24
+ def call(conn, user, password)
25
+ command = AdminCommand.new
26
+ command.authenticate(conn, user, password)
27
+ true
28
+ rescue ::Aerospike::Exceptions::Aerospike
29
+ conn.close if conn
30
+ raise ::Aerospike::Exceptions::InvalidCredentials
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2014-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
+ module Connection # :nodoc:
22
+ module Create
23
+ class << self
24
+ def call(host, port, timeout: 30, tls_name: nil, ssl_options: nil)
25
+ if !ssl_options.nil? && ssl_options[:enable] != false
26
+ ::Aerospike::Socket::SSL.connect(
27
+ host, port, timeout, tls_name, ssl_options
28
+ )
29
+ else
30
+ ::Aerospike::Socket::TCP.connect(host, port, timeout)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,12 +1,14 @@
1
1
  # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
2
+ # Copyright 2014-2018 Aerospike, Inc.
3
3
  #
4
4
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
5
  # license agreements.
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
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
9
+ # the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
10
12
  #
11
13
  # Unless required by applicable law or agreed to in writing, software
12
14
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
@@ -18,11 +20,12 @@ module Aerospike
18
20
 
19
21
  class Host
20
22
 
21
- attr_accessor :name, :port
23
+ attr_accessor :name, :port, :tls_name
22
24
 
23
- def initialize(host_name, host_port)
25
+ def initialize(host_name, host_port, tls_name = nil)
24
26
  @name = host_name
25
27
  @port = host_port
28
+ @tls_name = tls_name
26
29
  end
27
30
 
28
31
  def to_s
@@ -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 Host
22
+ module Parse
23
+ INTEGER_REGEX = /\A\d+\z/
24
+
25
+ class << self
26
+ # Parse hosts from string format: hostname1[:tlsname1][:port1],...
27
+ def call(hosts, default_port = 3000)
28
+ case hosts
29
+ when Host
30
+ [hosts]
31
+ when Array
32
+ hosts
33
+ when String
34
+ hosts.split(?,).map { |host|
35
+ addr, tls_name, port = host.split(?:)
36
+ if port.nil? && tls_name && tls_name.match(INTEGER_REGEX)
37
+ port = tls_name
38
+ tls_name = nil
39
+ end
40
+ port ||= default_port
41
+ Host.new(addr, port.to_i, tls_name)
42
+ }
43
+ else
44
+ fail TypeError, "hosts should be a Host object, an Array of Host objects, or a String"
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,232 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2014-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
+ require 'aerospike/atomic/atomic'
21
+
22
+ module Aerospike
23
+ class Node
24
+
25
+ attr_reader :reference_count, :responded, :name, :features, :cluster_name, :partition_generation, :peers_generation, :failures, :cluster, :peers_count, :host
26
+
27
+ PARTITIONS = 4096
28
+ FULL_HEALTH = 100
29
+
30
+ # Initialize server node with connection parameters.
31
+ def initialize(cluster, nv)
32
+ @cluster = cluster
33
+ @name = nv.name
34
+ @aliases = Atomic.new(nv.aliases)
35
+ @host = nv.host
36
+ @use_new_info = Atomic.new(nv.use_new_info)
37
+ @features = nv.features
38
+ @cluster_name = nv.cluster_name
39
+
40
+ # TODO: Re-use connection from node validator
41
+ @tend_connection = nil
42
+
43
+ # Assign host to first IP alias because the server identifies nodes
44
+ # by IP address (not hostname).
45
+ @host = nv.aliases[0]
46
+ @health = Atomic.new(FULL_HEALTH)
47
+ @peers_count = Atomic.new(0)
48
+ @peers_generation = ::Aerospike::Node::Generation.new
49
+ @partition_generation = ::Aerospike::Node::Generation.new
50
+ @reference_count = Atomic.new(0)
51
+ @responded = Atomic.new(false)
52
+ @active = Atomic.new(true)
53
+ @failures = Atomic.new(0)
54
+
55
+ @connections = Pool.new(@cluster.connection_queue_size)
56
+
57
+ # TODO: put in separate methods
58
+ @connections.create_block = Proc.new do
59
+ conn = nil
60
+ loop do
61
+ conn = Cluster::CreateConnection.(cluster, host)
62
+ break if conn.connected?
63
+ end
64
+ conn
65
+ end
66
+
67
+ @connections.cleanup_block = Proc.new { |conn| conn.close if conn }
68
+ end
69
+
70
+ # Get a connection to the node. If no cached connection is not available,
71
+ # a new connection will be created
72
+ def get_connection(timeout)
73
+ loop do
74
+ conn = @connections.poll
75
+ if conn.connected?
76
+ conn.timeout = timeout.to_f
77
+ return conn
78
+ end
79
+ end
80
+ end
81
+
82
+ # Put back a connection to the cache. If cache is full, the connection will be
83
+ # closed and discarded
84
+ def put_connection(conn)
85
+ conn.close if !active?
86
+ @connections.offer(conn)
87
+ end
88
+
89
+ # Separate connection for refreshing
90
+ def tend_connection
91
+ if @tend_connection.nil? || @tend_connection.closed?
92
+ @tend_connection = Cluster::CreateConnection.(cluster, host)
93
+ end
94
+ @tend_connection
95
+ end
96
+
97
+ # Mark the node as healthy
98
+ def restore_health
99
+ # There can be cases where health is full, but active is false.
100
+ # Once a node has been marked inactive, it stays inactive.
101
+ @health.value = FULL_HEALTH
102
+ end
103
+
104
+ # Decrease node Health as a result of bad connection or communication
105
+ def decrease_health
106
+ @health.update { |v| v - 1 }
107
+ end
108
+
109
+ # Check if the node is unhealthy
110
+ def unhealthy?
111
+ @health.value <= 0
112
+ end
113
+
114
+ # Retrieves host for the node
115
+ def get_host
116
+ @host
117
+ end
118
+
119
+ # Sets node as active
120
+ def active!
121
+ @active.update { |_| true }
122
+ end
123
+
124
+ # Sets node as inactive
125
+ def inactive!
126
+ @active.update { |_| false }
127
+ end
128
+
129
+ # Checks if the node is active
130
+ def active?
131
+ @active.value
132
+ end
133
+
134
+ def increase_reference_count!
135
+ @reference_count.update { |v| v + 1 }
136
+ end
137
+
138
+ def reset_reference_count!
139
+ @reference_count.value = 0
140
+ end
141
+
142
+ def responded!
143
+ @responded.value = true
144
+ end
145
+
146
+ def responded?
147
+ @responded.value == true
148
+ end
149
+
150
+ def reset_responded!
151
+ @responded.value = false
152
+ end
153
+
154
+ def has_peers?
155
+ @peers_count.value > 0
156
+ end
157
+
158
+ def failed?
159
+ @failures.value > 0
160
+ end
161
+
162
+ def failed!
163
+ @failures.update { |v| v + 1 }
164
+ end
165
+
166
+ def reset_failures!
167
+ @failures.value = 0
168
+ end
169
+
170
+ def aliases
171
+ @aliases.value
172
+ end
173
+
174
+ # Marks node as inactice and closes all cached connections
175
+ def close
176
+ inactive!
177
+ close_connections
178
+ end
179
+
180
+ def supports_feature?(feature)
181
+ @features.include?(feature.to_s)
182
+ end
183
+
184
+ def ==(other)
185
+ other && other.is_a?(Node) && (@name == other.name)
186
+ end
187
+ alias eql? ==
188
+
189
+ def use_new_info?
190
+ @use_new_info.value
191
+ end
192
+
193
+ def hash
194
+ @name.hash
195
+ end
196
+
197
+ def inspect
198
+ "#<Aerospike::Node: @name=#{@name}, @host=#{@host}>"
199
+ end
200
+
201
+ ##
202
+ # Convenience wrappers for applying refresh operations to a node
203
+ ##
204
+
205
+ def refresh_info(peers)
206
+ Node::Refresh::Info.(self, peers)
207
+ end
208
+
209
+ def refresh_partitions(peers)
210
+ Node::Refresh::Partitions.(self, peers)
211
+ end
212
+
213
+ def refresh_peers(peers)
214
+ Node::Refresh::Peers.(self, peers)
215
+ end
216
+
217
+ def refresh_reset
218
+ Node::Refresh::Reset.(self)
219
+ end
220
+
221
+ private
222
+
223
+ def close_connections
224
+ @tend_connection.close if @tend_connection
225
+ # drain connections and close all of them
226
+ # non-blocking, does not call create_block when passed false
227
+ while conn = @connections.poll(false)
228
+ conn.close if conn
229
+ end
230
+ end
231
+ end # class Node
232
+ end # module