connection_pool 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
data/Changes.md CHANGED
@@ -1,3 +1,20 @@
1
+ 0.9.3
2
+ --------
3
+
4
+ - `#with_connection` is now deprecated in favor of `#with`.
5
+
6
+ A warning will be issued in the 0.9 series and the method will be
7
+ removed in 1.0.
8
+
9
+ - We now reuse objects when possible.
10
+
11
+ This means that under no contention, the same object will be checked
12
+ out from the pool after subsequent calls to `ConnectionPool#with`.
13
+
14
+ This change should have no impact on end user performance. If
15
+ anything, it should be an improvement, depending on what objects you
16
+ are pooling.
17
+
1
18
  0.9.2
2
19
  --------
3
20
 
data/README.md CHANGED
@@ -11,35 +11,57 @@ Install
11
11
 
12
12
  gem install connection_pool
13
13
 
14
+
15
+ Notes
16
+ ------------
17
+
18
+ - Connections are eager created when the pool is created.
19
+ - There is no provision for repairing or checking the health of a
20
+ connection; connections should be self-repairing. This is
21
+ true of the dalli and redis clients.
22
+
23
+
14
24
  Usage
15
25
  ------------
16
26
 
17
27
  Create a pool of objects to share amongst the fibers or threads in your Ruby application:
18
28
 
19
- @memcached = ConnectionPool.new(:size => 5, :timeout => 5) { Dalli::Client.new }
29
+ ``` ruby
30
+ @memcached = ConnectionPool.new(:size => 5, :timeout => 5) { Dalli::Client.new }
31
+ ```
20
32
 
21
33
  Then use the pool in your application:
22
34
 
23
- @memcached.with_connection do |dalli|
24
- dalli.get('some-count')
25
- end
35
+ ``` ruby
36
+ @memcached.with do |dalli|
37
+ dalli.get('some-count')
38
+ end
39
+ ```
40
+
41
+ If all the objects in the connection pool are in use, `with` will block
42
+ until one becomes available. If no object is available within `:timeout` seconds,
43
+ `with` will raise a `Timeout::Error`.
26
44
 
27
45
  You can use `ConnectionPool::Wrapper` to wrap a single global connection, making
28
46
  it easier to port your connection code over time:
29
47
 
30
- $redis = ConnectionPool::Wrapper.new(:size => 5, :timeout => 3) { Redis.connect }
31
- $redis.sadd('foo', 1)
32
- $redis.smembers('foo')
48
+ ``` ruby
49
+ $redis = ConnectionPool::Wrapper.new(:size => 5, :timeout => 3) { Redis.connect }
50
+ $redis.sadd('foo', 1)
51
+ $redis.smembers('foo')
52
+ ```
33
53
 
34
54
  The Wrapper uses `method_missing` to checkout a connection, run the
35
55
  requested method and then immediately check the connection back into the
36
56
  pool. It's **not** high-performance so you'll want to port your
37
- performance sensitive code to use `with_connection` as soon as possible.
38
-
39
- $redis.with_connection do |conn|
40
- conn.sadd('foo', 1)
41
- conn.smembers('foo')
42
- end
57
+ performance sensitive code to use `with` as soon as possible.
58
+
59
+ ``` ruby
60
+ $redis.with do |conn|
61
+ conn.sadd('foo', 1)
62
+ conn.smembers('foo')
63
+ end
64
+ ```
43
65
 
44
66
  Once you've ported your entire system to use `with`, you can simply
45
67
  remove ::Wrapper and use a simple, fast ConnectionPool.
data/Rakefile CHANGED
@@ -1,5 +1,8 @@
1
- require 'bundler'
2
- Bundler::GemHelper.install_tasks
1
+ begin
2
+ require 'bundler'
3
+ Bundler::GemHelper.install_tasks
4
+ rescue LoadError
5
+ end
3
6
 
4
7
  require 'rake/testtask'
5
8
  Rake::TestTask.new(:test) do |test|
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Mike Perham"]
9
9
  s.email = ["mperham@gmail.com"]
