mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
Release that improves performance a bit on most platforms, but dramatically on freebsd.
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@117 19e92222-5c0b-0410-8929-a290d50e31e9
This commit is contained in:
parent
ebeac4b031
commit
6634d89019
6 changed files with 77 additions and 26 deletions
2
Rakefile
2
Rakefile
|
@ -32,7 +32,7 @@ end
|
|||
setup_extension("http11", "http11")
|
||||
|
||||
name="mongrel"
|
||||
version="0.3.11"
|
||||
version="0.3.12"
|
||||
|
||||
setup_gem(name, version) do |spec|
|
||||
spec.summary = "A small fast HTTP library and server that runs Rails, Camping, and Nitro apps."
|
||||
|
|
|
@ -113,6 +113,12 @@ class Start < GemPlugin::Plugin "/commands"
|
|||
File.unlink @pid_file if File.exist?(@pid_file)
|
||||
@restart = true
|
||||
}
|
||||
|
||||
trap("INT") {
|
||||
server.stop
|
||||
File.unlink @pid_file if File.exist?(@pid_file)
|
||||
@restart = false
|
||||
}
|
||||
end
|
||||
|
||||
# hook up any rails specific plugins
|
||||
|
|
|
@ -142,6 +142,40 @@ module Mongrel
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
def self.escape(s)
|
||||
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
||||
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
||||
}.tr(' ', '+')
|
||||
end
|
||||
|
||||
|
||||
def self.unescape(s)
|
||||
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
||||
[$1.delete('%')].pack('H*')
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def self.query_parse(qs, d = '&;')
|
||||
params = {}
|
||||
(qs||'').split(/[#{d}] */n).inject(params) { |h,p|
|
||||
k, v=unescape(p).split('=',2)
|
||||
if cur = params[k]
|
||||
if cur.class == Array
|
||||
params[k] << v
|
||||
else
|
||||
params[k] = [cur, v]
|
||||
end
|
||||
else
|
||||
params[k] = v
|
||||
end
|
||||
}
|
||||
|
||||
return params
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -292,25 +326,11 @@ module Mongrel
|
|||
# try lowering it (after you've tuned your stuff of course).
|
||||
def initialize(host, port, num_processors=20, timeout=120)
|
||||
@socket = TCPServer.new(host, port)
|
||||
|
||||
@classifier = URIClassifier.new
|
||||
@req_queue = Queue.new
|
||||
@host = host
|
||||
@port = port
|
||||
@processors = []
|
||||
|
||||
# create the worker threads
|
||||
num_processors.times do |i|
|
||||
@processors << Thread.new do
|
||||
parser = HttpParser.new
|
||||
while client = @req_queue.deq
|
||||
Timeout::timeout(timeout) do
|
||||
process_client(client, parser)
|
||||
parser.reset
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@worker_group = ThreadGroup.new
|
||||
@timeout = timeout
|
||||
|
||||
end
|
||||
|
||||
|
@ -320,8 +340,9 @@ module Mongrel
|
|||
# the performance just does not improve. It is currently carefully constructed
|
||||
# to make sure that it gets the best possible performance, but anyone who
|
||||
# thinks they can make it faster is more than welcome to take a crack at it.
|
||||
def process_client(client, parser)
|
||||
def process_client(client)
|
||||
begin
|
||||
parser = HttpParser.new
|
||||
params = {}
|
||||
|
||||
data = client.readpartial(Const::CHUNK_SIZE)
|
||||
|
@ -368,13 +389,22 @@ module Mongrel
|
|||
# Runs the thing. It returns the thread used so you can "join" it. You can also
|
||||
# access the HttpServer::acceptor attribute to get the thread later.
|
||||
def run
|
||||
|
||||
BasicSocket.do_not_reverse_lookup=true
|
||||
|
||||
@acceptor = Thread.new do
|
||||
Thread.current[:stopped] = false
|
||||
|
||||
|
||||
while not Thread.current[:stopped]
|
||||
begin
|
||||
@req_queue << @socket.accept
|
||||
client = @socket.accept
|
||||
|
||||
thread = Thread.new do
|
||||
process_client(client)
|
||||
end
|
||||
|
||||
thread.priority=1
|
||||
@worker_group.add(thread)
|
||||
rescue StopServer
|
||||
STDERR.puts "Server stopped. Exiting."
|
||||
@socket.close if not @socket.closed?
|
||||
|
@ -387,17 +417,14 @@ module Mongrel
|
|||
|
||||
# now that processing is done we feed enough false onto the request queue to get
|
||||
# each processor to exit and stop processing.
|
||||
@processors.length.times { @req_queue << false }
|
||||
|
||||
# finally we wait until the queue is empty
|
||||
while @req_queue.length > 0
|
||||
STDERR.puts "Shutdown waiting for #{@req_queue.length} requests" if @req_queue.length > 0
|
||||
while @worker_group.list.length > 0
|
||||
STDERR.puts "Shutdown waiting for #{@worker_group.list.length} requests" if @worker_group.list.length > 0
|
||||
sleep 1
|
||||
end
|
||||
end
|
||||
|
||||
@acceptor.priority = 1
|
||||
|
||||
return @acceptor
|
||||
end
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ setup_gem(name, version) do |spec|
|
|||
spec.description = spec.summary
|
||||
spec.author="Zed A. Shaw"
|
||||
spec.add_dependency('gem_plugin', '>= 0.2.1')
|
||||
spec.add_dependency('mongrel', '>= 0.2.1')
|
||||
spec.add_dependency('mongrel', '>= 0.3.11')
|
||||
spec.files += Dir.glob("resources/**/*")
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
require 'test/unit'
|
||||
require 'http11'
|
||||
require 'mongrel'
|
||||
require 'benchmark'
|
||||
|
||||
include Mongrel
|
||||
|
||||
class HttpParserTest < Test::Unit::TestCase
|
||||
|
||||
|
@ -34,5 +37,18 @@ class HttpParserTest < Test::Unit::TestCase
|
|||
assert !parser.finished?, "Parser shouldn't be finished"
|
||||
assert parser.error?, "Parser SHOULD have error"
|
||||
end
|
||||
|
||||
def test_query_parse
|
||||
puts HttpRequest.query_parse("zed=1&frank=2").inspect
|
||||
puts HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45").inspect
|
||||
|
||||
puts Benchmark.measure {
|
||||
10000.times do |i|
|
||||
g = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11").inspect
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'test/unit'
|
||||
require 'mongrel'
|
||||
require 'benchmark'
|
||||
|
||||
include Mongrel
|
||||
|
||||
|
@ -40,5 +41,6 @@ class ResponseTest < Test::Unit::TestCase
|
|||
assert io.length > 0, "output didn't have data"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue