cassilds-connection-pool 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pools*.gem
2
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) Michael Rykov
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,30 @@
1
+ cassilds-connection-pool
2
+ -----
3
+ (forked from rykov/pools)
4
+
5
+ Our interest in on Cassandra connection pooling.
6
+
7
+ See Cassilds, and Cassilds-Model.
8
+
9
+ -----
10
+
11
+ Provides connection pooling for multiple services that use persistent connections.
12
+
13
+ Installation
14
+ ============
15
+
16
+ $ gem install cassilds-connection-pool
17
+
18
+
19
+ Notes
20
+ =====
21
+
22
+ We have copied ActiveSupport::Concern to our initializer directory in Rails config!!
23
+
24
+
25
+ Author
26
+ =====
27
+
28
+ Michael Rykov :: mrykov@gmail.com
29
+
30
+ Umanni :: contato@umanni.com.br
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler'
2
+ require 'rspec/core'
3
+ require 'rspec/core/rake_task'
4
+
5
+ task :default => :spec
6
+ task :test => :spec
7
+
8
+ task :noop do; end
9
+
10
+ desc "Run all specs in spec directory (excluding plugin specs)"
11
+ RSpec::Core::RakeTask.new(:spec => :noop)
12
+
13
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "pools/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "cassilds-connection-pool"
7
+ s.version = Pools::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.date = Time.now.strftime('%Y-%m-%d')
10
+ s.summary = "Generalized connection pooling"
11
+ s.homepage = "http://github.com/umanni/cassilds-connection-pool"
12
+ s.email = ["mrykov@gmail", "contato@umanni.com.br"]
13
+ s.authors = [ "Michael Rykov", "Umanni" ]
14
+ s.has_rdoc = false
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'activesupport', '>= 3.0.0', '< 3.2'
22
+
23
+ s.description = <<DESCRIPTION
24
+ Generalized connection pooling
25
+ DESCRIPTION
26
+ end
@@ -0,0 +1,40 @@
1
+ require 'pools'
2
+ require 'cassandra'
3
+
4
+ class Cassandra
5
+ class Pooled
6
+ include ::Pools::Pooled
7
+
8
+ def initialize(*args)
9
+ @cassandra_args = args.dup
10
+ super
11
+ end
12
+
13
+ def __connection
14
+ Cassandra.new(*@cassandra_args)
15
+ end
16
+
17
+ def __disconnect(client)
18
+ client.disconnect! if client
19
+ end
20
+
21
+ preparation_methods :login!, :disable_node_auto_discovery!
22
+
23
+ connection_methods *(Cassandra.public_instance_methods(false) - [:login!, :disable_node_auto_discovery!])
24
+ # :add, :add_column_family, :add_keyspace, :auth_request,
25
+ # :batch, :clear_column_family!, :clear_keyspace!, :cluster_name,
26
+ # :column_families, :count_columns, :count_range, :create_idx_clause,
27
+ # :create_idx_expr, :create_index, :create_index_clause, :create_index_expression,
28
+ # :default_read_consistency=, :default_write_consistency=,
29
+ # :disable_node_auto_discovery!, :disconnect!, :drop_column_family, :drop_index,
30
+ # :drop_keyspace, :each, :each_key, :exists?, :get, :get_columns,
31
+ # :get_indexed_slices, :get_range, :get_range_batch, :get_range_keys,
32
+ # :get_range_single, :insert, :inspect, :keyspace, :keyspace=, :keyspaces,
33
+ # :login!, :multi_count_columns, :multi_get, :multi_get_columns,
34
+ # :partitioner, :remove, :rename_column_family, :rename_keyspace, :ring,
35
+ # :schema, :schema_agreement?, :servers, :thrift_client_class,
36
+ # :thrift_client_options, :truncate!, :update_column_family,
37
+ # :update_keyspace, :version
38
+
39
+ end
40
+ end
data/lib/pools.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'pools/connection_pool'
2
+ require 'pools/handler'
3
+ require 'pools/middleware'
4
+ require 'pools/pooled'
5
+
6
+ require 'pools/engine' if defined?(Rails)
@@ -0,0 +1,237 @@
1
+ ##
2
+ # This file adapted from activerecord gem
3
+ #
4
+
5
+ require 'thread'
6
+ require 'monitor'
7
+ require 'set'
8
+ require 'active_support/core_ext/module/synchronization'
9
+
10
+ module Pools
11
+ # Raised when a connection could not be obtained within the connection
12
+ # acquisition timeout period.
13
+ ConnectionNotEstablished = Class.new(StandardError)
14
+ ConnectionTimeoutError = Class.new(ConnectionNotEstablished)
15
+
16
+ # Connection pool base class for managing Active Record database
17
+ # connections.
18
+ #
19
+ # == Introduction
20
+ #
21
+ # A connection pool synchronizes thread access to a limited number of
22
+ # database connections. The basic idea is that each thread checks out a
23
+ # database connection from the pool, uses that connection, and checks the
24
+ # connection back in. ConnectionPool is completely thread-safe, and will
25
+ # ensure that a connection cannot be used by two threads at the same time,
26
+ # as long as ConnectionPool's contract is correctly followed. It will also
27
+ # handle cases in which there are more threads than connections: if all
28
+ # connections have been checked out, and a thread tries to checkout a
29
+ # connection anyway, then ConnectionPool will wait until some other thread
30
+ # has checked in a connection.
31
+ #
32
+ # == Obtaining (checking out) a connection
33
+ #
34
+ # Connections can be obtained and used from a connection pool in several
35
+ # ways:
36
+ #
37
+ # 1. Simply use ActiveRecord::Base.connection as with Active Record 2.1 and
38
+ # earlier (pre-connection-pooling). Eventually, when you're done with
39
+ # the connection(s) and wish it to be returned to the pool, you call
40
+ # ActiveRecord::Base.clear_active_connections!. This will be the
41
+ # default behavior for Active Record when used in conjunction with
42
+ # Action Pack's request handling cycle.
43
+ # 2. Manually check out a connection from the pool with
44
+ # ActiveRecord::Base.connection_pool.checkout. You are responsible for
45
+ # returning this connection to the pool when finished by calling
46
+ # ActiveRecord::Base.connection_pool.checkin(connection).
47
+ # 3. Use ActiveRecord::Base.connection_pool.with_connection(&block), which
48
+ # obtains a connection, yields it as the sole argument to the block,
49
+ # and returns it to the pool after the block completes.
50
+ #
51
+ # Connections in the pool are actually AbstractAdapter objects (or objects
52
+ # compatible with AbstractAdapter's interface).
53
+ #
54
+ # == Options
55
+ #
56
+ # There are two connection-pooling-related options that you can add to
57
+ # your database connection configuration:
58
+ #
59
+ # * +pool+: number indicating size of connection pool (default 20)
60
+ # * +wait_timeout+: number of seconds to block and wait for a connection
61
+ # before giving up and raising a timeout error (default 10 seconds).
62
+ class ConnectionPool
63
+ attr_reader :options, :connections
64
+
65
+ # Creates a new ConnectionPool object. +spec+ is a ConnectionSpecification
66
+ # object which describes database connection information (e.g. adapter,
67
+ # host name, username, password, etc), as well as the maximum size for
68
+ # this ConnectionPool.
69
+ #
70
+ # The default ConnectionPool maximum size is 20.
71
+ def initialize(pooled, options)
72
+ @pooled = pooled
73
+ @options = options
74
+
75
+ # The cache of reserved connections mapped to threads
76
+ @reserved_connections = {}
77
+
78
+ # The mutex used to synchronize pool access
79
+ @connection_mutex = Monitor.new
80
+ @queue = @connection_mutex.new_cond
81
+
82
+ # default 10 second timeout unless on ruby 1.9
83
+ @timeout = options[:wait_timeout] || 10
84
+
85
+ # default max pool size to 20
86
+ @size = (options[:pool] && options[:pool].to_i) || 20
87
+
88
+ @connections = []
89
+ @checked_out = []
90
+ end
91
+
92
+ # Retrieve the connection associated with the current thread, or call
93
+ # #checkout to obtain one if necessary.
94
+ #
95
+ # #connection can be called any number of times; the connection is
96
+ # held in a hash keyed by the thread id.
97
+ def connection
98
+ @reserved_connections[current_connection_id] ||= checkout
99
+ end
100
+
101
+ # Signal that the thread is finished with the current connection.
102
+ # #release_connection releases the connection-thread association
103
+ # and returns the connection to the pool.
104
+ def release_connection(with_id = current_connection_id)
105
+ conn = @reserved_connections.delete(with_id)
106
+ checkin conn if conn
107
+ end
108
+
109
+ # If a connection already exists yield it to the block. If no connection
110
+ # exists checkout a connection, yield it to the block, and checkin the
111
+ # connection when finished.
112
+ def with_connection
113
+ connection_id = current_connection_id
114
+ fresh_connection = true unless @reserved_connections[connection_id]
115
+ yield connection
116
+ ensure
117
+ release_connection(connection_id) if fresh_connection
118
+ end
119
+
120
+ # Returns true if a connection has already been opened.
121
+ def connected?
122
+ !@connections.empty?
123
+ end
124
+
125
+ # Disconnects all connections in the pool, and clears the pool.
126
+ def disconnect!
127
+ @reserved_connections.each do |name,conn|
128
+ checkin conn
129
+ end
130
+ @reserved_connections = {}
131
+ @connections.each do |conn|
132
+ @pooled.__disconnect(conn)
133
+ end
134
+ @connections = []
135
+ end
136
+
137
+ # Verify active connections and remove and disconnect connections
138
+ # associated with stale threads.
139
+ def verify_active_connections! #:nodoc:
140
+ clear_stale_cached_connections!
141
+ @connections.each do |connection|
142
+ @pooled.__disconnect(connection)
143
+ end
144
+ end
145
+
146
+ # Return any checked-out connections back to the pool by threads that
147
+ # are no longer alive.
148
+ def clear_stale_cached_connections!
149
+ keys = @reserved_connections.keys - Thread.list.find_all { |t|
150
+ t.alive?
151
+ }.map { |thread| thread.object_id }
152
+ keys.each do |key|
153
+ checkin @reserved_connections[key]
154
+ @reserved_connections.delete(key)
155
+ end
156
+ end
157
+
158
+ # Check-out a database connection from the pool, indicating that you want
159
+ # to use it. You should call #checkin when you no longer need this.
160
+ #
161
+ # This is done by either returning an existing connection, or by creating
162
+ # a new connection. If the maximum number of connections for this pool has
163
+ # already been reached, but the pool is empty (i.e. they're all being used),
164
+ # then this method will wait until a thread has checked in a connection.
165
+ # The wait time is bounded however: if no connection can be checked out
166
+ # within the timeout specified for this pool, then a ConnectionTimeoutError
167
+ # exception will be raised.
168
+ #
169
+ # Returns: an AbstractAdapter object.
170
+ #
171
+ # Raises:
172
+ # - ConnectionTimeoutError: no connection can be obtained from the pool
173
+ # within the timeout period.
174
+ def checkout
175
+ # Checkout an available connection
176
+ @connection_mutex.synchronize do
177
+ loop do
178
+ conn = if @checked_out.size < @connections.size
179
+ checkout_existing_connection
180
+ elsif @connections.size < @size
181
+ checkout_new_connection
182
+ end
183
+ return conn if conn
184
+
185
+ @queue.wait(@timeout)
186
+
187
+ if(@checked_out.size < @connections.size)
188
+ next
189
+ else
190
+ clear_stale_cached_connections!
191
+ if @size == @checked_out.size
192
+ raise ConnectionTimeoutError, "could not obtain a pooled connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
193
+ end
194
+ end
195
+
196
+ end
197
+ end
198
+ end
199
+
200
+ # Check-in a database connection back into the pool, indicating that you
201
+ # no longer need this connection.
202
+ #
203
+ # +conn+: an AbstractAdapter object, which was obtained by earlier by
204
+ # calling +checkout+ on this pool.
205
+ def checkin(conn)
206
+ @connection_mutex.synchronize do
207
+ @checked_out.delete conn
208
+ @queue.signal
209
+ end
210
+ end
211
+
212
+ synchronize :verify_active_connections!, :connected?, :disconnect!,
213
+ :with => :@connection_mutex
214
+
215
+ private
216
+ def current_connection_id #:nodoc:
217
+ Thread.current.object_id
218
+ end
219
+
220
+ def checkout_new_connection
221
+ c = @pooled.__connection
222
+ @pooled.__prepare(c)
223
+ @connections << c
224
+ checkout_connection(c)
225
+ end
226
+
227
+ def checkout_existing_connection
228
+ c = (@connections - @checked_out).first
229
+ checkout_connection(c)
230
+ end
231
+
232
+ def checkout_connection(c)
233
+ @checked_out << c
234
+ c
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,19 @@
1
+ require 'rails'
2
+
3
+ module Pools
4
+ class Engine < Rails::Engine
5
+ engine_name :pools
6
+
7
+ # The tests bellow did not work
8
+
9
+ # Test 1
10
+ # middleware.use Pools::Middleware
11
+
12
+ # Test 2
13
+ # initializer "pools.configure_pools_middleware" do |app|
14
+ # app.middleware.use Pools::Middleware
15
+ # end
16
+
17
+ end
18
+ end
19
+
@@ -0,0 +1,62 @@
1
+ ##
2
+ # This file adapted from activerecord gem
3
+ #
4
+
5
+ module Pools
6
+ class Handler
7
+ attr_reader :pools
8
+
9
+ def initialize(pools = {})
10
+ @pools = pools
11
+ end
12
+
13
+ # Add a new connection pool to the mix
14
+ def add(pool, name = nil)
15
+ @pools[name || pool.object_id] = pool
16
+ end
17
+
18
+ # Returns any connections in use by the current thread back to the
19
+ # pool, and also returns connections to the pool cached by threads
20
+ # that are no longer alive.
21
+ def clear_active_connections!
22
+ @pools.each_value {|pool| pool.release_connection }
23
+ end
24
+
25
+ def clear_all_connections!
26
+ @pools.each_value {|pool| pool.disconnect! }
27
+ end
28
+
29
+ # Verify active connections.
30
+ def verify_active_connections! #:nodoc:
31
+ @pools.each_value {|pool| pool.verify_active_connections! }
32
+ end
33
+
34
+ # Returns true if a connection that's accessible to this class has
35
+ # already been opened.
36
+ def connected?(name)
37
+ conn = retrieve_connection_pool(name)
38
+ conn && conn.connected?
39
+ end
40
+
41
+ # Remove the connection for this class. This will close the active
42
+ # connection and the defined connection (if they exist). The result
43
+ # can be used as an argument for establish_connection, for easily
44
+ # re-establishing the connection.
45
+ def remove_connection(name)
46
+ pool = retrieve_connection_pool(name)
47
+ return nil unless pool
48
+
49
+ @pools.delete_if { |key, value| value == pool }
50
+ pool.disconnect!
51
+ end
52
+
53
+ def retrieve_connection_pool(name)
54
+ pool = @pools[name]
55
+ return pool if pool
56
+ end
57
+ end
58
+
59
+ def self.handler
60
+ @@pool_handler ||= Handler.new
61
+ end
62
+ end
@@ -0,0 +1,17 @@
1
+ ##
2
+ # This file adapted from activerecord gem
3
+ #
4
+
5
+ module Pools
6
+ class Middleware
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ @app.call(env)
13
+ ensure
14
+ Pools.handler.clear_active_connections!
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,52 @@
1
+ require 'active_support/core_ext/array/extract_options'
2
+ require 'active_support/concern'
3
+
4
+ module Pools
5
+ module Pooled
6
+ extend ActiveSupport::Concern
7
+ attr_reader :connection_pool, :preparation_chain
8
+
9
+ def initialize(*args)
10
+ options = args.extract_options!
11
+ @preparation_chain = []
12
+ @connection_pool = ConnectionPool.new(self, options)
13
+ Pools.handler.add(@connection_pool, options[:pool_name])
14
+ end
15
+
16
+ def with_connection(&block)
17
+ @connection_pool.with_connection(&block)
18
+ end
19
+
20
+ def __connection
21
+ # Override in parent
22
+ end
23
+
24
+ def __disconnect(connection)
25
+ # Override in parent
26
+ end
27
+
28
+ def __prepare(connection)
29
+ @preparation_chain.each { |args| connection.send(*args) }
30
+ end
31
+
32
+ module ClassMethods
33
+ def connection_methods(*methods)
34
+ methods.each do |method|
35
+ define_method(method) do |*params, &block|
36
+ with_connection do |client|
37
+ client.send(method, *params, &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def preparation_methods(*methods)
44
+ methods.each do |method|
45
+ define_method(method) do |*params|
46
+ @preparation_chain << ([method] + params)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,4 @@
1
+ class Pools
2
+ VERSION = '0.0.2'
3
+ end
4
+
@@ -0,0 +1,44 @@
1
+ require 'pools'
2
+ require 'redis'
3
+
4
+ class Redis
5
+ class Pooled
6
+ include ::Pools::Pooled
7
+
8
+ def initialize(options = {})
9
+ @redis_options = options
10
+ super
11
+ end
12
+
13
+ def __connection
14
+ Redis.connect(@redis_options)
15
+ end
16
+
17
+ def __disconnect(client)
18
+ client.quit if client
19
+ end
20
+
21
+ # Method not supported:
22
+ # Subscribe/Unsubscribe methods and the following...
23
+ # :auth, :select, :discard, :quit, :watch, :unwatch
24
+ # :exec, :multi, :disconnect
25
+
26
+ connection_methods :info, :config, :flushdb, :flushall, :save,
27
+ :bgsave, :bgrewriteaof, :get, :getset, :mget, :append, :substr,
28
+ :strlen, :hgetall, :hget, :hdel, :hkeys, :keys, :randomkey,
29
+ :echo, :ping, :lastsave, :dbsize, :exists, :llen, :lrange,
30
+ :ltrim, :lindex, :linsert, :lset, :lrem, :rpush, :rpushx,
31
+ :lpush, :lpushx, :rpop, :blpop, :brpop, :rpoplpush, :lpop,
32
+ :smembers, :sismember, :sadd, :srem, :smove, :sdiff, :sdiffstore,
33
+ :sinter, :sinterstore, :sunion, :sunionstore, :spop, :scard,
34
+ :srandmember, :zadd, :zrank, :zrevrank, :zincrby, :zcard,
35
+ :zrange, :zrangebyscore, :zcount, :zrevrange, :zremrangebyscore,
36
+ :zremrangebyrank, :zscore, :zrem, :zinterstore, :zunionstore,
37
+ :move, :setnx, :del, :rename, :renamenx, :expire, :persist,
38
+ :ttl, :expireat, :hset, :hsetnx, :hmset, :mapped_hmset, :hmget,
39
+ :mapped_hmget, :hlen, :hvals, :hincrby, :hexists, :monitor,
40
+ :debug, :sync, :[], :[]=, :set, :setex, :mset, :mapped_mset,
41
+ :msetnx, :mapped_msetnx, :mapped_mget, :sort, :incr, :incrby,
42
+ :decr, :decrby, :type, :publish, :id
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ require 'redis-store'
2
+ require 'redis/pooled'
3
+
4
+ class Redis
5
+ class PooledStore < Pooled
6
+ include Store::Ttl, Store::Interface
7
+
8
+ def initialize(options = { })
9
+ super
10
+ _extend_marshalling options
11
+ end
12
+
13
+ def self.rails3? #:nodoc:
14
+ defined?(::Rails) && ::Rails::VERSION::MAJOR == 3
15
+ end
16
+
17
+ def to_s
18
+ with_connection do |c|
19
+ "Redis::Pooled => #{c.host}:#{c.port} against DB #{c.db}"
20
+ end
21
+ end
22
+
23
+ private
24
+ def _extend_marshalling(options) # Copied from Store
25
+ @marshalling = !(options[:marshalling] === false)
26
+ extend Store::Marshalling if @marshalling
27
+ end
28
+ end
29
+
30
+ class << Store
31
+ def new(*args)
32
+ if args.size == 1 && args.first.is_a?(Hash) && args.first[:pool]
33
+ PooledStore.new(*args)
34
+ else
35
+ super(*args)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'logger'
3
+
4
+ class TestPool
5
+ include Pools::Pooled
6
+
7
+ class Connection
8
+ attr_accessor :valid, :prepared
9
+
10
+ def test_method
11
+ '__TEST__'
12
+ end
13
+
14
+ def test_method_with_args(input)
15
+ input
16
+ end
17
+
18
+ def prepare_method(value)
19
+ self.prepared = value
20
+ end
21
+
22
+ def yielding_method(value)
23
+ yield(value)
24
+ end
25
+ end
26
+
27
+ def __connection
28
+ c = Connection.new
29
+ c.valid = true
30
+ c.prepared = false
31
+ c
32
+ end
33
+
34
+ preparation_methods :prepare_method
35
+ connection_methods :test_method, :test_method_with_args, :prepared,
36
+ :yielding_method
37
+ end
38
+
39
+ describe Pools::Pooled do
40
+ def checkout_connections
41
+ @pool = TestPool.new(:pool => 2, :wait_timeout => 0.3)
42
+ @connections = []
43
+ @timed_out = 0
44
+
45
+ 4.times do
46
+ Thread.new do
47
+ begin
48
+ @connections << @pool.connection_pool.checkout
49
+ rescue Pools::ConnectionTimeoutError
50
+ @timed_out += 1
51
+ end
52
+ end.join
53
+ end
54
+ end
55
+
56
+ it "test timeout" do
57
+ checkout_connections
58
+ @connections.length.should == 2
59
+ @timed_out.should == 2
60
+ end
61
+
62
+ def checkout_checkin_connections(pool_size, threads)
63
+ @pool = TestPool.new(:pool => pool_size, :wait_timeout => 0.5)
64
+ @connection_count = 0
65
+ @timed_out = 0
66
+ threads.times do
67
+ Thread.new do
68
+ begin
69
+ conn = @pool.connection_pool.checkout
70
+ sleep 0.1
71
+ @pool.connection_pool.checkin conn
72
+ @connection_count += 1
73
+ rescue ActiveRecord::ConnectionTimeoutError
74
+ @timed_out += 1
75
+ end
76
+ end.join
77
+ end
78
+ end
79
+
80
+ it "pass connection checkout" do
81
+ checkout_checkin_connections 1, 2
82
+ @connection_count.should == 2
83
+ @timed_out.should == 0
84
+ @pool.connection_pool.connections.size.should == 1
85
+ end
86
+
87
+ it "pass connection checkout overbooking" do
88
+ checkout_checkin_connections 2, 3
89
+ @connection_count.should == 3
90
+ @timed_out.should == 0
91
+ @pool.connection_pool.connections.size.should == 1
92
+ end
93
+
94
+ it "should check out an existing connection" do
95
+ cpool = TestPool.new(:pool => 1).connection_pool
96
+ orig_conn = cpool.checkout
97
+ cpool.checkin(orig_conn)
98
+ conn = cpool.checkout
99
+ conn.should == orig_conn
100
+ conn.should be_a(TestPool::Connection)
101
+ cpool.checkin(conn)
102
+ end
103
+
104
+ it "should not be connected on init" do
105
+ cpool = TestPool.new(:pool => 1).connection_pool
106
+ cpool.connected?.should be_false
107
+ cpool.with_connection { }
108
+ cpool.connected?.should be_true
109
+ end
110
+
111
+ it "with_connection provides a connection" do
112
+ pool = TestPool.new
113
+ pool.with_connection do |conn|
114
+ conn.should be_a(TestPool::Connection)
115
+ end
116
+ end
117
+
118
+ it "respond to client methods" do
119
+ pool = TestPool.new
120
+ pool.test_method.should == '__TEST__'
121
+ pool.test_method_with_args('hi').should == 'hi'
122
+ end
123
+
124
+ it "respond to yielding methods" do
125
+ pool = TestPool.new
126
+ pool.yielding_method(15) do |value|
127
+ value.should == 15
128
+ end
129
+ end
130
+
131
+ it "not prematurely call preparation methods" do
132
+ pool = TestPool.new
133
+ pool.prepared.should be_false
134
+ end
135
+
136
+ it "not prematurely call preparation methods" do
137
+ pool = TestPool.new
138
+ pool.prepare_method(15)
139
+ pool.prepared.should == 15
140
+ end
141
+ end
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'logger'
3
+ require 'redis/pooled'
4
+
5
+ describe Redis::Pooled do
6
+ let(:rpool) { Redis::Pooled.new(:pool => 1) }
7
+
8
+ it "create a client" do
9
+ rpool.with_connection do |conn|
10
+ conn.should be_a(Redis)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ $TESTING=true
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require 'pools'
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cassilds-connection-pool
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Rykov
9
+ - Umanni
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-22 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ requirement: &19260040 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.0
23
+ - - <
24
+ - !ruby/object:Gem::Version
25
+ version: '3.2'
26
+ type: :runtime
27
+ prerelease: false
28
+ version_requirements: *19260040
29
+ description: ! 'Generalized connection pooling
30
+
31
+ '
32
+ email:
33
+ - mrykov@gmail
34
+ - contato@umanni.com.br
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - .gitignore
40
+ - LICENSE
41
+ - README.md
42
+ - Rakefile
43
+ - cassilds-connection-pool.gemspec
44
+ - lib/cassandra/pooled.rb
45
+ - lib/pools.rb
46
+ - lib/pools/connection_pool.rb
47
+ - lib/pools/engine.rb
48
+ - lib/pools/handler.rb
49
+ - lib/pools/middleware.rb
50
+ - lib/pools/pooled.rb
51
+ - lib/pools/version.rb
52
+ - lib/redis/pooled.rb
53
+ - lib/redis/pooled_store.rb
54
+ - spec/pooled_spec.rb
55
+ - spec/redis_spec.rb
56
+ - spec/spec_helper.rb
57
+ homepage: http://github.com/umanni/cassilds-connection-pool
58
+ licenses: []
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.10
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Generalized connection pooling
81
+ test_files: []