blog.absurd:li - press play on tape
November 18th 2009
Tagged reading code, tricks, unix, ruby, unicorn, bearded unix gurus

Some tricks that can be learnt from the unicorn

My general disgust with threaded/evented programming has led me to read up on the good old unix techniques used in unicorn. What a good read it was. The mix of programmers that have constructed unicorns have very different styles. That makes reading fun. I guess anyone could distinguish Zed Shaw’s style from the rest of the pack…

But there are also some unix techniques that I’ve learnt from unicorn and that I will share with you now1.

The Self Pipe Trick

This trick allows you to handle signals safely in your code. A nice side-effect is that it will also allow you to trigger running of a process without using signalling.

Assume you have two processes, A and B. One process wants to be able to signal the other, awaking it from sleep. Lets assume that they share a FD to a pipe, where read_end is the end of the pipe that is open for reading and write_end the one open for writing to.


  # Process A: Sleep and wait for a signal: 
  IO.select([read_end])

The above code snippet is used to put the process A to sleep, waiting for a signal1. You would then use the following technique to wake the process up:


  # Process B: Awake process A
  write_end.write_nonblock('.')   # the '.' is arbitrary

Process A wakes up because you’ve just written something to the FD that its waiting on3.

Note that this technique can also be used to wake process A up from a signal handler. So you get safe IPC in just a few lines.

This trick seems to be well known in the unix world, there are even some alternatives (read that link).

Keepalive through an unlinked file

Another thing that I found most enlightening is how unicorn handles sending heartbeats to the controlling process from its workers. This is not as easy as it looks, since actively sending heartbeats will require the master to listen at the same moment. The solution unicorn uses decouples the master from the client in that respect.

The master opens one temporary file per worker and unlinks it right away4. The open file handle to that file is then shared with all the worker processes.

Each worker will then do the following to prove its alive and kicking:


  tmpfile.chmod(m = 0 == m ? 1 : 0)

The chmod will use either ‘1’ or ‘0’ each time this gets executed.5 (Assign ‘0’ to the local variable ‘m’, compare it to ‘0’. If it matches (m == 0), m = 1, otherwise m = 0. A one line toggle.)

Here’s what the master does to check the worker’s status6:


  stat = worker.tmpfile.stat
  unless (diff = (Time.now - stat.ctime)) <= timeout
    # Worker has gone stale and needs to be respawned
  end

Even though the file is unlinked it still has metadata associated with it. Using the file’s #ctime we can check when the file was last mode changed, and thus when the worker was last alive.

This nice gem of a technique uses the unix file system as an external data store. I really like the details that went into this, like the fact that its unlinked already or the small code hack that is explained in the parentheses above. I haven’t been able to find that technique elsewhere, though I am sure it is part of any bearded unix guru’s toolbox.

1 All references to unicorn code are made against revision 6311cc30b96b08f72fe00a9a0d1e291cf9923e52 of the repository @ git://git.bogomips.org/unicorn.git.

2 unicorn.rb, method #master_sleep, lines 422-429

3 unicorn.rb, method #awaken_master, lines 431-438

4 util.rb, Util.tmpio, lines 75-86

5 unicorn.rb, method #worker_loop, lines 631-639, be sure to read the interesting comment right above.

6 unicorn.rb, #murder_lazy_workers, lines 517-527