Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transaction Synchronization on MRI #1083

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Next Next commit
Don't stub synchronization on MRI
Having a GIL does not mean you don't have to perform any synchronization
at all. While most Ruby code won't be able to run in parallel native
extensions _can_ run in parallel by calling functions such as
rb_thread_check_ints() (which basically pauses the current thread when
needed).

Depending on the Ruby environment to figure out if you need
synchronization or not is _extremely_ dangerous. While this can work
most of the time, once in a while you'll get weird NoMethodErrors or
worse: segmentation faults, depending on the database adapter being
used. In particular the PostgreSQL adapter (which uses the "pg" Gem)
suffers from this as connection objects created by the "pg" Gem (or
really any other object it provedes) are not thread-safe.

While synchronizing access on MRI will have a slight performance impact,
it's either that or errors/segmentation faults.
  • Loading branch information
Yorick Peterse committed Sep 29, 2015
commit 6fc930d8a40e6f8b1630866e833d97a6df16c2fd
26 changes: 8 additions & 18 deletions lib/sequel/core.rb
Expand Up @@ -293,24 +293,14 @@ def self.string_to_time(string)
end
end

if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
# :nocov:
# Mutex used to protect mutable data structures
@data_mutex = Mutex.new

# Unless in single threaded mode, protects access to any mutable
# global data structure in Sequel.
# Uses a non-reentrant mutex, so calling code should be careful.
def self.synchronize(&block)
@single_threaded ? yield : @data_mutex.synchronize(&block)
end
# :nocov:
else
# Yield directly to the block. You don't need to synchronize
# access on MRI because the GVL makes certain methods atomic.
def self.synchronize
yield
end
# Mutex used to protect mutable data structures
@data_mutex = Mutex.new

# Unless in single threaded mode, protects access to any mutable
# global data structure in Sequel.
# Uses a non-reentrant mutex, so calling code should be careful.
def self.synchronize(&block)
@single_threaded ? yield : @data_mutex.synchronize(&block)
end

# Uses a transaction on all given databases with the given options. This:
Expand Down