oldmoe-neverblock-mysql 0.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/README +12 -0
- data/lib/never_block/db/fibered_mysql_connection.rb +96 -0
- data/lib/never_block/db/pooled_fibered_mysql_connection.rb +77 -0
- data/lib/neverblock-mysql.rb +4 -0
- data/neverblock-mysql.gemspec +25 -0
- data/test/test.rb +48 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
== NeverBlock MySQL
|
2
|
+
|
3
|
+
A fibered, evented MySQL database driver. Blocking queries running in fibers will run in async mode and yield the fiber.
|
4
|
+
|
5
|
+
The connection socket can be accessed for future notifications. This driver can be used together with other NeverBlock components to provide a full non-blocking stack for Ruby applications.
|
6
|
+
|
7
|
+
=== Credits
|
8
|
+
|
9
|
+
Roger Pack, for helping in the file descriptor hunt :)
|
10
|
+
|
11
|
+
=== License
|
12
|
+
Ruby License, http://www.ruby-lang.org/en/LICENSE.txt.
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'mysql'
|
2
|
+
|
3
|
+
module NeverBlock
|
4
|
+
|
5
|
+
module DB
|
6
|
+
# A modified postgres connection driver
|
7
|
+
# builds on the original pg driver.
|
8
|
+
# This driver is able to register the socket
|
9
|
+
# at a certain backend (EM or Rev)
|
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
|
14
|
+
class FiberedMysqlConnection < Mysql
|
15
|
+
# needed to access the sockect by the event loop
|
16
|
+
attr_reader :fd, :io
|
17
|
+
|
18
|
+
# Creates a new postgresql connection, sets it
|
19
|
+
# to nonblocking and wraps the descriptor in an IO
|
20
|
+
# object.
|
21
|
+
def initialize(*args)
|
22
|
+
#super(*args)
|
23
|
+
@fd = socket
|
24
|
+
@io = IO.new(socket)
|
25
|
+
end
|
26
|
+
#alias :real_connect :initialize
|
27
|
+
#alias :connect :initialize
|
28
|
+
|
29
|
+
# Assuming the use of NeverBlock fiber extensions and that the exec is run in
|
30
|
+
# the context of a fiber. One that have the value :neverblock set to true.
|
31
|
+
# All neverblock IO classes check this value, setting it to false will force
|
32
|
+
# the execution in a blocking way.
|
33
|
+
def query(sql)
|
34
|
+
if Fiber.respond_to? :current and Fiber.current[:neverblock]
|
35
|
+
send_query sql
|
36
|
+
@fiber = Fiber.current
|
37
|
+
Fiber.yield
|
38
|
+
else
|
39
|
+
super(sql)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Attaches the connection socket to an event loop.
|
44
|
+
# Currently only supports EM, but Rev support will be
|
45
|
+
# completed soon.
|
46
|
+
def register_with_event_loop(loop)
|
47
|
+
if loop == :em
|
48
|
+
unless EM.respond_to?(:attach)
|
49
|
+
puts "invalide EM version, please download the modified gem from: (http://github.com/riham/eventmachine)"
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
if EM.reactor_running?
|
53
|
+
@em_connection = EM::attach(@io,EMConnectionHandler,self)
|
54
|
+
else
|
55
|
+
raise "REACTOR NOT RUNNING YA ZALAMA"
|
56
|
+
end
|
57
|
+
elsif loop.class.name == "REV::Loop"
|
58
|
+
loop.attach(RevConnectionHandler.new(socket))
|
59
|
+
else
|
60
|
+
raise "could not register with the event loop"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Unattaches the connection socket from the event loop
|
65
|
+
def unregister_from_event_loop
|
66
|
+
if @loop == :em
|
67
|
+
@em_connection.unattach(false)
|
68
|
+
else
|
69
|
+
raise NotImplementedError.new("unregister_from_event_loop not implemented for #{@loop}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The callback, this is called whenever
|
74
|
+
# there is data available at the socket
|
75
|
+
def process_command
|
76
|
+
@fiber.resume get_result
|
77
|
+
end
|
78
|
+
|
79
|
+
end #FiberedPostgresConnection
|
80
|
+
|
81
|
+
# A connection handler for EM
|
82
|
+
# More to follow.
|
83
|
+
module EMConnectionHandler
|
84
|
+
def initialize connection
|
85
|
+
@connection = connection
|
86
|
+
end
|
87
|
+
def notify_readable
|
88
|
+
@connection.process_command
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end #DB
|
93
|
+
|
94
|
+
end #NeverBlock
|
95
|
+
|
96
|
+
NeverBlock::DB::FMysql = NeverBlock::DB::FiberedMysqlConnection
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module NeverBlock
|
2
|
+
module DB
|
3
|
+
# A pooled postgres connection class.
|
4
|
+
# This class represents a proxy interface
|
5
|
+
# to a connection pool of fibered postgresql
|
6
|
+
# connections.
|
7
|
+
class PooledFiberedMysqlConnection
|
8
|
+
|
9
|
+
# Requires a hash or an array with connection parameters
|
10
|
+
# and a pool size (defaults to 4)
|
11
|
+
def initialize(size=4, &block)
|
12
|
+
@pool = NB::Pool::FiberedConnectionPool.new(:size=>size, :eager=>true) do
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# A proxy for the connection's exec method
|
18
|
+
# quries the pool to get a connection first
|
19
|
+
def exec(query)
|
20
|
+
@pool.hold do |conn|
|
21
|
+
conn.exec(query)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method must be called for transactions to work correctly.
|
26
|
+
# One cannot just send "begin" as you never know which connection
|
27
|
+
# will be available next. This method ensures you get the same connection
|
28
|
+
# while in a transaction.
|
29
|
+
def begin_db_transaction
|
30
|
+
@pool.hold(true) do |conn|
|
31
|
+
conn.exec("begin")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# see =begin_db_transaction
|
36
|
+
def rollback_db_transaction
|
37
|
+
@pool.hold do |conn|
|
38
|
+
conn.exec("rollback")
|
39
|
+
@pool.release(Fiber.current,conn)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# see =begin_db_transaction
|
44
|
+
def commit_db_transaction
|
45
|
+
@pool.hold do |conn|
|
46
|
+
conn.exec("commit")
|
47
|
+
@pool.release(Fiber.current,conn)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#close all connections and remove them from the event loop
|
52
|
+
def close
|
53
|
+
@pool.all_connections do |conn|
|
54
|
+
conn.unregister_from_event_loop
|
55
|
+
conn.close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Pass unknown methods to the connection
|
60
|
+
def method_missing(method, *args)
|
61
|
+
@pool.hold do |conn|
|
62
|
+
conn.send(method, *args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Pass method queries to the connection
|
67
|
+
def respond_to?(method)
|
68
|
+
@pool.hold do |conn|
|
69
|
+
conn.respond_to?(method)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
NeverBlock::DB::PFMysql = NeverBlock::DB::PooledFiberedMysqlConnection
|
@@ -0,0 +1,25 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "neverblock-mysql"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2008-08-13"
|
5
|
+
s.summary = "Fibered MySQL connection"
|
6
|
+
s.email = "oldmoe@gmail.com"
|
7
|
+
s.homepage = "http://github.com/oldmoe/neverblock-mysql"
|
8
|
+
s.description = "Fibered MySQL connection."
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Muhammad A. Ali"]
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.files = [
|
13
|
+
"neverblock-mysql.gemspec",
|
14
|
+
"README",
|
15
|
+
"test/test.rb",
|
16
|
+
"lib/neverblock-mysql.rb",
|
17
|
+
"lib/never_block/db/fibered_mysql_connection.rb",
|
18
|
+
"lib/never_block/db/pooled_fibered_mysql_connection.rb"
|
19
|
+
]
|
20
|
+
s.rdoc_options = ["--main", "README"]
|
21
|
+
s.extra_rdoc_files = ["README"]
|
22
|
+
#s.add_dependency("mysqlplus")
|
23
|
+
#s.add_dependency("neverblock")
|
24
|
+
end
|
25
|
+
|
data/test/test.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'neverblock-mysql'
|
2
|
+
|
3
|
+
class Mysql
|
4
|
+
attr_accessor :fiber
|
5
|
+
alias :old_query :query
|
6
|
+
def query(sql)
|
7
|
+
if Fiber.current[:neverblock]
|
8
|
+
send_query(sql)
|
9
|
+
@fiber = Fiber.current
|
10
|
+
Fiber.yield
|
11
|
+
else
|
12
|
+
old_query(sql)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def process_command
|
17
|
+
@fiber.resume get_result
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
@count = 10
|
22
|
+
@connections = {}
|
23
|
+
@fpool = NB::Pool::FiberPool.new(@count)
|
24
|
+
@cpool = NB::Pool::FiberedConnectionPool.new(size:@count, eager:true) do
|
25
|
+
c = Mysql.real_connect('localhost','root',nil)
|
26
|
+
@connections[IO.new(c.socket)] = c
|
27
|
+
c
|
28
|
+
end
|
29
|
+
|
30
|
+
@break = false
|
31
|
+
@done = 0
|
32
|
+
@t = Time.now
|
33
|
+
@count.times do
|
34
|
+
@fpool.spawn(false) do
|
35
|
+
@cpool.hold do |conn|
|
36
|
+
conn.query('select sleep(1)').each{|r| r}
|
37
|
+
@done = @done + 1
|
38
|
+
puts "done in #{Time.now - @t}" if @done == @count
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
@sockets = @connections.keys
|
43
|
+
loop do
|
44
|
+
res = select(@sockets,nil,nil,nil)
|
45
|
+
if res
|
46
|
+
res.first.each{|c|@connections[c].process_command}
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oldmoe-neverblock-mysql
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Muhammad A. Ali
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Fibered MySQL connection.
|
17
|
+
email: oldmoe@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- neverblock-mysql.gemspec
|
26
|
+
- README
|
27
|
+
- test/test.rb
|
28
|
+
- lib/neverblock-mysql.rb
|
29
|
+
- lib/never_block/db/fibered_mysql_connection.rb
|
30
|
+
- lib/never_block/db/pooled_fibered_mysql_connection.rb
|
31
|
+
has_rdoc: true
|
32
|
+
homepage: http://github.com/oldmoe/neverblock-mysql
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --main
|
36
|
+
- README
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.2.0
|
55
|
+
signing_key:
|
56
|
+
specification_version: 2
|
57
|
+
summary: Fibered MySQL connection
|
58
|
+
test_files: []
|
59
|
+
|