Ruby One Niner

All my server’s Ruby applications, most notably my books site, have been running on 1.9.1 for over a month now. During the process of upgrading Ruby I jotted down a few notes on the process I followed, the problems I encountered and the ways in which I solved them. None of this is new information, but hopefully bringing these solutions together will be of use to those with similar setups, or at least to myself in the future.

Installing Ruby

I installed Ruby 1.9.1 on an Ubuntu 8.04 (LTS) server, which was reasonably simple in and of itself, although the Ruby ecosystem as a whole has clearly not quite caught up to the new VM.

Ruby 1.8.6 is still the default version of Ruby available on the Ubuntu package system, and while there is a version of Ruby 1.9 available, it’s quite out of date. For this reason, I recommend compiling it by hand from the source code provided on the Ruby website. This has the additional benefit of making upgrading your version of Ruby independent of the Ubuntu packaging hierarchy, which can be somewhat slow to update theirs.

Uninstalling Ruby 1.8.6—assuming it was installed with aptitude—is extremely simple:

sudo aptitude remove ruby1.8

The package manager will pick up on the fact that rdoc, ri and irb depend on Ruby, and uninstall them as well as ruby1.8-dev and libreadline-ruby1.8 which will be unused when ruby1.8 is gone.

If you’re following these instructions, make sure you use the latest stable version from the Ruby site, not the one I list here. Given that newer versions are likely to fix bugs and security vulnerabilities, this is extremely important. Blindly copying and pasting shell commands is a sure-fire way to create problems for yourself.

cd /usr/local/src/
sudo curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz
sudo tar xzvf ruby-1.9.1-p243.tar.gz
cd ruby-1.9.1-p243/
sudo ./configure
sudo make
sudo make install

Installing gems

The RubyGems packaging system is built into Ruby 1.9, but quite a few gems are not yet compatible with the new VM. There are lots of helpful notes in this blog post, although thankfully not all of them still apply.

Is it Ruby 1.9? generally gives one a good sense of whether just running gem install foo will work, but is often lacking when it doesn’t. Some research will likely be required if you have a lot of gems.

Some gems just worked

sudo gem install hpricot \
                 rake \
                 rack \
                 rails \
                 will_paginate \
                 rdiscount \
                 fastthread \
                 passenger

Mongrel

Getting Mongrel to even run was ludicrously complicated. Here are the steps I followed to do so, but before I list them I should note that I don’t think that this is generally worth doing, unless for some reason you can’t possibly switch to an alternative web server such as Passenger.

The changes you’ll need to make to the Mongrel source code concern references to the objects of the underlying C implementation: since Ruby 1.9 is based on an entirely new virtual machine, any direct references to MRI objects have to be changed to instead refer to YARV ones.

  1. Hack ext/http11/http11.c file to replace references to RSTRING(foo)->ptr with RSTRING_PTR(foo), RSTRING(bar)->len with RSTRING_LEN(bar), RARRAY(baz)->ptr with RARRAY_PTR(baz) and RARRAY(qux)->len with RARRAY_LEN(qux)
  2. Run sudo ruby setup.rb && sudo make && sudo make install
  3. Copy the mongrel.gemspec file to your RubyGems specifications directory as mongrel-1.1.5.gemspec

Obviously those changes won’t work on Ruby < 1.9. Ryan Bigg has a 1.9-compatible version, although I haven’t tried it personally.

While I did get Mongrel working, it didn’t play nicely with Rails 2.3.2 at all, so in the end I just dropped it and installed Passenger instead, which is much better in this regard, and a lot lower-maintenance. After removing Mongrel I cleaned up the following:

  • Config files in /etc/mongrel_cluster/
  • A symlink to one of the gem files in /etc/init.d/ to restart the cluster if the server rebooted
  • A load of mod_proxy_balancer cruft in my Apache configs

Coda Hale’s grown up server was a great hack, but its time is past. Slicehost have good articles on installing Passenger and using it to serve your application, but it’s basically very straightforward.

MySQL

The MySQL gem on RubyForge is outdated and not completely compatible with Ruby 1.9. The updated gem has to be built by hand, which is a fairly uncomplicated process.

Updating applications

Most of my application code just worked. The only real changes I had to deal with were those concerning the new String class, but these are well documented and shouldn’t be a surprise to anyone upgrading an application or library to work with 1.9. If in future I run across any other issues, I’ll add them in a supplementary section below.

