r18_connection_pool 2.2.2a

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c24bd0aef22d03af8f4cb6d589696e5c6bbe8f0e0f4c6d3be3f96e8a1a4a21a0
4
+ data.tar.gz: 17778a4163543a80f269f39edbe26e20e026734f747294b8c01a7c307ad78661
5
+ SHA512:
6
+ metadata.gz: a87b9e013ac7dd203c70aa4269183161850f9c017c369f4a150dd0875383104f3627239e88de1cdac3a3c86773a62969b101f9065edf25497f134911b208094a
7
+ data.tar.gz: c659492935abc74d1757b1d187a0c7a08b87cd11608b27d41ce705ea1dc0d710b6920d664edd9c1eddf034af19ac5d7c9e760a439f1a401b64ec3fa811b42569
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ ---
2
+ sudo: false
3
+ cache: bundler
4
+ language: ruby
5
+ rvm:
6
+ - 2.2.9
7
+ - 2.3.6
8
+ - 2.4.3
9
+ - 2.5.0
10
+ - jruby
data/Changes.md ADDED
@@ -0,0 +1,123 @@
1
+ connection\_pool changelog
2
+ ---------------------------
3
+
4
+ 2.2.2
5
+ ------
6
+
7
+ - Add pool `size` and `available` accessors for metrics and monitoring
8
+ purposes [#97, robholland]
9
+
10
+ 2.2.1
11
+ ------
12
+
13
+ - Allow CP::Wrapper to use an existing pool [#87, etiennebarrie]
14
+ - Use monotonic time for more accurate timeouts [#84, jdantonio]
15
+
16
+ 2.2.0
17
+ ------
18
+
19
+ - Rollback `Timeout` handling introduced in 2.1.1 and 2.1.2. It seems
20
+ impossible to safely work around the issue. Please never, ever use
21
+ `Timeout.timeout` in your code or you will see rare but mysterious bugs. [#75]
22
+
23
+ 2.1.3
24
+ ------
25
+
26
+ - Don't increment created count until connection is successfully
27
+ created. [mylesmegyesi, #73]
28
+
29
+ 2.1.2
30
+ ------
31
+
32
+ - The connection\_pool will now close any connections which respond to
33
+ `close` (Dalli) or `disconnect!` (Redis). This ensures discarded connections
34
+ from the fix in 2.1.1 are torn down ASAP and don't linger open.
35
+
36
+
37
+ 2.1.1
38
+ ------
39
+
40
+ - Work around a subtle race condition with code which uses `Timeout.timeout` and
41
+ checks out a connection within the timeout block. This might cause
42
+ connections to get into a bad state and raise very odd errors. [tamird, #67]
43
+
44
+
45
+ 2.1.0
46
+ ------
47
+
48
+ - Refactoring to better support connection pool subclasses [drbrain,
49
+ #55]
50
+ - `with` should return value of the last expression [#59]
51
+
52
+
53
+ 2.0.0
54
+ -----
55
+
56
+ - The connection pool is now lazy. Connections are created as needed
57
+ and retained until the pool is shut down. [drbrain, #52]
58
+
59
+ 1.2.0
60
+ -----
61
+
62
+ - Add `with(options)` and `checkout(options)`. [mattcamuto]
63
+ Allows the caller to override the pool timeout.
64
+ ```ruby
65
+ @pool.with(:timeout => 2) do |conn|
66
+ end
67
+ ```
68
+
69
+ 1.1.0
70
+ -----
71
+
72
+ - New `#shutdown` method (simao)
73
+
74
+ This method accepts a block and calls the block for each
75
+ connection in the pool. After calling this method, trying to get a
76
+ connection from the pool raises `PoolShuttingDownError`.
77
+
78
+ 1.0.0
79
+ -----
80
+
81
+ - `#with_connection` is now gone in favor of `#with`.
82
+
83
+ - We no longer pollute the top level namespace with our internal
84
+ `TimedStack` class.
85
+
86
+ 0.9.3
87
+ --------
88
+
89
+ - `#with_connection` is now deprecated in favor of `#with`.
90
+
91
+ A warning will be issued in the 0.9 series and the method will be
92
+ removed in 1.0.
93
+
94
+ - We now reuse objects when possible.
95
+
96
+ This means that under no contention, the same object will be checked
97
+ out from the pool after subsequent calls to `ConnectionPool#with`.
98
+
99
+ This change should have no impact on end user performance. If
100
+ anything, it should be an improvement, depending on what objects you
101
+ are pooling.
102
+
103
+ 0.9.2
104
+ --------
105
+
106
+ - Fix reentrant checkout leading to early checkin.
107
+
108
+ 0.9.1
109
+ --------
110
+
111
+ - Fix invalid superclass in version.rb
112
+
113
+ 0.9.0
114
+ --------
115
+
116
+ - Move method\_missing magic into ConnectionPool::Wrapper (djanowski)
117
+ - Remove BasicObject superclass (djanowski)
118
+
119
+ 0.1.0
120
+ --------
121
+
122
+ - More precise timeouts and better error message
123
+ - ConnectionPool now subclasses BasicObject so `method_missing` is more effective.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec(development_group: :runtime)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Mike Perham
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ connection\_pool
2
+ =================
3
+ [![Build Status](https://travis-ci.org/mperham/connection_pool.svg)](https://travis-ci.org/mperham/connection_pool)
4
+
5
+ Generic connection pooling for Ruby.
6
+
7
+ MongoDB has its own connection pool. ActiveRecord has its own connection pool.
8
+ This is a generic connection pool that can be used with anything, e.g. Redis,
9
+ Dalli and other Ruby network clients.
10
+
11
+
12
+ Usage
13
+ -----
14
+
15
+ Create a pool of objects to share amongst the fibers or threads in your Ruby
16
+ application:
17
+
18
+ ``` ruby
19
+ $memcached = ConnectionPool.new(size: 5, timeout: 5) { Dalli::Client.new }
20
+ ```
21
+
22
+ Then use the pool in your application:
23
+
24
+ ``` ruby
25
+ $memcached.with do |conn|
26
+ conn.get('some-count')
27
+ end
28
+ ```
29
+
30
+ If all the objects in the connection pool are in use, `with` will block
31
+ until one becomes available. If no object is available within `:timeout` seconds,
32
+ `with` will raise a `Timeout::Error`.
33
+
34
+ Optionally, you can specify a timeout override using the with-block semantics:
35
+
36
+ ``` ruby
37
+ $memcached.with(timeout: 2.0) do |conn|
38
+ conn.get('some-count')
39
+ end
40
+ ```
41
+
42
+ This will only modify the resource-get timeout for this particular
43
+ invocation. This is useful if you want to fail-fast on certain non critical
44
+ sections when a resource is not available, or conversely if you are comfortable
45
+ blocking longer on a particular resource. This is not implemented in the below
46
+ `ConnectionPool::Wrapper` class.
47
+
48
+ ## Migrating to a Connection Pool
49
+
50
+ You can use `ConnectionPool::Wrapper` to wrap a single global connection,
51
+ making it easier to migrate existing connection code over time:
52
+
53
+ ``` ruby
54
+ $redis = ConnectionPool::Wrapper.new(size: 5, timeout: 3) { Redis.connect }
55
+ $redis.sadd('foo', 1)
56
+ $redis.smembers('foo')
57
+ ```
58
+
59
+ The wrapper uses `method_missing` to checkout a connection, run the requested
60
+ method and then immediately check the connection back into the pool. It's
61
+ **not** high-performance so you'll want to port your performance sensitive code
62
+ to use `with` as soon as possible.
63
+
64
+ ``` ruby
65
+ $redis.with do |conn|
66
+ conn.sadd('foo', 1)
67
+ conn.smembers('foo')
68
+ end
69
+ ```
70
+
71
+ Once you've ported your entire system to use `with`, you can simply remove
72
+ `Wrapper` and use the simpler and faster `ConnectionPool`.
73
+
74
+
75
+ ## Shutdown
76
+
77
+ You can shut down a ConnectionPool instance once it should no longer be used.
78
+ Further checkout attempts will immediately raise an error but existing checkouts
79
+ will work.
80
+
81
+ ```ruby
82
+ cp = ConnectionPool.new { Redis.new }
83
+ cp.shutdown { |conn| conn.quit }
84
+ ```
85
+
86
+ Shutting down a connection pool will block until all connections are checked in and closed.
87
+ **Note that shutting down is completely optional**; Ruby's garbage collector will reclaim
88
+ unreferenced pools under normal circumstances.
89
+
90
+
91
+ Notes
92
+ -----
93
+
94
+ - Connections are lazily created as needed.
95
+ - There is no provision for repairing or checking the health of a connection;
96
+ connections should be self-repairing. This is true of the Dalli and Redis
97
+ clients.
98
+ - **WARNING**: Don't ever use `Timeout.timeout` in your Ruby code or you will see
99
+ occasional silent corruption and mysterious errors. The Timeout API is unsafe
100
+ and cannot be used correctly, ever. Use proper socket timeout options as
101
+ exposed by Net::HTTP, Redis, Dalli, etc.
102
+
103
+
104
+ Author
105
+ ------
106
+
107
+ Mike Perham, [@mperham](https://twitter.com/mperham), <http://mikeperham.com>
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+ Rake::TestTask.new
5
+
6
+ task :default => :test
data/devjournal ADDED
@@ -0,0 +1,15 @@
1
+ --------------------------------
2
+ 2023/08/04 takeshi:
3
+
4
+ I need connection_pool to run on ruby 1.8.
5
+ So I searched for a suitable gem version and it seems 2.2.3 (8b830d21fdc4c9ae1a41cc587e436478a280513c) will work with some small adjustment.
6
+
7
+ However, eventually, 2.2.3 required
8
+ Process::CLOCK_MONOTONIC
9
+ which we don't have in ruby 1.8
10
+
11
+ But 2.2.2 uses
12
+ Process::CLOCK_MONOTONIC
13
+ only if available so lets try to switch to it.
14
+
15
+ So this branch was created based on 2.2.2 (608f0f407161275d95e044adad48b9ae44d55ec1).
@@ -0,0 +1,66 @@
1
+ # Global monotonic clock from Concurrent Ruby 1.0.
2
+ # Copyright (c) Jerry D'Antonio -- released under the MIT license.
3
+ # Slightly modified; used with permission.
4
+ # https://github.com/ruby-concurrency/concurrent-ruby
5
+
6
+ require 'thread'
7
+
8
+ class ConnectionPool
9
+
10
+ class_definition = Class.new do
11
+
12
+ if defined?(Process::CLOCK_MONOTONIC)
13
+
14
+ # @!visibility private
15
+ def get_time
16
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
17
+ end
18
+
19
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
20
+
21
+ # @!visibility private
22
+ def get_time
23
+ java.lang.System.nanoTime() / 1_000_000_000.0
24
+ end
25
+
26
+ else
27
+
28
+ # @!visibility private
29
+ def initialize
30
+ @mutex = Mutex.new
31
+ @last_time = Time.now.to_f
32
+ end
33
+
34
+ # @!visibility private
35
+ def get_time
36
+ @mutex.synchronize do
37
+ now = Time.now.to_f
38
+ if @last_time < now
39
+ @last_time = now
40
+ else # clock has moved back in time
41
+ @last_time += 0.000_001
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ ##
49
+ # Clock that cannot be set and represents monotonic time since
50
+ # some unspecified starting point.
51
+ #
52
+ # @!visibility private
53
+ GLOBAL_MONOTONIC_CLOCK = class_definition.new
54
+ #private_constant :GLOBAL_MONOTONIC_CLOCK # MayamaTakeshi to permit to use in ruby 1.8
55
+
56
+ class << self
57
+ ##
58
+ # Returns the current time a tracked by the application monotonic clock.
59
+ #
60
+ # @return [Float] The current monotonic time when `since` not given else
61
+ # the elapsed monotonic time between `since` and the current time
62
+ def monotonic_time
63
+ GLOBAL_MONOTONIC_CLOCK.get_time
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,176 @@
1
+ require 'thread'
2
+ require 'timeout'
3
+ require 'connection_pool/monotonic_time'
4
+
5
+ ##
6
+ # Raised when you attempt to retrieve a connection from a pool that has been
7
+ # shut down.
8
+
9
+ class ConnectionPool::PoolShuttingDownError < RuntimeError; end
10
+
11
+ ##
12
+ # The TimedStack manages a pool of homogeneous connections (or any resource
13
+ # you wish to manage). Connections are created lazily up to a given maximum
14
+ # number.
15
+
16
+ # Examples:
17
+ #
18
+ # ts = TimedStack.new(1) { MyConnection.new }
19
+ #
20
+ # # fetch a connection
21
+ # conn = ts.pop
22
+ #
23
+ # # return a connection
24
+ # ts.push conn
25
+ #
26
+ # conn = ts.pop
27
+ # ts.pop timeout: 5
28
+ # #=> raises Timeout::Error after 5 seconds
29
+
30
+ class ConnectionPool::TimedStack
31
+ attr_reader :max
32
+
33
+ ##
34
+ # Creates a new pool with +size+ connections that are created from the given
35
+ # +block+.
36
+
37
+ def initialize(size = 0, &block)
38
+ @create_block = block
39
+ @created = 0
40
+ @que = []
41
+ @max = size
42
+ @mutex = Mutex.new
43
+ @resource = ConditionVariable.new
44
+ @shutdown_block = nil
45
+ end
46
+
47
+ ##
48
+ # Returns +obj+ to the stack. +options+ is ignored in TimedStack but may be
49
+ # used by subclasses that extend TimedStack.
50
+
51
+ def push(obj, options = {})
52
+ @mutex.synchronize do
53
+ if @shutdown_block
54
+ @shutdown_block.call(obj)
55
+ else
56
+ store_connection obj, options
57
+ end
58
+
59
+ @resource.broadcast
60
+ end
61
+ end
62
+ alias_method :<<, :push
63
+
64
+ ##
65
+ # Retrieves a connection from the stack. If a connection is available it is
66
+ # immediately returned. If no connection is available within the given
67
+ # timeout a Timeout::Error is raised.
68
+ #
69
+ # +:timeout+ is the only checked entry in +options+ and is preferred over
70
+ # the +timeout+ argument (which will be removed in a future release). Other
71
+ # options may be used by subclasses that extend TimedStack.
72
+
73
+ def pop(timeout = 0.5, options = {})
74
+ options, timeout = timeout, 0.5 if Hash === timeout
75
+ timeout = options.fetch :timeout, timeout
76
+
77
+ deadline = ConnectionPool.monotonic_time + timeout
78
+ @mutex.synchronize do
79
+ loop do
80
+ raise ConnectionPool::PoolShuttingDownError if @shutdown_block
81
+ return fetch_connection(options) if connection_stored?(options)
82
+
83
+ connection = try_create(options)
84
+ return connection if connection
85
+
86
+ to_wait = deadline - ConnectionPool.monotonic_time
87
+ raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
88
+ @resource.wait(@mutex, to_wait)
89
+ end
90
+ end
91
+ end
92
+
93
+ ##
94
+ # Shuts down the TimedStack which prevents connections from being checked
95
+ # out. The +block+ is called once for each connection on the stack.
96
+
97
+ def shutdown(&block)
98
+ raise ArgumentError, "shutdown must receive a block" unless block_given?
99
+
100
+ @mutex.synchronize do
101
+ @shutdown_block = block
102
+ @resource.broadcast
103
+
104
+ shutdown_connections
105
+ end
106
+ end
107
+
108
+ ##
109
+ # Returns +true+ if there are no available connections.
110
+
111
+ def empty?
112
+ (@created - @que.length) >= @max
113
+ end
114
+
115
+ ##
116
+ # The number of connections available on the stack.
117
+
118
+ def length
119
+ @max - @created + @que.length
120
+ end
121
+
122
+ private
123
+
124
+ ##
125
+ # This is an extension point for TimedStack and is called with a mutex.
126
+ #
127
+ # This method must returns true if a connection is available on the stack.
128
+
129
+ def connection_stored?(options = nil)
130
+ !@que.empty?
131
+ end
132
+
133
+ ##
134
+ # This is an extension point for TimedStack and is called with a mutex.
135
+ #
136
+ # This method must return a connection from the stack.
137
+
138
+ def fetch_connection(options = nil)
139
+ @que.pop
140
+ end
141
+
142
+ ##
143
+ # This is an extension point for TimedStack and is called with a mutex.
144
+ #
145
+ # This method must shut down all connections on the stack.
146
+
147
+ def shutdown_connections(options = nil)
148
+ while connection_stored?(options)
149
+ conn = fetch_connection(options)
150
+ @shutdown_block.call(conn)
151
+ end
152
+ end
153
+
154
+ ##
155
+ # This is an extension point for TimedStack and is called with a mutex.
156
+ #
157
+ # This method must return +obj+ to the stack.
158
+
159
+ def store_connection(obj, options = nil)
160
+ @que.push obj
161
+ end
162
+
163
+ ##
164
+ # This is an extension point for TimedStack and is called with a mutex.
165
+ #
166
+ # This method must create a connection if and only if the total number of
167
+ # connections allowed has not been met.
168
+
169
+ def try_create(options = nil)
170
+ unless @created == @max
171
+ object = @create_block.call
172
+ @created += 1
173
+ object
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,3 @@
1
+ class ConnectionPool
2
+ VERSION = "2.2.2a"
3
+ end