# Race condition in C-Adapter causes deadlock

**URL:** <https://www.ruby-forum.com/t/race-condition-in-c-adapter-causes-deadlock/175705>\
**Category:** Rails\
**Created:** [September 18, 2009, 1:57am UTC](https://www.ruby-forum.com/t/race-condition-in-c-adapter-causes-deadlock/175705 "2009-09-18T01:57:46Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Howard\_Y](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/d2c977/32.png) [@Howard\_Y](https://www.ruby-forum.com/u/Howard_Y)\
**Post date:** [September 18, 2009, 1:57am UTC](https://www.ruby-forum.com/t/race-condition-in-c-adapter-causes-deadlock/175705/1 "2009-09-18T01:57:46Z")

</div>

Hi,

I understand that ActiveRecord is threadsafe, but because the C-  
adapters for both postgresql and mysql use blocking calls, it’s  
surprisingly easy to cause deadlock.

assume Balance is a model that tracks the balance of a bank account,  
and we don’t use optimistic locking.

b = Balance.find\_or\_create\_by\_id(1)  
while true  
Thread.new {  
b = Balance.find(1) # assumes account is there  
b.balance = b.balance + 1  
b.save!  
puts “.”  
}  
end

this would reliably lock a process. it only happens when transaction  
is used (which it is, when balance.save!). The steps leading to the  
deadlock seems to be this

thread1 =\> begin  
thread1 =\> update =\> mysql  
thread1 preempted  
thread2 scheduled  
thread2 =\> begin  
thread2 =\> update =\> mysql  
thread2 =\> C read()  
thread2 blocks whole process on read()  
thread1 doesn’t get to commit

process blocks

you can try running the test script,

> ruby thread-test 1 # should be ok, because no transaction is used  
> ruby thread-test 2 # locks  
> ruby thread-test 3 # locks

File: ‘thread-test.rb’:

require ‘rubygems’  
require ‘thread’  
require ‘activerecord’

DB = ENV[“DB”] || “mysql”  
`rm sql.log` if File.exist?(“sql.log”)  
ActiveRecord::Base.logger = ::Logger.new(“sql.log”)  
ActiveRecord::Base.establish\_connection   
:adapter =\> DB,  
#:adapter =\> “mysql”  
#:adapter =\> “postgresql”  
#:adapter =\> “jdbcmysql”  
:database =\> “thread\_test”,  
:username =\> “vp”,  
:password =\> “vp”,  
:socket =\> “/var/run/mysqld/mysqld.sock”,  
:host =\> “localhost”,  
:port =\> 5432,  
:pool =\> 50

ActiveRecord::Schema.define(:version =\> 1) do  
create\_table “balances”, :force =\> true do |t|  
t.integer “balance”, :default =\> 0  
end  
end

class Balance \< ActiveRecord::Base  
end

b = Balance.find\_or\_create\_by\_id(2)  
puts b.balance

which\_test = ARGV[0].to\_i || 1

case which\_test  
when 1  
puts “Raw update, no transaction”  
while true  
Thread.new {  
sql = \<\<-SQL  
UPDATE balances SET balance = balance+1 WHERE id = 2  
SQL  
ActiveRecord::Base.connection.execute(sql)

```
  puts "."
}

```

end  
when 2  
puts “Update through ActiveRecord”  
while true  
Thread.new {  
b = Balance.find(2)  
b.balance = b.balance + 1  
b.save!  
puts “.”  
}  
end  
when 3  
puts “Raw update in transaction”  
while true  
Thread.new {  
sql = \<\<-SQL  
UPDATE balances SET balance = balance+1 WHERE id = 2  
SQL  
ActiveRecord::Base.transaction do  
ActiveRecord::Base.connection.execute(sql)  
end  
puts “.”  
}  
end  
end

---

<div class="post-metadata">

**Author:** ![Howard\_Y](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/d2c977/32.png) [@Howard\_Y](https://www.ruby-forum.com/u/Howard_Y)\
**Post date:** [September 18, 2009, 2:34am UTC](https://www.ruby-forum.com/t/race-condition-in-c-adapter-causes-deadlock/175705/2 "2009-09-18T02:34:39Z")

</div>

For PostgreSQL, set allow\_concurrency: true in your  
config/database.yml. It’ll use the async API which sidesteps these  
issues with blocking syscalls.

For MySQL, use the mysqlplus driver.

Best,  
jeremy

---

<div class="post-metadata">

**Author:** ![Howard\_Y](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/h/d2c977/32.png) [@Howard\_Y](https://www.ruby-forum.com/u/Howard_Y)\
**Post date:** [September 18, 2009, 2:26am UTC](https://www.ruby-forum.com/t/race-condition-in-c-adapter-causes-deadlock/175705/3 "2009-09-18T02:26:27Z")

</div>

On Sep 18, 12:55 am, Howard Y. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hi,
> 
> I understand that ActiveRecord is threadsafe, but because the C-  
> adapters for both postgresql and mysql use blocking calls, it’s  
> surprisingly easy to cause deadlock.

Does it eventually undeadlock ? when mysql blocks because there’s a  
deadlock it should eventually give up (although of course with your  
test script this would soon happen again). Deadlocks are just a risk  
of life when it comes to transactions. MRI’s threading model does  
indeed mean that a threadsafe rails is much less useful than on  
something like jruby

Fred
