espace-neverblock-pg 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,8 @@
1
+ == NeverBlock PG
2
+
3
+ A fibered, evented PostgreSQL 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
+ === License
8
+ Ruby License, http://www.ruby-lang.org/en/LICENSE.txt.
@@ -0,0 +1,98 @@
1
+ require 'pg'
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 FiberedPostgresConnection < PGconn
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
+ setnonblocking(true)
26
+ end
27
+
28
+ # Assuming the use of NeverBlock fiber extensions and that the exec is run in
29
+ # the context of a fiber. One that have the value :neverblock set to true.
30
+ # All neverblock IO classes check this value, setting it to false will force
31
+ # the execution in a blocking way.
32
+ def exec(sql)
33
+ if Fiber.respond_to? :current and Fiber.current[:neverblock]
34
+ self.send_query sql
35
+ @fiber = Fiber.current
36
+ Fiber.yield
37
+ else
38
+ super(sql)
39
+ end
40
+ end
41
+
42
+ # Attaches the connection socket to an event loop.
43
+ # Currently only supports EM, but Rev support will be
44
+ # completed soon.
45
+ def register_with_event_loop(loop)
46
+ if loop == :em
47
+ unless EM.respond_to?(:attach)
48
+ puts "invalide EM version, please download the modified gem from: (TBA) "
49
+ exit
50
+ end
51
+ if EM.reactor_running?
52
+ EM::attach(@io,EMConnectionHandler,self)
53
+ else
54
+ raise "REACTOR NOT RUNNING YA ZALAMA"
55
+ end
56
+ elsif loop.class.name == "REV::Loop"
57
+ loop.attach(RevConnectionHandler.new(socket))
58
+ else
59
+ raise "could not register with the event loop"
60
+ end
61
+ end
62
+
63
+ # The callback, this is called whenever
64
+ # there is data available at the socket
65
+ def process_command
66
+ # make sure all commands are sent
67
+ # before attempting to read
68
+ return unless self.flush
69
+ self.consume_input
70
+ unless is_busy
71
+ res, data = 0, []
72
+ while res != nil
73
+ res = self.get_result
74
+ data << res unless res.nil?
75
+ end
76
+ #let the fiber continue its work
77
+ @fiber.resume(data.last)
78
+ end
79
+ end
80
+
81
+ end #FiberedPostgresConnection
82
+
83
+ # A connection handler for EM
84
+ # More to follow.
85
+ module EMConnectionHandler
86
+ def initialize connection
87
+ @connection = connection
88
+ end
89
+ def notify_readable
90
+ @connection.process_command
91
+ end
92
+ end
93
+
94
+ end #DB
95
+
96
+ end #NeverBlock
97
+
98
+ NeverBlock::DB::FPGconn = NeverBlock::DB::FiberedPostgresConnection
@@ -0,0 +1,73 @@
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 PooledFiberedPostgresConnection
8
+
9
+ # Requires a hash or an array with connection parameters
10
+ # and a pool size (defaults to 4)
11
+ def initialize(conn_params, size=4)
12
+ @pool = NB::Pool::FiberedConnectionPool.new(:size=>size, :eager=>true) do
13
+ conn = NB::DB::FPGconn.new(*conn_params) if conn_params.is_a? Array
14
+ conn = NB::DB::FPGconn.new(conn_params) if conn_params.is_a? Hash
15
+ conn.register_with_event_loop(:em)
16
+ conn
17
+ end
18
+ end
19
+
20
+ # A proxy for the connection's exec method
21
+ # quries the pool to get a connection first
22
+ def exec(query)
23
+ @pool.hold do |conn|
24
+ conn.exec(query)
25
+ end
26
+ end
27
+
28
+ # This method must be called for transactions to work correctly.
29
+ # One cannot just send "begin" as you never know which connection
30
+ # will be available next. This method ensures you get the same connection
31
+ # while in a transaction.
32
+ def begin_db_transaction
33
+ @pool.hold(true) do |conn|
34
+ conn.exec("begin")
35
+ end
36
+ end
37
+
38
+ # see =begin_db_transaction
39
+ def rollback_db_transaction
40
+ @pool.hold do |conn|
41
+ conn.exec("rollback")
42
+ @pool.release(Fiber.current,conn)
43
+ end
44
+ end
45
+
46
+ # see =begin_db_transaction
47
+ def commit_db_transaction
48
+ @pool.hold do |conn|
49
+ conn.exec("commit")
50
+ @pool.release(Fiber.current,conn)
51
+ end
52
+ end
53
+
54
+ # Pass unknown methods to the connection
55
+ def method_missing(method, *args)
56
+ @pool.hold do |conn|
57
+ conn.send(method, *args)
58
+ end
59
+ end
60
+
61
+ # Pass method queries to the connection
62
+ def respond_to?(method)
63
+ @pool.hold do |conn|
64
+ conn.respond_to?(method)
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+
72
+ NB::DB::PFPGconn = NeverBlock::DB::FiberedPostgresConnection
73
+
@@ -0,0 +1,4 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__))
2
+
3
+ require 'never_block/db/fibered_postgres_connection'
4
+ require 'never_block/db/pooled_fibered_postgres_connection'
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "neverblock-pg"
3
+ s.version = "0.1.0"
4
+ s.date = "2008-08-13"
5
+ s.summary = "Fibered PostgreSQL connection"
6
+ s.email = "oldmoe@gmail.com"
7
+ s.homepage = "http://github.com/oldmoe/neverblock-pg"
8
+ s.description = "Fibered PostgreSQL connection."
9
+ s.has_rdoc = true
10
+ s.authors = ["Muhammad A. Ali", "Ahmed Sobhi"]
11
+ s.files = [
12
+ "neverblock-pg.gemspec",
13
+ "README",
14
+ "test/test.rb",
15
+ "lib/neverblock-pg.rb",
16
+ "lib/never_block/db/fibered_postgres_connection.rb",
17
+ "lib/never_block/db/pooled_fibered_postgres_connection.rb"]
18
+ s.rdoc_options = ["--main", "README"]
19
+ s.extra_rdoc_files = ["README"]
20
+ s.add_dependency("neverblock")
21
+ s.add_dependency("pg")
22
+ end
23
+
data/test/test.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'neverblock'
2
+ require 'neverblock-pg'
3
+
4
+ $fpool = NB::Pool::FiberPool.new(24)
5
+
6
+ $long_count = ARGV[0].to_i
7
+ $freq = ARGV[1].to_i
8
+ $done = false
9
+
10
+ $connections = {}
11
+ $sockets = []
12
+ $cpool = NB::Pool::FiberedConnectionPool.new(:size=>10, :eager=>true) {
13
+ conn = NB::DB::FPGconn.new({:host=>'localhost',:user=>'postgres',:dbname=>'evented'})
14
+ $sockets << socket = IO.new(conn.socket)
15
+ $connections[socket] = conn
16
+ }
17
+
18
+ def $cpool.exec(sql)
19
+ hold do |conn|
20
+ conn.exec(sql)
21
+ end
22
+ end
23
+
24
+ def $cpool.[](sql)
25
+ self.exec(sql)
26
+ end
27
+
28
+ def $cpool.begin_db_transaction
29
+ hold(true) do |conn|
30
+ conn.exec("begin")
31
+ end
32
+ end
33
+ def $cpool.rollback_db_transaction
34
+ hold do |conn|
35
+ conn.exec("rollback")
36
+ release(Fiber.current,conn)
37
+ end
38
+ end
39
+ def $cpool.commit_db_transaction
40
+ hold do |conn|
41
+ conn.exec("commit")
42
+ release(Fiber.current,conn)
43
+ end
44
+ end
45
+
46
+ $long_query = "select sleep(1)"
47
+ $short_query = "select 1"
48
+
49
+ def run_blocking
50
+ t = Time.now
51
+ $long_count.times do |i|
52
+ $cpool[$long_query]
53
+ $freq.times do |j|
54
+ $cpool[$short_query].each{|r|r}
55
+ end
56
+ end
57
+ Time.now - t
58
+ end
59
+ print "finished blocking queries in : "
60
+ puts $b_time = run_blocking
61
+
62
+ def run_evented
63
+ $count = 0
64
+ $count_long = 0
65
+ $finished = 0
66
+ $long_count.times do |i|
67
+ $fpool.spawn do
68
+ $cpool[$long_query].each{|r|r}
69
+ $finished = $finished + 1
70
+ if $finished == ($long_count * ($freq+1))
71
+ puts ($e_l_time = Time.now - $t)
72
+ puts "advantage = #{(100 - ( $e_l_time / $b_time ) * 100).to_i}%"
73
+ stop_loop
74
+ end
75
+ end
76
+ $freq.times do |j|
77
+ $fpool.spawn do
78
+ $cpool[$short_query].each{|r|r}
79
+ $finished = $finished + 1
80
+ if $finished == ($long_count * ($freq+1))
81
+ puts ($e_l_time = Time.now - $t)
82
+ puts "advantage = #{(100 - ( $e_l_time / $b_time ) * 100).to_i}%"
83
+ stop_loop
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def stop_loop
91
+ $done = true
92
+ end
93
+
94
+ $t = Time.now
95
+ print "finished evented queries in : "
96
+ run_evented
97
+ loop do
98
+ res = select($sockets,nil,nil,nil)
99
+ res.first.each{ |s|$connections[s].process_command } if res
100
+ break if $done
101
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: espace-neverblock-pg
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Muhammad A. Ali
8
+ - Ahmed Sobhi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-08-13 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: neverblock
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: pg
27
+ version_requirement:
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: "0"
33
+ version:
34
+ description: Fibered PostgreSQL connection.
35
+ email: oldmoe@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README
42
+ files:
43
+ - neverblock-pg.gemspec
44
+ - README
45
+ - test/test.rb
46
+ - lib/neverblock-pg.rb
47
+ - lib/never_block/db/fibered_postgres_connection.rb
48
+ - lib/never_block/db/pooled_fibered_postgres_connection.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/oldmoe/neverblock-pg
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --main
54
+ - README
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ version:
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ version:
69
+ requirements: []
70
+
71
+ rubyforge_project:
72
+ rubygems_version: 1.2.0
73
+ signing_key:
74
+ specification_version: 2
75
+ summary: Fibered PostgreSQL connection
76
+ test_files: []
77
+