oldmoe-neverblock 0.1.6 → 1.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/lib/never_block.rb +5 -78
- data/lib/neverblock.rb +3 -1
- data/lib/{never_block/extensions/fiber_extensions.rb → neverblock/core/fiber.rb} +20 -6
- data/lib/neverblock/core/pool.rb +72 -0
- data/lib/neverblock/core/reactor.rb +50 -0
- data/lib/neverblock/core/system/system.rb +38 -0
- data/lib/neverblock/core/system/timeout.rb +67 -0
- data/lib/{never_block/db/pooled_db_connection.rb → neverblock/io/db/connection.rb} +16 -2
- data/lib/neverblock/io/db/drivers/mysql.rb +73 -0
- data/lib/neverblock/io/db/drivers/postgres.rb +63 -0
- data/lib/neverblock/io/db/fibered_connection_pool.rb +130 -0
- data/lib/{never_block → neverblock/io}/db/fibered_mysql_connection.rb +5 -18
- data/lib/{never_block/pool/fibered_connection_pool.rb → neverblock/io/db/pool.rb} +25 -40
- data/lib/neverblock/io/file.rb +24 -0
- data/lib/neverblock/io/io.rb +219 -0
- data/lib/neverblock/io/socket.rb +75 -0
- data/lib/neverblock_io.rb +6 -0
- data/lib/system.rb +4 -0
- data/neverblock.gemspec +23 -21
- metadata +23 -20
- data/lib/active_record/connection_adapters/neverblock_mysql_adapter.rb +0 -68
- data/lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb +0 -85
- data/lib/never_block/db/fibered_db_connection.rb +0 -72
- data/lib/never_block/db/fibered_postgres_connection.rb +0 -64
- data/lib/never_block/frameworks/activerecord.rb +0 -37
- data/lib/never_block/frameworks/rails.rb +0 -65
- data/lib/never_block/pool/fiber_pool.rb +0 -74
- data/lib/never_block/servers/mongrel.rb +0 -236
- data/lib/never_block/servers/thin.rb +0 -32
- data/lib/neverblock-mysql.rb +0 -5
- data/lib/neverblock-pg.rb +0 -5
data/lib/never_block.rb
CHANGED
|
@@ -1,96 +1,23 @@
|
|
|
1
1
|
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009 eSpace, Inc.
|
|
3
3
|
# License:: Distributes under the same terms as Ruby
|
|
4
4
|
|
|
5
5
|
$:.unshift File.expand_path(File.dirname(__FILE__))
|
|
6
6
|
|
|
7
|
-
# Thanks to Aman Gupta for writing the Ruby 1.8 Fiber simulator
|
|
8
|
-
unless defined? Fiber
|
|
9
|
-
require 'thread'
|
|
10
|
-
require 'singleton'
|
|
11
|
-
class FiberError < StandardError; end
|
|
12
|
-
class Fiber
|
|
13
|
-
def initialize
|
|
14
|
-
raise ArgumentError, 'new Fiber requires a block' unless block_given?
|
|
15
|
-
|
|
16
|
-
@yield = Queue.new
|
|
17
|
-
@resume = Queue.new
|
|
18
|
-
|
|
19
|
-
@thread = Thread.new{ @yield.push [ *yield(*@resume.pop) ] }
|
|
20
|
-
@thread.abort_on_exception = true
|
|
21
|
-
@thread[:fiber] = self
|
|
22
|
-
end
|
|
23
|
-
attr_reader :thread
|
|
24
|
-
|
|
25
|
-
def resume *args
|
|
26
|
-
raise FiberError, 'dead fiber called' unless @thread.alive?
|
|
27
|
-
@resume.push(args)
|
|
28
|
-
result = @yield.pop
|
|
29
|
-
result.size > 1 ? result : result.first
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def yield *args
|
|
33
|
-
@yield.push(args)
|
|
34
|
-
result = @resume.pop
|
|
35
|
-
result.size > 1 ? result : result.first
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.yield *args
|
|
39
|
-
raise FiberError, "can't yield from root fiber" unless fiber = Thread.current[:fiber]
|
|
40
|
-
fiber.yield(*args)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def self.current
|
|
44
|
-
Thread.current[:fiber] or raise FiberError, 'not inside a fiber'
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def inspect
|
|
48
|
-
"#<#{self.class}:0x#{self.object_id.to_s(16)}>"
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
class RootFiber < Fiber
|
|
53
|
-
include Singleton
|
|
54
|
-
def initialize
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def resume *args
|
|
58
|
-
raise FiberError, "can't resume root fiber"
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def yield *args
|
|
62
|
-
raise FiberError, "can't yield from root fiber"
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
#attach the root fiber to the main thread
|
|
67
|
-
Thread.main[:fiber] = RootFiber.instance
|
|
68
|
-
else
|
|
69
|
-
require 'fiber'
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
require 'never_block/extensions/fiber_extensions'
|
|
73
|
-
require 'never_block/pool/fiber_pool'
|
|
74
|
-
require 'never_block/pool/fibered_connection_pool'
|
|
75
|
-
|
|
76
7
|
module NeverBlock
|
|
77
8
|
|
|
78
9
|
# Checks if we should be working in a non-blocking mode
|
|
79
10
|
def self.neverblocking?
|
|
80
|
-
Fiber.respond_to?(:current) && Fiber.current[:neverblock]
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def self.event_loop_available?
|
|
84
|
-
defined?(EM) && EM.reactor_running?
|
|
11
|
+
NB::Fiber.respond_to?(:current) && NB::Fiber.current.respond_to?('[]') && NB::Fiber.current[:neverblock] && NB.reactor.running?
|
|
85
12
|
end
|
|
86
13
|
|
|
87
14
|
# The given block will run its queries either in blocking or non-blocking
|
|
88
15
|
# mode based on the first parameter
|
|
89
16
|
def self.neverblock(nb = true, &block)
|
|
90
|
-
status = Fiber.current[:neverblock]
|
|
91
|
-
Fiber.current[:neverblock] = nb
|
|
17
|
+
status = NB::Fiber.current[:neverblock]
|
|
18
|
+
NB::Fiber.current[:neverblock] = nb
|
|
92
19
|
block.call
|
|
93
|
-
Fiber.current[:neverblock] = status
|
|
20
|
+
NB::Fiber.current[:neverblock] = status
|
|
94
21
|
end
|
|
95
22
|
|
|
96
23
|
# Exception to be thrown for all neverblock internal errors
|
data/lib/neverblock.rb
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
2
|
-
# Copyright:: Copyright (c)
|
|
2
|
+
# Copyright:: Copyright (c) 2009 eSpace, Inc.
|
|
3
3
|
# License:: Distributes under the same terms as Ruby
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
require 'fiber'
|
|
6
|
+
require File.expand_path(File.dirname(__FILE__)+'/../../never_block')
|
|
7
|
+
|
|
8
|
+
class NeverBlock::Fiber < Fiber
|
|
9
|
+
|
|
10
|
+
def initialize(neverblock = true, &block)
|
|
11
|
+
self[:neverblock] = neverblock
|
|
12
|
+
super()
|
|
13
|
+
end
|
|
14
|
+
|
|
8
15
|
|
|
9
|
-
class Fiber
|
|
10
|
-
|
|
11
16
|
#Attribute Reference--Returns the value of a fiber-local variable, using
|
|
12
17
|
#either a symbol or a string name. If the specified variable does not exist,
|
|
13
18
|
#returns nil.
|
|
@@ -21,6 +26,15 @@ class Fiber
|
|
|
21
26
|
local_fiber_variables[key] = value
|
|
22
27
|
end
|
|
23
28
|
|
|
29
|
+
#Sending an exception instance to resume will yield the fiber
|
|
30
|
+
#and then raise the exception. This is necessary to raise exceptions
|
|
31
|
+
#in their correct context.
|
|
32
|
+
def self.yield(*args)
|
|
33
|
+
result = super
|
|
34
|
+
raise result if result.is_a? Exception
|
|
35
|
+
result
|
|
36
|
+
end
|
|
37
|
+
|
|
24
38
|
private
|
|
25
39
|
|
|
26
40
|
def local_fiber_variables
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__)+'/fiber')
|
|
3
|
+
|
|
4
|
+
module NeverBlock
|
|
5
|
+
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
6
|
+
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
|
7
|
+
# License:: Distributes under the same terms as Ruby
|
|
8
|
+
#
|
|
9
|
+
# A pool of initialized fibers
|
|
10
|
+
# It does not grow in size or create transient fibers
|
|
11
|
+
# It will queue code blocks when needed (if all its fibers are busy)
|
|
12
|
+
#
|
|
13
|
+
# This class is particulary useful when you use the fibers
|
|
14
|
+
# to connect to evented back ends. It also does not generate
|
|
15
|
+
# transient objects and thus saves memory.
|
|
16
|
+
#
|
|
17
|
+
# Example:
|
|
18
|
+
# fiber_pool = NeverBlock::FiberPool.new(150)
|
|
19
|
+
#
|
|
20
|
+
# loop do
|
|
21
|
+
# fiber_pool.spawn do
|
|
22
|
+
# #fiber body goes here
|
|
23
|
+
# end
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
class FiberPool
|
|
27
|
+
|
|
28
|
+
# gives access to the currently free fibers
|
|
29
|
+
attr_reader :fibers
|
|
30
|
+
|
|
31
|
+
# Prepare a list of fibers that are able to run different blocks of code
|
|
32
|
+
# every time. Once a fiber is done with its block, it attempts to fetch
|
|
33
|
+
# another one from the queue
|
|
34
|
+
def initialize(count = 50)
|
|
35
|
+
@fibers,@busy_fibers,@queue = [],{},[]
|
|
36
|
+
count.times do |i|
|
|
37
|
+
fiber = NB::Fiber.new do |block|
|
|
38
|
+
loop do
|
|
39
|
+
block.call
|
|
40
|
+
# callbacks are called in a reverse order, much like c++ destructor
|
|
41
|
+
NB::Fiber.current[:callbacks].pop.call while NB::Fiber.current[:callbacks].length > 0
|
|
42
|
+
unless @queue.empty?
|
|
43
|
+
block = @queue.shift
|
|
44
|
+
else
|
|
45
|
+
@busy_fibers.delete(NB::Fiber.current.object_id)
|
|
46
|
+
@fibers << NB::Fiber.current
|
|
47
|
+
block = NB::Fiber.yield
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
fiber[:callbacks] = []
|
|
52
|
+
@fibers << fiber
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# If there is an available fiber use it, otherwise, leave it to linger
|
|
57
|
+
# in a queue
|
|
58
|
+
def spawn(evented = true, &block)
|
|
59
|
+
if fiber = @fibers.shift
|
|
60
|
+
fiber[:callbacks] = []
|
|
61
|
+
@busy_fibers[fiber.object_id] = fiber
|
|
62
|
+
fiber[:neverblock] = evented
|
|
63
|
+
fiber.resume(block)
|
|
64
|
+
else
|
|
65
|
+
@queue << block
|
|
66
|
+
end
|
|
67
|
+
self # we are keen on hiding our queue
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end # FiberPool
|
|
71
|
+
end # NeverBlock
|
|
72
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'reactor'
|
|
2
|
+
require 'thread'
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__)+'/fiber')
|
|
4
|
+
|
|
5
|
+
module NeverBlock
|
|
6
|
+
|
|
7
|
+
@@reactors = {}
|
|
8
|
+
|
|
9
|
+
@@queue = Queue.new
|
|
10
|
+
|
|
11
|
+
@@thread_pool = []
|
|
12
|
+
|
|
13
|
+
20.times do
|
|
14
|
+
@@thread_pool << Thread.new do
|
|
15
|
+
loop do
|
|
16
|
+
io, method, params, fiber, reactor = *(@@queue.shift)
|
|
17
|
+
begin
|
|
18
|
+
reactor.next_tick{fiber.resume(io.__send__(method, *params))} if fiber.alive?
|
|
19
|
+
rescue Exception => e
|
|
20
|
+
reactor.next_tick{fiber.resume(e)} if fiber.alive?
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.reactor
|
|
27
|
+
@@reactors[Thread.current.object_id] ||= ::Reactor::Base.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.wait(mode, io)
|
|
31
|
+
fiber = NB::Fiber.current
|
|
32
|
+
NB.reactor.attach(mode, io){fiber.resume}
|
|
33
|
+
NB::Fiber.yield
|
|
34
|
+
NB.reactor.detach(mode, io)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.sleep(time)
|
|
38
|
+
NB::Fiber.yield if time.nil?
|
|
39
|
+
return if time <= 0
|
|
40
|
+
fiber = NB::Fiber.current
|
|
41
|
+
NB.reactor.add_timer(time){fiber.resume}
|
|
42
|
+
NB::Fiber.yield
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.defer(io, action, args)
|
|
46
|
+
@@queue << [io, action, args, NB::Fiber.current, NB.reactor]
|
|
47
|
+
NB::Fiber.yield
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__)+'/../../../neverblock')
|
|
3
|
+
|
|
4
|
+
module Kernel
|
|
5
|
+
|
|
6
|
+
alias_method :rb_sleep, :sleep
|
|
7
|
+
|
|
8
|
+
def sleep(time=nil)
|
|
9
|
+
return rb_sleep(time) unless NB.neverblocking?
|
|
10
|
+
NB.sleep(time)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
alias_method :rb_system, :system
|
|
14
|
+
|
|
15
|
+
def system(cmd, *args)
|
|
16
|
+
return rb_system(cmd, *args) unless NB.neverblocking?
|
|
17
|
+
begin
|
|
18
|
+
backticks(cmd, *args)
|
|
19
|
+
result = $?.exitstatus
|
|
20
|
+
return true if result.zero?
|
|
21
|
+
return nil if result == 127
|
|
22
|
+
return false
|
|
23
|
+
rescue Errno::ENOENT => e
|
|
24
|
+
return nil
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def backticks(cmd, *args)
|
|
29
|
+
myargs = "#{cmd} "
|
|
30
|
+
myargs << args.join(' ') if args
|
|
31
|
+
res = ''
|
|
32
|
+
IO.popen(myargs) do |f|
|
|
33
|
+
res << f.read
|
|
34
|
+
end
|
|
35
|
+
res
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
require File.expand_path(File.dirname(__FILE__)+'/../../../neverblock')
|
|
3
|
+
|
|
4
|
+
module Timeout
|
|
5
|
+
|
|
6
|
+
alias_method :rb_timeout, :timeout
|
|
7
|
+
|
|
8
|
+
def timeout(time, klass=Timeout::Error, &block)
|
|
9
|
+
return rb_timeout(time, klass,&block) unless NB.neverblocking?
|
|
10
|
+
if time.nil? || time <= 0
|
|
11
|
+
block.call
|
|
12
|
+
else
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
fiber = NB::Fiber.current
|
|
16
|
+
|
|
17
|
+
timer = NB.reactor.add_timer(time) do
|
|
18
|
+
fiber[:timeouts].last.each do |event|
|
|
19
|
+
if event.is_a? Reactor::Timer
|
|
20
|
+
event.cancel
|
|
21
|
+
else
|
|
22
|
+
NB.reactor.detach(event[0], event[1])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
fiber.resume(klass.new)
|
|
26
|
+
end
|
|
27
|
+
(fiber[:timeouts] ||= []) << []
|
|
28
|
+
begin
|
|
29
|
+
block.call
|
|
30
|
+
rescue Exception => e
|
|
31
|
+
raise e
|
|
32
|
+
ensure
|
|
33
|
+
timer.cancel
|
|
34
|
+
fiber[:timeouts].pop
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
module_function :timeout
|
|
40
|
+
module_function :rb_timeout
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
NB.reactor.on_add_timer do |timer|
|
|
45
|
+
Kernel.puts "on add"
|
|
46
|
+
timeouts = NB::Fiber.current[:timeouts]
|
|
47
|
+
unless timeouts.nil? || timeouts.empty?
|
|
48
|
+
timeouts.last << timer
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
NB.reactor.on_attach do |mode, io|
|
|
53
|
+
Kernel.puts "on attach"
|
|
54
|
+
timeouts = NB::Fiber.current[:timeouts]
|
|
55
|
+
unless timeouts.nil? || timeouts.empty?
|
|
56
|
+
timeouts.last << [mode, io]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
NB.reactor.on_detach do |mode, io|
|
|
61
|
+
Kernel.puts "on detach"
|
|
62
|
+
timeouts = NB::Fiber.current[:timeouts]
|
|
63
|
+
unless timeouts.nil? || timeouts.empty?
|
|
64
|
+
timeouts.delete_if{|to|to.is_a? Array && to[0] == mode && to[1] == io}
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__)+'/pool')
|
|
2
|
+
|
|
1
3
|
module NeverBlock
|
|
4
|
+
|
|
2
5
|
module DB
|
|
3
6
|
# a proxy for pooled fibered connections
|
|
4
|
-
class
|
|
7
|
+
class Connection
|
|
5
8
|
# Requires a block with connection parameters
|
|
6
9
|
# and a pool size (defaults to 4)
|
|
7
10
|
def initialize(size=4, &block)
|
|
8
|
-
@pool = NB::Pool
|
|
11
|
+
@pool = NB::DB::Pool.new(:size=>size, :eager=>true) do
|
|
9
12
|
yield
|
|
10
13
|
end
|
|
11
14
|
end
|
|
@@ -37,7 +40,18 @@ module NeverBlock
|
|
|
37
40
|
@pool.hold do |conn|
|
|
38
41
|
conn.respond_to?(method)
|
|
39
42
|
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
protected
|
|
46
|
+
|
|
47
|
+
# are we in a transaction?
|
|
48
|
+
# if no then just hold a connection and run the block
|
|
49
|
+
# else get a connection, pass it to the block
|
|
50
|
+
# and move away
|
|
51
|
+
def hold_connection
|
|
52
|
+
|
|
40
53
|
end
|
|
54
|
+
|
|
41
55
|
end
|
|
42
56
|
end
|
|
43
57
|
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
require 'mysqlplus'
|
|
3
|
+
require File.expand_path(File.dirname(__FILE__)+'/../../../../neverblock')
|
|
4
|
+
require File.expand_path(File.dirname(__FILE__)+'/../connection')
|
|
5
|
+
require File.expand_path(File.dirname(__FILE__)+'/../fibered_mysql_connection')
|
|
6
|
+
require File.expand_path(File.dirname(__FILE__)+'/../pool')
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module NeverBlock
|
|
10
|
+
|
|
11
|
+
module DB
|
|
12
|
+
# A modified mysql connection driver. It builds on the original pg driver.
|
|
13
|
+
# This driver is able to register the socket at a certain backend (EM)
|
|
14
|
+
# and then whenever the query is executed within the scope of a friendly
|
|
15
|
+
# fiber. It will be done in async mode and the fiber will yield
|
|
16
|
+
class Mysql < ::Mysql
|
|
17
|
+
|
|
18
|
+
# Initializes the connection and remembers the connection params
|
|
19
|
+
def initialize(*args)
|
|
20
|
+
@connection_params = args
|
|
21
|
+
super(*@connection_params)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Does a normal real_connect if arguments are passed. If no arguments are
|
|
25
|
+
# passed it uses the ones it remembers
|
|
26
|
+
def real_connect(*args)
|
|
27
|
+
@connection_params = args unless args.empty?
|
|
28
|
+
super(*@connection_params)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :connect, :real_connect
|
|
32
|
+
|
|
33
|
+
# Assuming the use of NeverBlock fiber extensions and that the exec is run in
|
|
34
|
+
# the context of a fiber. One that have the value :neverblock set to true.
|
|
35
|
+
# All neverblock IO classes check this value, setting it to false will force
|
|
36
|
+
# the execution in a blocking way.
|
|
37
|
+
def query(sql)
|
|
38
|
+
if NB.neverblocking? && NB.reactor.running?
|
|
39
|
+
send_query sql
|
|
40
|
+
NB.wait(:read, IO.new(socket))
|
|
41
|
+
get_result
|
|
42
|
+
else
|
|
43
|
+
super(sql)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias_method :exec, :query
|
|
48
|
+
|
|
49
|
+
end #MySQL
|
|
50
|
+
|
|
51
|
+
class PooledMySQL < ::NeverBlock::DB::Connection
|
|
52
|
+
|
|
53
|
+
def initialize(*args)
|
|
54
|
+
options = {}
|
|
55
|
+
if args #&& (options = args.last).is_a? Hash
|
|
56
|
+
size = options[:size] || 4
|
|
57
|
+
eager = options[:eager] || true
|
|
58
|
+
args.pop
|
|
59
|
+
end
|
|
60
|
+
@pool = NB::DB::Pool.new(:size=>size, :eager=>eager) do
|
|
61
|
+
MySQL.new(*args)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end #PooledMySQL
|
|
66
|
+
|
|
67
|
+
end #DB
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
end #NeverBlock
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|