10
- s.homepage = ""
10
+ s.homepage = "https://github.com/mperham/connection_pool"
11
11
  s.description = s.summary = %q{Generic connection pool for Ruby}
12
12
 
13
13
  s.files = `git ls-files`.split("\n")
@@ -1,5 +1,5 @@
1
- require 'connection_pool/version'
2
- require 'timed_queue'
1
+ require_relative 'connection_pool/version'
2
+ require_relative 'timed_queue'
3
3
 
4
4
  # Generic connection pool class for e.g. sharing a limited number of network connections
5
5
  # among many threads. Note: Connections are eager created.
@@ -25,19 +25,19 @@ require 'timed_queue'
25
25
  # - :timeout - amount of time to wait for a connection if none currently available, defaults to 5 seconds
26
26
  #
27
27
  class ConnectionPool
28
- DEFAULTS = { :size => 5, :timeout => 5 }
28
+ DEFAULTS = {size: 5, timeout: 5}
29
29
 
30
30
  def self.wrap(options, &block)
31
31
  Wrapper.new(options, &block)
32
32
  end
33
33
 
34
- def initialize(options={}, &block)
34
+ def initialize(options = {}, &block)
35
35
  raise ArgumentError, 'Connection pool requires a block' unless block
36
36
 
37
37
  options = DEFAULTS.merge(options)
38
38
 
39
- @size = options[:size]
40
- @timeout = options[:timeout]
39
+ @size = options.fetch(:size)
40
+ @timeout = options.fetch(:timeout)
41
41
 
42
42
  @available = ::TimedQueue.new(@size, &block)
43
43
  @key = :"current-#{@available.object_id}"
@@ -51,7 +51,11 @@ class ConnectionPool
51
51
  checkin
52
52
  end
53
53
  end
54
- alias_method :with_connection, :with
54
+
55
+ def with_connection(&block)
56
+ warn("ConnectionPool#with_connection is deprecated and will be removed in version 1.0. Upgrade your code to use ConnectionPool#with instead. (in #{caller[0]})")
57
+ with(&block)
58
+ end
55
59
 
56
60
  def checkout
57
61
  stack = ::Thread.current[@key] ||= []
@@ -75,7 +79,9 @@ class ConnectionPool
75
79
  nil
76
80
  end
77
81
 
78
- class Wrapper
82
+ class Wrapper < ::BasicObject
83
+ METHODS = [:with]
84
+
79
85
  def initialize(options = {}, &block)
80
86
  @pool = ::ConnectionPool.new(options, &block)
81
87
  end
@@ -85,7 +91,15 @@ class ConnectionPool
85
91
  ensure
86
92
  @pool.checkin
87
93
  end
88
- alias_method :with_connection, :with
94
+
95
+ def with_connection(&block)
96
+ warn("ConnectionPool::Wrapper#with_connection is deprecated and will be removed in version 1.0. Upgrade your code to use ConnectionPool::Wrapper#with instead. (in #{caller[0]})")
97
+ with(&block)
98
+ end
99
+
100
+ def respond_to?(id, *args)
101
+ METHODS.include?(id) || @pool.with { |c| c.respond_to?(id, *args) }
102
+ end
89
103
 
90
104
  def method_missing(name, *args, &block)
91
105
  @pool.with do |connection|
@@ -1,3 +1,3 @@
1
1
  class ConnectionPool
2
- VERSION = "0.9.2"
2
+ VERSION = "0.9.3"
3
3
  end
data/lib/timed_queue.rb CHANGED
@@ -20,7 +20,7 @@ class TimedQueue
20
20
  deadline = Time.now + timeout
21
21
  @mutex.synchronize do
22
22
  loop do
23
- return @que.shift unless @que.empty?
23
+ return @que.pop unless @que.empty?
24
24
  to_wait = deadline - Time.now
25
25
  raise Timeout::Error, "Waited #{timeout} sec" if to_wait <= 0
26
26
  @resource.wait(@mutex, to_wait)
