michaelyta-neverblock-postgresql-adapter 0.1
Sign up to get free protection for your applications and to get access to all the features.
data/README
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Installation and Usage
|
2
|
+
======================
|
3
|
+
|
4
|
+
1. First, you need to get mysqlplus :
|
5
|
+
sudo gem install mysqlplus
|
6
|
+
|
7
|
+
2. Then, get the mysql neverblock adapter :
|
8
|
+
sudo gem install michaelyta-neverblock-postgresql-adapter -s http://gems.github.com
|
9
|
+
|
10
|
+
3. Finally, update config/database.yml :
|
11
|
+
production:
|
12
|
+
adapter: neverblock_postgresql
|
13
|
+
database: myapp_production
|
14
|
+
username: root
|
15
|
+
password:
|
16
|
+
host: localhost
|
17
|
+
pool: 6
|
18
|
+
|
19
|
+
And you are done, this will work seamlessly, no need to update any application code.
|
20
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Require original mysql adapter as we'll just extend it
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
require 'neverblock'
|
4
|
+
require 'fibered_postgresql_connection'
|
5
|
+
|
6
|
+
class ActiveRecord::ConnectionAdapters::NeverBlockPostgreSQLAdapter < ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
7
|
+
# Returns 'FiberedPostgreSQL' as adapter name for identification purposes.
|
8
|
+
def adapter_name
|
9
|
+
'NeverBlockPostgreSQL'
|
10
|
+
end
|
11
|
+
|
12
|
+
def connect
|
13
|
+
@connection = ::NB::DB::FiberedPostgresConnection.connect(*@connection_parameters[1..(@connection_parameters.length-1)])
|
14
|
+
end
|
15
|
+
|
16
|
+
# Close then reopen the connection.
|
17
|
+
def reconnect!
|
18
|
+
disconnect!
|
19
|
+
connect
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class ActiveRecord::ConnectionAdapters::ConnectionPool
|
25
|
+
def current_connection_id #:nodoc:
|
26
|
+
NB::Fiber.current.object_id
|
27
|
+
end
|
28
|
+
|
29
|
+
def checkout
|
30
|
+
# Checkout an available connection
|
31
|
+
loop do
|
32
|
+
conn = if @checked_out.size < @connections.size
|
33
|
+
checkout_existing_connection
|
34
|
+
elsif @connections.size < @size
|
35
|
+
checkout_new_connection
|
36
|
+
end
|
37
|
+
return conn if conn
|
38
|
+
# No connections available; wait for one
|
39
|
+
@waiting ||= []
|
40
|
+
NB::Fiber.yield @waiting << NB::Fiber.current
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def checkin(conn)
|
45
|
+
conn.run_callbacks :checkin
|
46
|
+
@checked_out.delete conn
|
47
|
+
if @waiting && @waiting.size > 0
|
48
|
+
@waiting.shift.resume
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class ActiveRecord::Base
|
54
|
+
# Establishes a connection to the database that's used by all Active Record objects
|
55
|
+
def self.neverblock_postgresql_connection(config) # :nodoc:
|
56
|
+
config = config.symbolize_keys
|
57
|
+
host = config[:host]
|
58
|
+
port = config[:port] || 5432
|
59
|
+
username = config[:username].to_s
|
60
|
+
password = config[:password].to_s
|
61
|
+
size = config[:connections] || 4
|
62
|
+
|
63
|
+
if config.has_key?(:database)
|
64
|
+
database = config[:database]
|
65
|
+
else
|
66
|
+
raise ArgumentError, "No database specified. Missing argument: database."
|
67
|
+
end
|
68
|
+
|
69
|
+
# The postgres drivers don't allow the creation of an unconnected PGconn object,
|
70
|
+
# so just pass a nil connection object for the time being.
|
71
|
+
::ActiveRecord::ConnectionAdapters::NeverBlockPostgreSQLAdapter.new(nil, logger, [size, host, port, nil, nil, database, username, password], config)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pg'
|
2
|
+
|
3
|
+
module NeverBlock
|
4
|
+
|
5
|
+
module DB
|
6
|
+
|
7
|
+
# A modified postgres connection driver
|
8
|
+
# builds on the original pg driver.
|
9
|
+
# This driver is able to register the socket
|
10
|
+
# at a certain backend (Reacotr)
|
11
|
+
# and then whenever the query is executed
|
12
|
+
# within the scope of a friendly fiber (NB::Fiber)
|
13
|
+
# it will be done in async mode and the fiber
|
14
|
+
# will yield
|
15
|
+
class FiberedPostgresConnection < PGconn
|
16
|
+
|
17
|
+
# Assuming the use of NeverBlock fiber extensions and that the exec is run in
|
18
|
+
# the context of a fiber. One that have the value :neverblock set to true.
|
19
|
+
# All neverblock IO classes check this value, setting it to false will force
|
20
|
+
# the execution in a blocking way.
|
21
|
+
def exec(sql)
|
22
|
+
# TODO Still not "killing the query process"-proof
|
23
|
+
# In some cases, the query is simply sent but the fiber never yields
|
24
|
+
if NB.neverblocking? && NB.reactor.running?
|
25
|
+
send_query sql
|
26
|
+
while is_busy
|
27
|
+
NB.wait(:read, IO.new(socket))
|
28
|
+
consume_input
|
29
|
+
end
|
30
|
+
res, data = 0, []
|
31
|
+
while res != nil
|
32
|
+
res = self.get_result
|
33
|
+
data << res unless res.nil?
|
34
|
+
end
|
35
|
+
data.last
|
36
|
+
else
|
37
|
+
super(sql)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
alias_method :query, :exec
|
42
|
+
|
43
|
+
end #FiberedPostgresConnection
|
44
|
+
|
45
|
+
end #DB
|
46
|
+
|
47
|
+
end #NeverBlock
|
48
|
+
|
49
|
+
NeverBlock::DB::FPGConn = NeverBlock::DB::FiberedPostgresConnection
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "neverblock-postgresql-adapter"
|
3
|
+
s.version = "0.1"
|
4
|
+
s.date = "2009-07-19"
|
5
|
+
s.summary = "PostgreSQL Asyncronous AR connection adapter"
|
6
|
+
s.email = "oldmoe@gmail.com"
|
7
|
+
s.homepage = "http://github.com/michaelyta/neverblock-postgresql-adapter"
|
8
|
+
s.description = "A new postgresql asyncronous connection adapter for active_record using neverblock"
|
9
|
+
s.has_rdoc = false
|
10
|
+
s.authors = ["Muhammad A. Ali", "Michael Youssef"]
|
11
|
+
s.files = [
|
12
|
+
"neverblock-postgresql-adapter.gemspec",
|
13
|
+
"README",
|
14
|
+
"lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb",
|
15
|
+
"lib/fibered_postgresql_connection.rb",
|
16
|
+
"test/active_record_postgresql_test.rb"
|
17
|
+
]
|
18
|
+
# s.rdoc_options = ["--main", "README"]
|
19
|
+
# s.extra_rdoc_files = ["README"]
|
20
|
+
s.add_dependency('neverblock', '>= 1.0')
|
21
|
+
s.add_dependency('mysqlplus', '>=0.1.1')
|
22
|
+
end
|
23
|
+
|
24
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'minitest/unit'
|
2
|
+
require 'neverblock'
|
3
|
+
require 'activerecord'
|
4
|
+
require '../lib/fibered_postgresql_connection'
|
5
|
+
|
6
|
+
class Book < ActiveRecord::Base
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
MiniTest::Unit.autorun
|
12
|
+
|
13
|
+
|
14
|
+
class ActiverecordTest < MiniTest::Unit::TestCase
|
15
|
+
def setup
|
16
|
+
super
|
17
|
+
ActiveRecord::Base.configurations = {
|
18
|
+
'test' => {
|
19
|
+
:adapter => 'neverblock_postgresql',
|
20
|
+
:username => 'postgres',
|
21
|
+
:password => 'postgres',
|
22
|
+
:encoding => 'utf8',
|
23
|
+
:database => 'postgres',
|
24
|
+
:pool => 8
|
25
|
+
}
|
26
|
+
}
|
27
|
+
ActiveRecord::Base.establish_connection 'test'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_concurrency
|
31
|
+
count = 17
|
32
|
+
done = 0
|
33
|
+
t = Time.now
|
34
|
+
NB.reactor.run do
|
35
|
+
(1..count).each do
|
36
|
+
NB::Fiber.new do
|
37
|
+
Book.find_by_sql("select sleep(1) as sleep")
|
38
|
+
ActiveRecord::Base.connection_pool.release_connection
|
39
|
+
done += 1
|
40
|
+
puts done
|
41
|
+
if done == count
|
42
|
+
NB.reactor.stop
|
43
|
+
end
|
44
|
+
end.resume
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_in_delta Time.now - t, 3, 1
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: michaelyta-neverblock-postgresql-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.1"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Muhammad A. Ali
|
8
|
+
- Michael Youssef
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2009-07-19 00:00:00 -07:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: neverblock
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "1.0"
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: mysqlplus
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.1.1
|
35
|
+
version:
|
36
|
+
description: A new postgresql asyncronous connection adapter for active_record using neverblock
|
37
|
+
email: oldmoe@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- neverblock-postgresql-adapter.gemspec
|
46
|
+
- README
|
47
|
+
- lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb
|
48
|
+
- lib/fibered_postgresql_connection.rb
|
49
|
+
- test/active_record_postgresql_test.rb
|
50
|
+
has_rdoc: false
|
51
|
+
homepage: http://github.com/michaelyta/neverblock-postgresql-adapter
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
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: PostgreSQL Asyncronous AR connection adapter
|
76
|
+
test_files: []
|
77
|
+
|