oldmoe-neverblock-mysql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,4 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+ require 'neverblock'
3
+ require 'never_block/db/fibered_mysql_connection'
4
+ require 'never_block/db/pooled_fibered_mysql_connection'
@@ -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
+
@@ -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
+