sequel 3.8.0 → 3.9.0
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.
- 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
|