Date | Commit message (Collapse) |
|
Timeouts of less than 2 seconds are unsafe due to the lack of
subsecond resolution in most POSIX filesystems. This is the
trade-off for using a low-complexity solution for timeouts.
Since this type of timeout is a last resort; 2 seconds is not
entirely unreasonable IMNSHO. Additionally, timing out too
aggressively can put us in a fork loop and slow down the system.
Of course, the default is 60 seconds and most people do not
bother to change it.
|
|
Since we've switched to readpartial, we'll already be protected
from any unpleasant errors that might get thrown at us. There's
no easy way to prevent MRI from calling a select() internally to
check for readiness, so speculative+blocking read() calls are
out already.
Additionally, most requests come in the form of GETs which are
fully-buffered in the kernel before we even accept() the socket;
so a single readpartial call will be enough to fully consume it.
|
|
readpartial is actually as low-level as sysread is,
except it's less likely to throw exceptions and
won't change the blocking/non-blocking status of
a file descriptor (we explicitly enable blocking I/O)
|
|
Simpler code on our end can be just a tick faster because
syscalls are still not as cheap as normal functions and this
still manages to play well with our lack of keepalive
support as closing the socket will flush it immediately.
|
|
Since the vast majority of web traffic is GET/HEAD
requests without bodies, avoid creating a StringIO
object for every single request that comes in.
|
|
"out" was an invalid variable in that context...
|
|
Only do speculative accept on the previous ready set of
listeners. This makes it less CPU-intensive to have per-process
debug listeners configured.
Unfortunately, this makes non-primary listeners unable to accept
connections if the server is under extremely heavy load and
speculative accept() on the previous listener is always
succeeding and hogging the process. Fortunately, this is an
uncommon case.
|
|
Don't allow newly created IO objects to get GC'ed and
subsequently close(2)-ed. We're not reopening the
{$std,STD}{in,out,err} variables since those can't be
trusted to have fileno 1, 2 and 3 respectively.
|
|
No need to use ensure since process_client will handle errors
regardless. And if not, there's a bug on our side that needs to
fixed.
|
|
|
|
Keep in mind that it's plenty possible to use Unicorn as a
library without using Rack itself. Most of the unit tests
do not depend on Rack, for example.
|
|
We were closing a no-longer-existent I/O object to break out of
IO.select. This was broken in 0.6.0 but did not affect the
worker when it was busy.
|
|
The following specifications to bind port 8080 on all interfaces
are now accepted in the configuration file:
listen "8080" # (with quotes)
listen 8080 # (without quotes)
|
|
|
|
We do this in both the worker and master processes, so avoid
repeating ourselves.
|
|
This allows dynamic tuning of the worker_processes count without
having to restart existing ones. This also allows
worker_processes to be set to a low initial amount in the config
file for low-traffic deployments/upgrades and then scaled up as
the old processes are killed off.
Remove the proposed reexec_worker_processes from TODO since this
is far more flexible and powerful.
This will allow not-yet-existent third-party monitoring tools to
dynamically change and scale worker processes according to site
load without increasing the complexity of Unicorn itself.
|
|
Seems like a good idea to be able to relocate log
files on a config reload.
|
|
Saying to the world that I may have OCD...
|
|
As long as our speculative accept()s are succeeding, then avoid
checking for master process death and keep processing requests.
This allows us to save some syscalls under extremely heavy
traffic spikes.
|
|
Oops, this was broken in another yak-shaving commit:
9206bb5e54a0837e394e8b1c1a96e27ebaf44e77
|
|
Avoid scaring the thread-safety-first crowd (as much :)
|
|
Since it has to work inside signal handlers, there's
no point in making it a per-object instance variable
given the price of an instance variable in MRI...
|
|
Avoid creating garbage every time we lookup the status code
along with the message. Also, we can use global const arrays
for a little extra performance because we only write one-at-a
time
Looking at MRI 1.8, Array#join with an empty string argument is
slightly better because it skips an append for every iteration.
|
|
|
|
Instance variables are expensive and we'd be encouraging
something like a thread-safe mentality for using ivars
when dealing with things that are global to the entire
process.
|
|
Since file descriptors are only private to a process,
do not treat them as Object-specific.
|
|
This leads to a ~10% improvement in test/benchmark/request.rb
Some of these changes will need to be reworked for
multi-threaded servers (Mongrel); but Unicorn will always be
single-threaded.
|
|
It was just a waste of space and would've caused line wrapping.
This reinstates the "unicorn" prefix when we create tempfiles,
too.
|
|
StringIO.new(partial_body) does not update the offset for new
writes. So instead create the StringIO object and then syswrite
to it and try to follow the same code path used by large uploads
which use Tempfiles.
|
|
|
|
It's pointless to support multiple instances of it since
this is per-process. However, the constant itself is now
modifiable if anybody needs to tweak things for reexecution
using a before_exec hook.
|
|
We no longer have anything outside of SocketHelper module in
that file, so just give it a more obvious name.
|
|
This removes the #unicorn_peeraddr methods from TCPSocket and
UNIXSocket core classes. Instead, just move that logic into the
only place it needs to be used in HttpRequest.
|
|
This avoids creating yet another binding. socket.syswrite()
should really only be called once since we use blocking sockets,
but just in case, we emulate a do+while loop with begin+while
|
|
|
|
|
|
Otherwise applications can change them behind our back
and affect subsequent requests.
|
|
It's part of the HTTP/1.1 (rfc2616), so we might as well
handle it in there and set PATH_INFO while we're at it.
Also, make "OPTIONS *" test not fail Rack::Lint
|
|
|
|
Avoid creating new string objects and then discarding them right
away by stuffing non-constant but always-present headers into
the initial output.
|
|
We never use it anywhere explicitly for hash lookups
|
|
Oops, that was not just speculative accept(), but
spammy accept()...
|
|
|
|
Trailing whitespace glows *RED* every time I open
this file to edit a constant and that annoys me.
|
|
There are weird (and possibly broken) clients out there that
require it despite being present in the first line of the
response. So be nice and accomodate them. Keep in mind that
the Rack SPEC explicitly forbids this header from being in the
headers returned by the Rack-based application; so we have to
always inject it ourselves and ignore it if the application
sets it.
|
|
Ensure we always fchmod our tempfile in case of client error to
avoid getting nuked in the next request cycle. Also, kill off
some unnecessary variables since this method has too many
variables anyways and we can overload the "nr" counter to do
what "accepted" and "reopen_logs" did..
|
|
So don't bother checking them again. Configurator already
ensures that they're Proc objects for us, and we've been
forgetting to check @before_fork since the beginning of
time anyways... Consistency + less code = good
|
|
We don't (and won't ever) do log rotation within the process.
That's the job of logrotate and tools like that. We just
reopen logs like other reasonable daemons out there.
|
|
Otherwise we get generally worthless backtraces and we don't
want to clobber those for other signals, either.
|
|
|