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 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
+