unicorn 0.8.2 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/GNUmakefile +4 -4
- data/lib/unicorn.rb +10 -13
- data/lib/unicorn/app/exec_cgi.rb +4 -9
- data/lib/unicorn/const.rb +1 -1
- data/lib/unicorn/util.rb +17 -0
- data/test/unit/test_util.rb +30 -28
- data/unicorn.gemspec +3 -3
- metadata +8 -8
data/CHANGELOG
CHANGED
data/GNUmakefile
CHANGED
@@ -48,7 +48,7 @@ http11: lib/unicorn/http11.$(DLEXT)
|
|
48
48
|
|
49
49
|
$(test_prefix)/.stamp: $(inst_deps)
|
50
50
|
mkdir -p $(test_prefix)/.ccache
|
51
|
-
tar c
|
51
|
+
tar c `cat Manifest` | (cd $(test_prefix) && tar x)
|
52
52
|
$(MAKE) -C $(test_prefix) clean
|
53
53
|
$(MAKE) -C $(test_prefix) http11 shebang
|
54
54
|
> $@
|
@@ -88,14 +88,14 @@ run_test = $(quiet_pre) setsid $(ruby) -w $(arg) $(TEST_OPTS) $(quiet_post) || \
|
|
88
88
|
%.n: arg = $(subst .n,,$(subst --, -n ,$@))
|
89
89
|
%.n: t = $(subst .n,$(log_suffix),$@)
|
90
90
|
%.n: export PATH := $(test_prefix)/bin:$(PATH)
|
91
|
-
%.n: export RUBYLIB := $(test_prefix)/lib:$(RUBYLIB)
|
91
|
+
%.n: export RUBYLIB := $(test_prefix):$(test_prefix)/lib:$(RUBYLIB)
|
92
92
|
%.n: $(test_prefix)/.stamp
|
93
93
|
$(run_test)
|
94
94
|
|
95
95
|
$(T): arg = $@
|
96
96
|
$(T): t = $(subst .rb,$(log_suffix),$@)
|
97
97
|
$(T): export PATH := $(test_prefix)/bin:$(PATH)
|
98
|
-
$(T): export RUBYLIB := $(test_prefix)/lib:$(RUBYLIB)
|
98
|
+
$(T): export RUBYLIB := $(test_prefix):$(test_prefix)/lib:$(RUBYLIB)
|
99
99
|
$(T): $(test_prefix)/.stamp
|
100
100
|
$(run_test)
|
101
101
|
|
@@ -141,7 +141,7 @@ $(T_r).%.r: rv = $(subst .r,,$(subst $(T_r).,,$@))
|
|
141
141
|
$(T_r).%.r: extra = ' 'v$(rv)
|
142
142
|
$(T_r).%.r: arg = $(T_r)
|
143
143
|
$(T_r).%.r: export PATH := $(test_prefix)/bin:$(PATH)
|
144
|
-
$(T_r).%.r: export RUBYLIB := $(test_prefix)/lib:$(RUBYLIB)
|
144
|
+
$(T_r).%.r: export RUBYLIB := $(test_prefix):$(test_prefix)/lib:$(RUBYLIB)
|
145
145
|
$(T_r).%.r: export UNICORN_RAILS_TEST_VERSION = $(rv)
|
146
146
|
$(T_r).%.r: export RAILS_GIT_REPO = $(CURDIR)/$(rails_git)
|
147
147
|
$(T_r).%.r: $(test_prefix)/.stamp $(rails_git)/info/cloned-stamp
|
data/lib/unicorn.rb
CHANGED
@@ -54,8 +54,7 @@ module Unicorn
|
|
54
54
|
0 => $0.dup,
|
55
55
|
}
|
56
56
|
|
57
|
-
Worker
|
58
|
-
class Worker
|
57
|
+
class Worker < Struct.new(:nr, :tmp)
|
59
58
|
# worker objects may be compared to just plain numbers
|
60
59
|
def ==(other_nr)
|
61
60
|
self.nr == other_nr
|
@@ -323,7 +322,7 @@ module Unicorn
|
|
323
322
|
self.pid = @pid.chomp('.oldbin') if @pid
|
324
323
|
proc_name 'master'
|
325
324
|
else
|
326
|
-
worker = WORKERS.delete(pid) and worker.
|
325
|
+
worker = WORKERS.delete(pid) and worker.tmp.close rescue nil
|
327
326
|
logger.info "reaped #{status.inspect} " \
|
328
327
|
"worker=#{worker.nr rescue 'unknown'}"
|
329
328
|
end
|
@@ -383,16 +382,16 @@ module Unicorn
|
|
383
382
|
end
|
384
383
|
|
385
384
|
# forcibly terminate all workers that haven't checked in in @timeout
|
386
|
-
# seconds. The timeout is implemented using an unlinked
|
385
|
+
# seconds. The timeout is implemented using an unlinked File
|
387
386
|
# shared between the parent process and each worker. The worker
|
388
|
-
# runs File#chmod to modify the ctime of the
|
387
|
+
# runs File#chmod to modify the ctime of the File. If the ctime
|
389
388
|
# is stale for >@timeout seconds, then we'll kill the corresponding
|
390
389
|
# worker.
|
391
390
|
def murder_lazy_workers
|
392
391
|
diff = stat = nil
|
393
392
|
WORKERS.dup.each_pair do |pid, worker|
|
394
393
|
stat = begin
|
395
|
-
worker.
|
394
|
+
worker.tmp.stat
|
396
395
|
rescue => e
|
397
396
|
logger.warn "worker=#{worker.nr} PID:#{pid} stat error: #{e.inspect}"
|
398
397
|
kill_worker(:QUIT, pid)
|
@@ -416,9 +415,7 @@ module Unicorn
|
|
416
415
|
SIG_QUEUE << :QUIT # forcibly emulate SIGQUIT
|
417
416
|
return
|
418
417
|
end
|
419
|
-
|
420
|
-
tempfile.unlink # don't allow other processes to find or see it
|
421
|
-
worker = Worker.new(worker_nr, tempfile)
|
418
|
+
worker = Worker.new(worker_nr, Unicorn::Util.tmpio)
|
422
419
|
@before_fork.call(self, worker)
|
423
420
|
pid = fork { worker_loop(worker) }
|
424
421
|
WORKERS[pid] = worker
|
@@ -466,10 +463,10 @@ module Unicorn
|
|
466
463
|
proc_name "worker[#{worker.nr}]"
|
467
464
|
START_CTX.clear
|
468
465
|
init_self_pipe!
|
469
|
-
WORKERS.values.each { |other| other.
|
466
|
+
WORKERS.values.each { |other| other.tmp.close rescue nil }
|
470
467
|
WORKERS.clear
|
471
468
|
LISTENERS.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
472
|
-
worker.
|
469
|
+
worker.tmp.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
473
470
|
@after_fork.call(self, worker) # can drop perms
|
474
471
|
@timeout /= 2.0 # halve it for select()
|
475
472
|
build_app! unless @preload_app
|
@@ -489,7 +486,7 @@ module Unicorn
|
|
489
486
|
master_pid = Process.ppid # slightly racy, but less memory usage
|
490
487
|
init_worker_process(worker)
|
491
488
|
nr = 0 # this becomes negative if we need to reopen logs
|
492
|
-
alive = worker.
|
489
|
+
alive = worker.tmp # tmp is our lifeline to the master process
|
493
490
|
ready = LISTENERS
|
494
491
|
t = ti = 0
|
495
492
|
|
@@ -555,7 +552,7 @@ module Unicorn
|
|
555
552
|
begin
|
556
553
|
Process.kill(signal, pid)
|
557
554
|
rescue Errno::ESRCH
|
558
|
-
worker = WORKERS.delete(pid) and worker.
|
555
|
+
worker = WORKERS.delete(pid) and worker.tmp.close rescue nil
|
559
556
|
end
|
560
557
|
end
|
561
558
|
|
data/lib/unicorn/app/exec_cgi.rb
CHANGED
@@ -42,11 +42,8 @@ module Unicorn::App
|
|
42
42
|
|
43
43
|
# Calls the app
|
44
44
|
def call(env)
|
45
|
-
out, err =
|
46
|
-
out.unlink
|
47
|
-
err.unlink
|
45
|
+
out, err = Unicorn::Util.tmpio, Unicorn::Util.tmpio
|
48
46
|
inp = force_file_input(env)
|
49
|
-
inp.sync = out.sync = err.sync = true
|
50
47
|
pid = fork { run_child(inp, out, err, env) }
|
51
48
|
inp.close
|
52
49
|
pid, status = Process.waitpid2(pid)
|
@@ -124,14 +121,12 @@ module Unicorn::App
|
|
124
121
|
if inp.respond_to?(:fileno) && Integer === inp.fileno
|
125
122
|
inp
|
126
123
|
elsif inp.size == 0 # inp could be a StringIO or StringIO-like object
|
127
|
-
::File.open('/dev/null')
|
124
|
+
::File.open('/dev/null', 'rb')
|
128
125
|
else
|
129
|
-
tmp =
|
130
|
-
tmp.unlink
|
131
|
-
tmp.binmode
|
126
|
+
tmp = Unicorn::Util.tmpio
|
132
127
|
|
133
128
|
# Rack::Lint::InputWrapper doesn't allow sysread :(
|
134
|
-
buf =
|
129
|
+
buf = Unicorn::Z.dup
|
135
130
|
while inp.read(CHUNK_SIZE, buf)
|
136
131
|
tmp.syswrite(buf)
|
137
132
|
end
|
data/lib/unicorn/const.rb
CHANGED
@@ -5,7 +5,7 @@ module Unicorn
|
|
5
5
|
# gave about a 3% to 10% performance improvement over using the strings directly.
|
6
6
|
# Symbols did not really improve things much compared to constants.
|
7
7
|
module Const
|
8
|
-
UNICORN_VERSION="0.8.
|
8
|
+
UNICORN_VERSION="0.8.3".freeze
|
9
9
|
|
10
10
|
DEFAULT_HOST = "0.0.0.0".freeze # default TCP listen host address
|
11
11
|
DEFAULT_PORT = "8080".freeze # default TCP listen port
|
data/lib/unicorn/util.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'fcntl'
|
2
|
+
require 'tmpdir'
|
2
3
|
|
3
4
|
module Unicorn
|
4
5
|
class Util
|
@@ -39,6 +40,22 @@ module Unicorn
|
|
39
40
|
nr
|
40
41
|
end
|
41
42
|
|
43
|
+
# creates and returns a new File object. The File is unlinked
|
44
|
+
# immediately, switched to binary mode, and userspace output
|
45
|
+
# buffering is disabled
|
46
|
+
def tmpio
|
47
|
+
fp = begin
|
48
|
+
File.open("#{Dir::tmpdir}/#{rand}",
|
49
|
+
File::RDWR|File::CREAT|File::EXCL, 0600)
|
50
|
+
rescue Errno::EEXIST
|
51
|
+
retry
|
52
|
+
end
|
53
|
+
File.unlink(fp.path)
|
54
|
+
fp.binmode
|
55
|
+
fp.sync = true
|
56
|
+
fp
|
57
|
+
end
|
58
|
+
|
42
59
|
end
|
43
60
|
|
44
61
|
end
|
data/test/unit/test_util.rb
CHANGED
@@ -43,20 +43,21 @@ class TestUtil < Test::Unit::TestCase
|
|
43
43
|
tmp = Tempfile.new(nil)
|
44
44
|
tmp_path = tmp.path.dup.freeze
|
45
45
|
Encoding.list.each { |encoding|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
46
|
+
File.open(tmp_path, "a:#{encoding.to_s}") { |fp|
|
47
|
+
fp.sync = true
|
48
|
+
assert_equal encoding, fp.external_encoding
|
49
|
+
assert_nil fp.internal_encoding
|
50
|
+
File.unlink(tmp_path)
|
51
|
+
assert ! File.exist?(tmp_path)
|
52
|
+
Unicorn::Util.reopen_logs
|
53
|
+
assert_equal tmp_path, fp.path
|
54
|
+
assert File.exist?(tmp_path)
|
55
|
+
assert_equal fp.stat.inspect, File.stat(tmp_path).inspect
|
56
|
+
assert_equal encoding, fp.external_encoding
|
57
|
+
assert_nil fp.internal_encoding
|
58
|
+
assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & fp.fcntl(Fcntl::F_GETFL))
|
59
|
+
assert fp.sync
|
60
|
+
}
|
60
61
|
}
|
61
62
|
end if STDIN.respond_to?(:external_encoding)
|
62
63
|
|
@@ -66,20 +67,21 @@ class TestUtil < Test::Unit::TestCase
|
|
66
67
|
Encoding.list.each { |ext|
|
67
68
|
Encoding.list.each { |int|
|
68
69
|
next if ext == int
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
70
|
+
File.open(tmp_path, "a:#{ext.to_s}:#{int.to_s}") { |fp|
|
71
|
+
fp.sync = true
|
72
|
+
assert_equal ext, fp.external_encoding
|
73
|
+
assert_equal int, fp.internal_encoding
|
74
|
+
File.unlink(tmp_path)
|
75
|
+
assert ! File.exist?(tmp_path)
|
76
|
+
Unicorn::Util.reopen_logs
|
77
|
+
assert_equal tmp_path, fp.path
|
78
|
+
assert File.exist?(tmp_path)
|
79
|
+
assert_equal fp.stat.inspect, File.stat(tmp_path).inspect
|
80
|
+
assert_equal ext, fp.external_encoding
|
81
|
+
assert_equal int, fp.internal_encoding
|
82
|
+
assert_equal(EXPECT_FLAGS, EXPECT_FLAGS & fp.fcntl(Fcntl::F_GETFL))
|
83
|
+
assert fp.sync
|
84
|
+
}
|
83
85
|
}
|
84
86
|
}
|
85
87
|
end if STDIN.respond_to?(:external_encoding)
|
data/unicorn.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{unicorn}
|
5
|
-
s.version = "0.8.
|
5
|
+
s.version = "0.8.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Eric Wong"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-19}
|
10
10
|
s.description = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
11
11
|
s.email = %q{normalperson@yhbt.net}
|
12
12
|
s.executables = ["unicorn", "unicorn_rails"]
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.rubyforge_project = %q{unicorn}
|
20
20
|
s.rubygems_version = %q{1.3.4}
|
21
21
|
s.summary = %q{Rack HTTP server for Unix, fast clients and nothing else}
|
22
|
-
s.test_files = ["test/unit/
|
22
|
+
s.test_files = ["test/unit/test_request.rb", "test/unit/test_http_parser.rb", "test/unit/test_server.rb", "test/unit/test_response.rb", "test/unit/test_configurator.rb", "test/unit/test_util.rb", "test/unit/test_upload.rb", "test/unit/test_signals.rb", "test/unit/test_socket_helper.rb"]
|
23
23
|
|
24
24
|
if s.respond_to? :specification_version then
|
25
25
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unicorn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Wong
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-07-
|
12
|
+
date: 2009-07-19 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -222,12 +222,12 @@ signing_key:
|
|
222
222
|
specification_version: 3
|
223
223
|
summary: Rack HTTP server for Unix, fast clients and nothing else
|
224
224
|
test_files:
|
225
|
-
- test/unit/test_configurator.rb
|
226
|
-
- test/unit/test_response.rb
|
227
225
|
- test/unit/test_request.rb
|
228
|
-
- test/unit/test_signals.rb
|
229
|
-
- test/unit/test_upload.rb
|
230
226
|
- test/unit/test_http_parser.rb
|
231
|
-
- test/unit/test_socket_helper.rb
|
232
|
-
- test/unit/test_util.rb
|
233
227
|
- test/unit/test_server.rb
|
228
|
+
- test/unit/test_response.rb
|
229
|
+
- test/unit/test_configurator.rb
|
230
|
+
- test/unit/test_util.rb
|
231
|
+
- test/unit/test_upload.rb
|
232
|
+
- test/unit/test_signals.rb
|
233
|
+
- test/unit/test_socket_helper.rb
|