From a9b7309f93ea47d90211313a078550297f0f42a5 Mon Sep 17 00:00:00 2001 From: Brian Akins Date: Mon, 2 Jul 2012 18:39:23 -0400 Subject: [PATCH 1/5] add options table to connect --- src/ngx_http_lua_socket_tcp.c | 41 ++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index c8e5f780eb..72ddc94d8c 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -264,8 +264,8 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; n = lua_gettop(L); - if (n != 2 && n != 3) { - return luaL_error(L, "ngx.socket connect: expecting 2 or 3 arguments " + if (n != 2 && n != 3 && n != 4) { + return luaL_error(L, "ngx.socket connect: expecting 2, 3, or 4 arguments " "(including the object), but seen %d", n); } @@ -310,16 +310,41 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) return 2; } - lua_pushliteral(L, ":"); - lua_insert(L, 3); - lua_concat(L, 3); - - dd("socket key: %s", lua_tostring(L, -1)); - } else { /* n == 2 */ port = 0; } + if(n == 4) { + luaL_checktype(L, 4, LUA_TTABLE); + + lua_getfield(L, 4, "pool"); + + switch (lua_type(L, -1)) { + case LUA_TNIL: + /* do nothing */ + break; + + case LUA_TSTRING: + /*stack is host, port, table, pool or host, table, pool*/ + lua_remove(L, -2); + /*stack is host, port, pool or host, pool*/ + break; + + default: + return luaL_error(L, "bad \"pool\" option value type: %s", + luaL_typename(L, -1)); + + } + } + + if(n > 2) { + lua_pushliteral(L, ":"); + lua_insert(L, n); + lua_concat(L, n); + + dd("socket key: %s", lua_tostring(L, -1)); + } + /* the key's index is 2 */ lua_pushvalue(L, -1); From 9a0dba25aefef376e0c10cdd100465c307ab099f Mon Sep 17 00:00:00 2001 From: Brian Akins Date: Mon, 2 Jul 2012 20:20:39 -0400 Subject: [PATCH 2/5] more like table.concat --- src/ngx_http_lua_socket_tcp.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 72ddc94d8c..9a25688a29 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -301,7 +301,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_memcpy(host.data, p, len); host.data[len] = '\0'; - if (n == 3) { + if (n >= 3) { port = luaL_checkinteger(L, 3); if (port < 0 || port > 65536) { @@ -320,11 +320,10 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) lua_getfield(L, 4, "pool"); switch (lua_type(L, -1)) { - case LUA_TNIL: - /* do nothing */ - break; + case LUA_TNIL: case LUA_TSTRING: + case LUA_TNUMBER: /*stack is host, port, table, pool or host, table, pool*/ lua_remove(L, -2); /*stack is host, port, pool or host, pool*/ @@ -338,11 +337,20 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } if(n > 2) { - lua_pushliteral(L, ":"); - lua_insert(L, n); - lua_concat(L, n); - - dd("socket key: %s", lua_tostring(L, -1)); + luaL_Buffer b; + int i; + luaL_buffinit(L, &b); + for (i = 2; i <= n; i++) { + lua_pushvalue(L, i); + luaL_addvalue(&b); + if (i != n) { + luaL_addlstring(&b, ":", strlen(":")); + } + } + luaL_pushresult(&b); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "socket key: %s", lua_tostring(L, -1)); + dd("socket key: %s", lua_tostring(L, -1)); } /* the key's index is 2 */ From f9b87d63ff37693f8a7d056f9404ab9652e6dc29 Mon Sep 17 00:00:00 2001 From: Brian Akins Date: Mon, 2 Jul 2012 20:33:30 -0400 Subject: [PATCH 3/5] Remove testign log message --- src/ngx_http_lua_socket_tcp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 9a25688a29..4df0b67687 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -348,8 +348,6 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } } luaL_pushresult(&b); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "socket key: %s", lua_tostring(L, -1)); dd("socket key: %s", lua_tostring(L, -1)); } From 217300abb335c21a43dc152286289387e49f810c Mon Sep 17 00:00:00 2001 From: Brian Akins Date: Tue, 3 Jul 2012 18:42:51 -0400 Subject: [PATCH 4/5] tests with pool --- t/086-socket-keepalive-pool.t | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 t/086-socket-keepalive-pool.t diff --git a/t/086-socket-keepalive-pool.t b/t/086-socket-keepalive-pool.t new file mode 100644 index 0000000000..65cab4368e --- /dev/null +++ b/t/086-socket-keepalive-pool.t @@ -0,0 +1,155 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +repeat_each(2); + +plan tests => blocks() * 2 * repeat_each(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port(); +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; +#$ENV{TEST_NGINX_REDIS_PORT} ||= 6379; + +$ENV{LUA_PATH} ||= + '/usr/local/openresty-debug/lualib/?.lua;/usr/local/openresty/lualib/?.lua;;'; + +no_long_string(); +#no_diff(); +#log_level 'warn'; + +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua ' + local port = ngx.var.port + for i=1,2 do + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, { pool = "test" }) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + '; + } +--- request +GET /t +--- response_body_like +^connected: 1, reused: \d+ +connected: 1, reused: [1-9]\d* + +=== TEST 2: two pools +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua ' + local port = ngx.var.port + function socktest(port, pool) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("127.0.0.1", port, { pool = pool }) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + for i=1,10 do + socktest(port, "one") + socktest(port, "two") + end + '; + } +--- request +GET /t +--- response_body_like +(connected: 1, reused: \d+\s+)* + +=== TEST 3: unix socket +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + default_type 'text/plain'; + } +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua ' + local port = ngx.var.port + for i=1,2 do + local sock = ngx.socket.tcp() + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock", nil, { pool = "nginx.sock" }) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + '; + } +--- request +GET /t +--- response_body_like +^connected: 1, reused: \d+ +connected: 1, reused: [1-9]\d* + + +=== TEST 2: unix socket - two pools +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + default_type 'text/plain'; + } +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + content_by_lua ' + local port = ngx.var.port + function socktest(port, pool) + local sock = ngx.socket.tcp() + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock", nil, { pool = pool }) + if not ok then + ngx.say("failed to connect: ", err) + return + end + ngx.say("connected: ", ok, ", reused: ", sock:getreusedtimes()) + local ok, err = sock:setkeepalive() + if not ok then + ngx.say("failed to set reusable: ", err) + end + end + for i=1,10 do + socktest(port, "one") + socktest(port, "two") + end + '; + } +--- request +GET /t +--- response_body_like +(connected: 1, reused: \d+\s+)* + + From 053209f095ef1a352fa2394a9d2642de17141ceb Mon Sep 17 00:00:00 2001 From: Brian Akins Date: Tue, 3 Jul 2012 18:43:26 -0400 Subject: [PATCH 5/5] major cleanup --- src/ngx_http_lua_socket_tcp.c | 58 ++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c index 4df0b67687..37cddf20df 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c @@ -260,6 +260,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) ngx_http_lua_loc_conf_t *llcf; ngx_peer_connection_t *pc; int timeout; + const char * pool; ngx_http_lua_socket_tcp_upstream_t *u; @@ -302,18 +303,33 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) host.data[len] = '\0'; if (n >= 3) { - port = luaL_checkinteger(L, 3); + switch (lua_type(L, 3)) { + case LUA_TNIL: + /* no port passed in */ + port = 0; + break; - if (port < 0 || port > 65536) { - lua_pushnil(L); - lua_pushfstring(L, "bad port number: %d", port); - return 2; + case LUA_TNUMBER: + case LUA_TSTRING: + port = lua_tonumber(L, 3); + if (port < 0 || port > 65536) { + lua_pushnil(L); + lua_pushfstring(L, "bad port number: %d", port); + return 2; + } + break; + + default: + lua_pushnil(L); + lua_pushfstring(L, "bad port option. Expected number, got %s", luaL_typename(L, 3)); + return 2; } } else { /* n == 2 */ port = 0; } + pool = NULL; if(n == 4) { luaL_checktype(L, 4, LUA_TTABLE); @@ -322,11 +338,15 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) switch (lua_type(L, -1)) { case LUA_TNIL: + /* remove table and nil from stack */ + lua_pop(L, 2); + break; + case LUA_TSTRING: - case LUA_TNUMBER: - /*stack is host, port, table, pool or host, table, pool*/ - lua_remove(L, -2); - /*stack is host, port, pool or host, pool*/ + /* clean up the stack */ + lua_replace(L, 2); + lua_pop(L, n - 2); + pool = lua_tostring(L, -1); break; default: @@ -336,21 +356,15 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) } } - if(n > 2) { - luaL_Buffer b; - int i; - luaL_buffinit(L, &b); - for (i = 2; i <= n; i++) { - lua_pushvalue(L, i); - luaL_addvalue(&b); - if (i != n) { - luaL_addlstring(&b, ":", strlen(":")); - } - } - luaL_pushresult(&b); - dd("socket key: %s", lua_tostring(L, -1)); + if(!pool && n == 3) { + lua_pushliteral(L, ":"); + lua_insert(L, 3); + lua_concat(L, 3); } + /* key is on top of stack. it may be host, host:port, or a pool name*/ + dd("socket key: %s", lua_tostring(L, -1)); + /* the key's index is 2 */ lua_pushvalue(L, -1);