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
@@ -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