sequel 3.8.0 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +48 -0
- data/Rakefile +6 -28
- data/bin/sequel +7 -2
- data/doc/release_notes/3.9.0.txt +233 -0
- data/lib/sequel/adapters/ado.rb +4 -8
- data/lib/sequel/adapters/amalgalite.rb +1 -1
- data/lib/sequel/adapters/dbi.rb +3 -3
- data/lib/sequel/adapters/do.rb +7 -13
- data/lib/sequel/adapters/jdbc.rb +10 -16
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +10 -23
- data/lib/sequel/adapters/odbc.rb +6 -10
- data/lib/sequel/adapters/postgres.rb +0 -5
- data/lib/sequel/adapters/shared/mssql.rb +17 -9
- data/lib/sequel/adapters/shared/mysql.rb +16 -7
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +2 -1
- data/lib/sequel/connection_pool.rb +67 -349
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +46 -15
- data/lib/sequel/database.rb +11 -9
- data/lib/sequel/dataset/convenience.rb +23 -0
- data/lib/sequel/dataset/graph.rb +2 -2
- data/lib/sequel/dataset/query.rb +9 -5
- data/lib/sequel/dataset/sql.rb +87 -12
- data/lib/sequel/extensions/inflector.rb +8 -1
- data/lib/sequel/extensions/schema_dumper.rb +3 -4
- data/lib/sequel/model/associations.rb +5 -43
- data/lib/sequel/model/base.rb +9 -2
- data/lib/sequel/model/default_inflections.rb +1 -1
- data/lib/sequel/model/exceptions.rb +11 -1
- data/lib/sequel/model/inflections.rb +8 -1
- data/lib/sequel/model/plugins.rb +2 -12
- data/lib/sequel/plugins/active_model.rb +5 -0
- data/lib/sequel/plugins/association_dependencies.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +65 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +14 -3
- data/lib/sequel/plugins/validation_helpers.rb +2 -2
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/timezones.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +19 -0
- data/spec/adapters/mysql_spec.rb +4 -0
- data/spec/adapters/postgres_spec.rb +180 -0
- data/spec/adapters/spec_helper.rb +15 -1
- data/spec/core/connection_pool_spec.rb +119 -78
- data/spec/core/database_spec.rb +41 -50
- data/spec/core/dataset_spec.rb +115 -4
- data/spec/extensions/active_model_spec.rb +40 -34
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/migration_spec.rb +43 -38
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/schema_dumper_spec.rb +4 -4
- data/spec/extensions/single_table_inheritance_spec.rb +19 -11
- data/spec/integration/dataset_test.rb +44 -1
- data/spec/integration/plugin_test.rb +39 -0
- data/spec/integration/prepared_statement_test.rb +58 -7
- data/spec/integration/spec_helper.rb +4 -0
- data/spec/model/eager_loading_spec.rb +24 -0
- data/spec/model/validations_spec.rb +5 -1
- metadata +114 -106
@@ -0,0 +1,84 @@
|
|
1
|
+
# A ShardedSingleConnectionPool is a single threaded connection pool that
|
2
|
+
# works with multiple shards/servers.
|
3
|
+
class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
4
|
+
# Initializes the instance with the supplied block as the connection_proc.
|
5
|
+
#
|
6
|
+
# The single threaded pool takes the following options:
|
7
|
+
#
|
8
|
+
# * :servers - A hash of servers to use. Keys should be symbols. If not
|
9
|
+
# present, will use a single :default server. The server name symbol will
|
10
|
+
# be passed to the connection_proc.
|
11
|
+
def initialize(opts={}, &block)
|
12
|
+
super
|
13
|
+
@conns = {}
|
14
|
+
@servers = Hash.new(:default)
|
15
|
+
add_servers([:default])
|
16
|
+
add_servers(opts[:servers].keys) if opts[:servers]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Adds new servers to the connection pool. Primarily used in conjunction with master/slave
|
20
|
+
# or shard configurations. Allows for dynamic expansion of the potential slaves/shards
|
21
|
+
# at runtime. servers argument should be an array of symbols.
|
22
|
+
def add_servers(servers)
|
23
|
+
servers.each{|s| @servers[s] = s}
|
24
|
+
end
|
25
|
+
|
26
|
+
# The connection for the given server.
|
27
|
+
def conn(server=:default)
|
28
|
+
@conns[@servers[server]]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Disconnects from the database. Once a connection is requested using
|
32
|
+
# #hold, the connection is reestablished. Options:
|
33
|
+
# * :server - Should be a symbol specifing the server to disconnect from,
|
34
|
+
# or an array of symbols to specify multiple servers.
|
35
|
+
def disconnect(opts={}, &block)
|
36
|
+
block ||= @disconnection_proc
|
37
|
+
(opts[:server] ? Array(opts[:server]) : servers).each{|s| disconnect_server(s, &block)}
|
38
|
+
end
|
39
|
+
|
40
|
+
# Yields the connection to the supplied block for the given server.
|
41
|
+
# This method simulates the ConnectionPool#hold API.
|
42
|
+
def hold(server=:default)
|
43
|
+
begin
|
44
|
+
server = @servers[server]
|
45
|
+
yield(@conns[server] ||= make_new(server))
|
46
|
+
rescue Sequel::DatabaseDisconnectError
|
47
|
+
disconnect_server(server, &@disconnection_proc)
|
48
|
+
raise
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Remove servers from the connection pool. Primarily used in conjunction with master/slave
|
53
|
+
# or shard configurations. Similar to disconnecting from all given servers,
|
54
|
+
# except that after it is used, future requests for the server will use the
|
55
|
+
# :default server instead.
|
56
|
+
def remove_servers(servers)
|
57
|
+
raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
|
58
|
+
servers.each do |server|
|
59
|
+
disconnect_server(server, &@disconnection_proc)
|
60
|
+
@servers.delete(server)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return an array of symbols for servers in the connection pool.
|
65
|
+
def servers
|
66
|
+
@servers.keys
|
67
|
+
end
|
68
|
+
|
69
|
+
# The number of different shards/servers this pool is connected to.
|
70
|
+
def size
|
71
|
+
@conns.length
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Disconnect from the given server, if connected.
|
77
|
+
def disconnect_server(server, &block)
|
78
|
+
if conn = @conns.delete(server)
|
79
|
+
block.call(conn) if block
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
CONNECTION_POOL_MAP[[true, true]] = self
|
84
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
Sequel.require 'connection_pool/threaded'
|
2
|
+
|
3
|
+
# The slowest and most advanced connection, dealing with both multi-threaded
|
4
|
+
# access and configurations with multiple shards/servers.
|
5
|
+
#
|
6
|
+
# In addition, this pool subclass also handles scheduling in-use connections
|
7
|
+
# to be removed from the pool when they are returned to it.
|
8
|
+
class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
9
|
+
# The following additional options are respected:
|
10
|
+
# * :servers - A hash of servers to use. Keys should be symbols. If not
|
11
|
+
# present, will use a single :default server. The server name symbol will
|
12
|
+
# be passed to the connection_proc.
|
13
|
+
def initialize(opts = {}, &block)
|
14
|
+
super
|
15
|
+
@available_connections = {}
|
16
|
+
@connections_to_remove = []
|
17
|
+
@servers = Hash.new(:default)
|
18
|
+
add_servers([:default])
|
19
|
+
add_servers(opts[:servers].keys) if opts[:servers]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds new servers to the connection pool. Primarily used in conjunction with master/slave
|
23
|
+
# or shard configurations. Allows for dynamic expansion of the potential slaves/shards
|
24
|
+
# at runtime. servers argument should be an array of symbols.
|
25
|
+
def add_servers(servers)
|
26
|
+
sync do
|
27
|
+
servers.each do |server|
|
28
|
+
unless @servers.has_key?(server)
|
29
|
+
@servers[server] = server
|
30
|
+
@available_connections[server] = []
|
31
|
+
@allocated[server] = {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# A hash of connections currently being used for the given server, key is the
|
38
|
+
# Thread, value is the connection. Nonexistent servers will return nil. Treat
|
39
|
+
# this as read only, do not modify the resulting object.
|
40
|
+
def allocated(server=:default)
|
41
|
+
@allocated[server]
|
42
|
+
end
|
43
|
+
|
44
|
+
# An array of connections opened but not currently used, for the given
|
45
|
+
# server. Nonexistent servers will return nil. Treat this as read only, do
|
46
|
+
# not modify the resulting object.
|
47
|
+
def available_connections(server=:default)
|
48
|
+
@available_connections[server]
|
49
|
+
end
|
50
|
+
|
51
|
+
# The total number of connections opened for the given server, should
|
52
|
+
# be equal to available_connections.length + allocated.length. Nonexistent
|
53
|
+
# servers will return the created count of the default server.
|
54
|
+
def size(server=:default)
|
55
|
+
server = @servers[server]
|
56
|
+
@allocated[server].length + @available_connections[server].length
|
57
|
+
end
|
58
|
+
|
59
|
+
# Removes all connection currently available on all servers, optionally
|
60
|
+
# yielding each connection to the given block. This method has the effect of
|
61
|
+
# disconnecting from the database, assuming that no connections are currently
|
62
|
+
# being used. If connections are being used, they are scheduled to be
|
63
|
+
# disconnected as soon as they are returned to the pool.
|
64
|
+
#
|
65
|
+
# Once a connection is requested using #hold, the connection pool
|
66
|
+
# creates new connections to the database. Options:
|
67
|
+
# * :server - Should be a symbol specifing the server to disconnect from,
|
68
|
+
# or an array of symbols to specify multiple servers.
|
69
|
+
def disconnect(opts={}, &block)
|
70
|
+
block ||= @disconnection_proc
|
71
|
+
sync do
|
72
|
+
(opts[:server] ? Array(opts[:server]) : @servers.keys).each do |s|
|
73
|
+
disconnect_server(s, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Chooses the first available connection to the given server, or if none are
|
79
|
+
# available, creates a new connection. Passes the connection to the supplied
|
80
|
+
# block:
|
81
|
+
#
|
82
|
+
# pool.hold {|conn| conn.execute('DROP TABLE posts')}
|
83
|
+
#
|
84
|
+
# Pool#hold is re-entrant, meaning it can be called recursively in
|
85
|
+
# the same thread without blocking.
|
86
|
+
#
|
87
|
+
# If no connection is immediately available and the pool is already using the maximum
|
88
|
+
# number of connections, Pool#hold will block until a connection
|
89
|
+
# is available or the timeout expires. If the timeout expires before a
|
90
|
+
# connection can be acquired, a Sequel::PoolTimeout is
|
91
|
+
# raised.
|
92
|
+
def hold(server=:default)
|
93
|
+
sync{server = @servers[server]}
|
94
|
+
t = Thread.current
|
95
|
+
if conn = owned_connection(t, server)
|
96
|
+
return yield(conn)
|
97
|
+
end
|
98
|
+
begin
|
99
|
+
unless conn = acquire(t, server)
|
100
|
+
time = Time.now
|
101
|
+
timeout = time + @timeout
|
102
|
+
sleep_time = @sleep_time
|
103
|
+
sleep sleep_time
|
104
|
+
until conn = acquire(t, server)
|
105
|
+
raise(::Sequel::PoolTimeout) if Time.now > timeout
|
106
|
+
sleep sleep_time
|
107
|
+
end
|
108
|
+
end
|
109
|
+
yield conn
|
110
|
+
rescue Sequel::DatabaseDisconnectError
|
111
|
+
sync{@connections_to_remove << conn} if conn
|
112
|
+
raise
|
113
|
+
ensure
|
114
|
+
sync{release(t, conn, server)} if conn
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Remove servers from the connection pool. Primarily used in conjunction with master/slave
|
119
|
+
# or shard configurations. Similar to disconnecting from all given servers,
|
120
|
+
# except that after it is used, future requests for the server will use the
|
121
|
+
# :default server instead.
|
122
|
+
def remove_servers(servers)
|
123
|
+
sync do
|
124
|
+
raise(Sequel::Error, "cannot remove default server") if servers.include?(:default)
|
125
|
+
servers.each do |server|
|
126
|
+
if @servers.include?(server)
|
127
|
+
disconnect_server(server, &@disconnection_proc)
|
128
|
+
@available_connections.delete(server)
|
129
|
+
@allocated.delete(server)
|
130
|
+
@servers.delete(server)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Return an array of symbols for servers in the connection pool.
|
137
|
+
def servers
|
138
|
+
sync{@servers.keys}
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# Assigns a connection to the supplied thread for the given server, if one
|
144
|
+
# is available. The calling code should NOT already have the mutex when
|
145
|
+
# calling this.
|
146
|
+
def acquire(thread, server)
|
147
|
+
sync do
|
148
|
+
if conn = available(server)
|
149
|
+
allocated(server)[thread] = conn
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns an available connection to the given server. If no connection is
|
155
|
+
# available, tries to create a new connection. The calling code should already
|
156
|
+
# have the mutex before calling this.
|
157
|
+
def available(server)
|
158
|
+
available_connections(server).pop || make_new(server)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Disconnect from the given server. Disconnects available connections
|
162
|
+
# immediately, and schedules currently allocated connections for disconnection
|
163
|
+
# as soon as they are returned to the pool. The calling code should already
|
164
|
+
# have the mutex before calling this.
|
165
|
+
def disconnect_server(server, &block)
|
166
|
+
if conns = available_connections(server)
|
167
|
+
conns.each{|conn| block.call(conn)} if block
|
168
|
+
conns.clear
|
169
|
+
end
|
170
|
+
@connections_to_remove.concat(allocated(server).values)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Creates a new connection to the given server if the size of the pool for
|
174
|
+
# the server is less than the maximum size of the pool. The calling code
|
175
|
+
# should already have the mutex before calling this.
|
176
|
+
def make_new(server)
|
177
|
+
if (n = size(server)) >= @max_size
|
178
|
+
allocated(server).to_a.each{|t, c| release(t, c, server) unless t.alive?}
|
179
|
+
n = nil
|
180
|
+
end
|
181
|
+
default_make_new(server) if (n || size(server)) < @max_size
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns the connection owned by the supplied thread for the given server,
|
185
|
+
# if any. The calling code should NOT already have the mutex before calling this.
|
186
|
+
def owned_connection(thread, server)
|
187
|
+
sync{@allocated[server][thread]}
|
188
|
+
end
|
189
|
+
|
190
|
+
# Releases the connection assigned to the supplied thread and server. If the
|
191
|
+
# server or connection given is scheduled for disconnection, remove the
|
192
|
+
# connection instead of releasing it back to the pool.
|
193
|
+
# The calling code should already have the mutex before calling this.
|
194
|
+
def release(thread, conn, server)
|
195
|
+
if @connections_to_remove.include?(conn)
|
196
|
+
remove(thread, conn, server)
|
197
|
+
else
|
198
|
+
available_connections(server) << allocated(server).delete(thread)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Removes the currently allocated connection from the connection pool. The
|
203
|
+
# calling code should already have the mutex before calling this.
|
204
|
+
def remove(thread, conn, server)
|
205
|
+
@connections_to_remove.delete(conn)
|
206
|
+
allocated(server).delete(thread) if @servers.include?(server)
|
207
|
+
@disconnection_proc.call(conn) if @disconnection_proc
|
208
|
+
end
|
209
|
+
|
210
|
+
CONNECTION_POOL_MAP[[false, true]] = self
|
211
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# This is the fastest connection pool, since it isn't a connection pool at all.
|
2
|
+
# It is just a wrapper around a single connection that uses the connection pool
|
3
|
+
# API.
|
4
|
+
class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
5
|
+
# The SingleConnectionPool always has a size of 1, since the connection
|
6
|
+
# is always available.
|
7
|
+
def size
|
8
|
+
@conn ? 1 : 0
|
9
|
+
end
|
10
|
+
|
11
|
+
# Disconnect and immediately reconnect from the database.
|
12
|
+
def disconnect(opts=nil, &block)
|
13
|
+
block ||= @disconnection_proc
|
14
|
+
block.call(@conn) if block
|
15
|
+
@conn = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Yield the connection to the block.
|
19
|
+
def hold(server=nil)
|
20
|
+
begin
|
21
|
+
yield(@conn ||= make_new(DEFAULT_SERVER))
|
22
|
+
rescue Sequel::DatabaseDisconnectError
|
23
|
+
disconnect
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
CONNECTION_POOL_MAP[[true, false]] = self
|
29
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# A connection pool allowing multi-threaded access to a pool of connections.
|
2
|
+
class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
3
|
+
# The maximum number of connections this pool will create (per shard/server
|
4
|
+
# if sharding).
|
5
|
+
attr_reader :max_size
|
6
|
+
|
7
|
+
# An array of connections that are available for use by the pool.
|
8
|
+
attr_reader :available_connections
|
9
|
+
|
10
|
+
# A hash with thread keys and connection values for currently allocated
|
11
|
+
# connections.
|
12
|
+
attr_reader :allocated
|
13
|
+
|
14
|
+
# The following additional options are respected:
|
15
|
+
# * :max_connections - The maximum number of connections the connection pool
|
16
|
+
# will open (default 4)
|
17
|
+
# * :pool_sleep_time - The amount of time to sleep before attempting to acquire
|
18
|
+
# a connection again (default 0.001)
|
19
|
+
# * :pool_timeout - The amount of seconds to wait to acquire a connection
|
20
|
+
# before raising a PoolTimeoutError (default 5)
|
21
|
+
def initialize(opts = {}, &block)
|
22
|
+
super
|
23
|
+
@max_size = Integer(opts[:max_connections] || 4)
|
24
|
+
raise(Sequel::Error, ':max_connections must be positive') if @max_size < 1
|
25
|
+
@mutex = Mutex.new
|
26
|
+
@available_connections = []
|
27
|
+
@allocated = {}
|
28
|
+
@timeout = Integer(opts[:pool_timeout] || 5)
|
29
|
+
@sleep_time = Float(opts[:pool_sleep_time] || 0.001)
|
30
|
+
end
|
31
|
+
|
32
|
+
# The total number of connections opened for the given server, should
|
33
|
+
# be equal to available_connections.length + allocated.length.
|
34
|
+
def size
|
35
|
+
@allocated.length + @available_connections.length
|
36
|
+
end
|
37
|
+
|
38
|
+
# Removes all connection currently available on all servers, optionally
|
39
|
+
# yielding each connection to the given block. This method has the effect of
|
40
|
+
# disconnecting from the database, assuming that no connections are currently
|
41
|
+
# being used. If connections are being used, they are scheduled to be
|
42
|
+
# disconnected as soon as they are returned to the pool.
|
43
|
+
#
|
44
|
+
# Once a connection is requested using #hold, the connection pool
|
45
|
+
# creates new connections to the database.
|
46
|
+
def disconnect(opts={}, &block)
|
47
|
+
block ||= @disconnection_proc
|
48
|
+
sync do
|
49
|
+
@available_connections.each{|conn| block.call(conn)} if block
|
50
|
+
@available_connections.clear
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Chooses the first available connection to the given server, or if none are
|
55
|
+
# available, creates a new connection. Passes the connection to the supplied
|
56
|
+
# block:
|
57
|
+
#
|
58
|
+
# pool.hold {|conn| conn.execute('DROP TABLE posts')}
|
59
|
+
#
|
60
|
+
# Pool#hold is re-entrant, meaning it can be called recursively in
|
61
|
+
# the same thread without blocking.
|
62
|
+
#
|
63
|
+
# If no connection is immediately available and the pool is already using the maximum
|
64
|
+
# number of connections, Pool#hold will block until a connection
|
65
|
+
# is available or the timeout expires. If the timeout expires before a
|
66
|
+
# connection can be acquired, a Sequel::PoolTimeout is
|
67
|
+
# raised.
|
68
|
+
def hold(server=nil)
|
69
|
+
t = Thread.current
|
70
|
+
if conn = owned_connection(t)
|
71
|
+
return yield(conn)
|
72
|
+
end
|
73
|
+
begin
|
74
|
+
unless conn = acquire(t)
|
75
|
+
time = Time.now
|
76
|
+
timeout = time + @timeout
|
77
|
+
sleep_time = @sleep_time
|
78
|
+
sleep sleep_time
|
79
|
+
until conn = acquire(t)
|
80
|
+
raise(::Sequel::PoolTimeout) if Time.now > timeout
|
81
|
+
sleep sleep_time
|
82
|
+
end
|
83
|
+
end
|
84
|
+
yield conn
|
85
|
+
rescue Sequel::DatabaseDisconnectError
|
86
|
+
@disconnection_proc.call(conn) if @disconnection_proc && conn
|
87
|
+
@allocated.delete(t)
|
88
|
+
conn = nil
|
89
|
+
raise
|
90
|
+
ensure
|
91
|
+
sync{release(t)} if conn
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Assigns a connection to the supplied thread for the given server, if one
|
98
|
+
# is available. The calling code should NOT already have the mutex when
|
99
|
+
# calling this.
|
100
|
+
def acquire(thread)
|
101
|
+
sync do
|
102
|
+
if conn = available
|
103
|
+
@allocated[thread] = conn
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns an available connection to the given server. If no connection is
|
109
|
+
# available, tries to create a new connection. The calling code should already
|
110
|
+
# have the mutex before calling this.
|
111
|
+
def available
|
112
|
+
@available_connections.pop || make_new(DEFAULT_SERVER)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Alias the default make_new method, so subclasses can call it directly.
|
116
|
+
alias default_make_new make_new
|
117
|
+
|
118
|
+
# Creates a new connection to the given server if the size of the pool for
|
119
|
+
# the server is less than the maximum size of the pool. The calling code
|
120
|
+
# should already have the mutex before calling this.
|
121
|
+
def make_new(server)
|
122
|
+
if (n = size) >= @max_size
|
123
|
+
@allocated.keys.each{|t| release(t) unless t.alive?}
|
124
|
+
n = nil
|
125
|
+
end
|
126
|
+
super if (n || size) < @max_size
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the connection owned by the supplied thread for the given server,
|
130
|
+
# if any. The calling code should NOT already have the mutex before calling this.
|
131
|
+
def owned_connection(thread)
|
132
|
+
sync{@allocated[thread]}
|
133
|
+
end
|
134
|
+
|
135
|
+
# Releases the connection assigned to the supplied thread and server. If the
|
136
|
+
# server or connection given is scheduled for disconnection, remove the
|
137
|
+
# connection instead of releasing it back to the pool.
|
138
|
+
# The calling code should already have the mutex before calling this.
|
139
|
+
def release(thread)
|
140
|
+
@available_connections << @allocated.delete(thread)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Yield to the block while inside the mutex. The calling code should NOT
|
144
|
+
# already have the mutex before calling this.
|
145
|
+
def sync
|
146
|
+
@mutex.synchronize{yield}
|
147
|
+
end
|
148
|
+
|
149
|
+
CONNECTION_POOL_MAP[[false, false]] = self
|
150
|
+
end
|