bugfix: the ngx.thread API did not work in access_by_lua*.

This commit is contained in:
agentzh (Yichun Zhang) 2012-09-25 17:20:27 -07:00
Родитель f4e8894e2d
Коммит 00e99d519f
5 изменённых файлов: 2961 добавлений и 7 удалений

Просмотреть файл

@ -88,11 +88,6 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
dd("entered? %d", (int) ctx->entered_access_phase);
if (ctx->waiting_more_body) {
dd("WAITING MORE BODY");
return NGX_DONE;
}
if (ctx->entered_access_phase) {
dd("calling wev handler");
rc = ctx->resume_handler(r);
@ -105,6 +100,11 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
return NGX_DECLINED;
}
if (ctx->waiting_more_body) {
dd("WAITING MORE BODY");
return NGX_DONE;
}
if (llcf->force_read_body && !ctx->read_body_done) {
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
@ -291,12 +291,25 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
}
if (rc == NGX_AGAIN) {
return ngx_http_lua_run_posted_threads(c, L, r, ctx);
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);
if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) {
return rc;
}
return NGX_DECLINED;
}
if (rc == NGX_DONE) {
ngx_http_finalize_request(r, NGX_DONE);
return ngx_http_lua_run_posted_threads(c, L, r, ctx);
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx);
if (rc == NGX_ERROR || rc == NGX_DONE || rc >= NGX_OK) {
return rc;
}
return NGX_DECLINED;
}
return NGX_DECLINED;

343
t/024-access/uthread-exec.t Normal file
Просмотреть файл

@ -0,0 +1,343 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:
use lib 'lib';
use Test::Nginx::Socket;
use t::StapThread;
our $GCScript = $t::StapThread::GCScript;
our $StapScript = $t::StapThread::StapScript;
repeat_each(2);
plan tests => repeat_each() * (blocks() * 4);
$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211';
#no_shuffle();
no_long_string();
run_tests();
__DATA__
=== TEST 1: exec in user thread (entry still pending)
--- config
location /lua {
access_by_lua '
function f()
ngx.exec("/foo")
end
ngx.thread.spawn(f)
ngx.sleep(1)
ngx.say("hello")
';
content_by_lua return;
}
location /foo {
echo i am foo;
}
--- request
GET /lua
--- stap2 eval: $::StapScript
--- stap eval: $::GCScript
--- stap_out
create 2 in 1
create user thread 2 in 1
delete thread 2
delete thread 1
--- response_body
i am foo
--- no_error_log
[error]
=== TEST 2: exec in user thread (entry already quits)
--- config
location /lua {
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.exec("/foo")
end
ngx.thread.spawn(f)
';
content_by_lua return;
}
location /foo {
echo i am foo;
}
--- request
GET /lua
--- stap2 eval: $::StapScript
--- stap eval: $::GCScript
--- stap_out
create 2 in 1
create user thread 2 in 1
delete thread 1
delete thread 2
--- response_body
i am foo
--- no_error_log
[error]
=== TEST 3: exec in user thread (entry thread is still pending on ngx.sleep)
--- config
location /lua {
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.exec("/foo")
end
ngx.thread.spawn(f)
ngx.sleep(1)
';
content_by_lua return;
}
location = /foo {
echo hello foo;
}
--- request
GET /lua
--- stap2 eval: $::StapScript
--- stap eval
<<'_EOC_' . $::GCScript;
global timers
F(ngx_http_free_request) {
println("free request")
}
M(timer-add) {
if ($arg2 == 1000 || $arg2 == 100) {
timers[$arg1] = $arg2
printf("add timer %d\n", $arg2)
}
}
M(timer-del) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("delete timer %d\n", tm)
delete timers[$arg1]
}
/*
if (tm == 1000) {
print_ubacktrace()
}
*/
}
M(timer-expire) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("expire timer %d\n", timers[$arg1])
delete timers[$arg1]
}
}
F(ngx_http_lua_sleep_cleanup) {
println("lua sleep cleanup")
}
_EOC_
--- stap_out
create 2 in 1
create user thread 2 in 1
add timer 100
add timer 1000
expire timer 100
lua sleep cleanup
delete timer 1000
delete thread 2
delete thread 1
free request
--- response_body
hello foo
--- no_error_log
[error]
=== TEST 4: exec in a user thread (another user thread is still pending on ngx.sleep)
--- config
location /lua {
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.exec("/foo")
end
function g()
ngx.sleep(1)
end
ngx.thread.spawn(f)
ngx.thread.spawn(g)
';
content_by_lua return;
}
location = /foo {
echo hello foo;
}
--- request
GET /lua
--- stap2 eval: $::StapScript
--- stap eval
<<'_EOC_' . $::GCScript;
global timers
F(ngx_http_free_request) {
println("free request")
}
M(timer-add) {
if ($arg2 == 1000 || $arg2 == 100) {
timers[$arg1] = $arg2
printf("add timer %d\n", $arg2)
}
}
M(timer-del) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("delete timer %d\n", tm)
delete timers[$arg1]
}
/*
if (tm == 1000) {
print_ubacktrace()
}
*/
}
M(timer-expire) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("expire timer %d\n", timers[$arg1])
delete timers[$arg1]
}
}
F(ngx_http_lua_sleep_cleanup) {
println("lua sleep cleanup")
}
_EOC_
--- stap_out
create 2 in 1
create user thread 2 in 1
add timer 100
create 3 in 1
create user thread 3 in 1
add timer 1000
delete thread 1
expire timer 100
lua sleep cleanup
delete timer 1000
delete thread 2
delete thread 3
free request
--- response_body
hello foo
--- no_error_log
[error]
=== TEST 5: exec in user thread (entry thread is still pending on ngx.location.capture), without pending output
--- config
location /lua {
client_body_timeout 12000ms;
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.exec("/foo")
end
ngx.thread.spawn(f)
ngx.location.capture("/sleep")
ngx.say("end")
';
content_by_lua return;
}
location = /sleep {
echo_sleep 0.2;
}
location = /foo {
echo hello world;
}
--- request
POST /lua
--- more_headers
Content-Length: 1024
--- stap2 eval: $::StapScript
--- stap eval
<<'_EOC_' . $::GCScript;
global timers
F(ngx_http_free_request) {
println("free request")
}
M(timer-add) {
if ($arg2 == 200 || $arg2 == 100) {
timers[$arg1] = $arg2
printf("add timer %d\n", $arg2)
}
}
M(timer-del) {
tm = timers[$arg1]
if (tm == 200 || tm == 100) {
printf("delete timer %d\n", tm)
delete timers[$arg1]
}
}
M(timer-expire) {
tm = timers[$arg1]
if (tm == 200 || tm == 100) {
printf("expire timer %d\n", timers[$arg1])
delete timers[$arg1]
}
}
_EOC_
--- stap_out
create 2 in 1
create user thread 2 in 1
add timer 100
add timer 200
expire timer 100
delete thread 2
delete thread 1
delete timer 200
free request
--- ignore_response
--- error_log
attempt to abort with pending subrequests
--- no_error_log
[alert]
[warn]

