Skip to content

Commit 7e279b0

Browse files
authored
perf: make inserting host match route several times faster (#62)
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.
1 parent f68d981 commit 7e279b0

File tree

3 files changed

+15
-7
lines changed

3 files changed

+15
-7
lines changed

benchmark/match-hosts.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local match_times = 1000 * 100
55
local path = "/12345"
66
local routes = {}
77
for i = 1, route_count do
8-
routes[i] = {paths = {path}, hosts = {ngx.md5(i)}, metadata = i}
8+
routes[i] = {paths = {path}, priority = i, hosts = {ngx.md5(i)}, metadata = i}
99
end
1010

1111
local rx = radix.new(routes)

benchmark/match-wildcard-hosts.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local match_times = 1000 * 50
55
local path = "/12345"
66
local routes = {}
77
for i = 1, route_count do
8-
routes[i] = {paths = {path}, hosts = {"*." .. ngx.md5(i)}, metadata = i}
8+
routes[i] = {paths = {path}, priority = i, hosts = {"*." .. ngx.md5(i)}, metadata = i}
99
end
1010

1111
local rx = radix.new(routes)

lib/resty/radixtree.lua

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ local ngx = ngx
2727
local table = table
2828
local clear_tab = base.clear_tab
2929
local new_tab = base.new_tab
30+
local move_tab = table.move
3031
local tonumber = tonumber
3132
local ipairs = ipairs
3233
local ffi = require("ffi")
@@ -49,7 +50,6 @@ local cur_level = ngx.config.subsystem == "http" and
4950
local ngx_var = ngx.var
5051
local re_find = ngx.re.find
5152
local re_match = ngx.re.match
52-
local sort_tab = table.sort
5353
local ngx_re = require("ngx.re")
5454
local ngx_null = ngx.null
5555
local empty_table = {}
@@ -179,6 +179,16 @@ local function sort_route(route_a, route_b)
179179
return (route_a.priority or 0) > (route_b.priority or 0)
180180
end
181181

182+
local function insert_tab_in_order(tab, val, func)
183+
for i, elem in ipairs(tab) do
184+
if func(val, elem) then
185+
move_tab(tab, i, #tab, i + 1)
186+
tab[i] = val
187+
return
188+
end
189+
end
190+
insert_tab(tab, val)
191+
end
182192

183193
local function insert_route(self, opts)
184194
local path = opts.path
@@ -190,10 +200,9 @@ local function insert_route(self, opts)
190200
if not self.hash_path[path] then
191201
self.hash_path[path] = {opts}
192202
else
193-
insert_tab(self.hash_path[path], opts)
203+
insert_tab_in_order(self.hash_path[path], opts, sort_route)
194204
end
195205

196-
sort_tab(self.hash_path[path], sort_route)
197206
return true
198207
end
199208

@@ -202,8 +211,7 @@ local function insert_route(self, opts)
202211
local idx = tonumber(ffi_cast('intptr_t', data_idx))
203212
local routes = self.match_data[idx]
204213
if routes and routes[1].path == path then
205-
insert_tab(routes, opts)
206-
sort_tab(routes, sort_route)
214+
insert_tab_in_order(routes, opts, sort_route)
207215
return true
208216
end
209217
end

0 commit comments

Comments
 (0)