r18_connection_pool 2.2.2a

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