Date | Commit message (Collapse) |
|
A follow-up-to commit 0c20f34c3d54e1c3d7b7a811c401e6858196e8a7
("rework master-to-worker signaling to use a pipe"), there is
no reason to use a real kill(2) here.
|
|
This quiets down our logs when acceptors do not die quickly
enough for us.
|
|
This prevents potential errors and compatibility problems with
buggy libraries which do not respond well to signal delivery.
Based on unicorn commit 6f6e4115b4bb03e5e7c55def91527799190566f2
|
|
There's almost no chance of blocking here, but better to
be safe than sorry inside signal handlers. We would
get the wakeup even if the pipe/event fd blocks.
|
|
We do this for conciseness.
|
|
When daemonizing, it is possible for the grandparent to be
terminated by another process before the master can notify
it. Do not abort the master in this case.
unicorn commit 27ae210dde9228cfa96ea6b0f3a7e4047d3f70a4
|
|
Much of this code was copied from the epoll queue.
|
|
We favor foo(&:bar) when possible for conciseness.
|
|
This likely makes no difference in 99% of real world situations with
fast response generation. The only case where lack of output buffer
bypass makes a difference is when the following sequence happens:
1) a giant response cannot fit into socket buffers
2) temporary file created for buffering
3) client consumes output so we get more space in socket buffers
4) app response generation continues (streaming response)
5) we successfully write _all_ previously buffered data to socket
6) we may bypass buffering for data generated in step 4
So right now, we cannot do step 6 outside of Linux. Instead, once an
output buffer is created; we must always write to the output buffers.
|
|
Tested on Debian GNU/kFreeBSD (sid):
make check SENDFILE_BROKEN=1
|
|
We may unnecessarily drop persistent connections from this bug,
and we had an incorrect assertion in our unit test, even.
|
|
We may pass a timeout to kgio_wait_writable during shutdown.
|
|
This will lead to ENOENT when placing writer into kqueue
changelist via kevent(2)
|
|
We must not cork response headers when the response body is empty,
otherwise those headers will be delayed by 200ms.
|
|
We'll let systems with updated glibc headers define those
(or interested users, if any, on those architectures test
and report back to us). No point in causing unnecessary
breakage if we screw things up.
|
|
We need this for "yahns --version" on the command line
|
|
If Content-Length is known, try to save some bandwidth by
corking the headers until the body is sendable. This allows
us to avoid sending an extra packet for small HTTP responses.
This allows high-performance websites like YHBT.net to be served
faster!
|
|
We can't do anything about EHOSTUNREACH, so quiet the backtrace.
I've noticed this happening very rarely (once every few weeks?)
while yahns was exposed to untrusted traffic.
|
|
Unicorn::HttpResponse#httpdate is currently not thread-safe without GVL.
|
|
We do not use these strings in string assignment, and we're not
in danger of modifying these strings in place, so do not freeze
them.
|
|
Simultaneously waiting for both readability and writability is
likely unnecessary. Sockets become writable much more commonly,
and if we need to read, we'll issue a read the next time it enters
yahns_step (after it becomes writable).
Also, this makes kqueue easier-to-implement as I don't believe it
implements a way to combine EVFILT_READ with EVFILT_WRITE
(especially not safely while relying on EV_ONESHOT behavior).
|
|
Multithreaded epoll is a tricky interface to use. Fortunately it
should be hidden from users and yahns is no different from any other
multithreaded server from a user application programming
perspective (which requires a lot of careful programming in the
first place).
|
|
Our QueueQuitter may race with epoll_wait and GC, potentially
triggering memory corruption if a level-trigger object was
placed into the ready list and no longer referenced.
We'll work around this problem by making the QueueQuitter object
a thread-local (on thread failure) to prevent concurency issues
where the epoll pointer no longer points to a Ruby object.
|
|
The first argument of the old __expire_for method was completely
unused in all but one invocation of it, so it is not worth it. This
also simplifies the code a bit too.
|
|
apps/responses may trickle infinitely, so our QueueQuitter may
not properly kill epoll worker threads, unfortunately. So we'll
start the timer and stop waiting (risking segfaults/ugliness) by
closing epoll descriptors
|
|
We must know we're daemonized after a SIGUSR2 upgrade, even if we
don't use the pipe to signal to the controlling terminal we've
started up.
|
|
The choice to jump directly to temporary files on EAGAIN may
seem odd to some, document our reasoning for choosing this approach.
|
|
We can use the wbuf_close return value instead to ensure we close
tmpio properly and follow the same code path as a normal
(:wait_writable-triggering) buffered response would.
Add a few tests to ensure we properly close the response body
for exec_cgi, where I noticed zombies and started me down this
rabbit hole looking for places where the response body was not
closed properly.
|
|
We may buffer a response partially, but no longer need the
buffer if we entered bypass mode. When doing this, we must
remember to close the body after using it.
|
|
Clients may timeout due to SO_KEEPALIVE handling after a few hours.
Since we have infinite keepalive, this may happen as we maintain no
timers in userspace.
|
|
This may happen if we get by a forceful exit, so we'll risk
triggering some bugs elsewhere, but forceful exits are never
pretty...
|
|
Double SIGQUIT defeats the use of graceful shutdown. We must not
watch the worker pipe again for readability after we've initiated
graceful shutdown.
|
|
We cannot declare apps before working_directory is bound.
|
|
It may be disconcerting to not know how long it takes a server
to gracefully exit, so provide that feedback. While we're at
it, avoid dropping acceptors if we want a forceful exit.
|
|
We allow applications to drop persistent connections, this does not
seem forbidden by Rack and gives the app author some control over
the lifetime of a connection.
|
|
We must not directly close descriptors allocated by applications
themselves. The only way we may close them is to issue
body.close on the response body.
A simple comparison we used before may not work because Rack
response bodies may be wrapped by middleware, so we use a
private subclass of File.
|
|
We must not reap processes we did not spawn if we're not using a
master/worker configuration. This may break applications which
depend on waitpid themselves. However we still trap SIGCHLD
currently. In the future, we could switch our notification
model mode to be compatible with apps which depend on SIGCHLD or
might indiscriminately on children (which might prevent us from
knowing about SIGCHLD).
|
|
We parse and use Content-Range, but do not drop it when sending
a response since that would confuse clients.
|
|
When running a static file server, we must account for filesystem
activity outside of our control where files may grow/shrink as
they're being served.
For truncated files, we must abort any persistent connections
downloading a truncated file to avoid confusing clients because
the Content-Length header was already set to the big value.
We also must ensure (we already did so before this commit,
this just adds a test for it) we do not send additional data
when a file grows on us after we've started sending the response.
|
|
Array#join implies string conversion and unicorn has been
doing that for ages.
|
|
We never use kgio_write for clients, only kgio_trywrite.
|
|
This allows users to specify alternative temporary directories
in case buffers get too large for one filesystem to handle or
to give priority to some clients on certain ports.
|
|
The first time we call wbuf_write, we do so because we already hit
:wait_writable in the caller. So we can avoid the extra
still-highly-likely-to-return-:wait_*) kgio_trywrite by writing to
the VFS, first.
|
|
This can prevent dirty data from being committed, saving the system
from unnecessary disk activity.
|
|
Sometimes buffering can catch up and we no longer need to
use the on-disk buffer, so keep trying to flush the data
out to the user to avoid VFS activity.
|
|
Some users may care to have sub-second or fractional timeouts for
various reasons. Do not reject those values to be consistent with
Ruby sleep/select.
|
|
It's conceivable a sub-optimally configured instance can have too
many Unix sockets connected to us. This also implements expiry for
systems without sufficient "struct tcp_info" support.
|
|
This should make it easier for Rack users to get started with yahns.
|
|
This should allow users to more-easily enable/disable apps
and their dependent atfork_* hooks.
|
|
It's usually given as a block, so Ruby won't care about arity there.
Users will get the worker ID number as the first arg, making it
possible to isolate some things to certain processes (e.g. for A/B
testing).
|