em-mysqlplus 0.1.3 → 0.1.4

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.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  EventMachine wrapper for the C-based MySQL / MySQLPlus Ruby gems, which provides
4
4
  callbacks, errbacks and all other niceties of EventMachine while keeping the API
5
- of the original C-based MySQL gem.
5
+ of the original C-based MySQL gem.
6
6
 
7
7
  Features:
8
8
 
@@ -25,19 +25,20 @@ Features:
25
25
 
26
26
  ## Query queueing:
27
27
 
28
- EventMachine.run {
29
- conn = EventMachine::MySQL.new(:host => 'localhost')
28
+ EventMachine.run {
29
+ conn = EventMachine::MySQL.new(:host => 'localhost')
30
30
 
31
- results = []
32
- conn.query("select 1") {|res| results.push res.fetch_row.first.to_i}
33
- conn.query("select 2") {|res| results.push res.fetch_row.first.to_i}
34
- conn.query("select 3") {|res| results.push res.fetch_row.first.to_i}
31
+ results = []
32
+ conn.query("select 1") {|res| results.push res.fetch_row.first.to_i}
33
+ conn.query("select 2") {|res| results.push res.fetch_row.first.to_i}
34
+ conn.query("select 3") {|res| results.push res.fetch_row.first.to_i}
35
35
 
36
- EventMachine.add_timer(0.05) {
37
- p results # => [1,2,3]
38
- }
39
- }
36
+ EventMachine.add_timer(0.05) {
37
+ p results # => [1,2,3]
38
+ }
39
+ }
40
40
 
41
41
  # Credits
42
42
 
