aerospike 2.5.1 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ccefb4dd82c2d6d15f9f0eac08d32acceacf2da1d93c8ca3a462f4c7e4e10e95
4
- data.tar.gz: f133ccde7da4ea553d933a30c367ecf2a354c2e85ecce0b141c2071f94702237
3
+ metadata.gz: 2cf4004182c5166b136433e8be338b9187718684c2783808d18b3ed31f1dbd17
4
+ data.tar.gz: 3a18cdde5294fb88ee0d4d710fb870c29db3273f5e29bd2d2ea92fd824857f00
5
5
  SHA512:
6
- metadata.gz: e9baa1554bad7b3f3f8625940ee2e62f08b7185a662401757b8b172d7b9734427245fd8a18fc2aaeb7e4a90c15f3fa3f2346bfc53cce41efe03c15794b63a01c
7
- data.tar.gz: 52be62b23c582cdcc7fd12c5961c7ed82847a57b90bf8aea88a56580c7e05c1c416a0a51f7b8e170afde63763560a6acfa4200b95917ee5bc6542ae028954aec
6
+ metadata.gz: ab75f0c1d0d57c37f3d3f16966a27017b706067e414306c25a3388ad4a02571cdb18b1f019d67472e35386ad659db1d23d8685664ea6a7f2279e904b4c52383b
7
+ data.tar.gz: 501dabb13c9eb471e83cbda40aa22f2df7ae7e2c6083d447917a02e71017b9b64abe4bbff37798ef2517bced052c17347a109c842b97ab6b16f921939c6ebe23
@@ -1,3 +1,16 @@
1
+ v2.6.0 / 2018-03-27
2
+ ===================
3
+
4
+ * **New Features**
5
+ * Support for peers protocol for cluster discovery. Requires Aerospike server version 3.10 or later. Thanks to [@wallin](https://github.com/wallin) of [castle.io](https://castle.io/)! [[#59](https://github.com/aerospike/aerospike-client-ruby/pull/59)]
6
+ * TLS encryption support for client <-> server connections. Requires Aerospike Enterprise Edition version 3.11 or later. Thanks to [@wallin](https://github.com/wallin) of [castle.io](https://castle.io/)! [[#59](https://github.com/aerospike/aerospike-client-ruby/pull/59)]
7
+
8
+ * **Bug Fixes**
9
+ * Fix min./max. boundary check for Integer bin values and improve performance. Thanks to [@wallin](https://github.com/wallin) of [castle.io](https://castle.io/)! [[#60](https://github.com/aerospike/aerospike-client-ruby/pull/60)]
10
+
11
+ * **Updates**
12
+ * Update minimum required Ruby version to v2.3.
13
+
1
14
  v2.5.1 / 2018-01-25
2
15
  ===================
3
16
 
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  An Aerospike library for Ruby.
9
9
 
10
- This library is compatible with Ruby 2.2+ and supports Linux, Mac OS X and various other BSDs.
10
+ This library is compatible with Ruby 2.3+ and supports Linux, Mac OS X and various other BSDs.
11
11
 
12
12
  - [Usage](#Usage)
13
13
  - [Prerequisites](#Prerequisites)
@@ -61,7 +61,7 @@ Details about the API are available in the [`docs`](docs) directory.
61
61
  <a name="Prerequisites"></a>
62
62
  ## Prerequisites
63
63
 
64
- [Ruby](https://ruby-lang.org) version v2.2+ is required.
64
+ [Ruby](https://ruby-lang.org) version v2.3+ is required.
65
65
 
66
66
  Aerospike Ruby client implements the wire protocol, and does not depend on the C client.
67
67
  It is thread friendly.
@@ -81,7 +81,7 @@ Supported operating systems:
81
81
 
82
82
  ### Installation from source
83
83
 
84
- 1. Install Ruby 2.2+
84
+ 1. Install Ruby 2.3+
85
85
  2. Install RubyGems
86
86
  3. Install Bundler: ```gem install bundler```
87
87
  4. Install dependencies: ```bundler install```
@@ -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
@@ -29,7 +31,9 @@ require 'aerospike/utils/pool'
29
31
  require 'aerospike/utils/packer'
30
32
  require 'aerospike/utils/unpacker'
31
33
  require 'aerospike/utils/buffer'
34
+ require 'aerospike/utils/string_parser'
32
35
  require 'aerospike/host'
36
+ require 'aerospike/host/parse'
33
37
  require 'aerospike/loggable'
34
38
  require 'aerospike/record'
35
39
  require 'aerospike/result_code'
@@ -77,13 +81,36 @@ require 'aerospike/policy/consistency_level'
77
81
  require 'aerospike/policy/commit_level'
78
82
  require 'aerospike/policy/admin_policy'
79
83
 
80
- require 'aerospike/cluster/connection'
81
- require 'aerospike/cluster/cluster'
82
- require 'aerospike/cluster/node_validator'
84
+ require 'aerospike/socket/base'
85
+ require 'aerospike/socket/ssl'
86
+ require 'aerospike/socket/tcp'
87
+
88
+ require 'aerospike/connection/authenticate'
89
+ require 'aerospike/connection/create'
90
+
91
+ require 'aerospike/cluster'
92
+ require 'aerospike/cluster/create_connection'
83
93
  require 'aerospike/cluster/partition'
84
- require 'aerospike/cluster/node'
94
+ require 'aerospike/cluster/find_node'
85
95
  require 'aerospike/cluster/partition_tokenizer_new'
86
96
  require 'aerospike/cluster/partition_tokenizer_old'
97
+ require 'aerospike/node'
98
+ require 'aerospike/node/generation'
99
+ require 'aerospike/node/refresh/failed'
100
+ require 'aerospike/node/refresh/friends'
101
+ require 'aerospike/node/refresh/info'
102
+ require 'aerospike/node/refresh/partitions'
103
+ require 'aerospike/node/refresh/peers'
104
+ require 'aerospike/node/refresh/reset'
105
+ require 'aerospike/node/verify/cluster_name'
106
+ require 'aerospike/node/verify/name'
107
+ require 'aerospike/node/verify/partition_generation'
108
+ require 'aerospike/node/verify/peers_generation'
109
+ require 'aerospike/node_validator'
110
+ require 'aerospike/peer'
111
+ require 'aerospike/peers'
112
+ require 'aerospike/peers/fetch'
113
+ require 'aerospike/peers/parse'
87
114
  require 'aerospike/info'
88
115
  require 'aerospike/udf'
89
116
  require 'aerospike/bin'
@@ -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
@@ -17,95 +19,76 @@
17
19
  require 'aerospike/result_code'
18
20
 
19
21
  module Aerospike
20
-
21
22
  module Exceptions
22
-
23
23
  class Aerospike < StandardError
24
-
25
24
  attr_reader :result_code
26
25
 
27
26
  def initialize(result_code, message = nil)
28
27
  @result_code = result_code
29
28
  message ||= ResultCode.message(result_code)
30
29
  super(message)
31
-
32
- self
33
30
  end
34
-
35
31
  end
36
32
 
37
33
  class Timeout < Aerospike
38
-
39
34
  attr_reader :timeout, :iterations, :failed_nodes, :failed_connections
40
35
 
41
36
  def initialize(timeout, iterations, failed_nodes=nil, failed_connections=nil)
42
-
43
37
  @timeout = timeout
44
38
  @iterations = iterations
45
39
  @failed_nodes = failed_nodes
46
40
  @failed_connections = failed_connections
47
41
 
48
42
  super(ResultCode::TIMEOUT)
49
-
50
43
  end
44
+ end
51
45
 
46
+ class InvalidCredentials < Aerospike
47
+ def initialize(msg = nil)
48
+ super(ResultCode::NOT_AUTHENTICATED, msg)
49
+ end
52
50
  end
53
51
 
54
52
  class Serialize < Aerospike
55
-
56
53
  def initialize(msg=nil)
57
54
  super(ResultCode::SERIALIZE_ERROR, msg)
58
55
  end
59
-
60
56
  end
61
57
 
62
58
  class Parse < Aerospike
63
-
64
59
  def initialize(msg=nil)
65
60
  super(ResultCode::PARSE_ERROR, msg)
66
61
  end
67
-
68
62
  end
69
63
 
70
64
  class Connection < Aerospike
71
-
72
65
  def initialize(msg=nil)
73
66
  super(ResultCode::SERVER_NOT_AVAILABLE, msg)
74
67
  end
75
-
76
68
  end
77
69
 
78
70
  class InvalidNode < Aerospike
79
-
80
71
  def initialize(msg=nil)
81
72
  super(ResultCode::INVALID_NODE_ERROR, msg)
82
73
  end
83
-
84
74
  end
85
75
 
86
76
  class ScanTerminated < Aerospike
87
-
88
77
  def initialize(msg=nil)
89
78
  super(ResultCode::SCAN_TERMINATED, msg)
90
79
  end
91
-
92
80
  end
93
81
 
94
82
  class QueryTerminated < Aerospike
95
-
96
83
  def initialize(msg=nil)
97
84
  super(ResultCode::QUERY_TERMINATED, msg)
98
85
  end
99
-
100
86
  end
101
87
 
102
88
  class CommandRejected < Aerospike
103
-
104
89
  def initialize(msg=nil)
105
90
  super(ResultCode::COMMAND_REJECTED, msg)
106
91
  end
107
-
108
92
  end
109
-
110
93
  end
111
94
  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
@@ -46,9 +48,9 @@ module Aerospike
46
48
  @default_query_policy = QueryPolicy.new
47
49
  @default_admin_policy = QueryPolicy.new
48
50
 
49
- hosts = parse_hosts(hosts || ENV["AEROSPIKE_HOSTS"] || "localhost")
51
+ hosts = ::Aerospike::Host::Parse.(hosts || ENV['AEROSPIKE_HOSTS'] || 'localhost')
50
52
  policy = create_policy(policy, ClientPolicy)
51
- @cluster = Cluster.new(policy, *hosts)
53
+ @cluster = Cluster.new(policy, hosts)
52
54
  @cluster.add_cluster_config_change_listener(self)
53
55
 
54
56
  self.connect if connect
@@ -88,7 +90,7 @@ module Aerospike
88
90
  # Returns list of active server node names in the cluster.
89
91
 
90
92
  def node_names
91
- @cluster.nodes.map(&:get_name)
93
+ @cluster.nodes.map(&:name)
92
94
  end
93
95
 
94
96
  def supports_feature?(feature)
@@ -826,23 +828,6 @@ module Aerospike
826
828
  end
827
829
  end
828
830
 
829
- def parse_hosts(hosts)
830
- case hosts
831
- when Host
832
- [hosts]
833
- when Array
834
- hosts
835
- when String
836
- hosts.split(?,).map { |host|
837
- (addr, port) = host.split(?:)
838
- port ||= 3000
839
- Host.new(addr, port.to_i)
840
- }
841
- else
842
- fail TypeError, "hosts should be a Host object, an Array of Host objects, or a String"
843
- end
844
- end
845
-
846
831
  def cluster=(cluster)
847
832
  @cluster = cluster
848
833
  end
@@ -1,12 +1,15 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 Aerospike, Inc.
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2014-2018 Aerospike, Inc.
3
4
  #
4
5
  # Portions may be licensed to Aerospike, Inc. under one or more contributor
5
6
  # license agreements.
6
7
  #
7
8
  # Licensed under the Apache License, Version 2.0 (the "License"); you may not
8
9
  # 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
+ # the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
10
13
  #
11
14
  # Unless required by applicable law or agreed to in writing, software
12
15
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
@@ -15,27 +18,26 @@
15
18
  # the License.
16
19
 
17
20
  require 'set'
18
- require 'thread'
19
21
  require 'timeout'
20
22
 
21
23
  require 'aerospike/atomic/atomic'
22
24
 
23
25
  module Aerospike
24
-
25
- private
26
-
27
26
  class Cluster
28
-
29
27
  attr_reader :connection_timeout, :connection_queue_size, :user, :password
30
- attr_reader :features
28
+ attr_reader :features, :ssl_options
29
+ attr_reader :cluster_id, :aliases
30
+ attr_reader :cluster_name
31
31
 
32
- def initialize(policy, *hosts)
32
+ def initialize(policy, hosts)
33
33
  @cluster_seeds = hosts
34
34
  @fail_if_not_connected = policy.fail_if_not_connected
35
35
  @connection_queue_size = policy.connection_queue_size
36
36
  @connection_timeout = policy.timeout
37
37
  @tend_interval = policy.tend_interval
38
38
  @cluster_name = policy.cluster_name
39
+ @ssl_options = policy.ssl_options
40
+
39
41
  @aliases = {}
40
42
  @cluster_nodes = []
41
43
  @partition_write_map = {}
@@ -53,21 +55,33 @@ module Aerospike
53
55
  @password = AdminCommand.hash_password(policy.password)
54
56
  end
55
57
 
56
- self
58
+ initialize_tls_host_names(hosts) if tls_enabled?
57
59
  end
58
60
 
59
61
  def connect
60
62
  wait_till_stablized
61
63
 
62
64
  if @fail_if_not_connected && !connected?
63
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE)
65
+ raise Aerospike::Exceptions::Aerospike, Aerospike::ResultCode::SERVER_NOT_AVAILABLE
64
66
  end
65
67
 
66
68
  launch_tend_thread
67
69
 
68
70
  Aerospike.logger.info('New cluster initialized and ready to be used...')
71
+ end
69
72
 
70
- self
73
+ def credentials_given?
74
+ !(@user.nil? || @user.empty?)
75
+ end
76
+
77
+ def tls_enabled?
78
+ !ssl_options.nil? && ssl_options[:enable] != false
79
+ end
80
+
81
+ def initialize_tls_host_names(hosts)
82
+ hosts.each do |host|
83
+ host.tls_name ||= cluster_id.nil? ? host.name : cluster_id
84
+ end
71
85
  end
72
86
 
73
87
  def add_seeds(hosts)
@@ -94,12 +108,10 @@ module Aerospike
94
108
  if node_array = nmap[partition.namespace]
95
109
  node = node_array.value[partition.partition_id]
96
110
 
97
- if node && node.active?
98
- return node
99
- end
111
+ return node if node && node.active?
100
112
  end
101
113
 
102
- return random_node
114
+ random_node
103
115
  end
104
116
 
105
117
  # Returns a random node on the cluster
@@ -110,16 +122,14 @@ module Aerospike
110
122
  i = 0
111
123
  while i < length
112
124
  # Must handle concurrency with other non-tending threads, so node_index is consistent.
113
- index = (@node_index.update{|v| v+1} % node_array.length).abs
125
+ index = (@node_index.update{ |v| v+1 } % node_array.length).abs
114
126
  node = node_array[index]
115
127
 
116
- if node.active?
117
- return node
118
- end
128
+ return node if node.active?
119
129
 
120
130
  i = i.succ
121
131
  end
122
- raise Aerospike::Exceptions::InvalidNode.new
132
+ raise Aerospike::Exceptions::InvalidNode
123
133
  end
124
134
 
125
135
  # Returns a list of all nodes in the cluster
@@ -134,23 +144,19 @@ module Aerospike
134
144
  def get_node_by_name(node_name)
135
145
  node = find_node_by_name(node_name)
136
146
 
137
- raise Aerospike::Exceptions::InvalidNode.new unless node
147
+ raise Aerospike::Exceptions::InvalidNode unless node
138
148
 
139
149
  node
140
150
  end
141
151
 
142
152
  # Closes all cached connections to the cluster nodes and stops the tend thread
143
153
  def close
144
- unless @closed.value
145
- # send close signal to maintenance channel
146
- @closed.value = true
147
- @tend_thread.kill
148
-
149
- nodes.each do |node|
150
- node.close
151
- end
152
- end
154
+ return if @closed.value
155
+ # send close signal to maintenance channel
156
+ @closed.value = true
157
+ @tend_thread.kill
153
158
 
159
+ nodes.each(&:close)
154
160
  end
155
161
 
156
162
  def find_alias(aliass)
@@ -159,25 +165,12 @@ module Aerospike
159
165
  end
160
166
  end
161
167
 
162
- def update_partitions(conn, node)
163
- # TODO: Cluster should not care about version of tokenizer
164
- # decouple clstr interface
165
- nmap = {}
166
- if node.use_new_info?
167
- Aerospike.logger.info("Updating partitions using new protocol...")
168
-
169
- tokens = PartitionTokenizerNew.new(conn)
170
- nmap = tokens.update_partition(partitions, node)
171
- else
172
- Aerospike.logger.info("Updating partitions using old protocol...")
173
- tokens = PartitionTokenizerOld.new(conn)
174
- nmap = tokens.update_partition(partitions, node)
175
- end
176
-
168
+ def update_partitions(tokens, node)
169
+ nmap = tokens.update_partition(partitions, node)
177
170
  # update partition write map
178
171
  set_partitions(nmap) if nmap
179
172
 
180
- Aerospike.logger.info("Partitions updated...")
173
+ Aerospike.logger.info("Partitions for node #{node.name} updated")
181
174
  end
182
175
 
183
176
  def request_info(policy, *commands)
@@ -192,9 +185,13 @@ module Aerospike
192
185
  @features.get.include?(feature.to_s)
193
186
  end
194
187
 
188
+ def supports_peers_protocol?
189
+ nodes.all? { |node| node.supports_feature?('peers') }
190
+ end
191
+
195
192
  def change_password(user, password)
196
- # change password ONLY if the user is the same
197
- @password = password if @user == user
193
+ # change password ONLY if the user is the same
194
+ @password = password if @user == user
198
195
  end
199
196
 
200
197
  def add_cluster_config_change_listener(listener)
@@ -213,85 +210,96 @@ module Aerospike
213
210
  "#<Aerospike::Cluster @cluster_nodes=#{@cluster_nodes}>"
214
211
  end
215
212
 
216
- private
217
-
218
213
  def launch_tend_thread
219
214
  @tend_thread = Thread.new do
220
215
  Thread.current.abort_on_exception = false
221
- while true
216
+ loop do
222
217
  begin
223
218
  tend
224
219
  sleep(@tend_interval / 1000.0)
225
220
  rescue => e
226
221
  Aerospike.logger.error("Exception occured during tend: #{e}")
222
+ Aerospike.logger.debug { e.backtrace.join("\n") }
227
223
  end
228
224
  end
229
225
  end
230
226
  end
231
227
 
228
+ # Check health of all nodes in cluster
232
229
  def tend
233
- nodes = self.nodes
230
+ was_changed = refresh_nodes
231
+
232
+ return unless was_changed
233
+
234
+ update_cluster_features
235
+ notify_cluster_config_changed
236
+ # only log the tend finish IF the number of nodes has been changed.
237
+ # This prevents spamming the log on every tend interval
238
+ log_tend_stats(nodes)
239
+ end
240
+
241
+ # Refresh status of all nodes in cluster. Adds new nodes and/or removes
242
+ # unhealty ones
243
+ def refresh_nodes
234
244
  cluster_config_changed = false
235
245
 
236
- # All node additions/deletions are performed in tend thread.
237
- # If active nodes don't exist, seed cluster.
246
+ nodes = self.nodes
238
247
  if nodes.empty?
239
- Aerospike.logger.info("No connections available; seeding...")
240
248
  seed_nodes
241
249
  cluster_config_changed = true
242
-
243
- # refresh nodes list after seeding
244
250
  nodes = self.nodes
245
251
  end
246
252
 
247
- # Refresh all known nodes.
248
- friend_list = []
249
- refresh_count = 0
253
+ peers = Peers.new
250
254
 
251
- # Clear node reference counts.
255
+ # Clear node reference count
252
256
  nodes.each do |node|
253
- node.reference_count.value = 0
254
- node.responded.value = false
257
+ node.refresh_reset
258
+ end
255
259
 
256
- if node.active?
257
- begin
258
- friends = node.refresh
259
- refresh_count += 1
260
- friend_list.concat(friends) if friends
261
- rescue => e
262
- Aerospike.logger.error("Node `#{node}` refresh failed: #{e}")
263
- Aerospike.logger.error(e.backtrace.join("\n"))
264
- end
260
+ peers.use_peers = supports_peers_protocol?
261
+
262
+ # refresh all known nodes
263
+ nodes.each do |node|
264
+ node.refresh_info(peers)
265
+ end
266
+
267
+ # refresh peers when necessary
268
+ if peers.generation_changed?
269
+ # Refresh peers for all nodes that responded the first time even if only
270
+ # one node's peers changed.
271
+ nodes.each do |node|
272
+ node.refresh_peers(peers)
265
273
  end
266
274
  end
267
275
 
268
- # Add nodes in a batch.
269
- add_list = find_nodes_to_add(friend_list)
270
- unless add_list.empty?
271
- add_nodes(add_list)
272
- cluster_config_changed = true
276
+ nodes.each do |node|
277
+ node.refresh_partitions(peers) if node.partition_generation.changed?
273
278
  end
274
279
 
275
- # Handle nodes changes determined from refreshes.
276
- # Remove nodes in a batch.
277
- remove_list = find_nodes_to_remove(refresh_count)
278
- unless remove_list.empty?
279
- remove_nodes(remove_list)
280
- cluster_config_changed = true
280
+ if peers.generation_changed? || !peers.use_peers?
281
+ nodes_to_remove = find_nodes_to_remove(peers.refresh_count)
282
+ if nodes_to_remove.any?
283
+ remove_nodes(nodes_to_remove)
284
+ cluster_config_changed = true
285
+ end
281
286
  end
282
287
 
283
- if cluster_config_changed
284
- update_cluster_features
288
+ # Add any new nodes from peer refresh
289
+ if peers.nodes.any?
290
+ # peers.nodes is a Hash. Pass only values, ie. the array of nodes
291
+ add_nodes(peers.nodes.values)
292
+ cluster_config_changed = true
293
+ end
285
294
 
286
- # only log the tend finish IF the number of nodes has been changed.
287
- # This prevents spamming the log on every tend interval
288
- diff = nodes.length - @old_node_count
289
- action = "#{diff.abs} #{diff.abs == 1 ? "node has" : "nodes have"} #{diff > 0 ? "joined" : "left"} the cluster."
290
- Aerospike.logger.info("Tend finished. #{action} Old node count: #{@old_node_count}, New node count: #{nodes.length}")
291
- @old_node_count = nodes.length
295
+ cluster_config_changed
296
+ end
292
297
 
293
- notify_cluster_config_changed
294
- end
298
+ def log_tend_stats(nodes)
299
+ diff = nodes.size - @old_node_count
300
+ action = "#{diff.abs} #{diff.abs == 1 ? "node has" : "nodes have"} #{diff > 0 ? "joined" : "left"} the cluster."
301
+ Aerospike.logger.info("Tend finished. #{action} Old node count: #{@old_node_count}, New node count: #{nodes.size}")
302
+ @old_node_count = nodes.size
295
303
  end
296
304
 
297
305
  def wait_till_stablized
@@ -299,14 +307,12 @@ module Aerospike
299
307
 
300
308
  # will run until the cluster is stablized
301
309
  thr = Thread.new do
302
- while true
310
+ loop do
303
311
  tend
304
312
 
305
313
  # Check to see if cluster has changed since the last Tend.
306
314
  # If not, assume cluster has stabilized and return.
307
- if count == nodes.length
308
- break
309
- end
315
+ break if count == nodes.length
310
316
 
311
317
  sleep(0.001) # sleep for a miliseconds
312
318
 
@@ -324,13 +330,12 @@ module Aerospike
324
330
  end
325
331
 
326
332
  @closed.value = false if @cluster_nodes.length > 0
327
-
328
333
  end
329
334
 
330
335
  def update_cluster_features
331
336
  # Cluster supports features that are supported by all nodes
332
337
  @features.update do
333
- node_features = self.nodes.map(&:features)
338
+ node_features = nodes.map(&:features)
334
339
  node_features.reduce(&:intersection) || Set.new
335
340
  end
336
341
  end
@@ -366,45 +371,39 @@ module Aerospike
366
371
 
367
372
  seed_array.each do |seed|
368
373
  begin
369
- seed_node_validator = NodeValidator.new(self, seed, @connection_timeout, @cluster_name)
374
+ seed_node_validator = NodeValidator.new(self, seed, @connection_timeout, @cluster_name, ssl_options)
370
375
  rescue => e
371
- Aerospike.logger.error("Seed #{seed.to_s} failed: #{e.backtrace.join("\n")}")
376
+ Aerospike.logger.error("Seed #{seed} failed: #{e}\n#{e.backtrace.join("\n")}")
372
377
  next
373
378
  end
374
379
 
375
380
  nv = nil
376
381
  # Seed host may have multiple aliases in the case of round-robin dns configurations.
377
382
  seed_node_validator.aliases.each do |aliass|
378
-
379
383
  if aliass == seed
380
384
  nv = seed_node_validator
381
385
  else
382
386
  begin
383
- nv = NodeValidator.new(self, aliass, @connection_timeout, @cluster_name)
387
+ nv = NodeValidator.new(self, aliass, @connection_timeout, @cluster_name, ssl_options)
384
388
  rescue => e
385
- Aerospike.logger.error("Seed #{seed.to_s} failed: #{e}")
389
+ Aerospike.logger.error("Seed #{seed} failed: #{e}")
386
390
  next
387
391
  end
388
392
  end
393
+ next if find_node_name(list, nv.name)
389
394
 
390
- if !find_node_name(list, nv.name)
391
- node = create_node(nv)
392
- add_aliases(node)
393
- list << node
394
- end
395
+ node = create_node(nv)
396
+ add_aliases(node)
397
+ list << node
395
398
  end
396
-
397
- end
398
-
399
- if list.length > 0
400
- add_nodes_copy(list)
401
399
  end
402
400
 
401
+ add_nodes_copy(list) if list.length > 0
403
402
  end
404
403
 
405
404
  # Finds a node by name in a list of nodes
406
405
  def find_node_name(list, name)
407
- list.any?{|node| node.name == name}
406
+ list.any? { |node| node.name == name }
408
407
  end
409
408
 
410
409
  def add_alias(host, node)
@@ -423,44 +422,8 @@ module Aerospike
423
422
  end
424
423
  end
425
424
 
426
- def find_nodes_to_add(hosts)
427
- list = []
428
-
429
- hosts.each do |host|
430
- begin
431
- nv = NodeValidator.new(self, host, @connection_timeout, @cluster_name)
432
-
433
- # if node is already in cluster's node list,
434
- # or already included in the list to be added, we should skip it
435
- node = find_node_by_name(nv.name)
436
- node ||= list.detect{|n| n.name == nv.name}
437
-
438
- # make sure node is not already in the list to add
439
- if node
440
- # Duplicate node name found. This usually occurs when the server
441
- # services list contains both internal and external IP addresses
442
- # for the same node. Add new host to list of alias filters
443
- # and do not add new node.
444
- node.reference_count.update{|v| v + 1}
445
- node.add_alias(host)
446
- add_alias(host, node)
447
- next
448
- end
449
-
450
- node = create_node(nv)
451
- list << node
452
-
453
- rescue => e
454
- Aerospike.logger.error("Add node #{node} failed: #{e}")
455
- Aerospike.logger.error(e.backtrace.join("\n"))
456
- end
457
- end
458
-
459
- list
460
- end
461
-
462
425
  def create_node(nv)
463
- Node.new(self, nv)
426
+ ::Aerospike::Node.new(self, nv)
464
427
  end
465
428
 
466
429
  def find_nodes_to_remove(refresh_count)
@@ -482,7 +445,7 @@ module Aerospike
482
445
 
483
446
  when 2
484
447
  # Two node clusters require at least one successful refresh before removing.
485
- if refresh_count == 2 && node.reference_count.value == 0 && !node.responded.value
448
+ if refresh_count == 2 && node.reference_count.value == 0 && !node.responded?
486
449
  # Node is not referenced nor did it respond.
487
450
  remove_list << node
488
451
  end
@@ -492,9 +455,9 @@ module Aerospike
492
455
  if refresh_count >= 2 && node.reference_count.value == 0
493
456
  # Node is not referenced by other nodes.
494
457
  # Check if node responded to info request.
495
- if node.responded.value
458
+ if node.responded?
496
459
  # Node is alive, but not referenced by other nodes. Check if mapped.
497
- if !find_node_in_partition_map(node)
460
+ unless find_node_in_partition_map(node)
498
461
  # Node doesn't have any partitions mapped to it.
499
462
  # There is not point in keeping it in the cluster.
500
463
  remove_list << node
@@ -531,7 +494,7 @@ module Aerospike
531
494
  def add_aliases(node)
532
495
  # Add node's aliases to global alias set.
533
496
  # Aliases are only used in tend thread, so synchronization is not necessary.
534
- node.get_aliases.each do |aliass|
497
+ node.aliases.each do |aliass|
535
498
  @aliases[aliass] = node
536
499
  end
537
500
  end
@@ -551,7 +514,7 @@ module Aerospike
551
514
  nodes_to_remove.each do |node|
552
515
  # Remove node's aliases from cluster alias set.
553
516
  # Aliases are only used in tend thread, so synchronization is not necessary.
554
- node.get_aliases.each do |aliass|
517
+ node.aliases.each do |aliass|
555
518
  Aerospike.logger.debug("Removing alias #{aliass}")
556
519
  remove_alias(aliass)
557
520
  end
@@ -607,7 +570,5 @@ module Aerospike
607
570
  def find_node_by_name(node_name)
608
571
  nodes.detect{|node| node.name == node_name }
609
572
  end
610
-
611
573
  end
612
-
613
574
  end