neverblock 0.1.6.2
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 +24 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/neverblock_mysql_adapter.rb +68 -0
- data/lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb +85 -0
- data/lib/never_block.rb +102 -0
- data/lib/never_block/db/fibered_db_connection.rb +72 -0
- data/lib/never_block/db/fibered_mysql_connection.rb +62 -0
- data/lib/never_block/db/fibered_postgres_connection.rb +64 -0
- data/lib/never_block/db/pooled_db_connection.rb +43 -0
- data/lib/never_block/extensions/fiber_extensions.rb +31 -0
- data/lib/never_block/frameworks/activerecord.rb +37 -0
- data/lib/never_block/frameworks/rails.rb +65 -0
- data/lib/never_block/pool/fiber_pool.rb +74 -0
- data/lib/never_block/pool/fibered_connection_pool.rb +130 -0
- data/lib/never_block/servers/mongrel.rb +236 -0
- data/lib/never_block/servers/thin.rb +32 -0
- data/lib/neverblock-mysql.rb +5 -0
- data/lib/neverblock-pg.rb +5 -0
- data/lib/neverblock.rb +8 -0
- data/neverblock.gemspec +73 -0
- data/spec/fiber_extensions_spec.rb +24 -0
- data/spec/fiber_pool_spec.rb +60 -0
- data/spec/fibered_connection_pool_spec.rb +106 -0
- data/tasks/spec.rake +12 -0
- data/test/test_mysql.rb +36 -0
- data/test/test_pg.rb +102 -0
- metadata +97 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
$:.unshift File.expand_path('..')
|
2
|
+
require 'lib/neverblock'
|
3
|
+
|
4
|
+
class MockConnection; end
|
5
|
+
|
6
|
+
describe NB::Pool::FiberedConnectionPool do
|
7
|
+
before(:each) do
|
8
|
+
@pool = NB::Pool::FiberedConnectionPool.new(:size => 10) do
|
9
|
+
MockConnection.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should create all connections lazily by default" do
|
14
|
+
@pool.instance_variable_get(:@connections).length.should == 0
|
15
|
+
@pool.instance_variable_get(:@busy_connections).length.should == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should create all connections eagerly if specified" do
|
19
|
+
@pool = NB::Pool::FiberedConnectionPool.new(:size => 10, :eager => true) do
|
20
|
+
MockConnection.new
|
21
|
+
end
|
22
|
+
@pool.instance_variable_get(:@connections).length.should == 10
|
23
|
+
@pool.instance_variable_get(:@busy_connections).length.should == 0
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should create and yield a connection if :size not reached" do
|
27
|
+
@pool.instance_variable_get(:@connections).length.should == 0
|
28
|
+
@pool.instance_variable_get(:@busy_connections).length.should == 0
|
29
|
+
|
30
|
+
@pool.hold {|conn| conn.should be_instance_of(MockConnection)}
|
31
|
+
|
32
|
+
@pool.instance_variable_get(:@connections).length.should == 1
|
33
|
+
@pool.instance_variable_get(:@busy_connections).length.should == 0
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should create connections up to :size and queue other requests" do
|
37
|
+
# prepate the fiber pool
|
38
|
+
fpool = NB::Pool::FiberPool.new(15)
|
39
|
+
fibers = []; fpool.fibers.each {|f| fibers << f}
|
40
|
+
progress = Array.new(15, false)
|
41
|
+
|
42
|
+
# send 15 requests to the connection pool (of size 10)
|
43
|
+
10.times do |i|
|
44
|
+
fpool.spawn do
|
45
|
+
@pool.hold do |conn|
|
46
|
+
Fiber.yield
|
47
|
+
progress[i] = Fiber.current #mark task finished
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
(10..14).each do |i|
|
52
|
+
fpool.spawn do
|
53
|
+
@pool.hold do |conn|
|
54
|
+
progress[i] = Fiber.current #mark task finished
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# 10 requests should be in progress and 5 should be queued
|
60
|
+
@pool.instance_variable_get(:@connections).length.should == 0
|
61
|
+
@pool.instance_variable_get(:@busy_connections).length.should == 10
|
62
|
+
@pool.instance_variable_get(:@queue).length.should == 5
|
63
|
+
|
64
|
+
#resume first request which will finish it and will also handle the
|
65
|
+
#queued requests
|
66
|
+
fibers[0].resume
|
67
|
+
[0,*10..14].each {|i| fibers[i].should == progress[i]}
|
68
|
+
[*1..9].each do |i|
|
69
|
+
progress[i].should == false
|
70
|
+
fibers[i].resume
|
71
|
+
progress[i].should == fibers[i]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should use the same connection in a transaction" do
|
76
|
+
#make sure there are more than one connection in the pool
|
77
|
+
@pool = NB::Pool::FiberedConnectionPool.new(:size => 10, :eager => true) do
|
78
|
+
MockConnection.new
|
79
|
+
end
|
80
|
+
fpool = NB::Pool::FiberPool.new(12)
|
81
|
+
fibers = []; fpool.fibers.each {|f| fibers << f}
|
82
|
+
t_conn = nil
|
83
|
+
fpool.spawn do
|
84
|
+
#announce the beginning of a transaction
|
85
|
+
@pool.hold(true) {|conn| t_conn = conn}
|
86
|
+
|
87
|
+
#another call to hold should get the same transaction's connection
|
88
|
+
@pool.hold {|conn| t_conn.should == conn}
|
89
|
+
|
90
|
+
#release the transaction connection
|
91
|
+
@pool.hold do |conn|
|
92
|
+
t_conn.should == conn
|
93
|
+
@pool.release(Fiber.current, conn)
|
94
|
+
end
|
95
|
+
|
96
|
+
#will now get a connection other than the transation's one (since there
|
97
|
+
#are many connections. If there was only one then it would have been
|
98
|
+
#returned anyways)
|
99
|
+
@pool.hold {|conn| t_conn.should_not == conn}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
after(:each) do
|
104
|
+
@pool = nil
|
105
|
+
end
|
106
|
+
end
|
data/tasks/spec.rake
ADDED
data/test/test_mysql.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neverblock'
|
3
|
+
require 'neverblock-mysql'
|
4
|
+
|
5
|
+
class Mysql
|
6
|
+
attr_accessor :fiber
|
7
|
+
end
|
8
|
+
|
9
|
+
@count = 100
|
10
|
+
@connections = {}
|
11
|
+
@fpool = NB::Pool::FiberPool.new(@count)
|
12
|
+
@cpool = NB::Pool::FiberedConnectionPool.new(size:@count, eager:true) do
|
13
|
+
c = NB::DB::FiberedMysqlConnection.real_connect('localhost','root',nil)
|
14
|
+
@connections[c.io] = c
|
15
|
+
c
|
16
|
+
end
|
17
|
+
|
18
|
+
@break = false
|
19
|
+
@done = 0
|
20
|
+
@t = Time.now
|
21
|
+
@count.times do
|
22
|
+
@fpool.spawn do
|
23
|
+
@cpool.hold do |conn|
|
24
|
+
conn.query('select sleep(1) as sleep').each{|r|p r}
|
25
|
+
@done = @done + 1
|
26
|
+
puts "done in #{Time.now - @t}" if @done == @count
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@sockets = @connections.keys
|
31
|
+
loop do
|
32
|
+
res = select(@sockets,nil,nil,nil)
|
33
|
+
if res
|
34
|
+
res.first.each{|s|@connections[s].resume_command}
|
35
|
+
end
|
36
|
+
end
|
data/test/test_pg.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'neverblock'
|
3
|
+
require 'neverblock-pg'
|
4
|
+
|
5
|
+
$fpool = NB::Pool::FiberPool.new(50)
|
6
|
+
|
7
|
+
$long_count = ARGV[0].to_i
|
8
|
+
$freq = ARGV[1].to_i
|
9
|
+
$done = false
|
10
|
+
|
11
|
+
$connections = {}
|
12
|
+
$sockets = []
|
13
|
+
$cpool = NB::Pool::FiberedConnectionPool.new(:size=>10, :eager=>true) {
|
14
|
+
conn = NB::DB::FPGconn.new({:host=>'localhost',:user=>'postgres',:dbname=>'evented'})
|
15
|
+
$sockets << socket = IO.new(conn.socket)
|
16
|
+
$connections[socket] = conn
|
17
|
+
}
|
18
|
+
|
19
|
+
def $cpool.exec(sql)
|
20
|
+
hold do |conn|
|
21
|
+
conn.exec(sql)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def $cpool.[](sql)
|
26
|
+
self.exec(sql)
|
27
|
+
end
|
28
|
+
|
29
|
+
def $cpool.begin_db_transaction
|
30
|
+
hold(true) do |conn|
|
31
|
+
conn.exec("begin")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
def $cpool.rollback_db_transaction
|
35
|
+
hold do |conn|
|
36
|
+
conn.exec("rollback")
|
37
|
+
release(Fiber.current,conn)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
def $cpool.commit_db_transaction
|
41
|
+
hold do |conn|
|
42
|
+
conn.exec("commit")
|
43
|
+
release(Fiber.current,conn)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
$long_query = "select sleep(1)"
|
48
|
+
$short_query = "select 1"
|
49
|
+
|
50
|
+
def run_blocking
|
51
|
+
t = Time.now
|
52
|
+
$long_count.times do |i|
|
53
|
+
$cpool[$long_query]
|
54
|
+
$freq.times do |j|
|
55
|
+
$cpool[$short_query].each{|r|r}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Time.now - t
|
59
|
+
end
|
60
|
+
print "finished blocking queries in : "
|
61
|
+
puts $b_time = run_blocking
|
62
|
+
|
63
|
+
def run_evented
|
64
|
+
$count = 0
|
65
|
+
$count_long = 0
|
66
|
+
$finished = 0
|
67
|
+
$long_count.times do |i|
|
68
|
+
$fpool.spawn do
|
69
|
+
$cpool[$long_query].each{|r|r}
|
70
|
+
$finished = $finished + 1
|
71
|
+
if $finished == ($long_count * ($freq+1))
|
72
|
+
puts ($e_l_time = Time.now - $t)
|
73
|
+
puts "advantage = #{(100 - ( $e_l_time / $b_time ) * 100).to_i}%"
|
74
|
+
stop_loop
|
75
|
+
end
|
76
|
+
end
|
77
|
+
$freq.times do |j|
|
78
|
+
$fpool.spawn do
|
79
|
+
$cpool[$short_query].each{|r|r}
|
80
|
+
$finished = $finished + 1
|
81
|
+
if $finished == ($long_count * ($freq+1))
|
82
|
+
puts ($e_l_time = Time.now - $t)
|
83
|
+
puts "advantage = #{(100 - ( $e_l_time / $b_time ) * 100).to_i}%"
|
84
|
+
stop_loop
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def stop_loop
|
92
|
+
$done = true
|
93
|
+
end
|
94
|
+
|
95
|
+
$t = Time.now
|
96
|
+
print "finished evented queries in : "
|
97
|
+
run_evented
|
98
|
+
loop do
|
99
|
+
res = select($sockets,nil,nil,nil)
|
100
|
+
res.first.each{ |s|$connections[s].resume_command } if res
|
101
|
+
break if $done
|
102
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: neverblock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.6.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Muhammad A. Ali
|
8
|
+
- Ahmed Sobhi
|
9
|
+
- Osama Brekaa
|
10
|
+
- Nicholas Silva
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
|
15
|
+
date: 2010-02-03 00:00:00 -05:00
|
16
|
+
default_executable:
|
17
|
+
dependencies:
|
18
|
+
- !ruby/object:Gem::Dependency
|
19
|
+
name: eventmachine
|
20
|
+
type: :runtime
|
21
|
+
version_requirement:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.12.2
|
27
|
+
version:
|
28
|
+
description: NeverBlock is a collection of classes and modules that help you write evented non-blocking applications in a seemingly blocking mannner.
|
29
|
+
email: conickal@gmail.com
|
30
|
+
executables: []
|
31
|
+
|
32
|
+
extensions: []
|
33
|
+
|
34
|
+
extra_rdoc_files:
|
35
|
+
- README
|
36
|
+
files:
|
37
|
+
- README
|
38
|
+
- Rakefile
|
39
|
+
- VERSION
|
40
|
+
- lib/active_record/connection_adapters/neverblock_mysql_adapter.rb
|
41
|
+
- lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb
|
42
|
+
- lib/never_block.rb
|
43
|
+
- lib/never_block/db/fibered_db_connection.rb
|
44
|
+
- lib/never_block/db/fibered_mysql_connection.rb
|
45
|
+
- lib/never_block/db/fibered_postgres_connection.rb
|
46
|
+
- lib/never_block/db/pooled_db_connection.rb
|
47
|
+
- lib/never_block/extensions/fiber_extensions.rb
|
48
|
+
- lib/never_block/frameworks/activerecord.rb
|
49
|
+
- lib/never_block/frameworks/rails.rb
|
50
|
+
- lib/never_block/pool/fiber_pool.rb
|
51
|
+
- lib/never_block/pool/fibered_connection_pool.rb
|
52
|
+
- lib/never_block/servers/mongrel.rb
|
53
|
+
- lib/never_block/servers/thin.rb
|
54
|
+
- lib/neverblock-mysql.rb
|
55
|
+
- lib/neverblock-pg.rb
|
56
|
+
- lib/neverblock.rb
|
57
|
+
- neverblock.gemspec
|
58
|
+
- spec/fiber_extensions_spec.rb
|
59
|
+
- spec/fiber_pool_spec.rb
|
60
|
+
- spec/fibered_connection_pool_spec.rb
|
61
|
+
- tasks/spec.rake
|
62
|
+
- test/test_mysql.rb
|
63
|
+
- test/test_pg.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: http://github.com/conickal/neverblock
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options:
|
70
|
+
- --charset=UTF-8
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.3.5
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Utilities for non-blocking stack components
|
92
|
+
test_files:
|
93
|
+
- spec/fiber_extensions_spec.rb
|
94
|
+
- spec/fiber_pool_spec.rb
|
95
|
+
- spec/fibered_connection_pool_spec.rb
|
96
|
+
- test/test_mysql.rb
|
97
|
+
- test/test_pg.rb
|