43
- Original Async MySQL driver for Ruby/EventMachine - (c) 2008 Aman Gupta (tmm1)
43
+ * Original Async MySQL driver for Ruby/EventMachine - (c) 2008 Aman Gupta (tmm1)
44
+ * ActiveRecord fiber patches - Mike Perham (mperham)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{em-mysqlplus}
8
+ s.version = "0.1.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ilya Grigorik", "Aman Gupta"]
12
+ s.date = %q{2010-07-06}
13
+ s.description = %q{Async MySQL driver for Ruby/Eventmachine}
14
+ s.email = %q{ilya@igvita.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ "README.md",
20
+ "Rakefile",
21
+ "VERSION",
22
+ "em-mysqlplus.gemspec",
23
+ "lib/active_record/connection_adapters/em_mysqlplus_adapter.rb",
24
+ "lib/active_record/patches.rb",
25
+ "lib/em-activerecord.rb",
26
+ "lib/em-mysqlplus.rb",
27
+ "lib/em-mysqlplus/connection.rb",
28
+ "lib/em-mysqlplus/mysql.rb",
29
+ "spec/activerecord_spec.rb",
30
+ "spec/database.yml",
31
+ "spec/helper.rb",
32
+ "spec/mysql_spec.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/igrigorik/em-mysql}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubyforge_project = %q{em-mysqlplus}
38
+ s.rubygems_version = %q{1.3.6}
39
+ s.summary = %q{Async MySQL driver for Ruby/Eventmachine}
40
+ s.test_files = [
41
+ "spec/activerecord_spec.rb",
42
+ "spec/helper.rb",
43
+ "spec/mysql_spec.rb"
44
+ ]
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0.12.9"])
52
+ else
53
+ s.add_dependency(%q<eventmachine>, [">= 0.12.9"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<eventmachine>, [">= 0.12.9"])
57
+ end
58
+ end
59
+
@@ -0,0 +1,50 @@
1
+ require 'em-synchrony'
2
+ require 'em-synchrony/em-mysqlplus'
3
+
4
+ require 'active_record/connection_adapters/mysql_adapter'
5
+
6
+ module ActiveRecord
7
+ module ConnectionAdapters
8
+
9
+ class EmMysqlAdapter < MysqlAdapter
10
+ def initialize(connection, logger, host_parameters, connection_parameters, config)
11
+ @hostname = host_parameters[0]
12
+ @port = host_parameters[1]
13
+ @connect_parameters, @config = connection_parameters, config
14
+ super(connection, logger, nil, config)
15
+ end
16
+
17
+ def connect
18
+ @connection = EventMachine::MySQL.new({
19
+ :host => @hostname,
20
+ :port => @port,
21
+ :database => @config[:database],
22
+ :password => @config[:password],
23
+ :socket => @config[:socket]
24
+ })
25
+
26
+ configure_connection
27
+ @connection
28
+ end
29
+
30
+ end
31
+ end
32
+
33
+ class Base
34
+ def self.em_mysqlplus_connection(config) # :nodoc:
35
+ config = config.symbolize_keys
36
+ host = config[:host]
37
+ port = config[:port]
38
+ username = config[:username].to_s if config[:username]
39
+ password = config[:password].to_s if config[:password]
40
+
41
+ if config.has_key?(:database)
42
+ database = config[:database]
43
+ else
44
+ raise ArgumentError, "No database specified. Missing argument: database."
45
+ end
46
+
47
+ ConnectionAdapters::EmMysqlAdapter.new(nil, logger, [host, port], [database, username, password], config)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,102 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+
4
+ def self.fiber_pools
5
+ @fiber_pools ||= []
6
+ end
7
+ def self.register_fiber_pool(fp)
8
+ fiber_pools << fp
9
+ end
10
+
11
+ class FiberedMonitor
12
+ class Queue
13
+ def initialize
14
+ @queue = []
15
+ end
16
+
17
+ def wait(timeout)
18
+ t = timeout || 5
19
+ fiber = Fiber.current
20
+ x = EM::Timer.new(t) do
21
+ @queue.delete(fiber)
22
+ fiber.resume(false)
23
+ end
24
+ @queue << fiber
25
+ returning Fiber.yield do
26
+ x.cancel
27
+ end
28
+ end
29
+
30
+ def signal
31
+ fiber = @queue.pop
32
+ fiber.resume(true) if fiber
33
+ end
34
+ end
35
+
36
+ def synchronize
37
+ yield
38
+ end
39
+
40
+ def new_cond
41
+ Queue.new
42
+ end
43
+ end
44
+
45
+ # ActiveRecord's connection pool is based on threads. Since we are working
46
+ # with EM and a single thread, multiple fiber design, we need to provide
47
+ # our own connection pool that keys off of Fiber.current so that different
48
+ # fibers running in the same thread don't try to use the same connection.
49
+ class ConnectionPool
50
+ def initialize(spec)
51
+ @spec = spec
52
+
53
+ # The cache of reserved connections mapped to threads
54
+ @reserved_connections = {}
55
+
56
+ # The mutex used to synchronize pool access
57
+ @connection_mutex = FiberedMonitor.new
58
+ @queue = @connection_mutex.new_cond
59
+
60
+ # default 5 second timeout unless on ruby 1.9
61
+ @timeout = spec.config[:wait_timeout] || 5
62
+
63
+ # default max pool size to 5
64
+ @size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
65
+
66
+ @connections = []
67
+ @checked_out = []
68
+ end
69
+
70
+ private
71
+
72
+ def current_connection_id #:nodoc:
73
+ Fiber.current.object_id
74
+ end
75
+
76
+ # Remove stale fibers from the cache.
77
+ def remove_stale_cached_threads!(cache, &block)
78
+ keys = Set.new(cache.keys)
79
+
80
+ ActiveRecord::ConnectionAdapters.fiber_pools.each do |pool|
81
+ pool.busy_fibers.each_pair do |object_id, fiber|
82
+ keys.delete(object_id)
83
+ end
84
+ end
85
+
86
+ keys.each do |key|
87
+ next unless cache.has_key?(key)
88
+ block.call(key, cache[key])
89
+ cache.delete(key)
90
+ end
91
+ end
92
+
93
+ def checkout_and_verify(c)
94
+ @checked_out << c
95
+ c.run_callbacks :checkout
96
+ c.verify!
97
+ c
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,4 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'active_record/connection_adapters/em_mysqlplus_adapter'
4
+ require 'active_record/patches'
@@ -0,0 +1,51 @@
1
+ require 'helper'
2
+ require 'logger'
3
+ require 'yaml'
4
+ require 'erb'
5
+
6
+ require 'active_record'
7
+ require 'lib/em-activerecord'
8
+
9
+ RAILS_ENV='test'
10
+
11
+ ActiveRecord::Base.configurations = YAML::load(ERB.new(File.read(File.join(File.dirname(__FILE__), 'database.yml'))).result)
12
+ ActiveRecord::Base.default_timezone = :utc
13
+ ActiveRecord::Base.logger = Logger.new(STDOUT)
14
+ ActiveRecord::Base.logger.level = Logger::INFO
15
+ ActiveRecord::Base.pluralize_table_names = true
16
+ ActiveRecord::Base.time_zone_aware_attributes = true
17
+ Time.zone = 'UTC'
18
+
19
+ class Widget < ActiveRecord::Base; end;
20
+
21
+ describe "ActiveRecord Driver for EM-MySQLPlus" do
22
+ it "should establish AR connection" do
23
+ EventMachine.run {
24
+ Fiber.new {
25
+ ActiveRecord::Base.establish_connection
26
+ result = Widget.find_by_sql("select sleep(1)")
27
+ result.size.should == 1
28
+
29
+ EventMachine.stop
30
+ }.resume
31
+ }
32
+ end
33
+
34
+ it "should use fiber aware ConnectionPool" do
35
+ EventMachine.run {
36
+ results = []
37
+
38
+ 3.times do |n|
39
+ Fiber.new {
40
+ ActiveRecord::Base.establish_connection
41
+ results.push Widget.find_by_sql("select sleep(1)")
42
+ }.resume
43
+ end
44
+
45
+ EM.add_timer(1.5) {
46
+ results.size.should == 3
47
+ EventMachine.stop
48
+ }
49
+ }
50
+ end
51
+ end
data/spec/database.yml ADDED
@@ -0,0 +1,5 @@
1
+ test:
2
+ adapter: em_mysqlplus
3
+ database: widgets
4
+ user: root
5
+ pool: 3
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 3
9
- version: 0.1.3
8
+ - 4
9
+ version: 0.1.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ilya Grigorik
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-04-10 00:00:00 -04:00
18
+ date: 2010-07-06 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -44,9 +44,15 @@ files:
44
44
  - README.md
45
45
  - Rakefile
46
46
  - VERSION
47
+ - em-mysqlplus.gemspec
48
+ - lib/active_record/connection_adapters/em_mysqlplus_adapter.rb
49
+ - lib/active_record/patches.rb
50
+ - lib/em-activerecord.rb
47
51
  - lib/em-mysqlplus.rb
48
52
  - lib/em-mysqlplus/connection.rb
49
53
  - lib/em-mysqlplus/mysql.rb
54
+ - spec/activerecord_spec.rb
55
+ - spec/database.yml
50
56
  - spec/helper.rb
51
57
  - spec/mysql_spec.rb
52
58
  has_rdoc: true
@@ -80,5 +86,6 @@ signing_key:
80
86
  specification_version: 3
81
87
  summary: Async MySQL driver for Ruby/Eventmachine
82
88
  test_files:
89
+ - spec/activerecord_spec.rb
83
90
  - spec/helper.rb
84
91
  - spec/mysql_spec.rb