data/test/helper.rb CHANGED
@@ -2,8 +2,6 @@ require 'rubygems'
2
2
  require 'minitest/pride'
3
3
  require 'minitest/autorun'
4
4
 
5
- require 'connection_pool'
6
-
7
5
  puts RUBY_DESCRIPTION
8
6
 
9
7
  class MiniTest::Unit::TestCase
@@ -15,3 +13,7 @@ class MiniTest::Unit::TestCase
15
13
  end
16
14
 
17
15
  end
16
+
17
+ $VERBOSE = 1
18
+
19
+ require_relative '../lib/connection_pool'
@@ -7,19 +7,26 @@ class TestConnectionPool < MiniTest::Unit::TestCase
7
7
  def initialize
8
8
  @x = 0
9
9
  end
10
+
10
11
  def do_something
11
12
  @x += 1
12
13
  sleep 0.05
13
14
  @x
14
15
  end
16
+
15
17
  def fast
16
18
  @x += 1
17
19
  end
20
+
18
21
  def do_something_with_block
19
22
  @x += yield
20
23
  sleep 0.05
21
24
  @x
22
25
  end
26
+
27
+ def respond_to?(method_id, *args)
28
+ method_id == :do_magic || super(method_id, *args)
29
+ end
23
30
  end
24
31
 
25
32
  def test_basic_multithreaded_usage
@@ -27,7 +34,7 @@ class TestConnectionPool < MiniTest::Unit::TestCase
27
34
  threads = []
28
35
  15.times do
29
36
  threads << Thread.new do
30
- pool.with_connection do |net|
37
+ pool.with do |net|
31
38
  net.do_something
32
39
  end
33
40
  end
@@ -67,9 +74,17 @@ class TestConnectionPool < MiniTest::Unit::TestCase
67
74
  assert_equal 6, pool.with { |net| net.fast }
68
75
  end
69
76
 
77
+ def test_passthru_respond_to
78
+ pool = ConnectionPool.wrap(:timeout => 0.1, :size => 1) { NetworkConnection.new }
79
+ assert pool.respond_to?(:with)
80
+ assert pool.respond_to?(:do_something)
81
+ assert pool.respond_to?(:do_magic)
82
+ refute pool.respond_to?(:do_lots_of_magic)
83
+ end
84
+
70
85
  def test_return_value
71
86
  pool = ConnectionPool.new(:timeout => 0.1, :size => 1) { NetworkConnection.new }
72
- result = pool.with_connection do |net|
87
+ result = pool.with do |net|
73
88
  net.fast
74
89
  end
75
90
  assert_equal 1, result
@@ -87,6 +102,16 @@ class TestConnectionPool < MiniTest::Unit::TestCase
87
102
  sleep 0.5
88
103
  end
89
104
 
105
+ def test_reuses_objects_when_pool_not_saturated
106
+ pool = ConnectionPool.new(:size => 5) { NetworkConnection.new }
107
+
108
+ ids = 10.times.map do
109
+ pool.with { |c| c.object_id }
110
+ end
111
+
112
+ assert_equal 1, ids.uniq.size
113
+ end
114
+
90
115
  class Recorder
91
116
  def initialize
92
117
  @calls = []
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: connection_pool
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-30 00:00:00.000000000 Z
12
+ date: 2012-12-19 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Generic connection pool for Ruby
15
15
  email:
@@ -30,7 +30,7 @@ files:
30
30
  - lib/timed_queue.rb
31
31
  - test/helper.rb
32
32
  - test/test_connection_pool.rb
33
- homepage: ''
33
+ homepage: https://github.com/mperham/connection_pool
34
34
  licenses: []
35
35
  post_install_message:
36
36
  rdoc_options: []
@@ -50,7 +50,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
50
50
  version: '0'
51
51
  requirements: []
52
52
  rubyforge_project:
53
- rubygems_version: 1.8.15
53
+ rubygems_version: 1.8.24
54
54
  signing_key:
55
55
  specification_version: 3
56
56
  summary: Generic connection pool for Ruby