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
@@ -1,124 +0,0 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 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 'socket'
18
-
19
- module Aerospike
20
-
21
- private
22
-
23
- class Connection # :nodoc:
24
-
25
- def initialize(host, port, timeout = 30)
26
-
27
- connect(host, port, timeout).tap do |socket|
28
- @socket = socket
29
- @timeout = timeout
30
- end
31
-
32
- self
33
- end
34
-
35
- def connect(host, port, timeout)
36
- socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
37
- @sockaddr = Socket.sockaddr_in(port, host)
38
- begin
39
- socket.connect_nonblock(@sockaddr)
40
- socket
41
- rescue IO::WaitWritable, Errno::EINPROGRESS
42
- # Block until the socket is ready, then try again
43
- IO.select(nil, [socket], nil, timeout.to_f)
44
- begin
45
- socket.connect_nonblock(@sockaddr)
46
- rescue Errno::EISCONN
47
- rescue => e
48
- socket.close
49
- raise e
50
- end
51
- socket
52
- end
53
- end
54
-
55
- def write(buffer, length)
56
- total = 0
57
- while total < length
58
- begin
59
- written = @socket.write_nonblock(buffer.read(total, length - total))
60
- total += written
61
- rescue IO::WaitWritable, Errno::EAGAIN
62
- IO.select(nil, [@socket])
63
- retry
64
- rescue => e
65
- raise Aerospike::Exceptions::Connection.new("#{e}")
66
- end
67
- end
68
- end
69
-
70
- def read(buffer, length)
71
- total = 0
72
- while total < length
73
- begin
74
- bytes = @socket.recv_nonblock(length - total)
75
- if bytes.bytesize > 0
76
- buffer.write_binary(bytes, total)
77
- else
78
- # connection is dead; return an error
79
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Connection to the server node is dead.")
80
- end
81
- total += bytes.bytesize
82
- rescue IO::WaitReadable, Errno::EAGAIN
83
- IO.select([@socket], nil)
84
- retry
85
- rescue => e
86
- raise Aerospike::Exceptions::Connection.new("#{e}")
87
- end
88
- end
89
- end
90
-
91
- def connected?
92
- @socket != nil
93
- end
94
-
95
- def valid?
96
- @socket != nil
97
- end
98
-
99
- def close
100
- @socket.close if @socket
101
- @socket = nil
102
- end
103
-
104
- def timeout=(timeout)
105
- if timeout > 0 && timeout != @timeout
106
- @timeout = timeout
107
- if IO.select([@socket], [@socket], [@socket], timeout.to_f)
108
- begin
109
- # Verify there is now a good connection
110
- @socket.connect_nonblock(@sockaddr)
111
- rescue Errno::EISCONN
112
- # operation successful
113
- rescue => e
114
- # An unexpected exception was raised - the connection is no good.
115
- close
116
- raise Aerospike::Exceptions::Connection.new("#{e}")
117
- end
118
- end
119
- end
120
- end
121
-
122
- end
123
-
124
- end
@@ -1,274 +0,0 @@
1
- # encoding: utf-8
2
- # Copyright 2014-2017 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 'aerospike/atomic/atomic'
18
-
19
- module Aerospike
20
-
21
- private
22
-
23
- class Node
24
-
25
- attr_reader :reference_count, :responded, :name, :features, :cluster_name
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
- # Assign host to first IP alias because the server identifies nodes
41
- # by IP address (not hostname).
42
- @host = nv.aliases[0]
43
- @health = Atomic.new(FULL_HEALTH)
44
- @partition_generation = Atomic.new(-1)
45
- @reference_count = Atomic.new(0)
46
- @responded = Atomic.new(false)
47
- @active = Atomic.new(true)
48
-
49
- @connections = Pool.new(@cluster.connection_queue_size)
50
- @connections.create_block = Proc.new do
51
- while conn = Connection.new(@host.name, @host.port, @cluster.connection_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
64
-
65
- break if conn.connected?
66
- end
67
- conn
68
- end
69
-
70
- @connections.cleanup_block = Proc.new { |conn| conn.close if conn }
71
- end
72
-
73
- # Request current status from server node, and update node with the result
74
- def refresh
75
- friends = []
76
-
77
- begin
78
- conn = get_connection(1)
79
- info_map = Info.request(conn, "node", "partition-generation", "services", "cluster-name")
80
- rescue => e
81
- Aerospike.logger.error("Error during refresh for node #{self}: #{e}")
82
- Aerospike.logger.error(e.backtrace.join("\n"))
83
-
84
- conn.close if conn
85
- decrease_health
86
-
87
- return friends
88
- end
89
-
90
- verify_node_name_and_cluster_name(info_map)
91
- restore_health
92
-
93
- @responded.update{|v| true}
94
-
95
- friends = add_friends(info_map)
96
- update_partitions(conn, info_map)
97
- put_connection(conn)
98
- friends
99
- end
100
-
101
- # Get a connection to the node. If no cached connection is not available,
102
- # a new connection will be created
103
- def get_connection(timeout)
104
- while true
105
- conn = @connections.poll
106
- if conn.connected?
107
- conn.timeout = timeout.to_f
108
- return conn
109
- end
110
- end
111
- end
112
-
113
- # Put back a connection to the cache. If cache is full, the connection will be
114
- # closed and discarded
115
- def put_connection(conn)
116
- conn.close if !@active.value
117
- @connections.offer(conn)
118
- end
119
-
120
- # Mark the node as healthy
121
- def restore_health
122
- # There can be cases where health is full, but active is false.
123
- # Once a node has been marked inactive, it stays inactive.
124
- @health.value = FULL_HEALTH
125
- end
126
-
127
- # Decrease node Health as a result of bad connection or communication
128
- def decrease_health
129
- @health.update {|v| v -= 1 }
130
- end
131
-
132
- # Check if the node is unhealthy
133
- def unhealthy?
134
- @health.value <= 0
135
- end
136
-
137
- # Retrieves host for the node
138
- def get_host
139
- @host
140
- end
141
-
142
- # Checks if the node is active
143
- def active?
144
- @active.value
145
- end
146
-
147
- # Returns node name
148
- def get_name
149
- @name
150
- end
151
-
152
- # Returns node aliases
153
- def get_aliases
154
- @aliases.value
155
- end
156
-
157
- # Adds an alias for the node
158
- def add_alias(alias_to_add)
159
- # Aliases are only referenced in the cluster tend threads,
160
- # so synchronization is not necessary.
161
- aliases = get_aliases
162
- aliases ||= []
163
-
164
- aliases << alias_to_add
165
- set_aliases(aliases)
166
- end
167
-
168
- # Marks node as inactice and closes all cached connections
169
- def close
170
- @active.value = false
171
- close_connections
172
- end
173
-
174
- def supports_feature?(feature)
175
- @features.include?(feature.to_s)
176
- end
177
-
178
- def ==(other)
179
- other && other.is_a?(Node) && (@name == other.name)
180
- end
181
- alias eql? ==
182
-
183
- def use_new_info?
184
- @use_new_info.value
185
- end
186
-
187
- def hash
188
- @name.hash
189
- end
190
-
191
- def inspect
192
- "#<Aerospike::Node: @name=#{@name}, @host=#{@host}>"
193
- end
194
-
195
- private
196
-
197
- def close_connections
198
- # drain connections and close all of them
199
- # non-blocking, does not call create_block when passed false
200
- while conn = @connections.poll(false)
201
- conn.close if conn
202
- end
203
- end
204
-
205
-
206
- # Sets node aliases
207
- def set_aliases(aliases)
208
- @aliases.value = aliases
209
- end
210
-
211
- def verify_node_name_and_cluster_name(info_map)
212
- info_name = info_map['node']
213
-
214
- if !info_name
215
- decrease_health
216
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Node name is empty")
217
- end
218
-
219
- if !(@name == info_name)
220
- # Set node to inactive immediately.
221
- @active.update{|v| false}
222
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Node name has changed. Old=#{@name} New= #{info_name}")
223
- end
224
-
225
- if cluster_name && cluster_name != info_map['cluster-name']
226
- @active.update{|v| false}
227
- raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::INVALID_NODE_ERROR, "Cluster name does not match. expected: #{cluster_name}, got: #{info_map['cluster-name']}")
228
- end
229
- end
230
-
231
- def add_friends(info_map)
232
- friend_string = info_map['services']
233
- friends = []
234
-
235
- return [] if friend_string.to_s.empty?
236
-
237
- friend_names = friend_string.split(';')
238
-
239
- friend_names.each do |friend|
240
- friend_info = friend.split(':')
241
- host = friend_info[0]
242
- port = friend_info[1].to_i
243
- aliass = Host.new(host, port)
244
- node = @cluster.find_alias(aliass)
245
-
246
- if node
247
- node.reference_count.update{|v| v + 1}
248
- else
249
- unless friends.any? {|h| h == aliass}
250
- friends << aliass
251
- end
252
- end
253
- end
254
-
255
- friends
256
- end
257
-
258
- def update_partitions(conn, info_map)
259
- gen_string = info_map['partition-generation']
260
-
261
- raise Aerospike::Exceptions::Parse.new("partition-generation is empty") if gen_string.to_s.empty?
262
-
263
- generation = gen_string.to_i
264
-
265
- if @partition_generation.value != generation
266
- Aerospike.logger.info("Node #{get_name} partition generation #{generation} changed")
267
- @cluster.update_partitions(conn, self)
268
- @partition_generation.value = generation
269
- end
270
- end
271
-
272
- end # class Node
273
-
274
- end # module