Skip to content

Commit

Permalink
perf: make inserting host match route several times faster (#62)
Browse files Browse the repository at this point in the history
Previously, `insert_route` will sort the table with `table.sort`.
The `table.sort` is implemented via quick-sort, which is in O(nlogn)
complexity and perform worse when the table is already mostly sorted.

Since we can ensure the table is sorted before inserting, we can
implement a naive insert sort in O(n) complexity to replace `table.sort`.

Via `time resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-hosts.lua`
I see an impressive time reduction with this optimization.
  • Loading branch information
spacewander authored Sep 13, 2020
1 parent f68d981 commit 7e279b0
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 7 deletions.
2 changes: 1 addition & 1 deletion benchmark/match-hosts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local match_times = 1000 * 100
local path = "/12345"
local routes = {}
for i = 1, route_count do
routes[i] = {paths = {path}, hosts = {ngx.md5(i)}, metadata = i}
routes[i] = {paths = {path}, priority = i, hosts = {ngx.md5(i)}, metadata = i}
end

local rx = radix.new(routes)
Expand Down
2 changes: 1 addition & 1 deletion benchmark/match-wildcard-hosts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ local match_times = 1000 * 50
local path = "/12345"
local routes = {}
for i = 1, route_count do
routes[i] = {paths = {path}, hosts = {"*." .. ngx.md5(i)}, metadata = i}
routes[i] = {paths = {path}, priority = i, hosts = {"*." .. ngx.md5(i)}, metadata = i}
end

local rx = radix.new(routes)
Expand Down
18 changes: 13 additions & 5 deletions lib/resty/radixtree.lua
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ local ngx = ngx
local table = table
local clear_tab = base.clear_tab
local new_tab = base.new_tab
local move_tab = table.move
local tonumber = tonumber
local ipairs = ipairs
local ffi = require("ffi")
Expand All @@ -49,7 +50,6 @@ local cur_level = ngx.config.subsystem == "http" and
local ngx_var = ngx.var
local re_find = ngx.re.find
local re_match = ngx.re.match
local sort_tab = table.sort
local ngx_re = require("ngx.re")
local ngx_null = ngx.null
local empty_table = {}
Expand Down Expand Up @@ -179,6 +179,16 @@ local function sort_route(route_a, route_b)
return (route_a.priority or 0) > (route_b.priority or 0)
end

local function insert_tab_in_order(tab, val, func)
for i, elem in ipairs(tab) do
if func(val, elem) then
move_tab(tab, i, #tab, i + 1)
tab[i] = val
return
end
end
insert_tab(tab, val)
end

local function insert_route(self, opts)
local path = opts.path
Expand All @@ -190,10 +200,9 @@ local function insert_route(self, opts)
if not self.hash_path[path] then
self.hash_path[path] = {opts}
else
insert_tab(self.hash_path[path], opts)
insert_tab_in_order(self.hash_path[path], opts, sort_route)
end

sort_tab(self.hash_path[path], sort_route)
return true
end

Expand All @@ -202,8 +211,7 @@ local function insert_route(self, opts)
local idx = tonumber(ffi_cast('intptr_t', data_idx))
local routes = self.match_data[idx]
if routes and routes[1].path == path then
insert_tab(routes, opts)
sort_tab(routes, sort_route)
insert_tab_in_order(routes, opts, sort_route)
return true
end
end
Expand Down

0 comments on commit 7e279b0

Please sign in to comment.