"upstream timed out" after upgrades

Eric Wong normalperson at yhbt.net
Thu Feb 4 16:52:01 EST 2010

John-Paul Bader <hukl at h3q.com> wrote:
> Hmm,
> my C skills are really weak but this patch suppresses any IO errors
> right? At least on BSD? Can you explain what exactly it is doing? Just
> want to understand entirely.

>From the beginning (a bit long, feel free to ask me for more
clarification, too much of this is second nature to me by now
and I may glance over important details...):

There are two standard ways of doing IO in C: stdio.h (fwrite(3)/
fread(3)/fseek(2) ...) and the lower-level Unix system calls found in
unistd.h (write(2)/read(2)/lseek(2)...)

stdio.h functions are wrappers that do buffering in userspace and wrap
the underlying unistd.h syscalls.  They should not be used
interchangeably on the same file descriptors.

Unfortunately, Ruby 1.8 makes this mistake and uses them interchangeably
in some places: bad.

So when working with regular files, file offsets maintained in userspace
via stdio did not get properly synchronized to the underlying
kernel-level file offsets.  That's why the fseeko(lseek()) was added to
fix an issue exposed by Unicorn.  lseek() was used to read the offset
from the kernel, and then fseeko() is then used to synchronize the
userspace offset to that of the kernel.   All of this works well for
seekable regular files.

Now, sockets and pipes aren't seekable, so you'll get an error from the
kernel if you try to seek on them.  Errors from system calls are stored
in "errno", a global variable that stores the error of the last system
call executed.  So since attempting to seek on an unseekable file sets
errno, it clobbers the previous clean (or the "safe" value of EAGAIN[1])

Eventually, this caused rb_sys_fail() function to be called, which
raises a Ruby exception matching the current value of errno.

[1] - EAGAIN (and EWOULDBLOCK on some systems) basically means "try
calling this same function again, later".  It gets returned when kernel
buffers (not the userspace ones) are full if attempting to write, or
empty if attempting to read.  Since Ruby 1.8 relies on non-blocking I/O
for sockets/pipes, the "blocking" write methods are coded to
(eventually) retry on EAGAIN.

> I thought your diff was the ruby diff of r26253 and didn't realize it
> was yours ;)

Actually, it's not mine, I just submitted the ticket that fixed one bug
and introduced the one you hit :)

Eric Wong

More information about the mongrel-unicorn mailing list