fibered_mysql2 0.1.0.pre.3 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/Appraisals +1 -1
- data/CHANGELOG.md +20 -6
- data/Gemfile +1 -0
- data/Gemfile.lock +18 -11
- data/README.md +1 -1
- data/fibered_mysql2.gemspec +6 -4
- data/gemfiles/rails_6.gemfile +1 -1
- data/lib/active_record/connection_adapters/fibered_mysql2_adapter.rb +23 -4
- data/lib/fibered_mysql2.rb +5 -1
- data/lib/fibered_mysql2/fibered_database_connection_pool.rb +223 -0
- data/lib/fibered_mysql2/fibered_mutex_with_waiter_priority.rb +33 -0
- data/lib/fibered_mysql2/fibered_mysql2_connection_factory.rb +81 -0
- data/lib/fibered_mysql2/version.rb +1 -1
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 03d7285011a1fd36ca7d030a233bdeb46900e44c512161abd0241c653b5cabd4
|
4
|
+
data.tar.gz: 5ec6253f493c773a11207664df054dab32f5cfaf996fbb4706bb76d89cd04b1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 890bb36f3cbd96021d0afa0d3ce06b1d02765afc8be3d7335d5b6234ec6b6e11b58a24b4b499d0332a2a01c778757dd5c880af6291e7f535a740e2da9be2ef62
|
7
|
+
data.tar.gz: 0cc5c22298ca1bd4c6c443738b6aa1c306d412894141660f1ce49e4dc592474c172c014073b0a6e088506d3422c8983b21b00a9bd8bd018fd75a1b0904f33782
|
data/.rspec
CHANGED
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,11 +4,25 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
4
4
|
|
5
5
|
Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
-
## [0.1.
|
7
|
+
## [0.1.2] - 2021-06-16
|
8
|
+
### Fixed
|
9
|
+
- Added checking to be certain that @owner is never overwritten with a non-Fiber by another mixin.
|
10
|
+
|
11
|
+
## [0.1.1] - 2021-02-12
|
12
|
+
### Fixed
|
13
|
+
- Fixed bug with Rails 5+ adapter where connections that have `steal!` called on them were not having their owner updated to the current Fiber, which would then cause an exception when trying to expire the connection (this showed up with the Rails 5 `ConnectionPool::Reaper` that reaps unused connections)
|
14
|
+
|
15
|
+
### Changed
|
16
|
+
- Updated Rails 6 dependency to 6.0.x for now as 6.1+ requires a newer version of the mysql gem (0.5+) that we do not yet support
|
17
|
+
|
18
|
+
|
19
|
+
## [0.1.0] - 2020-10-23
|
8
20
|
### Added
|
9
|
-
-
|
10
|
-
-
|
11
|
-
- TravisCI unit test pipeline.
|
12
|
-
-
|
21
|
+
- Added an adapter for Rails 4, 5, and 6.
|
22
|
+
- Added appraisals for Rails 4, 5, and 6.
|
23
|
+
- Added TravisCI unit test pipeline.
|
24
|
+
- Added coverage reports via Coveralls.
|
13
25
|
|
14
|
-
[0.1.
|
26
|
+
[0.1.2]: https://github.com/Invoca/fibered_mysql2/compare/v0.1.1..v0.1.2
|
27
|
+
[0.1.1]: https://github.com/Invoca/fibered_mysql2/compare/v0.1.0..v0.1.1
|
28
|
+
[0.1.0]: https://github.com/Invoca/fibered_mysql2/tree/v0.1.0
|
data/Gemfile
CHANGED
@@ -8,6 +8,7 @@ gemspec
|
|
8
8
|
gem 'appraisal'
|
9
9
|
gem 'bundler', '~> 1.8'
|
10
10
|
gem 'coveralls', require: false
|
11
|
+
gem 'mimemagic', '~> 0.3', git: 'git@github.com:Invoca/mimemagic', ref: 'b084ce8d50c080f5a312156498be21a541fe72a2'
|
11
12
|
gem 'mysql2', '0.4.5'
|
12
13
|
gem 'pry', '~> 0.13'
|
13
14
|
gem 'pry-byebug', '~> 3.9'
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git@github.com:Invoca/mimemagic
|
3
|
+
revision: b084ce8d50c080f5a312156498be21a541fe72a2
|
4
|
+
ref: b084ce8d50c080f5a312156498be21a541fe72a2
|
5
|
+
specs:
|
6
|
+
mimemagic (0.3.5)
|
7
|
+
|
1
8
|
PATH
|
2
9
|
remote: .
|
3
10
|
specs:
|
4
|
-
fibered_mysql2 (0.1.
|
11
|
+
fibered_mysql2 (0.1.2)
|
5
12
|
em-synchrony (~> 1.0)
|
6
13
|
rails (>= 4.2, < 7)
|
7
14
|
|
@@ -63,14 +70,14 @@ GEM
|
|
63
70
|
minitest (~> 5.1)
|
64
71
|
tzinfo (~> 1.1)
|
65
72
|
zeitwerk (~> 2.2, >= 2.2.2)
|
66
|
-
appraisal (2.
|
73
|
+
appraisal (2.4.0)
|
67
74
|
bundler
|
68
75
|
rake
|
69
76
|
thor (>= 0.14.0)
|
70
77
|
builder (3.2.4)
|
71
78
|
byebug (11.1.3)
|
72
79
|
coderay (1.1.3)
|
73
|
-
concurrent-ruby (1.1.
|
80
|
+
concurrent-ruby (1.1.8)
|
74
81
|
coveralls (0.8.23)
|
75
82
|
json (>= 1.8, < 3)
|
76
83
|
simplecov (~> 0.16.1)
|
@@ -82,14 +89,14 @@ GEM
|
|
82
89
|
docile (1.3.2)
|
83
90
|
em-synchrony (1.0.6)
|
84
91
|
eventmachine (>= 1.0.0.beta.1)
|
85
|
-
erubi (1.
|
92
|
+
erubi (1.10.0)
|
86
93
|
eventmachine (1.2.7)
|
87
94
|
globalid (0.4.2)
|
88
95
|
activesupport (>= 4.2.0)
|
89
|
-
i18n (1.8.
|
96
|
+
i18n (1.8.7)
|
90
97
|
concurrent-ruby (~> 1.0)
|
91
98
|
json (2.3.1)
|
92
|
-
loofah (2.
|
99
|
+
loofah (2.8.0)
|
93
100
|
crass (~> 1.0.2)
|
94
101
|
nokogiri (>= 1.5.9)
|
95
102
|
mail (2.7.1)
|
@@ -97,10 +104,9 @@ GEM
|
|
97
104
|
marcel (0.3.3)
|
98
105
|
mimemagic (~> 0.3.2)
|
99
106
|
method_source (1.0.0)
|
100
|
-
mimemagic (0.3.5)
|
101
107
|
mini_mime (1.0.2)
|
102
108
|
mini_portile2 (2.4.0)
|
103
|
-
minitest (5.14.
|
109
|
+
minitest (5.14.3)
|
104
110
|
mysql2 (0.4.5)
|
105
111
|
nio4r (2.5.4)
|
106
112
|
nokogiri (1.10.10)
|
@@ -173,12 +179,12 @@ GEM
|
|
173
179
|
thread_safe (0.3.6)
|
174
180
|
tins (1.25.0)
|
175
181
|
sync
|
176
|
-
tzinfo (1.2.
|
182
|
+
tzinfo (1.2.9)
|
177
183
|
thread_safe (~> 0.1)
|
178
184
|
websocket-driver (0.7.3)
|
179
185
|
websocket-extensions (>= 0.1.0)
|
180
186
|
websocket-extensions (0.1.5)
|
181
|
-
zeitwerk (2.4.
|
187
|
+
zeitwerk (2.4.1)
|
182
188
|
|
183
189
|
PLATFORMS
|
184
190
|
ruby
|
@@ -188,6 +194,7 @@ DEPENDENCIES
|
|
188
194
|
bundler (~> 1.8)
|
189
195
|
coveralls
|
190
196
|
fibered_mysql2!
|
197
|
+
mimemagic (~> 0.3)!
|
191
198
|
mysql2 (= 0.4.5)
|
192
199
|
pry (~> 0.13)
|
193
200
|
pry-byebug (~> 3.9)
|
@@ -195,4 +202,4 @@ DEPENDENCIES
|
|
195
202
|
rspec (~> 3.0)
|
196
203
|
|
197
204
|
BUNDLED WITH
|
198
|
-
1.17.
|
205
|
+
1.17.3
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Behaves the same as `ActiveRecord::ConnectionAdapters::EMMysql2Adapter` but with
|
|
29
29
|
```ruby
|
30
30
|
connection = FiberedMysql2::FiberedMysql2Adapter.new(client, logger, options, config)
|
31
31
|
connection.lease
|
32
|
-
connection.expire
|
32
|
+
connection.expire # Rails 5+ only
|
33
33
|
```
|
34
34
|
|
35
35
|
## Development
|
data/fibered_mysql2.gemspec
CHANGED
@@ -7,16 +7,18 @@ require "fibered_mysql2/version"
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = "fibered_mysql2"
|
9
9
|
spec.version = FiberedMysql2::VERSION
|
10
|
-
spec.authors = ["
|
11
|
-
spec.email = ["
|
10
|
+
spec.authors = ["Invoca Development"]
|
11
|
+
spec.email = ["development@invoca.com"]
|
12
12
|
|
13
13
|
spec.summary = "An adapter for fibered mysql2"
|
14
14
|
spec.homepage = "https://github.com/Invoca/fibered_mysql2"
|
15
15
|
|
16
16
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
17
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
-
spec.metadata
|
19
|
-
|
18
|
+
spec.metadata = {
|
19
|
+
"allowed_push_host" => "https://rubygems.org",
|
20
|
+
"homepage_uri" => spec.homepage
|
21
|
+
}
|
20
22
|
|
21
23
|
# Specify which files should be added to the gem when it is released.
|
22
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
data/gemfiles/rails_6.gemfile
CHANGED
@@ -20,10 +20,10 @@ module FiberedMysql2
|
|
20
20
|
def lease
|
21
21
|
if in_use?
|
22
22
|
msg = "Cannot lease connection, ".dup
|
23
|
-
if
|
23
|
+
if owner_fiber == Fiber.current
|
24
24
|
msg << "it is already leased by the current fiber."
|
25
25
|
else
|
26
|
-
msg << "it is already in use by a different fiber: #{
|
26
|
+
msg << "it is already in use by a different fiber: #{owner_fiber}. " \
|
27
27
|
"Current fiber: #{Fiber.current}."
|
28
28
|
end
|
29
29
|
raise ::ActiveRecord::ActiveRecordError, msg
|
@@ -37,9 +37,9 @@ module FiberedMysql2
|
|
37
37
|
# Because we are actively releasing connections from dead fibers, we only want
|
38
38
|
# to enforce that we're expiring the current fibers connection, iff the owner
|
39
39
|
# of the connection is still alive.
|
40
|
-
if
|
40
|
+
if owner_fiber.alive? && owner_fiber != Fiber.current
|
41
41
|
raise ::ActiveRecord::ActiveRecordError, "Cannot expire connection, " \
|
42
|
-
"it is owned by a different fiber: #{
|
42
|
+
"it is owned by a different fiber: #{owner_fiber}. " \
|
43
43
|
"Current fiber: #{Fiber.current}."
|
44
44
|
end
|
45
45
|
|
@@ -49,6 +49,25 @@ module FiberedMysql2
|
|
49
49
|
raise ::ActiveRecord::ActiveRecordError, "Cannot expire connection, it is not currently leased."
|
50
50
|
end
|
51
51
|
end
|
52
|
+
|
53
|
+
def steal!
|
54
|
+
if in_use?
|
55
|
+
if owner_fiber != Fiber.current
|
56
|
+
pool.send :remove_connection_from_thread_cache, self, owner_fiber
|
57
|
+
|
58
|
+
@owner = Fiber.current
|
59
|
+
end
|
60
|
+
else
|
61
|
+
raise ::ActiveRecord::ActiveRecordError, "Cannot steal connection, it is not currently leased."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def owner_fiber
|
68
|
+
@owner.is_a?(Fiber) or raise "@owner must be a Fiber! Found #{@owner.inspect}"
|
69
|
+
@owner
|
70
|
+
end
|
52
71
|
end
|
53
72
|
|
54
73
|
class FiberedMysql2Adapter < ::ActiveRecord::ConnectionAdapters::EMMysql2Adapter
|
data/lib/fibered_mysql2.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'fibered_mysql2/version'
|
4
|
+
require_relative '../lib/active_record/connection_adapters/fibered_mysql2_adapter'
|
5
|
+
require 'fibered_mysql2/fibered_database_connection_pool'
|
6
|
+
require 'fibered_mysql2/fibered_mutex_with_waiter_priority'
|
7
|
+
require 'fibered_mysql2/fibered_mysql2_connection_factory'
|
4
8
|
|
5
9
|
module FiberedMysql2
|
6
10
|
class Error < StandardError; end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This class behaves the same as ActiveRecord's ConnectionPool, but synchronizes with fibers rather than threads.
|
4
|
+
|
5
|
+
# Note - trace statements have been commented out. This is useful trace but we do not want it on by default.
|
6
|
+
# When we have configurable logging we can put this back and have it off by default.
|
7
|
+
|
8
|
+
require 'em-synchrony'
|
9
|
+
require 'em-synchrony/thread'
|
10
|
+
require 'fibered_mysql2/fibered_mutex_with_waiter_priority'
|
11
|
+
|
12
|
+
EventMachine::Synchrony::Thread::Mutex.prepend(FiberedMysql2::FiberedMutexWithWaiterPriority)
|
13
|
+
|
14
|
+
module FiberedMysql2
|
15
|
+
class FiberedConditionVariable < MonitorMixin::ConditionVariable
|
16
|
+
def initialize(monitor)
|
17
|
+
@monitor = monitor
|
18
|
+
@cond = EM::Synchrony::Thread::ConditionVariable.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# From Ruby's MonitorMixin, with all occurrences of Thread changed to Fiber
|
23
|
+
module FiberedMonitorMixin
|
24
|
+
def self.extend_object(obj)
|
25
|
+
super
|
26
|
+
obj.__send__(:mon_initialize)
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Attempts to enter exclusive section. Returns +false+ if lock fails.
|
31
|
+
#
|
32
|
+
def mon_try_enter
|
33
|
+
if @mon_owner != Fiber.current
|
34
|
+
@mon_mutex.try_lock or return false
|
35
|
+
@mon_owner = Fiber.current
|
36
|
+
@mon_count = 0
|
37
|
+
end
|
38
|
+
@mon_count += 1
|
39
|
+
true
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Enters exclusive section.
|
44
|
+
#
|
45
|
+
def mon_enter
|
46
|
+
if @mon_owner != Fiber.current
|
47
|
+
@mon_mutex.lock
|
48
|
+
@mon_owner = Fiber.current
|
49
|
+
@mon_count = 0
|
50
|
+
end
|
51
|
+
@mon_count += 1
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Leaves exclusive section.
|
56
|
+
#
|
57
|
+
def mon_exit
|
58
|
+
mon_check_owner
|
59
|
+
@mon_count -= 1
|
60
|
+
if @mon_count == 0
|
61
|
+
@mon_owner = nil
|
62
|
+
@mon_mutex.unlock
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Enters exclusive section and executes the block. Leaves the exclusive
|
68
|
+
# section automatically when the block exits. See example under
|
69
|
+
# +MonitorMixin+.
|
70
|
+
#
|
71
|
+
def mon_synchronize
|
72
|
+
mon_enter
|
73
|
+
begin
|
74
|
+
yield
|
75
|
+
ensure
|
76
|
+
begin
|
77
|
+
mon_exit
|
78
|
+
rescue => ex
|
79
|
+
ActiveRecord::Base.logger.error("Exception occurred while executing mon_exit: #{ex}")
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
alias synchronize mon_synchronize
|
84
|
+
|
85
|
+
#
|
86
|
+
# Creates a new FiberedConditionVariable associated with the
|
87
|
+
# receiver.
|
88
|
+
#
|
89
|
+
def new_cond
|
90
|
+
FiberedConditionVariable.new(self)
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# Initializes the FiberedMonitorMixin after being included in a class
|
96
|
+
def mon_initialize
|
97
|
+
@mon_owner = nil
|
98
|
+
@mon_count = 0
|
99
|
+
@mon_mutex = EM::Synchrony::Thread::Mutex.new
|
100
|
+
end
|
101
|
+
|
102
|
+
def mon_check_owner
|
103
|
+
@mon_owner == Fiber.current or raise FiberError, "current fiber not owner"
|
104
|
+
end
|
105
|
+
|
106
|
+
def mon_enter_for_cond(count)
|
107
|
+
@mon_owner = Fiber.current
|
108
|
+
@mon_count = count
|
109
|
+
end
|
110
|
+
|
111
|
+
# returns the old mon_count
|
112
|
+
def mon_exit_for_cond
|
113
|
+
count = @mon_count
|
114
|
+
@mon_owner = nil
|
115
|
+
@mon_count = 0
|
116
|
+
count
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
module FiberedDatabaseConnectionPool
|
121
|
+
include FiberedMonitorMixin
|
122
|
+
|
123
|
+
module Adapter_4_2
|
124
|
+
def cached_connections
|
125
|
+
@reserved_connections
|
126
|
+
end
|
127
|
+
|
128
|
+
def current_connection_id
|
129
|
+
ActiveRecord::Base.connection_id ||= Fiber.current.object_id
|
130
|
+
end
|
131
|
+
|
132
|
+
def checkout
|
133
|
+
begin
|
134
|
+
reap_connections
|
135
|
+
rescue => ex
|
136
|
+
ActiveRecord::Base.logger.error("Exception occurred while executing reap_connections: #{ex}")
|
137
|
+
end
|
138
|
+
super
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
module Adapter_5_2
|
143
|
+
def cached_connections
|
144
|
+
@thread_cached_conns
|
145
|
+
end
|
146
|
+
|
147
|
+
def current_connection_id
|
148
|
+
connection_cache_key(current_thread)
|
149
|
+
end
|
150
|
+
|
151
|
+
def checkout(checkout_timeout = @checkout_timeout)
|
152
|
+
begin
|
153
|
+
reap_connections
|
154
|
+
rescue => ex
|
155
|
+
ActiveRecord::Base.logger.error("Exception occurred while executing reap_connections: #{ex}")
|
156
|
+
end
|
157
|
+
super
|
158
|
+
end
|
159
|
+
|
160
|
+
def release_connection(owner_thread = Fiber.current)
|
161
|
+
if (conn = @thread_cached_conns.delete(connection_cache_key(owner_thread)))
|
162
|
+
checkin(conn)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
case Rails::VERSION::MAJOR
|
168
|
+
when 4
|
169
|
+
include Adapter_4_2
|
170
|
+
when 5, 6
|
171
|
+
include Adapter_5_2
|
172
|
+
end
|
173
|
+
|
174
|
+
def initialize(connection_spec, *args, **keyword_args)
|
175
|
+
connection_spec.config[:reaping_frequency] and raise "reaping_frequency is not supported (the ActiveRecord Reaper is thread-based)"
|
176
|
+
|
177
|
+
super(connection_spec, *args, **keyword_args)
|
178
|
+
|
179
|
+
@reaper = nil # no need to keep a reference to this since it does nothing in this sub-class
|
180
|
+
|
181
|
+
# note that @reserved_connections is a ThreadSafe::Cache which is overkill in a fibered world, but harmless
|
182
|
+
end
|
183
|
+
|
184
|
+
def connection
|
185
|
+
# this is correctly done double-checked locking
|
186
|
+
# (ThreadSafe::Cache's lookups have volatile semantics)
|
187
|
+
if (result = cached_connections[current_connection_id])
|
188
|
+
result
|
189
|
+
else
|
190
|
+
synchronize do
|
191
|
+
if (result = cached_connections[current_connection_id])
|
192
|
+
result
|
193
|
+
else
|
194
|
+
cached_connections[current_connection_id] = checkout
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def reap_connections
|
201
|
+
cached_connections.values.each do |connection|
|
202
|
+
unless connection.owner.alive?
|
203
|
+
checkin(connection)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
#--
|
211
|
+
# This hook-in method allows for easier monkey-patching fixes needed by
|
212
|
+
# JRuby users that use Fibers.
|
213
|
+
def connection_cache_key(fiber)
|
214
|
+
fiber
|
215
|
+
end
|
216
|
+
|
217
|
+
def current_thread
|
218
|
+
Fiber.current
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(FiberedMysql2::FiberedDatabaseConnectionPool)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FiberedMysql2
|
4
|
+
module FiberedMutexWithWaiterPriority
|
5
|
+
# Note: @waiters is a bit confusing because the first waiter is actually the current fiber that has it locked;
|
6
|
+
# the _rest_ of @waiters are the actual waiters
|
7
|
+
def sleep(timeout = nil)
|
8
|
+
unlock
|
9
|
+
beg = Time.now
|
10
|
+
current = Fiber.current
|
11
|
+
@slept[current] = true
|
12
|
+
if timeout
|
13
|
+
timer = EM.add_timer(timeout) do
|
14
|
+
_wakeup(current)
|
15
|
+
end
|
16
|
+
Fiber.yield
|
17
|
+
EM.cancel_timer(timer) # if we resumed not via timer
|
18
|
+
else
|
19
|
+
Fiber.yield
|
20
|
+
end
|
21
|
+
@slept.delete(current)
|
22
|
+
yield if block_given?
|
23
|
+
|
24
|
+
# Invoca patch: inline lock that puts us at the front of the mutex @waiters queue instead of the back
|
25
|
+
# ==========================
|
26
|
+
@waiters.unshift(current)
|
27
|
+
Fiber.yield if @waiters.size > 1
|
28
|
+
# ==========================
|
29
|
+
|
30
|
+
Time.now - beg
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../active_record/connection_adapters/fibered_mysql2_adapter'
|
4
|
+
|
5
|
+
module EM::Synchrony
|
6
|
+
module ActiveRecord
|
7
|
+
_ = Adapter_4_2
|
8
|
+
module Adapter_4_2
|
9
|
+
def configure_connection
|
10
|
+
super # undo EM::Synchrony's override here
|
11
|
+
end
|
12
|
+
|
13
|
+
def transaction(*args)
|
14
|
+
super # and here
|
15
|
+
end
|
16
|
+
|
17
|
+
_ = TransactionManager
|
18
|
+
class TransactionManager < _
|
19
|
+
if Rails::VERSION::MAJOR > 5
|
20
|
+
# Overriding the em-synchrony override to bring it up to rails 6 requirements.
|
21
|
+
# Changes from the original Rails 6 source are:
|
22
|
+
# 1. the usage of _current_stack created by em-synchrony instead of the Rails provided @stack instance variable
|
23
|
+
# 2. the usage of Fiber.current.object_id as a part of the savepoint transaction name
|
24
|
+
#
|
25
|
+
# Original EM Synchrony Source:
|
26
|
+
# https://github.com/igrigorik/em-synchrony/blob/master/lib/em-synchrony/activerecord_4_2.rb#L35-L44
|
27
|
+
#
|
28
|
+
# Original Rails Source:
|
29
|
+
# https://github.com/rails/rails/blob/6-0-stable/activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L205-L224
|
30
|
+
def begin_transaction(options = {})
|
31
|
+
@connection.lock.synchronize do
|
32
|
+
run_commit_callbacks = !current_transaction.joinable?
|
33
|
+
transaction =
|
34
|
+
if _current_stack.empty?
|
35
|
+
::ActiveRecord::ConnectionAdapters::RealTransaction.new(@connection, options, run_commit_callbacks: run_commit_callbacks)
|
36
|
+
else
|
37
|
+
::ActiveRecord::ConnectionAdapters::SavepointTransaction.new(@connection, "active_record_#{Fiber.current.object_id}_#{open_transactions}", _current_stack.last, options,
|
38
|
+
run_commit_callbacks: run_commit_callbacks)
|
39
|
+
end
|
40
|
+
|
41
|
+
if @connection.supports_lazy_transactions? && lazy_transactions_enabled? && options[:_lazy] != false
|
42
|
+
@has_unmaterialized_transactions = true
|
43
|
+
else
|
44
|
+
transaction.materialize!
|
45
|
+
end
|
46
|
+
_current_stack.push(transaction)
|
47
|
+
transaction
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module FiberedMysql2
|
57
|
+
module FiberedMysql2ConnectionFactory
|
58
|
+
def fibered_mysql2_connection(raw_config)
|
59
|
+
config = raw_config.symbolize_keys
|
60
|
+
|
61
|
+
config[:username] = 'root' if config[:username].nil?
|
62
|
+
config[:flags] = Mysql2::Client::FOUND_ROWS if Mysql2::Client.const_defined?(:FOUND_ROWS)
|
63
|
+
|
64
|
+
client =
|
65
|
+
begin
|
66
|
+
Mysql2::EM::Client.new(config)
|
67
|
+
rescue Mysql2::Error => error
|
68
|
+
if error.message.include?("Unknown database")
|
69
|
+
raise ActiveRecord::NoDatabaseError.new(error.message, error)
|
70
|
+
else
|
71
|
+
raise
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
76
|
+
FiberedMysql2Adapter.new(client, logger, options, config)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
ActiveRecord::Base.class.prepend(FiberedMysql2::FiberedMysql2ConnectionFactory)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fibered_mysql2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
autorequire:
|
7
|
+
- Invoca Development
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-synchrony
|
@@ -44,9 +44,9 @@ dependencies:
|
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '7'
|
47
|
-
description:
|
47
|
+
description:
|
48
48
|
email:
|
49
|
-
-
|
49
|
+
- development@invoca.com
|
50
50
|
executables: []
|
51
51
|
extensions: []
|
52
52
|
extra_rdoc_files: []
|
@@ -68,13 +68,16 @@ files:
|
|
68
68
|
- gemfiles/rails_6.gemfile
|
69
69
|
- lib/active_record/connection_adapters/fibered_mysql2_adapter.rb
|
70
70
|
- lib/fibered_mysql2.rb
|
71
|
+
- lib/fibered_mysql2/fibered_database_connection_pool.rb
|
72
|
+
- lib/fibered_mysql2/fibered_mutex_with_waiter_priority.rb
|
73
|
+
- lib/fibered_mysql2/fibered_mysql2_connection_factory.rb
|
71
74
|
- lib/fibered_mysql2/version.rb
|
72
75
|
homepage: https://github.com/Invoca/fibered_mysql2
|
73
76
|
licenses: []
|
74
77
|
metadata:
|
75
78
|
allowed_push_host: https://rubygems.org
|
76
79
|
homepage_uri: https://github.com/Invoca/fibered_mysql2
|
77
|
-
post_install_message:
|
80
|
+
post_install_message:
|
78
81
|
rdoc_options: []
|
79
82
|
require_paths:
|
80
83
|
- lib
|
@@ -85,12 +88,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
88
|
version: '0'
|
86
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
90
|
requirements:
|
88
|
-
- - "
|
91
|
+
- - ">="
|
89
92
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
93
|
+
version: '0'
|
91
94
|
requirements: []
|
92
95
|
rubygems_version: 3.0.1
|
93
|
-
signing_key:
|
96
|
+
signing_key:
|
94
97
|
specification_version: 4
|
95
98
|
summary: An adapter for fibered mysql2
|
96
99
|
test_files: []
|