oldmoe-neverblock 0.1.4 → 0.1.5
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/active_record/connection_adapters/neverblock_mysql_adapter.rb +20 -32
- data/lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb +2 -2
- data/lib/never_block.rb +18 -0
- data/lib/never_block/db/fibered_db_connection.rb +33 -26
- data/lib/never_block/db/fibered_mysql_connection.rb +39 -37
- data/lib/never_block/db/fibered_postgres_connection.rb +20 -21
- data/lib/never_block/db/pooled_db_connection.rb +4 -32
- data/lib/never_block/extensions/fiber_extensions.rb +2 -1
- data/lib/never_block/pool/fiber_pool.rb +9 -11
- data/lib/never_block/pool/fibered_connection_pool.rb +40 -39
- data/lib/neverblock-pg.rb +3 -2
- data/neverblock.gemspec +2 -2
- metadata +2 -2
|
@@ -11,50 +11,38 @@ class ActiveRecord::ConnectionAdapters::NeverBlockMysqlAdapter < ActiveRecord::C
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
|
14
|
-
begin_db_transaction
|
|
15
14
|
super sql, name
|
|
16
15
|
id_value || @connection.insert_id
|
|
17
|
-
commit_db_transaction
|
|
18
16
|
end
|
|
19
17
|
|
|
20
18
|
def update_sql(sql, name = nil) #:nodoc:
|
|
21
|
-
begin_db_transaction
|
|
22
19
|
super
|
|
23
20
|
@connection.affected_rows
|
|
24
|
-
commit_db_transaction
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def begin_db_transaction
|
|
28
|
-
@connection.begin_db_transaction
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def commit_db_transaction
|
|
32
|
-
@connection.commit_db_transaction
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def rollback_db_transaction
|
|
36
|
-
@connection.rollback_db_transaction
|
|
37
21
|
end
|
|
38
22
|
|
|
39
23
|
def connect
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
conn.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
24
|
+
#initialize the connection pool
|
|
25
|
+
unless @connection
|
|
26
|
+
@connection = ::NB::DB::PooledDBConnection.new(@connection_options[0]) do
|
|
27
|
+
conn = ::NB::DB::FMysql.init
|
|
28
|
+
encoding = @config[:encoding]
|
|
29
|
+
if encoding
|
|
30
|
+
conn.options(::NB::DB::FMysql::SET_CHARSET_NAME, encoding) rescue nil
|
|
31
|
+
end
|
|
32
|
+
conn.ssl_set(@config[:sslkey], @config[:sslcert], @config[:sslca], @config[:sslcapath], @config[:sslcipher]) if @config[:sslkey]
|
|
33
|
+
conn.real_connect(*@connection_options[1..(@connection_options.length-1)])
|
|
34
|
+
NB.neverblock(false) do
|
|
35
|
+
conn.query("SET NAMES '#{encoding}'") if encoding
|
|
36
|
+
# By default, MySQL 'where id is null' selects the last inserted id.
|
|
37
|
+
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
|
38
|
+
conn.query("SET SQL_AUTO_IS_NULL=0")
|
|
39
|
+
end
|
|
40
|
+
conn
|
|
53
41
|
end
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
else # we have a connection pool, we need to recover a connection
|
|
43
|
+
@connection.replace_acquired_connection
|
|
56
44
|
end
|
|
57
|
-
end
|
|
45
|
+
end
|
|
58
46
|
|
|
59
47
|
end
|
|
60
48
|
|
|
@@ -28,8 +28,8 @@ class ActiveRecord::ConnectionAdapters::NeverBlockPostgreSQLAdapter < ActiveReco
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def connect
|
|
31
|
-
@connection = ::NB::DB::PooledFiberedPostgresConnection.new(@
|
|
32
|
-
conn = PGconn.connect(*@
|
|
31
|
+
@connection = ::NB::DB::PooledFiberedPostgresConnection.new(@connection_options[0]) do
|
|
32
|
+
conn = PGconn.connect(*@connection_options[1..(@connection_options.length-1)])
|
|
33
33
|
PGconn.translate_results = false if PGconn.respond_to?(:translate_results=)
|
|
34
34
|
# Ignore async_exec and async_query when using postgres-pr.
|
|
35
35
|
@async = @config[:allow_concurrency] && @connection.respond_to?(:async_exec)
|
data/lib/never_block.rb
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
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
|
|
7
8
|
unless defined? Fiber
|
|
8
9
|
require 'thread'
|
|
9
10
|
require 'singleton'
|
|
@@ -73,12 +74,29 @@ require 'never_block/pool/fiber_pool'
|
|
|
73
74
|
require 'never_block/pool/fibered_connection_pool'
|
|
74
75
|
|
|
75
76
|
module NeverBlock
|
|
77
|
+
|
|
78
|
+
# Checks if we should be working in a non-blocking mode
|
|
79
|
+
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?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The given block will run its queries either in blocking or non-blocking
|
|
88
|
+
# mode based on the first parameter
|
|
76
89
|
def self.neverblock(nb = true, &block)
|
|
77
90
|
status = Fiber.current[:neverblock]
|
|
78
91
|
Fiber.current[:neverblock] = nb
|
|
79
92
|
block.call
|
|
80
93
|
Fiber.current[:neverblock] = status
|
|
81
94
|
end
|
|
95
|
+
|
|
96
|
+
# Exception to be thrown for all neverblock internal errors
|
|
97
|
+
class NBError < StandardError
|
|
98
|
+
end
|
|
99
|
+
|
|
82
100
|
end
|
|
83
101
|
|
|
84
102
|
NB = NeverBlock
|
|
@@ -1,46 +1,53 @@
|
|
|
1
1
|
module NeverBlock
|
|
2
2
|
module DB
|
|
3
3
|
module FiberedDBConnection
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
|
|
5
|
+
# Attaches the connection socket to an event loop and adds a callback
|
|
6
|
+
# to the fiber's callbacks that unregisters the connection from event loop
|
|
7
|
+
# Raises NB::NBError
|
|
8
|
+
def register_with_event_loop
|
|
9
|
+
#puts ">>>>>register_with_event_loop"
|
|
10
|
+
if EM.reactor_running?
|
|
11
|
+
@fiber = Fiber.current
|
|
12
|
+
#puts ">>>>>register_with_event_loop fiber #{@fiber.inspect}"
|
|
13
|
+
# When there's no previous em_connection
|
|
14
|
+
unless @fiber[:em_connection]
|
|
15
|
+
@fiber[:em_connection] = EM::attach(socket,EMConnectionHandler,self)
|
|
16
|
+
@fiber[:callbacks] << self.method(:unregister_from_event_loop)
|
|
15
17
|
end
|
|
16
|
-
elsif loop.class.name == "REV::Loop"
|
|
17
|
-
loop.attach(RevConnectionHandler.new(@fd))
|
|
18
18
|
else
|
|
19
|
-
raise "
|
|
19
|
+
raise ::NB::NBError.new("FiberedDBConnection: EventMachine reactor not running")
|
|
20
20
|
end
|
|
21
|
-
@loop = loop
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
# Unattaches the connection socket from the event loop
|
|
25
24
|
def unregister_from_event_loop
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
#puts ">>>>>unregister_from_event_loop #{self.inspect} #{@fiber.inspect}"
|
|
26
|
+
if em_c = @fiber[:em_connection]
|
|
27
|
+
em_c.detach
|
|
28
|
+
@fiber[:em_connection] = nil
|
|
29
|
+
true
|
|
28
30
|
else
|
|
29
|
-
|
|
31
|
+
false
|
|
30
32
|
end
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
# Removes the unregister_from_event_loop callback from the fiber's
|
|
36
|
+
# callbacks. It should be used when errors occur in an already registered
|
|
37
|
+
# connection
|
|
38
|
+
def remove_unregister_from_event_loop_callbacks
|
|
39
|
+
@fiber[:callbacks].delete self.method(:unregister_from_event_loop)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Closes the connection using event loop
|
|
43
|
+
def event_loop_connection_close
|
|
44
|
+
@fiber[:em_connection].close_connection if @fiber[:em_connection]
|
|
45
|
+
end
|
|
32
46
|
|
|
33
47
|
# The callback, this is called whenever
|
|
34
48
|
# there is data available at the socket
|
|
35
49
|
def resume_command
|
|
36
|
-
|
|
37
|
-
if @fiber
|
|
38
|
-
f = @fiber
|
|
39
|
-
@fiber = nil
|
|
40
|
-
f.resume
|
|
41
|
-
else
|
|
42
|
-
unregister_from_event_loop
|
|
43
|
-
end
|
|
50
|
+
@fiber.resume if @fiber
|
|
44
51
|
end
|
|
45
52
|
|
|
46
53
|
end
|
|
@@ -3,55 +3,57 @@ require 'mysqlplus'
|
|
|
3
3
|
module NeverBlock
|
|
4
4
|
|
|
5
5
|
module DB
|
|
6
|
-
# A modified mysql connection driver
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# and then whenever the query is executed
|
|
11
|
-
# within the scope of a friendly fiber
|
|
12
|
-
# it will be done in async mode and the fiber
|
|
13
|
-
# will yield
|
|
6
|
+
# A modified mysql connection driver. It builds on the original pg driver.
|
|
7
|
+
# This driver is able to register the socket at a certain backend (EM)
|
|
8
|
+
# and then whenever the query is executed within the scope of a friendly
|
|
9
|
+
# fiber. It will be done in async mode and the fiber will yield
|
|
14
10
|
class FiberedMysqlConnection < Mysql
|
|
15
11
|
|
|
16
12
|
include FiberedDBConnection
|
|
17
|
-
|
|
13
|
+
|
|
14
|
+
# Initializes the connection and remembers the connection params
|
|
15
|
+
def initialize(*args)
|
|
16
|
+
@connection_params = args
|
|
17
|
+
super(*@connection_params)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Does a normal real_connect if arguments are passed. If no arguments are
|
|
21
|
+
# passed it uses the ones it remembers
|
|
22
|
+
def real_connect(*args)
|
|
23
|
+
@connection_params = args unless args.empty?
|
|
24
|
+
super(*@connection_params)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
alias_method :connect, :real_connect
|
|
28
|
+
|
|
18
29
|
# Assuming the use of NeverBlock fiber extensions and that the exec is run in
|
|
19
30
|
# the context of a fiber. One that have the value :neverblock set to true.
|
|
20
31
|
# All neverblock IO classes check this value, setting it to false will force
|
|
21
32
|
# the execution in a blocking way.
|
|
22
33
|
def query(sql)
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
if NB.event_loop_available? && NB.neverblocking?
|
|
35
|
+
raise ::NB::NBError.new("FiberedMysqlConnection: The running fiber is attached to a connection other than the current one") if (c = Fiber.current[:connection]) && c != self
|
|
36
|
+
begin
|
|
25
37
|
send_query sql
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
38
|
+
Fiber.yield register_with_event_loop
|
|
39
|
+
get_result
|
|
40
|
+
rescue Exception => e
|
|
41
|
+
if error = ['not connected', 'gone away', 'Lost connection'].detect{|msg| e.message.include? msg}
|
|
42
|
+
event_loop_connection_close
|
|
43
|
+
unregister_from_event_loop
|
|
44
|
+
remove_unregister_from_event_loop_callbacks
|
|
45
|
+
#connect
|
|
46
|
+
end
|
|
47
|
+
raise e
|
|
31
48
|
end
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
connect
|
|
36
|
-
end
|
|
37
|
-
raise e
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
alias :exec :query
|
|
42
|
-
|
|
43
|
-
# stop the connection and deattach from the event loop
|
|
44
|
-
def stop
|
|
45
|
-
unregister_from_event_loop
|
|
49
|
+
else
|
|
50
|
+
super(sql)
|
|
51
|
+
end
|
|
46
52
|
end
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
register_with_event_loop(@loop)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
end #FiberedMySQLConnection
|
|
54
|
+
alias_method :exec, :query
|
|
55
|
+
|
|
56
|
+
end #FiberedMySQLConnection
|
|
55
57
|
|
|
56
58
|
end #DB
|
|
57
59
|
|
|
@@ -21,11 +21,13 @@ module NeverBlock
|
|
|
21
21
|
# All neverblock IO classes check this value, setting it to false will force
|
|
22
22
|
# the execution in a blocking way.
|
|
23
23
|
def exec(sql)
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
# TODO Still not "killing the query process"-proof
|
|
25
|
+
# In some cases, the query is simply sent but the fiber never yields
|
|
26
|
+
if NB.event_loop_available? && NB.neverblocking?
|
|
27
|
+
begin
|
|
26
28
|
send_query sql
|
|
27
|
-
@fiber = Fiber.current
|
|
28
|
-
Fiber.yield
|
|
29
|
+
@fiber = Fiber.current
|
|
30
|
+
Fiber.yield register_with_event_loop
|
|
29
31
|
while is_busy
|
|
30
32
|
consume_input
|
|
31
33
|
Fiber.yield if is_busy
|
|
@@ -35,26 +37,23 @@ module NeverBlock
|
|
|
35
37
|
res = self.get_result
|
|
36
38
|
data << res unless res.nil?
|
|
37
39
|
end
|
|
38
|
-
data.last
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
data.last
|
|
41
|
+
rescue Exception => e
|
|
42
|
+
if error = ['not connected', 'gone away', 'Lost connection','no connection'].detect{|msg| e.message.include? msg}
|
|
43
|
+
#event_loop_connection_close
|
|
44
|
+
unregister_from_event_loop
|
|
45
|
+
reset
|
|
46
|
+
end
|
|
47
|
+
raise e
|
|
48
|
+
ensure
|
|
49
|
+
unregister_from_event_loop
|
|
41
50
|
end
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
end
|
|
51
|
+
else
|
|
52
|
+
super(sql)
|
|
53
|
+
end
|
|
46
54
|
end
|
|
47
55
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
# reset the connection
|
|
51
|
-
# and reattach to the
|
|
52
|
-
# event loop
|
|
53
|
-
def reset
|
|
54
|
-
unregister_from_event_loop
|
|
55
|
-
super
|
|
56
|
-
register_with_event_loop(@loop)
|
|
57
|
-
end
|
|
56
|
+
alias_method :query, :exec
|
|
58
57
|
|
|
59
58
|
end #FiberedPostgresConnection
|
|
60
59
|
|
|
@@ -19,40 +19,12 @@ module NeverBlock
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
alias :exec :query
|
|
22
|
-
|
|
23
|
-
# This method must be called for transactions to work correctly.
|
|
24
|
-
# One cannot just send "begin" as you never know which connection
|
|
25
|
-
# will be available next. This method ensures you get the same connection
|
|
26
|
-
# while in a transaction.
|
|
27
|
-
def begin_db_transaction
|
|
28
|
-
@pool.hold(true) do |conn|
|
|
29
|
-
conn.query("begin")
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# see =begin_db_transaction
|
|
34
|
-
def rollback_db_transaction
|
|
35
|
-
@pool.hold do |conn|
|
|
36
|
-
conn.query("rollback")
|
|
37
|
-
@pool.release(Fiber.current,conn)
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# see =begin_db_transaction
|
|
42
|
-
def commit_db_transaction
|
|
43
|
-
@pool.hold do |conn|
|
|
44
|
-
conn.query("commit")
|
|
45
|
-
@pool.release(Fiber.current,conn)
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
22
|
|
|
49
|
-
#
|
|
50
|
-
def
|
|
51
|
-
@pool.
|
|
52
|
-
conn.close
|
|
53
|
-
end
|
|
23
|
+
# Replaces the current connection with a brand new one
|
|
24
|
+
def replace_acquired_connection
|
|
25
|
+
@pool.replace_acquired_connection
|
|
54
26
|
end
|
|
55
|
-
|
|
27
|
+
|
|
56
28
|
# Pass unknown methods to the connection
|
|
57
29
|
def method_missing(method, *args)
|
|
58
30
|
@pool.hold do |conn|
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
# we need Fiber.current
|
|
2
|
-
# so we must require
|
|
3
|
-
# fiber
|
|
4
|
-
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
5
|
-
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
|
6
|
-
# License:: Distributes under the same terms as Ruby
|
|
7
|
-
|
|
8
|
-
#require 'fiber'
|
|
9
|
-
|
|
10
1
|
module NeverBlock
|
|
11
2
|
module Pool
|
|
12
3
|
|
|
@@ -40,18 +31,23 @@ module NeverBlock
|
|
|
40
31
|
# every time. Once a fiber is done with its block, it attempts to fetch
|
|
41
32
|
# another one from the queue
|
|
42
33
|
def initialize(count = 50)
|
|
43
|
-
@fibers,@queue = [],[]
|
|
34
|
+
@fibers,@busy_fibers,@queue = [],{},[]
|
|
44
35
|
count.times do |i|
|
|
45
36
|
fiber = Fiber.new do |block|
|
|
46
37
|
loop do
|
|
47
38
|
block.call
|
|
39
|
+
# callbacks are called in a reverse order, much like c++ destructor
|
|
40
|
+
Fiber.current[:callbacks].pop.call while Fiber.current[:callbacks].length > 0
|
|
48
41
|
unless @queue.empty?
|
|
49
42
|
block = @queue.shift
|
|
50
43
|
else
|
|
51
|
-
|
|
44
|
+
@busy_fibers.delete(Fiber.current.object_id)
|
|
45
|
+
@fibers << Fiber.current
|
|
46
|
+
block = Fiber.yield
|
|
52
47
|
end
|
|
53
48
|
end
|
|
54
49
|
end
|
|
50
|
+
fiber[:callbacks] = []
|
|
55
51
|
fiber[:neverblock] = true
|
|
56
52
|
@fibers << fiber
|
|
57
53
|
end
|
|
@@ -61,6 +57,8 @@ module NeverBlock
|
|
|
61
57
|
# in a queue
|
|
62
58
|
def spawn(evented = true, &block)
|
|
63
59
|
if fiber = @fibers.shift
|
|
60
|
+
fiber[:callbacks] = []
|
|
61
|
+
@busy_fibers[fiber.object_id] = fiber
|
|
64
62
|
fiber[:neverblock] = evented
|
|
65
63
|
fiber.resume(block)
|
|
66
64
|
else
|
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
2
|
-
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
|
3
|
-
# License:: Distributes under the same terms as Ruby
|
|
4
|
-
|
|
5
1
|
module NeverBlock
|
|
6
2
|
module Pool
|
|
7
|
-
|
|
8
|
-
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
9
|
-
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
|
10
|
-
# License:: Distributes under the same terms as Ruby
|
|
11
|
-
#
|
|
12
3
|
# This class represents a pool of connections,
|
|
13
4
|
# you hold or release conncetions from the pool
|
|
14
5
|
# hold requests that cannot be fullfiled will be queued
|
|
@@ -58,31 +49,19 @@ module NeverBlock
|
|
|
58
49
|
end
|
|
59
50
|
end
|
|
60
51
|
|
|
52
|
+
def replace_acquired_connection
|
|
53
|
+
fiber = Fiber.current
|
|
54
|
+
conn = @connection_proc.call
|
|
55
|
+
@busy_connections[fiber] = conn
|
|
56
|
+
fiber[:connection] = conn
|
|
57
|
+
end
|
|
58
|
+
|
|
61
59
|
# If a connection is available, pass it to the block, otherwise pass
|
|
62
60
|
# the fiber to the queue till a connection is available
|
|
63
|
-
|
|
64
|
-
# before releasing the connection
|
|
65
|
-
# if inside a transaction, don't release the fiber
|
|
66
|
-
def hold(transactional = false)
|
|
61
|
+
def hold()
|
|
67
62
|
fiber = Fiber.current
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
end
|
|
71
|
-
conn = acquire(fiber)
|
|
72
|
-
begin
|
|
73
|
-
yield conn
|
|
74
|
-
ensure
|
|
75
|
-
release(fiber, conn) unless transactional
|
|
76
|
-
process_queue
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Give the fiber back to the pool
|
|
81
|
-
# you have to call this explicitly if
|
|
82
|
-
# you held a connection for a transaction
|
|
83
|
-
def release(fiber, conn)
|
|
84
|
-
@busy_connections.delete(fiber)
|
|
85
|
-
@connections << conn
|
|
63
|
+
conn = acquire(fiber)
|
|
64
|
+
yield conn
|
|
86
65
|
end
|
|
87
66
|
|
|
88
67
|
def all_connections
|
|
@@ -95,14 +74,36 @@ module NeverBlock
|
|
|
95
74
|
# Can we create one?
|
|
96
75
|
# Wait in the queue then
|
|
97
76
|
def acquire(fiber)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
77
|
+
# A special case for rails when doing ActiveRecord stuff when not yet
|
|
78
|
+
# running in the context of a request (fiber) like in the case of AR
|
|
79
|
+
# queries in environment.rb (Root Fiber)
|
|
80
|
+
return @connections.first unless fiber[:callbacks]
|
|
81
|
+
|
|
82
|
+
return fiber[:connection] if fiber[:connection]
|
|
83
|
+
conn = if !@connections.empty?
|
|
84
|
+
@connections.shift
|
|
85
|
+
elsif (@connections.length + @busy_connections.length) < @size
|
|
86
|
+
@connection_proc.call
|
|
87
|
+
else
|
|
104
88
|
Fiber.yield @queue << fiber
|
|
105
|
-
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# They're called in reverse order i.e. release then process_queue
|
|
92
|
+
fiber[:callbacks] << self.method(:process_queue)
|
|
93
|
+
fiber[:callbacks] << self.method(:release)
|
|
94
|
+
|
|
95
|
+
@busy_connections[fiber] = conn
|
|
96
|
+
fiber[:connection] = conn
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Give the fiber's connection back to the pool
|
|
100
|
+
def release()
|
|
101
|
+
fiber = Fiber.current
|
|
102
|
+
if fiber[:connection]
|
|
103
|
+
@busy_connections.delete(fiber)
|
|
104
|
+
@connections << fiber[:connection]
|
|
105
|
+
fiber[:connection] = nil
|
|
106
|
+
end
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
# Check if there are waiting fibers and
|
|
@@ -113,7 +114,7 @@ module NeverBlock
|
|
|
113
114
|
# What is really happening here?
|
|
114
115
|
# we are resuming a fiber from within
|
|
115
116
|
# another, should we call transfer instead?
|
|
116
|
-
fiber.resume @
|
|
117
|
+
fiber.resume @connections.shift
|
|
117
118
|
end
|
|
118
119
|
end
|
|
119
120
|
|
data/lib/neverblock-pg.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
$:.unshift File.expand_path(File.dirname(__FILE__))
|
|
2
|
-
|
|
2
|
+
require 'neverblock'
|
|
3
|
+
require 'never_block/db/fibered_db_connection'
|
|
4
|
+
require 'never_block/db/pooled_db_connection'
|
|
3
5
|
require 'never_block/db/fibered_postgres_connection'
|
|
4
|
-
require 'never_block/db/pooled_fibered_postgres_connection'
|
data/neverblock.gemspec
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = "neverblock"
|
|
3
|
-
s.version = "0.1.
|
|
4
|
-
s.date = "2008-
|
|
3
|
+
s.version = "0.1.5"
|
|
4
|
+
s.date = "2008-11-06"
|
|
5
5
|
s.summary = "Utilities for non-blocking stack components"
|
|
6
6
|
s.email = "oldmoe@gmail.com"
|
|
7
7
|
s.homepage = "http://github.com/oldmoe/neverblock"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: oldmoe-neverblock
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Muhammad A. Ali
|
|
@@ -11,7 +11,7 @@ autorequire:
|
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
13
|
|
|
14
|
-
date: 2008-
|
|
14
|
+
date: 2008-11-06 00:00:00 -08:00
|
|
15
15
|
default_executable:
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|