I've completed a beta implementation of my take on the replication pre-cache tool... Sorry nothing to download yet, I have to get it through an internal committee at Yahoo before I can release it (and you can imagine things are kind of crazy here). I wrote it myself because:
- I had it mostly done before I found out there were other versions out there
- I have to maintain it inside of Yahoo anyway
- I wanted to learn Ruby :)
It's just over 250 lines of Ruby, my new favorite language and fairly compact. It doesn't use the Ruby Mysql library, rather just IO.popen calls to the mysql command line client. I did this for two reasons:
- I haven't figured out the "right" way to deploy ruby gems at Yahoo yet (it's complicated).
- effectively I just have multiple Ruby threads blasting SELECT statements into mysql client children processes. I wanted the mysql clients to handle all the waiting, and let the threads stay nice and fast (Ruby's threads are not native).
The nasty piece of writing this is trying to work with the relay log. I use the mysqlbinlog tool to read the relay log off of disk, have one thread look for UPDATE statements to convert to SELECTs and then pass those off to a Ruby Queue object, which the worker threads pop from.
Anyway, I know where the SQL thread is reading from in the relay log, so I start there. I wanted to start ahead of that, so my first idea was to just add to the current position, but that means I have to scan to find a valid position from there, which is expensive and clunky.
Instead, I start right from the slave, but use the --offset option to skip ahead a number of records and set a --stop-pos that (not needing to be a valid position) is just the starting position plus an offset. As I'm scanning the log, I track the lines that look like 'at #somenumber#', which is the current (valid) position. By keeping track of this, I know where to start on the next iteration. However, before that, I check the relay position and make sure I'm still ahead of it, and additionally I make sure I'm not too far ahead. With all of this I have a few tuning variables:
- worker_clients: the number of mysql connections to open and pipe SELECTs into. I default to 10, hoping your innodb_thread_concurrency is larger than 10.
- binlog_scanahead: how far to increment the binary position from the starting point in --stop-pos.
- binlog_max_scanahead: a multiplier for the scanahead. The precacher won't go this times the scanahead ahead of the SQL thread.
- binlog_row_offset: how many records to skip when starting from the slave's position.
So, one of my complains is I'm working in different units: records versus byte-offsets, but it seems to work ok.
How fast is it? Fast.
I'm using sysbench with 10 clients on a master server for 10 minutes with an OLTP table with 100M records (innodb) that occupies about 25G (4.1) on disk (23G on 5.1) and a 6G buffer pool (8G machine). I'm doing UPDATEs only, with a random distribution across the primary.
Without the precacher running, the slave server will take around 30-40 minutes to do the same work done on the master. (i.e., it catches up in 20-30 minutes after the writes stop on the master).
With the precacher running, it simply keeps up, not too shabby. Granted, this is a "perfect" case, 100% UPDATE statements, but I'm pretty happy with it.

You might never be able to
You might never be able to release it..... Microsoft isn't exactly a big fan of Open Source!
:-P