common-pool 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/README +51 -0
- data/lib/common_pool.rb +349 -0
- data/test/common_pool_test.rb +169 -0
- metadata +57 -0
data/CHANGELOG
ADDED
data/README
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
== common-pool
|
2
|
+
|
3
|
+
Object pooling with idle objects eviction check similar with Apache Common Pool.
|
4
|
+
|
5
|
+
Links:
|
6
|
+
* http://common-pool.rubyforge.org
|
7
|
+
* http://www.pluitsolutions.com/common-pool
|
8
|
+
|
9
|
+
== INSTALLATION
|
10
|
+
|
11
|
+
$ gem install common-pool
|
12
|
+
|
13
|
+
== EXAMPLE
|
14
|
+
|
15
|
+
require 'common_pool'
|
16
|
+
|
17
|
+
# Extend data source object
|
18
|
+
class RandomNumberDataSource < CommonPool::PoolDataSource
|
19
|
+
# Overwrite to return object to be stored in the pool.
|
20
|
+
def create_object
|
21
|
+
rand(1000)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Overwrite to check if idle object in the pool is still valid.
|
25
|
+
def valid?(object)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create a new object pool
|
31
|
+
object_pool = ObjectPool.new(RandomNumberDataSource.new)
|
32
|
+
|
33
|
+
# Borrow and return an object from the pool
|
34
|
+
object = object_pool.borrow_object
|
35
|
+
object_pool.return_object(object)
|
36
|
+
|
37
|
+
# Borrow and invalidate object
|
38
|
+
object = object_pool.borrow_object
|
39
|
+
object_pool.return_object(object)
|
40
|
+
|
41
|
+
# Create object pool with idle objects eviction thread
|
42
|
+
object_pool = ObjectPool.new(RandomNumberDataSource.new) do |config|
|
43
|
+
config.min_idle = 5
|
44
|
+
config.max_idle = 10
|
45
|
+
config.idle_check_no_per_run = 10 # check max 10 idle objects per run
|
46
|
+
config.idle_check_interval = 10 * 60 # check every 10 minutes
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return a hash of pool instance status variables, including active and idle objects list and
|
50
|
+
# configuration options
|
51
|
+
object_pool.status_info
|
data/lib/common_pool.rb
ADDED
@@ -0,0 +1,349 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 Herryanto Siatono, Pluit Solutions
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require 'timeout'
|
25
|
+
require 'thread'
|
26
|
+
require 'logger'
|
27
|
+
|
28
|
+
module CommonPool
|
29
|
+
class CommonPoolError < StandardError; end;
|
30
|
+
|
31
|
+
# Pool configuration.
|
32
|
+
class Configuration
|
33
|
+
# Minimum number of idle objects in the pool. Default: 0.
|
34
|
+
attr_accessor :min_idle
|
35
|
+
|
36
|
+
# Maximum number of idle objects in the pool. Default: 8.
|
37
|
+
attr_accessor :max_idle
|
38
|
+
|
39
|
+
# Maximum idle time in seconds, before an object can be evicted. Default: 1800.
|
40
|
+
attr_accessor :max_idle_time
|
41
|
+
|
42
|
+
# Maximum number of active objects in the pool. Default: 8.
|
43
|
+
attr_accessor :max_active
|
44
|
+
|
45
|
+
# Request timeout when creating object for the pool, timeout in seconds. Default: 30.
|
46
|
+
# If set to 0 or less, there will be no timeout.
|
47
|
+
attr_accessor :timeout
|
48
|
+
|
49
|
+
# Request timeout when validation idle object in the pool, timeout in seconds. Default: 30.
|
50
|
+
# If set to 0 or less, there will be no timeout.
|
51
|
+
attr_accessor :validation_timeout
|
52
|
+
|
53
|
+
# Number of objects to check per eviction thread run. Default: 3.
|
54
|
+
# If set to 0 or less, all idle objects will be checked.
|
55
|
+
attr_accessor :idle_check_no_per_run
|
56
|
+
|
57
|
+
# Eviction thread interval in seconds. Default: 0.
|
58
|
+
# If set to 0 or less, the eviction thread will not run.
|
59
|
+
attr_accessor :idle_check_interval
|
60
|
+
|
61
|
+
# Assign a logger, to log pool debug/info messages, used this for debugging purpose.
|
62
|
+
attr_accessor :logger
|
63
|
+
|
64
|
+
# The data source object to be extended, code>create_object</code> method need to be
|
65
|
+
# overridden
|
66
|
+
attr_accessor :data_source
|
67
|
+
|
68
|
+
# Initilize configuration with default settings.
|
69
|
+
def initialize
|
70
|
+
self.min_idle = 0
|
71
|
+
self.max_idle = 8
|
72
|
+
self.max_idle_time = 30 * 60
|
73
|
+
self.max_active = 8
|
74
|
+
self.idle_check_no_per_run = 3
|
75
|
+
self.idle_check_interval= 0
|
76
|
+
self.timeout = 30
|
77
|
+
self.validation_timeout = 30
|
78
|
+
end
|
79
|
+
|
80
|
+
# Convert configuration properties to hash object.
|
81
|
+
def to_hash
|
82
|
+
{ :timeout => self.timeout,
|
83
|
+
:min_idle => self.min_idle,
|
84
|
+
:max_idle => self.max_idle,
|
85
|
+
:max_idle_time => self.max_idle_time,
|
86
|
+
:max_active => self.max_active,
|
87
|
+
:idle_check_no_per_run => self.idle_check_no_per_run,
|
88
|
+
:idle_check_interval => self.idle_check_interval}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Data source for objects to be stored in the pool.
|
93
|
+
class PoolDataSource
|
94
|
+
# Override to create an object to be stored in the pool.
|
95
|
+
def create_object
|
96
|
+
raise CommonPoolError, "Overwrite this method to create an object to be stored in the pool."
|
97
|
+
end
|
98
|
+
|
99
|
+
# Override to check the validity of your idle object, called when idle object eviction stread.
|
100
|
+
def valid?(object)
|
101
|
+
true
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# First in, first out object pooling implementation.
|
106
|
+
class ObjectPool
|
107
|
+
attr_reader :active_list, :idle_list, :idle_check_thread, :idle_check_status
|
108
|
+
attr_accessor :config, :data_source
|
109
|
+
|
110
|
+
# Initialize pool instance with default configuration options. Override config as a parameter passed to the block.
|
111
|
+
def initialize(data_source = nil, &proc)
|
112
|
+
raise ArgumentError, "Data source is required." unless data_source
|
113
|
+
self.config = Configuration.new
|
114
|
+
self.data_source = data_source
|
115
|
+
@active_list = {}
|
116
|
+
@idle_list = []
|
117
|
+
@idle_check_status = "Not Running"
|
118
|
+
@mutex = Mutex.new
|
119
|
+
@cond = ConditionVariable.new
|
120
|
+
|
121
|
+
yield self.config if block_given?
|
122
|
+
self.start_check_idle_thread
|
123
|
+
end
|
124
|
+
|
125
|
+
# Configure pool instance after initialization.
|
126
|
+
def configure(&proc)
|
127
|
+
yield self.config
|
128
|
+
self.start_check_idle_thread
|
129
|
+
end
|
130
|
+
|
131
|
+
# Alias for <code>check_idle_thread</code>.
|
132
|
+
def start
|
133
|
+
start_check_idle_thread
|
134
|
+
end
|
135
|
+
|
136
|
+
# Borrow object from the pool. If max number of active objects reached, <code>CommonPoolErrror</code> will be thrown.
|
137
|
+
def borrow_object
|
138
|
+
@mutex.synchronize {
|
139
|
+
if !@idle_list.empty?
|
140
|
+
result = @idle_list.shift
|
141
|
+
|
142
|
+
elsif @active_list.size < @config.max_active
|
143
|
+
result = create_with_timestamp
|
144
|
+
|
145
|
+
elsif @active_list.size >= @config.max_active
|
146
|
+
raise CommonPoolError, "Max number of %d active objects reached." % @config.max_active
|
147
|
+
|
148
|
+
else
|
149
|
+
begin
|
150
|
+
timeout(@config.timeout){ @cond.wait(@mutex) }
|
151
|
+
rescue TimeoutError
|
152
|
+
raise TimeoutError, "#{@config.timeout} seconds request timeout reached."
|
153
|
+
end
|
154
|
+
result = @idle_list.shift
|
155
|
+
end
|
156
|
+
@active_list.store(result[1].__id__, result)
|
157
|
+
|
158
|
+
logger.debug("* Get #{result[1]}") if logger
|
159
|
+
result[1]
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
# Return object back to the pool.
|
164
|
+
def return_object(object)
|
165
|
+
logger.debug("* Return #{object}") if logger
|
166
|
+
return if object.nil?
|
167
|
+
if @active_list.delete(object.__id__)
|
168
|
+
add_to_idle_list(object)
|
169
|
+
else
|
170
|
+
logger.debug("Session #{object} not returned, coz has been invalidated from used list.") if logger
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Invalidate object
|
175
|
+
def invalidate_object(object)
|
176
|
+
@mutex.synchronize {
|
177
|
+
logger.debug("* Invalidate #{object}") if logger
|
178
|
+
@active_list.delete(object.__id__)
|
179
|
+
nil
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
# Clear object pool, set the idle list and used list to empty.
|
184
|
+
def clear()
|
185
|
+
@mutex.synchronize {
|
186
|
+
@idle_list = []
|
187
|
+
@active_list = {}
|
188
|
+
}
|
189
|
+
end
|
190
|
+
|
191
|
+
# Reset the max active objects in the pool.
|
192
|
+
def max_active=(size)
|
193
|
+
@mutex.synchronize {
|
194
|
+
if @idle_list.size + @active_list.size > size
|
195
|
+
raise ArgumentError, "Cannot change max size to %d. There are objects over the size." % size
|
196
|
+
end
|
197
|
+
@config.max_active = size
|
198
|
+
}
|
199
|
+
size
|
200
|
+
end
|
201
|
+
|
202
|
+
# Start check idle objects thread, will only run if <code>idle_check_interval</code> is greater than 0.
|
203
|
+
def start_check_idle_thread
|
204
|
+
@mutex.synchronize {
|
205
|
+
return unless @config.idle_check_interval > 0 and @idle_check_thread.nil?
|
206
|
+
@idle_check_status = "Checking..."
|
207
|
+
|
208
|
+
@idle_check_thread = Thread.new do
|
209
|
+
loop do
|
210
|
+
thread_id = @idle_check_thread.__id__ if @idle_check_thread
|
211
|
+
|
212
|
+
begin
|
213
|
+
logger.debug(">> Starting idle objects check (Object ID: #{self.__id__}, Thread ID: #{thread_id})") if logger
|
214
|
+
logger.debug("Status: " + self.status_info.map {|k,v| "#{k}=#{v}"}.join(', ')) if logger
|
215
|
+
@idle_check_status = "Checking..."
|
216
|
+
|
217
|
+
check_idle
|
218
|
+
|
219
|
+
@idle_check_status = "Check status: OK. Sleeping now..."
|
220
|
+
rescue Exception => e
|
221
|
+
@idle_check_status = "Check status: Error - #{e.to_s} \n#{e.backtrace.join("\n")}. Sleeping...\n"
|
222
|
+
end
|
223
|
+
|
224
|
+
logger.debug(@idle_check_status) if logger
|
225
|
+
if @config.idle_check_interval > 0
|
226
|
+
logger.debug(">> Sleeping (Object ID: #{self.__id__}, Thread ID: #{thread_id}) #{@config.idle_check_interval} seconds ...\n\n") if logger
|
227
|
+
sleep @config.idle_check_interval
|
228
|
+
else
|
229
|
+
logger.debug(">> Idle check interval is set 0 or less. Thus idle check thread will only be executed once.") if logger
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
# Stop idle check thread
|
237
|
+
def stop_idle_check_thread
|
238
|
+
if @idle_check_thread
|
239
|
+
logger.debug(">> Stopping idle objects check thread ...") if logger
|
240
|
+
@idle_check_status = "Stopping..."
|
241
|
+
@idle_check_thread.kill
|
242
|
+
@idle_check_thread = nil
|
243
|
+
@idle_check_status = "Not Running"
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Restart idle check thread
|
248
|
+
def restart_check_idle_thread
|
249
|
+
stop_idle_check_thread
|
250
|
+
start_idle_check_thread
|
251
|
+
end
|
252
|
+
|
253
|
+
# Return a hash of active and idle objects size with pool instance configuration options.
|
254
|
+
def status_info
|
255
|
+
{:active_objects => @active_list.size,
|
256
|
+
:idle_objects => @idle_list.size}.merge(self.config.to_hash)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Check if an idle object is valid, return false if <code>validation_timeout</code> period reached.
|
260
|
+
def valid_idle_object?(object)
|
261
|
+
begin
|
262
|
+
timeout(self.config.validation_timeout) do
|
263
|
+
self.data_source.valid?(object)
|
264
|
+
end
|
265
|
+
rescue TimeoutError => e
|
266
|
+
logger.debug("Timeout #{@config.validation_timeout} seconds validating object: #{object}") if logger
|
267
|
+
false
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
protected
|
272
|
+
|
273
|
+
def logger
|
274
|
+
self.config.logger
|
275
|
+
end
|
276
|
+
|
277
|
+
def create_with_timestamp
|
278
|
+
[Time.new, self.data_source.create_object]
|
279
|
+
end
|
280
|
+
|
281
|
+
def add_to_idle_list(object)
|
282
|
+
@mutex.synchronize {
|
283
|
+
if (@config.max_idle > 0) and (@idle_list.size >= @config.max_idle)
|
284
|
+
logger.debug("Not returned, max idle #{@config.max_idle} reached") if logger
|
285
|
+
return
|
286
|
+
end
|
287
|
+
|
288
|
+
logger.debug("* Add #{object}") if logger
|
289
|
+
@idle_list.push([Time.new, object])
|
290
|
+
@cond.signal
|
291
|
+
}
|
292
|
+
end
|
293
|
+
|
294
|
+
def check_min_idle
|
295
|
+
logger.debug("Minimum idle objects: #{@config.min_idle}, current idle size: #{@idle_list.size}") if logger
|
296
|
+
return if (@config.min_idle < 1) || (@idle_list.size >= @config.min_idle)
|
297
|
+
|
298
|
+
objects_to_create = @config.min_idle - @idle_list.size
|
299
|
+
logger.debug("Creating additional #{objects_to_create} object(s).") if logger
|
300
|
+
objects_to_create.times do
|
301
|
+
add_to_idle_list(self.data_source.create_object)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
def check_idle
|
306
|
+
logger.debug("Checking idle objects list size: #{@idle_list.size}, min idle: #{@config.min_idle}") if logger
|
307
|
+
|
308
|
+
counter = 0
|
309
|
+
checked_obj = []
|
310
|
+
@idle_list.size.times do
|
311
|
+
break if (@config.idle_check_no_per_run > 0) and (counter >= @config.idle_check_no_per_run)
|
312
|
+
|
313
|
+
counter += 1
|
314
|
+
result = @idle_list.shift
|
315
|
+
logger.debug("Checking idle object: #{result.join('|')}") if logger
|
316
|
+
if result
|
317
|
+
if (within_max_idle_time?(result[0]) && valid_idle_object?(result[1]))
|
318
|
+
checked_obj.push(result)
|
319
|
+
else
|
320
|
+
invalidate(result[1])
|
321
|
+
end
|
322
|
+
else
|
323
|
+
logger.debug("No more object available.") if logger
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
checked_obj.each {|result| @idle_list.push(result)}
|
328
|
+
check_min_idle
|
329
|
+
end
|
330
|
+
|
331
|
+
def within_max_idle_time?(objtime)
|
332
|
+
return true if (@config.max_idle_time < 0)
|
333
|
+
|
334
|
+
seconds_passed = Time.now - objtime
|
335
|
+
exceed_time = seconds_passed > @config.max_idle_time
|
336
|
+
|
337
|
+
if (@config.max_idle_time == 0) || (exceed_time)
|
338
|
+
logger.debug("Idle for #{seconds_passed} seconds, exceeded #{seconds_passed - @config.max_idle_time} seconds") if logger
|
339
|
+
return false
|
340
|
+
else
|
341
|
+
return true
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def idle_check_status=(s)
|
346
|
+
@config.idle_check_status = s
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007 Herryanto Siatono, Pluit Solutions
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
require File.dirname(__FILE__) + '/../lib/common_pool'
|
25
|
+
|
26
|
+
class CommonPoolTest < Test::Unit::TestCase
|
27
|
+
include CommonPool
|
28
|
+
|
29
|
+
def test_get_and_release_session_pool
|
30
|
+
# test get sessions from pool
|
31
|
+
pool = create_pool
|
32
|
+
|
33
|
+
session_a = pool.borrow_object
|
34
|
+
session_b = pool.borrow_object
|
35
|
+
|
36
|
+
assert_not_equal session_a, session_b
|
37
|
+
assert_equal 2, pool.active_list.size
|
38
|
+
assert_equal 0, pool.idle_list.size
|
39
|
+
|
40
|
+
pool.return_object(session_a)
|
41
|
+
pool.return_object(session_b)
|
42
|
+
assert_equal 0, pool.active_list.size
|
43
|
+
assert_equal 2, pool.idle_list.size
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_first_in_first_out
|
47
|
+
pool = create_pool
|
48
|
+
session_a = pool.borrow_object
|
49
|
+
session_b = pool.borrow_object
|
50
|
+
|
51
|
+
pool.return_object(session_b)
|
52
|
+
pool.return_object(session_a)
|
53
|
+
|
54
|
+
session_new = pool.borrow_object
|
55
|
+
assert_equal session_b, session_new
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_max_active_reached
|
59
|
+
pool = create_pool
|
60
|
+
until pool.active_list.size == pool.config.max_active
|
61
|
+
obj = pool.borrow_object
|
62
|
+
end
|
63
|
+
|
64
|
+
begin
|
65
|
+
# max active reached, relase object to retrieve a new one
|
66
|
+
pool.return_object(obj)
|
67
|
+
wait_obj = pool.borrow_object
|
68
|
+
assert_equal obj, wait_obj
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_timeout_reached
|
73
|
+
pool = create_pool do |config|
|
74
|
+
config.timeout = 1
|
75
|
+
end
|
76
|
+
|
77
|
+
until pool.active_list.size == pool.config.max_active
|
78
|
+
obj = pool.borrow_object
|
79
|
+
end
|
80
|
+
|
81
|
+
# max active reached wait till timeout
|
82
|
+
assert_raise(CommonPoolError) do
|
83
|
+
wait_obj = pool.borrow_object
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_invalidate
|
88
|
+
pool = create_pool
|
89
|
+
session_a = pool.borrow_object
|
90
|
+
session_b = pool.borrow_object
|
91
|
+
|
92
|
+
assert_equal 2, pool.active_list.size
|
93
|
+
assert_equal 0, pool.idle_list.size
|
94
|
+
|
95
|
+
pool.invalidate_object(session_a)
|
96
|
+
assert_equal 1, pool.active_list.size
|
97
|
+
assert_equal 0, pool.idle_list.size
|
98
|
+
|
99
|
+
pool.return_object(session_b)
|
100
|
+
assert_equal 0, pool.active_list.size
|
101
|
+
assert_equal 1, pool.idle_list.size
|
102
|
+
|
103
|
+
session_new = pool.borrow_object
|
104
|
+
assert_equal session_new, session_b
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def test_check_min_idle
|
109
|
+
pool = create_pool do |config|
|
110
|
+
config.min_idle = 2
|
111
|
+
config.idle_check_interval = 60
|
112
|
+
end
|
113
|
+
|
114
|
+
# sleep to let the pool populate
|
115
|
+
until pool.idle_check_status.match(/Sleeping/)
|
116
|
+
sleep 2
|
117
|
+
end
|
118
|
+
|
119
|
+
assert_equal 2, pool.idle_list.size
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_check_max_idle
|
123
|
+
pool = create_pool do |config|
|
124
|
+
config.min_idle = 0
|
125
|
+
config.max_idle = 2
|
126
|
+
config.idle_check_interval = 60
|
127
|
+
end
|
128
|
+
|
129
|
+
a = pool.borrow_object
|
130
|
+
b = pool.borrow_object
|
131
|
+
c = pool.borrow_object
|
132
|
+
|
133
|
+
# idle will keep up to 2
|
134
|
+
pool.return_object(a)
|
135
|
+
pool.return_object(b)
|
136
|
+
assert_equal 2, pool.idle_list.size
|
137
|
+
|
138
|
+
# throw away no 3
|
139
|
+
pool.return_object(c)
|
140
|
+
assert_equal 2, pool.idle_list.size
|
141
|
+
end
|
142
|
+
|
143
|
+
# def test_run
|
144
|
+
# pool = create_pool do |config|
|
145
|
+
# config.debug = true
|
146
|
+
# config.min_idle = 2
|
147
|
+
# config.max_active = 3
|
148
|
+
# config.max_idle_time = 15
|
149
|
+
# config.idle_check = true
|
150
|
+
# config.idle_check_interval = 3
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# pool.idle_check_thread.join
|
154
|
+
# end
|
155
|
+
|
156
|
+
protected
|
157
|
+
class TestDataSource < PoolDataSource
|
158
|
+
def create_object
|
159
|
+
rand(1000)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def create_pool(&proc)
|
164
|
+
pool = ObjectPool.new(TestDataSource.new) do |config|
|
165
|
+
config.logger = Logger.new(STDOUT)
|
166
|
+
yield config if block_given?
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.2
|
3
|
+
specification_version: 1
|
4
|
+
name: common-pool
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2007-05-14 00:00:00 +08:00
|
8
|
+
summary: Common Pool - Object Pooling
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: herryanto@pluitsolutions.com
|
12
|
+
homepage: http://common-pool.rubyforge.net/
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: name
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Herryanto Siatono
|
31
|
+
files:
|
32
|
+
- lib/common_pool.rb
|
33
|
+
- README
|
34
|
+
- CHANGELOG
|
35
|
+
test_files:
|
36
|
+
- test/common_pool_test.rb
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README
|
41
|
+
- CHANGELOG
|
42
|
+
executables: []
|
43
|
+
|
44
|
+
extensions: []
|
45
|
+
|
46
|
+
requirements: []
|
47
|
+
|
48
|
+
dependencies:
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: hpricot
|
51
|
+
version_requirement:
|
52
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0.4"
|
57
|
+
version:
|