The new String class

James Edward Gray II has written some very helpful articles on Ruby 1.9’s new String class and default encodings. They proved invaluable when trying to track down bugs in code written for Ruby 1.8.6 (most of the fruits of my labours in this regard are visible in URLify).

Backwards-incompatible Tempfile changes

After upgrading to Ruby 1.9.1-p243, Books on Extralogical died, with Passenger reporting an IOError. Apparently a change was made to Tempfile#unlink to fix some issues with the library on Windows, resulting in a behaviour change that broke programs on *nix systems. I edited the library file and reverted the change, which fixed the application. Hopefully a future version of Ruby will revert this change, or it will be fixed at the library level in Rack. Here’s the path to the file in question on my system:

/usr/local/lib/ruby/1.9.1/tempfile.rb
Update, 26th August 2009

This behaviour has been reverted for the Ruby 1.9 development branch, and the fix will be backported to the 1.9.1 branch. Many thanks to Hongli Lai for pursuing this.

Update, 7th January 2009

Having switched to Gemcutter as my primary gem source, I’ve removed the GitHub gem source details from the article.

In conclusion

In the end, only two things caused me any trouble: installing Mongrel, and installing MySQL. The latter was relatively painless once I found the right version of the library; I really don’t know why the newer version isn’t available on RubyForge. The former was a complete pain, and my advice is to scrap any Mongrel-based setup and install Passenger from the get-go—it’ll be quicker than trying to hack your old setup back together. Now that Passenger is available for nginx as well as Apache, the case is thoroughly compelling.

Last updated 7th Jan 2010

, , , , ,

9 responses

That was very useful, wish I had found it sooner before banging my head on the wall so many times.
Thanks

~ Computer Plumber

Very useful. Thank you.

~ Nick Mudge

And how is performance post-upgrade?

~ unsane1

Hard to tell, to be honest. As I explained in the article, I switched application servers from Mongrel to Passenger, so I can’t really make a direct comparison. Overall application performance has definitely improved, but I’d hesitate to attribute it solely to the new Ruby VM.

The test suites for my Ruby applications and libraries run a lot faster under Ruby 1.9.1 than they ever did on Ruby 1.8.6. However, my experiences are strictly anecdotal: I strongly recommend reading the Antonio Cangiano’s benchmarks and profiling your own code under the different VMs if you really want to know what kind of performance improvements to expect.

~ Benedict

I’ve been using thin instead of mongrel, it seems to be fine and 1.9 compatible.

Is passenger better? how does it compare to thin?

~ Kamatsu

FYI, the 3rd Edition of the Pickaxe (i.e. specifically for 1.9) shows that it’s pretty easy to default to the 1.9 versions of the C pointer and length stuff and use macros to define them in terms of the old syntax for 1.8.x. Kind of strange that whoever’s in charge of mongrel these days hasn’t picked that up. Also, it would be great if someone who knows the maintainer of the mysql lib could do some encouraging to get him to put the newest version on rubyforge in gem form. Anyone?

~ Dan DeLeo

Kamatsu: I don’t know, I’ve never used Thin.

Dan: thanks for pointing that out, I may have to get the updated Pickaxe. If it really is a portable solution for libraries which need to run C code, then it’s hard to see why it wouldn’t be used to create 1.8- and 1.9-compatible gems.

It does seem strange that fixes of that sort haven’t been rolled into Mongrel—perhaps it’s just that the people who are moving their applications to Ruby 1.9 are also changing their application servers (like I have), and so there’s less pressure to do so. I know there are some Mongrel forks on GitHub, so perhaps one of them has take this approach.

~ Benedict

According to the link for the p243 bug, the file reverted is actually:

/usr/local/lib/ruby/1.9.1/tempfile.rb

I’m experimenting with just commenting out line 140 for now. I’m completely new to ruby and am amassing instructions from across various web sites to get 1.9.1 and rails installed properly.

Thanks for the helpful page!

~ Joe Lapp

Joe: I’ve corrected that typo, thanks. Glad to hear the article was of some help.

Some knowledgeable folks on Hacker News suggested running sudo checkinstall instead of sudo make install. I intend to try that out when I next upgrade my Ruby version, and amend the article appropriately.

~ Benedict