diff options
-rw-r--r-- | ext/http11/http11_parser.c | 47 | ||||
-rw-r--r-- | lib/mongrel.rb | 29 | ||||
-rw-r--r-- | lib/mongrel/debug.rb | 44 | ||||
-rw-r--r-- | lib/mongrel/rails.rb | 47 |
4 files changed, 91 insertions, 76 deletions
diff --git a/ext/http11/http11_parser.c b/ext/http11/http11_parser.c index 9b399f8..8343127 100644 --- a/ext/http11/http11_parser.c +++ b/ext/http11/http11_parser.c @@ -21,11 +21,11 @@ /** Data **/ #line 24 "ext/http11/http11_parser.c" -static int http_parser_start = 0; +static const int http_parser_start = 0; -static int http_parser_first_final = 53; +static const int http_parser_first_final = 53; -static int http_parser_error = 1; +static const int http_parser_error = 1; #line 118 "ext/http11/http11_parser.rl" @@ -66,8 +66,7 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, #line 68 "ext/http11/http11_parser.c" { - p -= 1; - if ( ++p == pe ) + if ( p == pe ) goto _out; switch ( cs ) { @@ -95,7 +94,7 @@ st2: if ( ++p == pe ) goto _out2; case 2: -#line 99 "ext/http11/http11_parser.c" +#line 98 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr17; case 36: goto st34; @@ -121,7 +120,7 @@ st3: if ( ++p == pe ) goto _out3; case 3: -#line 125 "ext/http11/http11_parser.c" +#line 124 "ext/http11/http11_parser.c" switch( (*p) ) { case 42: goto tr10; case 43: goto tr11; @@ -145,7 +144,7 @@ st4: if ( ++p == pe ) goto _out4; case 4: -#line 149 "ext/http11/http11_parser.c" +#line 148 "ext/http11/http11_parser.c" if ( (*p) == 32 ) goto tr19; goto st1; @@ -198,7 +197,7 @@ st5: if ( ++p == pe ) goto _out5; case 5: -#line 202 "ext/http11/http11_parser.c" +#line 201 "ext/http11/http11_parser.c" if ( (*p) == 72 ) goto tr3; goto st1; @@ -210,7 +209,7 @@ st6: if ( ++p == pe ) goto _out6; case 6: -#line 214 "ext/http11/http11_parser.c" +#line 213 "ext/http11/http11_parser.c" if ( (*p) == 84 ) goto st7; goto st1; @@ -286,7 +285,7 @@ st14: if ( ++p == pe ) goto _out14; case 14: -#line 290 "ext/http11/http11_parser.c" +#line 289 "ext/http11/http11_parser.c" if ( (*p) == 10 ) goto st15; goto st1; @@ -338,7 +337,7 @@ st53: if ( ++p == pe ) goto _out53; case 53: -#line 342 "ext/http11/http11_parser.c" +#line 341 "ext/http11/http11_parser.c" goto st1; tr21: #line 23 "ext/http11/http11_parser.rl" @@ -348,7 +347,7 @@ st17: if ( ++p == pe ) goto _out17; case 17: -#line 352 "ext/http11/http11_parser.c" +#line 351 "ext/http11/http11_parser.c" switch( (*p) ) { case 33: goto st17; case 58: goto tr16; @@ -387,7 +386,7 @@ st18: if ( ++p == pe ) goto _out18; case 18: -#line 391 "ext/http11/http11_parser.c" +#line 390 "ext/http11/http11_parser.c" switch( (*p) ) { case 13: goto tr36; case 32: goto tr38; @@ -401,7 +400,7 @@ st19: if ( ++p == pe ) goto _out19; case 19: -#line 405 "ext/http11/http11_parser.c" +#line 404 "ext/http11/http11_parser.c" if ( (*p) == 13 ) goto tr36; goto st19; @@ -413,7 +412,7 @@ st20: if ( ++p == pe ) goto _out20; case 20: -#line 417 "ext/http11/http11_parser.c" +#line 416 "ext/http11/http11_parser.c" switch( (*p) ) { case 43: goto st20; case 58: goto st21; @@ -438,7 +437,7 @@ st21: if ( ++p == pe ) goto _out21; case 21: -#line 442 "ext/http11/http11_parser.c" +#line 441 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr19; case 37: goto st22; @@ -486,7 +485,7 @@ st24: if ( ++p == pe ) goto _out24; case 24: -#line 490 "ext/http11/http11_parser.c" +#line 489 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr31; case 37: goto st25; @@ -539,7 +538,7 @@ st27: if ( ++p == pe ) goto _out27; case 27: -#line 543 "ext/http11/http11_parser.c" +#line 542 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr19; case 37: goto st28; @@ -591,7 +590,7 @@ st30: if ( ++p == pe ) goto _out30; case 30: -#line 595 "ext/http11/http11_parser.c" +#line 594 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr40; case 37: goto tr41; @@ -613,7 +612,7 @@ st31: if ( ++p == pe ) goto _out31; case 31: -#line 617 "ext/http11/http11_parser.c" +#line 616 "ext/http11/http11_parser.c" switch( (*p) ) { case 32: goto tr28; case 37: goto st32; @@ -635,7 +634,7 @@ st32: if ( ++p == pe ) goto _out32; case 32: -#line 639 "ext/http11/http11_parser.c" +#line 638 "ext/http11/http11_parser.c" if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st33; @@ -1061,7 +1060,7 @@ case 52: if(parser->body_start) { /* final \r\n combo encountered so stop right here */ -#line 1065 "ext/http11/http11_parser.c" +#line 1064 "ext/http11/http11_parser.c" #line 163 "ext/http11/http11_parser.rl" parser->nread++; } @@ -1074,7 +1073,7 @@ int http_parser_finish(http_parser *parser) int cs = parser->cs; -#line 1078 "ext/http11/http11_parser.c" +#line 1077 "ext/http11/http11_parser.c" #line 174 "ext/http11/http11_parser.rl" parser->cs = cs; diff --git a/lib/mongrel.rb b/lib/mongrel.rb index ca4ea12..8d0c57c 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -228,15 +228,13 @@ module Mongrel def read_body(remain, total, dispatcher) begin # write the odd sized chunk first - remain -= @body.write(@socket.read(remain % Const::CHUNK_SIZE)) + + remain -= @body.write(read_socket(remain % Const::CHUNK_SIZE)) dispatcher.request_progress(params, remain, total) if dispatcher # then stream out nothing but perfectly sized chunks until remain <= 0 or @socket.closed? - data = @socket.read(Const::CHUNK_SIZE) - # have to do it this way since @socket.eof? causes it to block - raise "Socket closed or read failure" if not data or data.length != Const::CHUNK_SIZE - remain -= @body.write(data) + remain -= @body.write(read_socket(Const::CHUNK_SIZE)) # ASSUME: we are writing to a disk and these writes always write the requested amount dispatcher.request_progress(params, remain, total) if dispatcher end @@ -250,6 +248,20 @@ module Mongrel end end + def read_socket(len) + if !@socket.closed? + data = @socket.read(len) + if !data + raise "Socket read return nil" + elsif data.length != len + raise "Socket read returned insufficient data: #{data.length}" + else + data + end + else + raise "Socket already closed when reading." + end + end # Performs URI escaping so that you can construct proper # query strings faster. Use this rather than the cgi.rb @@ -386,8 +398,9 @@ module Mongrel elsif @header_sent raise "You have already sent the request headers." else - @header.out.rewind - @body.rewind + @header.out.truncate(0) + @body.close + @body = StringIO.new end end @@ -587,7 +600,7 @@ module Mongrel end end rescue EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF - # ignored + client.close rescue Object rescue HttpParserError if $mongrel_debug_client STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!" diff --git a/lib/mongrel/debug.rb b/lib/mongrel/debug.rb index 4746792..64a1a16 100644 --- a/lib/mongrel/debug.rb +++ b/lib/mongrel/debug.rb @@ -20,7 +20,7 @@ module MongrelDbg Dir.mkdir(log_dir) if not File.exist?(log_dir) @log_dir = log_dir $objects_out=open(File.join("log","mongrel_debug","objects.log"),"w") - $objects_out.puts "run,classname,last,count,delta" + $objects_out.puts "run,classname,last,count,delta,lenmean,lensd,lenmax" $objects_out.sync = true $last_stat = nil $run_count = 0 @@ -122,20 +122,40 @@ module RequestLog include Mongrel::HttpHandlerPlugin def process(request,response) - stats = Hash.new(0) - ObjectSpace.each_object {|o| stats[o.class] += 1} - - stats.sort {|(k1,v1),(k2,v2)| v2 <=> v1}.each do |k,v| - if $last_stat - delta = v - $last_stat[k] - if v > 10 and delta != 0 - $objects_out.printf "%d,%s,%d,%d,%d\n", $run_count, k, $last_stat[k], v, delta + begin + stats = Hash.new(0) + lengths = {} + ObjectSpace.each_object do |o| + begin + if o.respond_to? :length + len = o.length + lengths[o.class] ||= Stats.new(o.class) + lengths[o.class].sample(len) + end + rescue Object + end + + stats[o.class] += 1 + end + + stats.sort {|(k1,v1),(k2,v2)| v2 <=> v1}.each do |k,v| + if $last_stat + delta = v - $last_stat[k] + if v > 10 and delta != 0 + if lengths[k] + $objects_out.printf "%d,%s,%d,%d,%d,%f,%f,%f\n", $run_count, k, $last_stat[k], v, delta,lengths[k].mean,lengths[k].sd,lengths[k].max + else + $objects_out.printf "%d,%s,%d,%d,%d,,,\n", $run_count, k, $last_stat[k], v, delta + end + end end end - end - $run_count += 1 - $last_stat = stats + $run_count += 1 + $last_stat = stats + rescue Object + STDERR.puts "object.log ERROR: #$!" + end end end diff --git a/lib/mongrel/rails.rb b/lib/mongrel/rails.rb index c1a7043..5dcbf7f 100644 --- a/lib/mongrel/rails.rb +++ b/lib/mongrel/rails.rb @@ -6,10 +6,11 @@ require 'mongrel' require 'cgi' +require 'sync' -class Mutex +class Sync # modified to open the waiting list for reporting purposes - attr_accessor :waiting + attr_accessor :sync_waiting end module Mongrel @@ -41,7 +42,7 @@ module Mongrel def initialize(dir, mime_map = {}) @files = Mongrel::DirHandler.new(dir,false) - @guard = Mutex.new + @guard = Sync.new @tick = Time.now # register the requested mime types @@ -75,11 +76,11 @@ module Mongrel # we don't want the output to be really final until we're out of the lock cgi.default_really_final = false - lock! request.params[Mongrel::Const::PATH_INFO] + log_threads_waiting_for(request.params["PATH_INFO"]) - Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body) - - unlock! + @guard.synchronize(:EX) { + Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, response.body) + } # This finalizes the output using the proper HttpResponse way cgi.out("text/html",true) {""} @@ -88,26 +89,13 @@ module Mongrel rescue Object => rails_error STDERR.puts "#{Time.now}: Error calling Dispatcher.dispatch #{rails_error.inspect}" STDERR.puts rails_error.backtrace.join("\n") - ensure - unlock! end end end - def lock!(path) - # ultra dangerous, but people are asking to kill themselves. here's the Katana - log_threads_waiting_for path - @guard.lock unless ActionController::Base.allow_concurrency - end - - def unlock! - log_threads_waiting_for "unlock" - @guard.unlock unless ActionController::Base.allow_concurrency - end - def log_threads_waiting_for(event) if $mongrel_debug_client and (Time.now - @tick > 10) - STDERR.puts "#{Time.now}: #{@guard.waiting.length} threads waiting for #{event}." + STDERR.puts "#{Time.now}: #{@guard.sync_waiting.length} threads sync_waiting for #{event}, #{self.listener.workers.list.length} still active in mongrel." @tick = Time.now end end @@ -116,13 +104,12 @@ module Mongrel # sometimes you get exceptions. In that case just do a real restart. def reload! begin - lock! "RAILS RELOAD" - $".replace $orig_dollar_quote - GC.start - Dispatcher.reset_application! - ActionController::Routing::Routes.reload - ensure - unlock! + @guard.synchronize(:EX) { + $".replace $orig_dollar_quote + GC.start + Dispatcher.reset_application! + ActionController::Routing::Routes.reload + } end end end @@ -173,10 +160,6 @@ module Mongrel require 'dispatcher' require 'mongrel/rails' - if ActionController::Base.allow_concurrency - log "[RAILS] ActionController::Base.allow_concurrency is true. Wow, you're very brave." - end - ActionController::AbstractRequest.relative_url_root = ops[:prefix] if ops[:prefix] @rails_handler = RailsHandler.new(ops[:docroot], ops[:mime]) |