1316
t/024-access/uthread-exit.t Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,191 @@
# vim:set ft= ts=4 sw=4 et fdm=marker:
use lib 'lib';
use Test::Nginx::Socket;
use t::StapThread;
our $GCScript = $t::StapThread::GCScript;
our $StapScript = $t::StapThread::StapScript;
repeat_each(2);
plan tests => repeat_each() * (blocks() * 4);
$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= '11211';
$ENV{TEST_NGINX_REDIS_PORT} ||= '6379';
#no_shuffle();
no_long_string();
run_tests();
__DATA__
=== TEST 1: ngx.redirect() in user thread (entry thread is still pending on ngx.location.capture_multi), without pending output
--- config
location /lua {
client_body_timeout 12000ms;
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.redirect(301)
end
ngx.thread.spawn(f)
ngx.location.capture_multi{
{"/echo"},
{"/sleep"}
}
ngx.say("end")
';
content_by_lua return;
}
location = /echo {
echo hello;
}
location = /sleep {
echo_sleep 0.2;
}
--- request
POST /lua
--- more_headers
Content-Length: 1024
--- stap2 eval: $::StapScript
--- stap eval
<<'_EOC_' . $::GCScript;
global timers
F(ngx_http_free_request) {
println("free request")
}
M(timer-add) {
if ($arg2 == 200 || $arg2 == 100) {
timers[$arg1] = $arg2
printf("add timer %d\n", $arg2)
}
}
M(timer-del) {
tm = timers[$arg1]
if (tm == 200 || tm == 100) {
printf("delete timer %d\n", tm)
delete timers[$arg1]
}
}
M(timer-expire) {
tm = timers[$arg1]
if (tm == 200 || tm == 100) {
printf("expire timer %d\n", timers[$arg1])
delete timers[$arg1]
}
}
F(ngx_http_lua_post_subrequest) {
printf("post subreq %s\n", ngx_http_req_uri($r))
}
_EOC_
--- stap_out
create 2 in 1
create user thread 2 in 1
add timer 100
post subreq /echo
add timer 200
expire timer 100
delete thread 2
delete thread 1
delete timer 200
free request
--- ignore_response
--- error_log
attempt to abort with pending subrequests
--- no_error_log
[alert]
[warn]
=== TEST 2: redirect in user thread (entry thread is still pending on ngx.sleep)
--- config
location /lua {
access_by_lua '
function f()
ngx.sleep(0.1)
ngx.redirect(301)
end
ngx.thread.spawn(f)
ngx.sleep(1)
ngx.say("end")
';
content_by_lua return;
}
--- request
GET /lua
--- stap2 eval: $::StapScript
--- stap eval
<<'_EOC_' . $::GCScript;
global timers
F(ngx_http_free_request) {
println("free request")
}
M(timer-add) {
if ($arg2 == 1000 || $arg2 == 100) {
timers[$arg1] = $arg2
printf("add timer %d\n", $arg2)
}
}
M(timer-del) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("delete timer %d\n", tm)
delete timers[$arg1]
}
/*
if (tm == 1000) {
print_ubacktrace()
}
*/
}
M(timer-expire) {
tm = timers[$arg1]
if (tm == 1000 || tm == 100) {
printf("expire timer %d\n", timers[$arg1])
delete timers[$arg1]
}
}
F(ngx_http_lua_sleep_cleanup) {
println("lua sleep cleanup")
}
_EOC_
--- stap_out
create 2 in 1
create user thread 2 in 1
add timer 100
add timer 1000
expire timer 100
lua sleep cleanup
delete timer 1000
delete thread 2
delete thread 1
free request
--- response_body_like: 302 Found
--- error_code: 302
--- no_error_log
[error]

1091
t/024-access/uthread.t Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу