moped 2.0.0.beta3 → 2.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of moped might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eaafa3e24e927991736aecf8de32a4387b676f26
4
- data.tar.gz: 69bff1f57e4ab5051f18bdd29b5f4ddbe31a00be
3
+ metadata.gz: dcc02534c2e5692e3ec6ec5d413a84affae01928
4
+ data.tar.gz: 9f68b061f00712169ab5b0ff7cab3013bb70275d
5
5
  SHA512:
6
- metadata.gz: ba51eaa03eaa3d0258195cbb3bd8c0e47c7f1743e7ec8a74f412cb65d12d13e52b94e8f9c09d444a5a51cddb74d4ecd571206d59faf3eb46b1bb8b00a7b04fe6
7
- data.tar.gz: 2111c5001c36a1ff85cb80fd97ebfe23e595fe782eb311098ccb77558524e95cb3327360cd49dc0cb1ce12abae1a51ec408ac48c0c853a7e7fd42c96eef132b7
6
+ metadata.gz: c4e346563b648daf55642a42cd4df9292848bd03cc87f31edfca2f5f5661a3a884ed97fe064a0355325bbde151cac169d00a4bf24b074ad173bff2efbcf8bb1c
7
+ data.tar.gz: e476c83c7abc0d42e73629962457cc8403658e645ae7ee62ad2041659a69745172861793db667eeef781b45015a175a9ecea4c7d88fa5cae31321bbbbc365472
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Moped [![Build Status](https://secure.travis-ci.org/mongoid/moped.png?branch=master&.png)](http://travis-ci.org/mongoid/moped) [![Code Climate](https://codeclimate.com/github/mongoid/moped.png)](https://codeclimate.com/github/mongoid/moped) [![Coverage Status](https://coveralls.io/repos/mongoid/moped/badge.png?branch=master)](https://coveralls.io/r/mongoid/moped?branch=master)
1
+ Moped [![Build Status](https://secure.travis-ci.org/mongoid/moped.png?branch=master)](http://travis-ci.org/mongoid/moped) [![Code Climate](https://codeclimate.com/github/mongoid/moped.png)](https://codeclimate.com/github/mongoid/moped) [![Coverage Status](https://coveralls.io/repos/mongoid/moped/badge.png?branch=master)](https://coveralls.io/r/mongoid/moped?branch=master)
2
2
  ========
3
3
 
4
4
  Moped is a MongoDB driver for Ruby, which exposes a simple, elegant, and fast
@@ -60,14 +60,19 @@ module Moped
60
60
  # @since 2.0.0
61
61
  def login(database, username, password)
62
62
  getnonce = Protocol::Command.new(database, getnonce: 1)
63
- result = Operation::Read.new(getnonce).execute(self)
64
- authenticate = Protocol::Commands::Authenticate.new(database, username, password, result["nonce"])
65
- connection do |conn|
66
- conn.write([ authenticate ])
67
- document = conn.read.documents.first
68
- raise Errors::AuthenticationFailure.new(authenticate, document) unless document["ok"] == 1
69
- credentials[database] = [username, password]
63
+ self.write([getnonce])
64
+ reply = self.receive_replies([getnonce]).first
65
+ if getnonce.failure?(reply)
66
+ return
70
67
  end
68
+ result = getnonce.results(reply)
69
+
70
+ authenticate = Protocol::Commands::Authenticate.new(database, username, password, result["nonce"])
71
+ self.write([ authenticate ])
72
+ document = self.read.documents.first
73
+
74
+ raise Errors::AuthenticationFailure.new(authenticate, document) unless document["ok"] == 1
75
+ credentials[database] = [username, password]
71
76
  end
72
77
 
73
78
  # Logout the user from the provided database.
@@ -82,7 +87,11 @@ module Moped
82
87
  # @since 2.0.0
83
88
  def logout(database)
84
89
  command = Protocol::Command.new(database, logout: 1)
85
- Operation::Read.new(command).execute(self)
90
+ self.write([command])
91
+ reply = self.receive_replies([command]).first
92
+ if command.failure?(reply)
93
+ return
94
+ end
86
95
  credentials.delete(database)
87
96
  end
88
97
  end
data/lib/moped/cluster.rb CHANGED
@@ -32,16 +32,32 @@ module Moped
32
32
  # @return [ Array<Node> ] The seed nodes.
33
33
  attr_reader :options, :peers, :seeds
34
34
 
35
- # Get the credentials for the cluster.
35
+ # Add a credential to the cluster
36
36
  #
37
37
  # @example Get the applied credentials.
38
38
  # node.credentials
39
39
  #
40
- # @return [ Hash ] The credentials.
40
+ # @return [ Boolean ] true
41
41
  #
42
42
  # @since 2.0.0
43
- def credentials
43
+ def add_credential(db, username, password)
44
44
  @credentials ||= {}
45
+ @credentials[db] = [ username, password ]
46
+ apply_credentials
47
+ end
48
+
49
+ # Remove a credential from the cluster
50
+ #
51
+ # @example Get the applied credentials.
52
+ # node.delete_credential(database_name)
53
+ #
54
+ # @return [ Boolean ] true
55
+ #
56
+ # @since 2.0.0
57
+ def delete_credential(db)
58
+ return true unless @credentials
59
+ @credentials.delete(db)
60
+ apply_credentials
45
61
  end
46
62
 
47
63
  # Disconnects all nodes in the cluster. This should only be used in cases
@@ -224,7 +240,7 @@ module Moped
224
240
  if node = nodes.find(&:primary?)
225
241
  begin
226
242
  node.ensure_primary do
227
- return yield(node.apply_credentials(credentials))
243
+ return yield(node)
228
244
  end
229
245
  rescue Errors::ConnectionFailure, Errors::ReplicaSetReconfigured
230
246
  end
@@ -251,7 +267,7 @@ module Moped
251
267
  available_nodes = nodes.select(&:secondary?).shuffle!
252
268
  while node = available_nodes.shift
253
269
  begin
254
- return yield(node.apply_credentials(credentials))
270
+ return yield(node)
255
271
  rescue Errors::ConnectionFailure => e
256
272
  next
257
273
  end
@@ -261,6 +277,23 @@ module Moped
261
277
 
262
278
  private
263
279
 
280
+ # Apply the credentials on all nodes
281
+ #
282
+ # @api private
283
+ #
284
+ # @example Apply the credentials.
285
+ # cluster.apply_credentials
286
+ #
287
+ # @return [ Boolean ] True
288
+ #
289
+ # @since 2.0.0
290
+ def apply_credentials
291
+ seeds.each do |node|
292
+ node.credentials = @credentials || {}
293
+ end
294
+ true
295
+ end
296
+
264
297
  # Get the boundary where a node that is down would need to be refreshed.
265
298
  #
266
299
  # @api private
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ require "connection_pool"
3
+
2
4
  module Moped
3
5
  class Connection
4
6
 
@@ -11,6 +13,12 @@ module Moped
11
13
  # Used for synchronization of pools access.
12
14
  MUTEX = Mutex.new
13
15
 
16
+ # The default max size for the connection pool.
17
+ POOL_SIZE = 5
18
+
19
+ # The default timeout for getting connections from the queue.
20
+ TIMEOUT = 0.5
21
+
14
22
  # Get a connection pool for the provided node.
15
23
  #
16
24
  # @example Get a connection pool for the node.
@@ -23,13 +31,38 @@ module Moped
23
31
  # @since 2.0.0
24
32
  def pool(node)
25
33
  MUTEX.synchronize do
26
- pools[node.address.resolved] ||=
27
- Pool.new(node.address.ip, node.address.port, node.options)
34
+ pools[node.address.resolved] ||= create_pool(node)
28
35
  end
29
36
  end
30
37
 
31
38
  private
32
39
 
40
+ # Create a new connection pool for the provided node.
41
+ #
42
+ # @api private
43
+ #
44
+ # @example Get a connection pool for the node.
45
+ # Manager.create_pool(node)
46
+ #
47
+ # @param [ Node ] node The node.
48
+ #
49
+ # @return [ ConnectionPool ] A connection pool.
50
+ #
51
+ # @since 2.0.0
52
+ def create_pool(node)
53
+ ConnectionPool.new(
54
+ size: node.options[:pool_size] || POOL_SIZE,
55
+ timeout: node.options[:pool_timeout] || TIMEOUT
56
+ ) do
57
+ Connection.new(
58
+ node.address.ip,
59
+ node.address.port,
60
+ node.options[:timeout] || Connection::TIMEOUT,
61
+ node.options
62
+ )
63
+ end
64
+ end
65
+
33
66
  # Get all the connection pools. This is a cache that stores each pool
34
67
  # with lookup by it's resolved address.
35
68
  #
@@ -1,8 +1,5 @@
1
1
  # encoding: utf-8
2
2
  require "moped/connection/manager"
3
- require "moped/connection/pool"
4
- require "moped/connection/queue"
5
- require "moped/connection/reaper"
6
3
  require "moped/connection/sockets"
7
4
 
8
5
  module Moped
@@ -11,6 +8,7 @@ module Moped
11
8
  #
12
9
  # @since 2.0.0
13
10
  class Connection
11
+ include Authenticatable
14
12
 
15
13
  # The default connection timeout, in seconds.
16
14
  #
@@ -170,7 +168,7 @@ module Moped
170
168
  sock_read = read_data(socket, reply.length - 36)
171
169
  buffer = StringIO.new(sock_read)
172
170
  reply.documents = reply.count.times.map do
173
- BSON::Document.from_bson(buffer)
171
+ ::BSON::Document.from_bson(buffer)
174
172
  end
175
173
  end
176
174
  reply
@@ -112,7 +112,7 @@ module Moped
112
112
  #
113
113
  # @since 1.0.0
114
114
  def login(username, password)
115
- cluster.credentials[name] = [ username, password ]
115
+ cluster.add_credential(name, username, password)
116
116
  end
117
117
 
118
118
  # Log out from the current database.
@@ -122,7 +122,7 @@ module Moped
122
122
  #
123
123
  # @since 1.0.0
124
124
  def logout
125
- cluster.credentials.delete(name)
125
+ cluster.delete_credential(name)
126
126
  end
127
127
  end
128
128
  end
@@ -26,7 +26,9 @@ module Moped
26
26
  def execute(exception, node)
27
27
  node.disconnect
28
28
  begin
29
- yield if block_given?
29
+ node.connection do |conn|
30
+ yield(conn) if block_given?
31
+ end
30
32
  rescue Exception => e
31
33
  node.down!
32
34
  raise(e)
data/lib/moped/node.rb CHANGED
@@ -13,7 +13,6 @@ module Moped
13
13
  #
14
14
  # @since 1.0.0
15
15
  class Node
16
- include Authenticatable
17
16
  include Executable
18
17
  include Instrumentable
19
18
 
@@ -29,6 +28,10 @@ module Moped
29
28
  # @return [ Time ] The last time the node did a refresh.
30
29
  attr_reader :address, :down_at, :latency, :options, :refreshed_at
31
30
 
31
+ # @!attribute credentials
32
+ # @return [ Hash ] The credentials of the node.
33
+ attr_accessor :credentials
34
+
32
35
  # Is this node equal to another?
33
36
  #
34
37
  # @example Is the node equal to another.
@@ -87,24 +90,6 @@ module Moped
87
90
  read(Protocol::Command.new(database, cmd, options))
88
91
  end
89
92
 
90
- # Connect the node on the underlying connection.
91
- #
92
- # @example Connect the node.
93
- # node.connect
94
- #
95
- # @raise [ Errors::ConnectionFailure ] If connection failed.
96
- #
97
- # @return [ true ] If the connection suceeded.
98
- #
99
- # @since 2.0.0
100
- def connect
101
- start = Time.now
102
- connection{ |conn| conn.connect }
103
- @latency = Time.now - start
104
- @down_at = nil
105
- true
106
- end
107
-
108
93
  # Is the node currently connected?
109
94
  #
110
95
  # @example Is the node connected?
@@ -126,11 +111,23 @@ module Moped
126
111
  #
127
112
  # @since 2.0.0
128
113
  def connection
129
- pool.with_connection do |conn|
114
+ pool.with do |conn|
130
115
  yield(conn)
131
116
  end
132
117
  end
133
118
 
119
+ # Is the node down?
120
+ #
121
+ # @example Is the node down?
122
+ # node.down?
123
+ #
124
+ # @return [ Time, nil ] The time the node went down, or nil if up.
125
+ #
126
+ # @since 1.0.0
127
+ def down?
128
+ @down_at
129
+ end
130
+
134
131
  # Force the node to disconnect from the server.
135
132
  #
136
133
  # @example Disconnect the node.
@@ -140,23 +137,11 @@ module Moped
140
137
  #
141
138
  # @since 1.2.0
142
139
  def disconnect
143
- credentials.clear
140
+ @credentials.clear
144
141
  connection{ |conn| conn.disconnect }
145
142
  true
146
143
  end
147
144
 
148
- # Is the node down?
149
- #
150
- # @example Is the node down?
151
- # node.down?
152
- #
153
- # @return [ Time, nil ] The time the node went down, or nil if up.
154
- #
155
- # @since 1.0.0
156
- def down?
157
- @down_at
158
- end
159
-
160
145
  # Mark the node as down.
161
146
  #
162
147
  # @example Mark the node as down.
@@ -168,7 +153,7 @@ module Moped
168
153
  def down!
169
154
  @down_at = Time.new
170
155
  @latency = nil
171
- disconnect if connected?
156
+ disconnect
172
157
  end
173
158
 
174
159
  # Yields the block if a connection can be established, retrying when a
@@ -185,15 +170,23 @@ module Moped
185
170
  #
186
171
  # @since 1.0.0
187
172
  def ensure_connected(&block)
188
- return yield if executing?(:connection)
189
- execute(:connection) do
190
- begin
191
- connect unless connected?
192
- yield(self)
193
- rescue Exception => e
194
- Failover.get(e).execute(e, self, &block)
173
+ unless (conn = stack(:connection)).empty?
174
+ return yield(conn.first)
175
+ end
176
+
177
+ begin
178
+ connection do |conn|
179
+ stack(:connection) << conn
180
+ connect(conn) unless conn.connected?
181
+ conn.apply_credentials(@credentials)
182
+ yield(conn)
195
183
  end
184
+ rescue Exception => e
185
+ Failover.get(e).execute(e, self, &block)
186
+ ensure
187
+ end_execution(:connection)
196
188
  end
189
+
197
190
  end
198
191
 
199
192
  # Set a flag on the node for the duration of provided block so that an
@@ -259,6 +252,7 @@ module Moped
259
252
  @latency = nil
260
253
  @primary = nil
261
254
  @secondary = nil
255
+ @credentials = {}
262
256
  @instrumenter = options[:instrumenter] || Instrumentable::Log
263
257
  @address = Address.new(address, timeout)
264
258
  @address.resolve(self)
@@ -523,6 +517,24 @@ module Moped
523
517
 
524
518
  private
525
519
 
520
+ # Connect the node on the underlying connection.
521
+ #
522
+ # @example Connect the node.
523
+ # node.connect
524
+ #
525
+ # @raise [ Errors::ConnectionFailure ] If connection failed.
526
+ #
527
+ # @return [ true ] If the connection suceeded.
528
+ #
529
+ # @since 2.0.0
530
+ def connect(conn)
531
+ start = Time.now
532
+ conn.connect
533
+ @latency = Time.now - start
534
+ @down_at = nil
535
+ true
536
+ end
537
+
526
538
  # Configure the node based on the return from the ismaster command.
527
539
  #
528
540
  # @api private
@@ -554,7 +566,7 @@ module Moped
554
566
  def discover(*nodes)
555
567
  nodes.flatten.compact.each do |peer|
556
568
  node = Node.new(peer, options)
557
- node.credentials.merge!(credentials)
569
+ node.credentials.merge!(@credentials)
558
570
  peers.push(node)
559
571
  end
560
572
  end
@@ -574,16 +586,14 @@ module Moped
574
586
  def flush(ops = queue)
575
587
  operations, callbacks = ops.transpose
576
588
  logging(operations) do
577
- ensure_connected do
578
- replies = nil
579
- connection do |conn|
580
- conn.write(operations)
581
- replies = conn.receive_replies(operations)
582
- end
583
- replies.zip(callbacks).map do |reply, callback|
584
- callback ? callback[reply] : reply
585
- end.last
589
+ replies = nil
590
+ ensure_connected do |conn|
591
+ conn.write(operations)
592
+ replies = conn.receive_replies(operations)
586
593
  end
594
+ replies.zip(callbacks).map do |reply, callback|
595
+ callback ? callback[reply] : reply
596
+ end.last
587
597
  end
588
598
  ensure
589
599
  ops.clear
@@ -47,12 +47,7 @@ module Moped
47
47
  def execute(node)
48
48
  node.process(operation) do |reply|
49
49
  if operation.failure?(reply)
50
- if reply.unauthorized? && node.credentials.has_key?(database)
51
- node.login(database, *node.credentials[database])
52
- return execute(node)
53
- else
54
- raise operation.failure_exception(reply)
55
- end
50
+ raise operation.failure_exception(reply)
56
51
  end
57
52
  operation.results(reply)
58
53
  end
@@ -156,7 +156,7 @@ module Moped
156
156
  def deserialize_documents(buffer)
157
157
  documents = []
158
158
  count.times do
159
- documents << BSON::Document.from_bson(buffer)
159
+ documents << ::BSON::Document.from_bson(buffer)
160
160
  end
161
161
  @documents = documents
162
162
  end
data/lib/moped/query.rb CHANGED
@@ -77,6 +77,17 @@ module Moped
77
77
  cursor.each(*args, &blk)
78
78
  end
79
79
 
80
+ # Get the Moped cursor to iterate over documents
81
+ # on the db.
82
+ #
83
+ # @example Iterate over the matching documents.
84
+ # db[:people].cursor.each do |doc|
85
+ # #...
86
+ # end
87
+ #
88
+ # @return [ Moped::Cursor ]
89
+ #
90
+ # @since 2.0.0
80
91
  def cursor
81
92
  Cursor.new(session, operation)
82
93
  end
data/lib/moped/session.rb CHANGED
@@ -215,10 +215,15 @@ module Moped
215
215
  # @since 2.0.0
216
216
  option(:retry_interval).allow(Optionable.any(Numeric))
217
217
 
218
- # Setup validation of allowed reap interval options. (Any numeric)
218
+ # Setup validation of allowed refresh interval options. (Any numeric)
219
219
  #
220
220
  # @since 2.0.0
221
- option(:reap_interval).allow(Optionable.any(Numeric))
221
+ option(:refresh_interval).allow(Optionable.any(Numeric))
222
+
223
+ # Setup validation of allowed down interval options. (Any numeric)
224
+ #
225
+ # @since 2.0.0
226
+ option(:down_interval).allow(Optionable.any(Numeric))
222
227
 
223
228
  # Setup validation of allowed ssl options. (Any boolean)
224
229
  #
@@ -230,6 +235,11 @@ module Moped
230
235
  # @since 2.0.0
231
236
  option(:timeout).allow(Optionable.any(Numeric))
232
237
 
238
+ # Pass an object that responds to instrument as an instrumenter.
239
+ #
240
+ # @since 2.0.0
241
+ option(:instrumenter).allow(Optionable.any(Object))
242
+
233
243
  # Initialize a new database session.
234
244
  #
235
245
  # @example Initialize a new session.
data/lib/moped/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  module Moped
3
- VERSION = "2.0.0.beta3"
3
+ VERSION = "2.0.0.beta4"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moped
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta3
4
+ version: 2.0.0.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Durran Jordan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-14 00:00:00.000000000 Z
12
+ date: 2013-12-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bson
@@ -17,28 +17,42 @@ dependencies:
17
17
  requirements:
18
18
  - - ~>
19
19
  - !ruby/object:Gem::Version
20
- version: 2.0.0.rc3
20
+ version: '2.0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
- version: 2.0.0.rc3
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: connection_pool
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: '1.2'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ version: '1.2'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: optionable
30
44
  requirement: !ruby/object:Gem::Requirement
31
45
  requirements:
32
46
  - - ~>
33
47
  - !ruby/object:Gem::Version
34
- version: 0.1.1
48
+ version: 0.2.0
35
49
  type: :runtime
36
50
  prerelease: false
37
51
  version_requirements: !ruby/object:Gem::Requirement
38
52
  requirements:
39
53
  - - ~>
40
54
  - !ruby/object:Gem::Version
41
- version: 0.1.1
55
+ version: 0.2.0
42
56
  description: A MongoDB driver for Ruby.
43
57
  email:
44
58
  - durran@gmail.com
@@ -51,9 +65,6 @@ files:
51
65
  - lib/moped/cluster.rb
52
66
  - lib/moped/collection.rb
53
67
  - lib/moped/connection/manager.rb
54
- - lib/moped/connection/pool.rb
55
- - lib/moped/connection/queue.rb
56
- - lib/moped/connection/reaper.rb
57
68
  - lib/moped/connection/socket/connectable.rb
58
69
  - lib/moped/connection/socket/ssl.rb
59
70
  - lib/moped/connection/socket/tcp.rb
@@ -128,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
139
  version: 1.3.1
129
140
  requirements: []
130
141
  rubyforge_project:
131
- rubygems_version: 2.0.6
142
+ rubygems_version: 2.1.11
132
143
  signing_key:
133
144
  specification_version: 4
134
145
  summary: A MongoDB driver for Ruby.
@@ -1,198 +0,0 @@
1
- # encoding: utf-8
2
- module Moped
3
- class Connection
4
-
5
- # This class contains behaviour of connection pools for specific addresses.
6
- #
7
- # @since 2.0.0
8
- class Pool
9
-
10
- # The default max size for the connection pool.
11
- POOL_SIZE = 5
12
-
13
- # The default timeout for getting connections from the queue.
14
- TIMEOUT = 0.25
15
-
16
- # @!attribute host
17
- # @return [ String ] The host the pool is for.
18
- # @!attribute port
19
- # @return [ Integer ] The port on the host.
20
- # @!attribute options
21
- # @return [ Hash ] The connection pool options.
22
- # @!attribute reaper
23
- # @return [ Reaper ] The connection pool reaper.
24
- attr_reader :host, :port, :options, :reaper
25
-
26
- # Checkout a connection from the connection pool. If there exists a
27
- # connection pinned to the current thread, then we return that first. If
28
- # no connection is pinned, we will take an unpinned connection or create
29
- # a new one if no unpinned exist and the pool is not saturated.
30
- #
31
- # @example Checkout a connection.
32
- # pool.checkout
33
- #
34
- # @return [ Connection ] A connection.
35
- #
36
- # @since 2.0.0
37
- def checkout
38
- mutex.synchronize do
39
- connection = pinned[thread_id]
40
- if connection
41
- unless connection.expired?
42
- raise Errors::ConnectionInUse, "The connection on thread: #{thread_id} is in use."
43
- else
44
- lease(connection)
45
- end
46
- else
47
- connection = pinned[thread_id] = next_connection
48
- lease(connection)
49
- end
50
- end
51
- end
52
-
53
- # Checkin the connection, indicating that it is finished being used. The
54
- # connection will stay pinned to the current thread.
55
- #
56
- # @example Checkin the connection.
57
- # pool.checkin(connection)
58
- #
59
- # @param [ Connection ] connection The connection to checkin.
60
- #
61
- # @since 2.0.0
62
- def checkin(connection)
63
- mutex.synchronize do
64
- expire(connection)
65
- end
66
- end
67
-
68
- # Initialize the connection pool.
69
- #
70
- # @example Instantiate the connection pool.
71
- # Pool.new(max_size: 4)
72
- #
73
- # @param [ Hash ] options The connection pool options.
74
- #
75
- # @since 2.0.0
76
- def initialize(host, port, options = {})
77
- @host = host
78
- @port = port
79
- @options = options
80
- @reaper = Reaper.new(options[:reap_interval] || Reaper::INTERVAL, self)
81
- @mutex = Mutex.new
82
- @resource = ConditionVariable.new
83
- @pinned = {}
84
- @unpinned = Queue.new(max_size) do
85
- Connection.new(host, port, options[:timeout] || Connection::TIMEOUT, options)
86
- end
87
- reaper.start
88
- end
89
-
90
- # Get the max size for the connection pool.
91
- #
92
- # @example Get the max size.
93
- # pool.max_size
94
- #
95
- # @return [ Integer ] The max size of the pool.
96
- #
97
- # @since 2.0.0
98
- def max_size
99
- @max_size ||= (options[:pool_size] || POOL_SIZE)
100
- end
101
-
102
- # Reap all connections that are active and associated with dead threads.
103
- #
104
- # @example Reap the connections.
105
- # pool.reap([ 12351122313 ])
106
- #
107
- # @param [ Array<Integer> ] ids The ids of the current active threads.
108
- #
109
- # @return [ Pool ] The connection pool.
110
- #
111
- # @since 2.0.0
112
- def reap(ids = active_threads)
113
- pinned.each do |id, conn|
114
- unless ids.include?(id)
115
- conn.expire
116
- unpinned.push(pinned.delete(id))
117
- end
118
- end and self
119
- end
120
-
121
- # Get the current size of the connection pool. Is the total of pinned
122
- # plus unpinned connections.
123
- #
124
- # @example Get the pool's current size.
125
- # pool.size
126
- #
127
- # @return [ Integer ] The current size of the pool.
128
- #
129
- # @since 2.0.0
130
- def size
131
- unpinned.size + pinned.size
132
- end
133
-
134
- # Get the timeout when attempting to check out items from the pool.
135
- #
136
- # @example Get the checkout timeout.
137
- # pool.timeout
138
- #
139
- # @return [ Float ] The pool timeout.
140
- #
141
- # @since 2.0.0
142
- def timeout
143
- @timeout ||= (options[:pool_timeout] || TIMEOUT)
144
- end
145
-
146
- # Execute the block with a connection, ensuring that the checkin/checkout
147
- # workflow is properly executed.
148
- #
149
- # @example Execute the block with a connection.
150
- # pool.with_connection do |conn|
151
- # conn.connect
152
- # end
153
- #
154
- # @return [ Object ] The result of the yield.
155
- #
156
- # @since 2.0.0
157
- def with_connection
158
- connection = checkout
159
- begin
160
- yield(connection)
161
- ensure
162
- checkin(connection)
163
- end
164
- end
165
-
166
- private
167
-
168
- attr_reader :mutex, :resource, :pinned, :unpinned
169
-
170
- def expire(connection)
171
- connection.expire
172
- pinned[thread_id] = connection
173
- end
174
-
175
- def lease(connection)
176
- connection.lease
177
- connection
178
- end
179
-
180
- def next_connection
181
- reap if saturated?
182
- unpinned.pop(timeout)
183
- end
184
-
185
- def saturated?
186
- size == max_size
187
- end
188
-
189
- def thread_id
190
- Thread.current.object_id
191
- end
192
-
193
- def active_threads
194
- Thread.list.select{ |thread| thread.alive? }.map{ |thread| thread.object_id }
195
- end
196
- end
197
- end
198
- end
@@ -1,93 +0,0 @@
1
- # encoding: utf-8
2
- module Moped
3
- class Connection
4
-
5
- # This class contains behaviour of a queue of unpinned connections.
6
- #
7
- # @since 2.0.0
8
- class Queue
9
-
10
- # Initialize a queue with the provided size.
11
- #
12
- # @example Instantiate the queue.
13
- # Moped::Connection::Queue.new(10)
14
- #
15
- # @param [ Integer ] size The number of connections in the queue.
16
- #
17
- # @since 2.0.0
18
- def initialize(size)
19
- @queue = Array.new(size) { yield }
20
- @mutex = Mutex.new
21
- @resource = ConditionVariable.new
22
- end
23
-
24
- # Push a connection on the queue.
25
- #
26
- # @example Push a connection on the queue.
27
- # queue.push(connection)
28
- #
29
- # @param [ Moped::Connection ] connection The connection to add.
30
- #
31
- # @since 2.0.0
32
- def push(connection)
33
- mutex.synchronize do
34
- queue.push(connection)
35
- resource.broadcast
36
- end
37
- end
38
-
39
- # Pop the next connection off the queue.
40
- #
41
- # @example Pop a connection off the queue.
42
- # queue.pop(0.5)
43
- #
44
- # @param [ Float ] timeout The time to wait for the connection.
45
- #
46
- # @return [ Moped::Connection ] The next connection.
47
- #
48
- # @since 2.0.0
49
- def pop(timeout = 0.5)
50
- mutex.synchronize do
51
- wait_for_next(Time.now + timeout)
52
- end
53
- end
54
-
55
- # Is the queue empty?
56
- #
57
- # @example Is the queue empty?
58
- # queue.empty?
59
- #
60
- # @return [ true, false ] Is the queue empty?
61
- #
62
- # @since 2.0.0
63
- def empty?
64
- queue.empty?
65
- end
66
-
67
- # Get the current size of the queue.
68
- #
69
- # @example Get the size of the queue.
70
- # queue.size
71
- #
72
- # @return [ Integer ] The number of connections in the queue.
73
- #
74
- # @since 2.0.0
75
- def size
76
- queue.size
77
- end
78
-
79
- private
80
-
81
- attr_reader :queue, :mutex, :resource
82
-
83
- def wait_for_next(deadline)
84
- loop do
85
- return queue.pop unless queue.empty?
86
- wait = deadline - Time.now
87
- raise Timeout::Error, "Waited for item but none was pushed." if wait <= 0
88
- resource.wait(mutex, wait)
89
- end
90
- end
91
- end
92
- end
93
- end
@@ -1,52 +0,0 @@
1
- # encoding: utf-8
2
- module Moped
3
- class Connection
4
-
5
- # This object cleans up connections on dead threads at a specified time
6
- # interval.
7
- #
8
- # @since 2.0.0
9
- class Reaper
10
-
11
- # The default interval for reaping connections.
12
- #
13
- # @since 2.0.0
14
- INTERVAL = 5
15
-
16
- # @!attribute interval
17
- # @return [ Float ] The reaping interval, in seconds.
18
- # @!attribute pool
19
- # @return [ Pool ] The connection pool to reap.
20
- attr_reader :interval, :pool
21
-
22
- # Initialize a new connection pool reaper.
23
- #
24
- # @example Initialize the reaper.
25
- # Moped::Connection::Reaper.new(5, pool)
26
- #
27
- # @param [ Float ] interval The reaping interval.
28
- # @param [ Pool ] pool The connection pool to reap.
29
- #
30
- # @since 2.0.0
31
- def initialize(interval, pool)
32
- @interval = interval
33
- @pool = pool
34
- end
35
-
36
- # Start the reaper. Will execute continually on a separate thread.
37
- #
38
- # @example Start the reaper.
39
- # reaper.start
40
- #
41
- # @since 2.0.0
42
- def start
43
- Thread.new(interval, pool) do |i, p|
44
- while (true)
45
- sleep(i)
46
- p.reap
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end