From 2e003e4a674ce84f6ea8fb8bbf93d17fd972f3fd Mon Sep 17 00:00:00 2001 From: Chrono Date: Mon, 19 Dec 2022 17:00:47 +0800 Subject: [PATCH 1/2] perf(router): use `table.new` to pre-allocate for more routes --- lib/resty/router/router.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/resty/router/router.lua b/lib/resty/router/router.lua index 68b296b8..02dae803 100644 --- a/lib/resty/router/router.lua +++ b/lib/resty/router/router.lua @@ -5,6 +5,7 @@ local _MT = { __index = _M, } local ffi = require("ffi") local base = require("resty.core.base") local cdefs = require("resty.router.cdefs") +local tb_new = require("table.new") local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local ffi_string = ffi.string @@ -19,7 +20,7 @@ local ERR_BUF_MAX_LEN = cdefs.ERR_BUF_MAX_LEN local clib = cdefs.clib -function _M.new(schema) +function _M.new(schema, routes_n) local router = clib.router_new(schema.schema) -- Note on this weird looking finalizer: -- @@ -33,7 +34,7 @@ function _M.new(schema) clib.router_free(r) end), schema = schema, - priorities = {}, + priorities = tb_new(0, routes_n or 10), }, _MT) return r From bcb547e2eedd713e518ad5229d5653bda5e82518 Mon Sep 17 00:00:00 2001 From: Chrono Date: Mon, 19 Dec 2022 17:04:52 +0800 Subject: [PATCH 2/2] style(*): share closures for freeing up objects instead of creating a new one for each instance Related to #3. This is a more efficient way of doing basically the same thing. --- lib/resty/router/cdefs.lua | 12 +++++++ lib/resty/router/context.lua | 5 ++- lib/resty/router/router.lua | 5 ++- lib/resty/router/schema.lua | 8 ++--- t/02-gc.t | 62 ++++++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 t/02-gc.t diff --git a/lib/resty/router/cdefs.lua b/lib/resty/router/cdefs.lua index 08c16a6d..b42b77d8 100644 --- a/lib/resty/router/cdefs.lua +++ b/lib/resty/router/cdefs.lua @@ -138,4 +138,16 @@ end return { clib = clib, ERR_BUF_MAX_LEN = ERR_BUF_MAX_LEN, + + context_free = function(c) + clib.context_free(c) + end, + + schema_free = function(s) + clib.schema_free(s) + end, + + router_free = function(r) + clib.router_free(r) + end, } diff --git a/lib/resty/router/context.lua b/lib/resty/router/context.lua index 82086e75..c8f887ce 100644 --- a/lib/resty/router/context.lua +++ b/lib/resty/router/context.lua @@ -23,14 +23,13 @@ local CACHED_VALUE = ffi_new("CValue[1]") local UUID_BUF = ffi_new("uint8_t[?]", UUID_LEN) local ERR_BUF_MAX_LEN = cdefs.ERR_BUF_MAX_LEN local clib = cdefs.clib +local context_free = cdefs.context_free function _M.new(schema) local context = clib.context_new(schema.schema) local c = setmetatable({ - context = ffi_gc(context, function(c) - clib.context_free(c) - end), + context = ffi_gc(context, context_free), schema = schema, }, _MT) diff --git a/lib/resty/router/router.lua b/lib/resty/router/router.lua index 02dae803..d505c948 100644 --- a/lib/resty/router/router.lua +++ b/lib/resty/router/router.lua @@ -18,6 +18,7 @@ local setmetatable = setmetatable local ERR_BUF_MAX_LEN = cdefs.ERR_BUF_MAX_LEN local clib = cdefs.clib +local router_free = cdefs.router_free function _M.new(schema, routes_n) @@ -30,9 +31,7 @@ function _M.new(schema, routes_n) -- causing instruction fetch faults because the `router` finalizer will -- attempt to execute from unmapped memory region local r = setmetatable({ - router = ffi_gc(router, function(r) - clib.router_free(r) - end), + router = ffi_gc(router, router_free), schema = schema, priorities = tb_new(0, routes_n or 10), }, _MT) diff --git a/lib/resty/router/schema.lua b/lib/resty/router/schema.lua index 3a7b3a1b..58e1039a 100644 --- a/lib/resty/router/schema.lua +++ b/lib/resty/router/schema.lua @@ -1,5 +1,5 @@ local _M = {} -local clib = require("resty.router.cdefs").clib +local cdefs = require("resty.router.cdefs") local ffi = require("ffi") @@ -8,14 +8,14 @@ local _MT = { __index = _M, } local setmetatable = setmetatable local ffi_gc = ffi.gc +local clib = cdefs.clib +local schema_free = cdefs.schema_free function _M.new() local schema = clib.schema_new() local s = setmetatable({ - schema = ffi_gc(schema, function(s) - clib.schema_free(s) - end), + schema = ffi_gc(schema, schema_free), field_types = {}, field_ctypes = {}, clib = clib, diff --git a/t/02-gc.t b/t/02-gc.t new file mode 100644 index 00000000..adcaa8b9 --- /dev/null +++ b/t/02-gc.t @@ -0,0 +1,62 @@ +# vim:set ft= ts=4 sw=4 et: + +use Test::Nginx::Socket::Lua; +use Cwd qw(cwd); + +repeat_each(1); + +plan tests => repeat_each() * blocks() * 5; + +my $pwd = cwd(); + +our $HttpConfig = qq{ + lua_package_path "$pwd/lib/?.lua;;"; + lua_package_cpath "$pwd/target/debug/?.so;;"; +}; + +no_long_string(); +no_diff(); + +run_tests(); + +__DATA__ + +=== TEST 1: gc schema, router +--- http_config eval: $::HttpConfig +--- config + location = /t { + content_by_lua_block { + local schema = require("resty.router.schema") + local router = require("resty.router.router") + + local s = schema.new() + local r = router.new(s) + + schema = nil + router = nil + + rawset(package.loaded, "resty.router.schema", nil) + rawset(package.loaded, "resty.router.router", nil) + rawset(package.loaded, "resty.router.cdefs", nil) + + collectgarbage() + + s = nil + r = nil + + collectgarbage() + + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +[warn] +[crit] + + +