Skip to content

Commit 2676ca6

Browse files
authored
feature: support to cache the parsed parameter. (#38)
* feature: support to cache the parsed parameter. * feature: support new grammar `:xxxx` and `*xxxx`. * doc: updated benchmark result.
1 parent c6d6653 commit 2676ca6

File tree

9 files changed

+452
-91
lines changed

9 files changed

+452
-91
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,4 @@ dkms.conf
5454
#
5555
t/servroot
5656
.*
57+
deps

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ install:
3434
script:
3535
- export PATH=$OPENRESTY_PREFIX/nginx/sbin:$PATH
3636
- make compile > build.log 2>&1 || (cat build.log && exit 1)
37-
- sudo make dev > build.log 2>&1 || (cat build.log && exit 1)
37+
- sudo make deps > build.log 2>&1 || (cat build.log && exit 1)
3838
- prove -Itest-nginx/lib -r t

Makefile

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ INST_LIBDIR ?= $(INST_PREFIX)/lib/lua/5.1
33
INST_LUADIR ?= $(INST_PREFIX)/share/lua/5.1
44
INSTALL ?= install
55
UNAME ?= $(shell uname)
6+
OR_EXEC ?= $(shell which openresty)
7+
LUAROCKS_VER ?= $(shell luarocks --version | grep -E -o "luarocks [0-9]+.")
8+
LUAJIT_DIR ?= $(shell ${OR_EXEC} -V 2>&1 | grep prefix | grep -Eo 'prefix=(.*)/nginx\s+--' | grep -Eo '/.*/')luajit
69

710
CFLAGS := -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast
811

@@ -57,18 +60,33 @@ install:
5760
$(INSTALL) $(C_SO_NAME) $(INST_LIBDIR)/
5861

5962

60-
### dev: Create a development ENV
61-
.PHONY: dev
62-
dev:
63-
ifeq ($(UNAME),Darwin)
64-
luarocks install --lua-dir=$(LUA_JIT_DIR) rockspec/lua-resty-radixtree-master-1.0-0.rockspec --only-deps
65-
else ifneq ($(LUAROCKS_VER),'luarocks 3.')
66-
luarocks install rockspec/lua-resty-radixtree-master-1.0-0.rockspec --only-deps
63+
### deps: Installation dependencies
64+
.PHONY: deps
65+
deps:
66+
ifneq ($(LUAROCKS_VER),luarocks 3.)
67+
luarocks install rockspec/lua-resty-radixtree-master-0-0.rockspec --tree=deps --only-deps --local
6768
else
68-
luarocks install --lua-dir=/usr/local/openresty/luajit rockspec/lua-resty-radixtree-master-1.0-0.rockspec --only-deps
69+
luarocks install --lua-dir=$(LUAJIT_DIR) rockspec/lua-resty-radixtree-master-0-0.rockspec --tree=deps --only-deps --local
6970
endif
7071

7172

73+
### lint: Lint Lua source code
74+
.PHONY: lint
75+
lint:
76+
luacheck -q lib
77+
78+
79+
### bench: Run benchmark
80+
.PHONY: bench
81+
bench:
82+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-parameter.lua
83+
@echo ""
84+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-prefix.lua
85+
@echo ""
86+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-static.lua
87+
@echo ""
88+
89+
7290
### help: Show Makefile rules
7391
.PHONY: help
7492
help:

README.md

Lines changed: 124 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1-
Name
2-
====
1+
# Table of Contents
2+
3+
* [Name](#name)
4+
* [Status](#status)
5+
* [Synopsis](#synopsis)
6+
* [Methods](#methods)
7+
* [new](#new)
8+
* [match](#match)
9+
* [dispatch](#dispatch)
10+
* [Install](#install)
11+
* [DEV ENV](#dev-env)
12+
* [Benchmark](#benchmark)
13+
14+
## Name
15+
316
This is Lua-Openresty implementation library base on FFI for [rax](https://github.com/antirez/rax).
417

518
[![Build Status](https://travis-ci.org/iresty/lua-resty-radixtree.svg?branch=master)](https://travis-ci.org/iresty/lua-resty-radixtree)
@@ -11,30 +24,15 @@ This project has been working in microservices API gateway [Apache APISIX](https
1124

1225
The project is open sourced by Shenzhen [ZhiLiu](https://www.iresty.com/) Technology Company. In addition to this open source version, our company also provides a more powerful and performing commercial version, and provides technical support. If you are interested in our commercial version, please contact us. email: [[email protected]]([email protected]) .
1326

14-
Table of Contents
15-
=================
16-
17-
* [Name](#name)
18-
* [Status](#status)
19-
* [Synopsis](#synopsis)
20-
* [Methods](#methods)
21-
* [new](#new)
22-
* [match](#match)
23-
* [dispatch](#dispatch)
24-
* [Install](#install)
25-
* [DEV ENV](#dev-env)
26-
* [Benchmark](#benchmark)
27-
28-
Synopsis
29-
========
27+
## Synopsis
3028

3129
```lua
3230
location / {
3331
content_by_lua_block {
3432
local radix = require("resty.radixtree")
3533
local rx = radix.new({
3634
{
37-
paths = {"/bb*", "/aa"},
35+
paths = {"/aa", "/bb*", "/name/:name/*other"},
3836
hosts = {"*.bar.com", "foo.com"},
3937
methods = {"GET", "POST", "PUT"},
4038
remote_addrs = {"127.0.0.1","192.168.0.0/16",
@@ -52,21 +50,33 @@ Synopsis
5250
})
5351

5452
-- try to match
55-
ngx.say(rx:match("/aa", {host = "foo.com",
56-
method = "GET",
57-
remote_addr = "127.0.0.1",
58-
vars = ngx.var}))
53+
local opts = {
54+
host = "foo.com",
55+
method = "GET",
56+
remote_addr = "127.0.0.1",
57+
vars = ngx.var,
58+
}
59+
ngx.say(rx:match("/aa", opts))
60+
61+
-- try to match and store the cached value
62+
local opts = {
63+
host = "foo.com",
64+
method = "GET",
65+
remote_addr = "127.0.0.1",
66+
vars = ngx.var,
67+
matched = {}
68+
}
69+
ngx.say(rx:match("/name/json/foo/bar/gloo", opts))
70+
ngx.say("name: ", opts.matched.name, " other:", opts.matched.other)
5971
}
6072
}
6173
```
6274

6375
[Back to TOC](#table-of-contents)
6476

65-
Methods
66-
=======
77+
## Methods
6778

68-
new
69-
---
79+
### new
7080

7181
`syntax: rx, err = radix.new(routes)`
7282

@@ -87,6 +97,63 @@ The attributes of each element may contain these:
8797
|metadata |option |Will return this field if using `rx:match` to match route.||
8898
|handler |option |Will call this function using `rx:dispatch` to match route.||
8999

100+
### Path
101+
102+
#### Full path match
103+
104+
```lua
105+
local rx = radix.new({
106+
{
107+
paths = {"/aa", "/bb/cc", "/dd/ee/index.html"},
108+
metadata = "metadata /aa",
109+
},
110+
{
111+
paths = {"/gg"},
112+
metadata = "metadata /gg",
113+
},
114+
{
115+
paths = {"/index.html"},
116+
metadata = "metadata /index.html",
117+
},
118+
})
119+
```
120+
121+
Full path matching, allowing multiple paths to be specified at the same time.
122+
123+
#### Prefix match
124+
125+
```lua
126+
local rx = radix.new({
127+
{
128+
paths = {"/aa/*", "/bb/cc/*"},
129+
metadata = "metadata /aa",
130+
},
131+
{
132+
paths = {"/gg/*"},
133+
metadata = "metadata /gg",
134+
},
135+
})
136+
```
137+
138+
Path prefix matching, allowing multiple paths to be specified at the same time.
139+
140+
#### Parameters in path
141+
142+
```lua
143+
local rx = radix.new({
144+
{
145+
-- This handler will match /user/john but will not match /user/ or /user
146+
paths = {"/user/:user"},
147+
metadata = "metadata /user",
148+
},
149+
{
150+
-- However, this one will match /user/john/ and also /user/john/send/data
151+
paths = {"/user/:user/*action"},
152+
metadata = "metadata action",
153+
},
154+
})
155+
```
156+
90157
#### Operator List
91158

92159
|operator|description|example|
@@ -99,18 +166,17 @@ The attributes of each element may contain these:
99166

100167
[Back to TOC](#table-of-contents)
101168

102-
match
103-
-----
169+
### match
104170

105171
`syntax: metadata = rx:match(path, opts)`
106172

107173
* `path`: client request path.
108174
* `opts`: a Lua tale (optional).
109-
* `method`: optional, method name of client request.
110-
* `host`: optional, client request host.
111-
* `remote_addr`: optional, client remote address like `192.168.1.100`.
112-
* `uri`: optional, client request uri.
113-
* `vars`: optional, a Lua table to fetch variable, default value is `ngx.var` to fetch Ningx builtin variable.
175+
* `method`: optional, method name of client request.
176+
* `host`: optional, client request host.
177+
* `remote_addr`: optional, client remote address like `192.168.1.100`.
178+
* `uri`: optional, client request uri.
179+
* `vars`: optional, a Lua table to fetch variable, default value is `ngx.var` to fetch Ningx builtin variable.
114180

115181
Matchs the route by `method`, `path` and `host` etc, and return `metadata` if successful.
116182

@@ -120,18 +186,17 @@ local metadata = rx:match(ngx.var.uri, {...})
120186

121187
[Back to TOC](#table-of-contents)
122188

123-
dispatch
124-
--------
189+
### dispatch
125190

126191
`syntax: ok = rx:dispatch(path, opts, ...)`
127192

128193
* `path`: client request path.
129194
* `opts`: a Lua tale (optional).
130-
* `method`: optional, method name of client request.
131-
* `host`: optional, client request host.
132-
* `remote_addr`: optional, client remote address like `192.168.1.100`.
133-
* `uri`: optional, client request uri.
134-
* `vars`: optional, a Lua table to fetch variable, default value is `ngx.var` to fetch Ningx builtin variable.
195+
* `method`: optional, method name of client request.
196+
* `host`: optional, client request host.
197+
* `remote_addr`: optional, client remote address like `192.168.1.100`.
198+
* `uri`: optional, client request uri.
199+
* `vars`: optional, a Lua table to fetch variable, default value is `ngx.var` to fetch Ningx builtin variable.
135200

136201
Matchs the route by `method`, `path` and `host` etc, and call `handler` function if successful.
137202

@@ -141,67 +206,57 @@ local ok = rx:dispatch(ngx.var.uri, {...})
141206

142207
[Back to TOC](#table-of-contents)
143208

144-
Install
145-
=======
209+
## Install
146210

147211
### Compile and install
148212

149-
```
213+
```shell
150214
make install
151215
```
152216

153217
[Back to TOC](#table-of-contents)
154218

155-
156-
DEV ENV
157-
=======
158-
219+
## DEV ENV
159220

160221
### Install Dependencies
161222

162-
```
223+
```shell
163224
make dev
164225
```
165226

166-
Benchmark
167-
=========
227+
## Benchmark
168228

169229
We wrote some simple benchmark scripts.
170-
Machine environment: Macbook pro 2015 15-inch i7 2.8G CPU.
230+
Machine environment: 9600kf 3.7G CPU.
171231

172232
```shell
173233
$ make
174234
cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/rax.c -o src/rax.o
175235
cc -O2 -g -Wall -fpic -std=c99 -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -DBUILDING_SO -c src/easy_rax.c -o src/easy_rax.o
176236
cc -shared -fvisibility=hidden src/rax.o src/easy_rax.o -o librestyradixtree.so
177237

178-
$ resty -I./lib benchmark/match-static.lua
179-
matched res: 500
180-
route count: 100000
181-
match times: 1000000
182-
time used : 0.089999914169312 sec
183-
QPS : 11111121
184-
185-
$ resty -I./lib benchmark/match-static.lua
186-
matched res: 500
238+
$ make bench
239+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-parameter.lua
240+
matched res: 1
187241
route count: 100000
188242
match times: 1000000
189-
time used : 0.094000101089478 sec
190-
QPS : 10638286
243+
time used : 0.51699995994568 sec
244+
QPS : 1934236
245+
each time : 0.51699995994568 ns
191246

192-
$ resty -I./lib benchmark/match-prefix.lua
247+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-prefix.lua
193248
matched res: 500
194249
route count: 100000
195250
match times: 1000000
196-
time used : 0.85500001907349 sec
197-
QPS : 1169590
251+
time used : 0.625 sec
252+
QPS : 1600000
198253

199-
$ resty -I./lib benchmark/match-prefix.lua
254+
resty -I=./lib -I=./deps/share/lua/5.1 benchmark/match-static.lua
200255
matched res: 500
201256
route count: 100000
202257
match times: 1000000
203-
time used : 0.83500003814697 sec
204-
QPS : 1197604
258+
time used : 0.10099983215332 sec
259+
QPS : 9901006
205260
```
206261

207262
[Back to TOC](#table-of-contents)

benchmark/match-parameter.lua

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
local radix = require("resty.radixtree")
2+
local route_count = 1000 * 100
3+
local match_times = 1000 * 1000
4+
5+
local routes = {}
6+
for i = 1, 1 do
7+
routes[i] = {paths = {"/user/:name"}, metadata = i}
8+
end
9+
10+
local rx = radix.new(routes)
11+
12+
ngx.update_time()
13+
local start_time = ngx.now()
14+
15+
local res
16+
local uri = "/user/gordon"
17+
for _ = 1, match_times do
18+
res = rx:match(uri)
19+
end
20+
21+
ngx.update_time()
22+
local used_time = ngx.now() - start_time
23+
ngx.say("matched res: ", res)
24+
ngx.say("route count: ", route_count)
25+
ngx.say("match times: ", match_times)
26+
ngx.say("time used : ", used_time, " sec")
27+
ngx.say("QPS : ", math.floor(match_times / used_time))
28+
ngx.say("each time : ", used_time * 1000 * 1000 / match_times, " ns")

0 commit comments

Comments
 (0)