Hi guys,

One of the odd things that's blocking one big app I work on from moving up to 
Rails 3.0 or 3.1 is that with these versions whenever an object is saved, a 
reference to it is retained until the end of the enclosing transaction block, 
so that its state (new_record?, etc.) can be rolled back if the transaction is 
rolled back.  This is a nice feature, but because Ruby's WeakRef implementation 
is broken on 1.9, the ActiveRecord implementation uses regular strong 
references.

This is bearable in production code in most cases, but it's absolutely killing 
large test suites.  When transactional fixtures is on, then the transaction in 
question is open for the length of the entire set of tests, so all objects ever 
saved at any point during the test cases are retained in memory.

Our test suite bloats up to 6GB before we give up and kill it - by that point 
the VM is doing almost nothing but garbage collecting.  (It can run with 
transactional fixtures off, but that's very, very slow for an app with many 
tables.)

There are several ways we can fix this, and I thought it would be good to 
discuss on the list which is best because they will have different behavior.  
The options as I see them are:

1. Change the transaction code to not count the test transaction when 
determining whether to fire the commit/rollback hooks and discard the reference 
list.  This is a bit of work, and will change the behavior of tests, but some 
might argue in a good way (if you want to test that your after_commit and 
after_rollback hooks work, pretending that you are not already inside a test 
transaction).

2. Explicitly throw away the reference list after each test completes, so that 
after_commit and after_rollback are not fired.  A bit of a hack, but I  imagine 
some will prefer it given what after_commit and after_rollback are typically 
used for.

3. Hassle someone to fix that WeakRef so that we can use it, making the issue 
largely moot (assuming you didn't care about those callbacks).  The best 
long-term solution for other reasons, but difficult (1.9 needs patching).   See 
http://redmine.ruby-lang.org/issues/4168.


If you want to see the problem yourself, just save some records (any model will 
do) in tests and watch them not get GCd:

class TestTest < ActiveSupport::TestCase
  self.use_transactional_fixtures = true

  1.upto(20) do |i|
    test "some test #{i}" do
      TestRecord.first.update_attributes!({})

      GC.start
      count = 0
      ObjectSpace.each_object(ActiveRecord::Base) do |b|
        count += 1
      end
      puts "#{count} ActiveRecord"
    end
  end
end

-- 
You received this message because you are subscribed to the Google Groups "Ruby 
on Rails: Core" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en.

Reply via email to