From 8ebc6759db94ce5b7bee8fbb5d4579ed165ad876 Mon Sep 17 00:00:00 2001 From: yanghao <1570707497@qq.com> Date: Tue, 16 Jan 2024 20:30:43 -0500 Subject: [PATCH] perf: add rax_tree_up() to iterate the routes tree (#136) --- benchmark/match-prefix.lua | 20 +++++++++++++- lib/resty/radixtree.lua | 3 ++- src/easy_rax.c | 24 +++++++++++++++++ src/easy_rax.h | 1 + src/rax.c | 54 ++++++++++++++++++++++++++++++++++++++ src/rax.h | 1 + 6 files changed, 101 insertions(+), 2 deletions(-) diff --git a/benchmark/match-prefix.lua b/benchmark/match-prefix.lua index 0b8a5a84..07582f93 100644 --- a/benchmark/match-prefix.lua +++ b/benchmark/match-prefix.lua @@ -8,7 +8,7 @@ for i = 1, route_count do end local rx = radix.new(routes) - +ngx.say("case 1: route matched ") ngx.update_time() local start_time = ngx.now() @@ -25,3 +25,21 @@ ngx.say("route count: ", route_count) ngx.say("match times: ", match_times) ngx.say("time used : ", used_time, " sec") ngx.say("QPS : ", math.floor(match_times / used_time)) + +ngx.say("=================") +ngx.say("case 2: route not matched ") +ngx.update_time() +start_time = ngx.now() + +path = "/" .. ngx.md5(route_count + 1) .. "/a" +for _ = 1, match_times do + res = rx:match(path) +end + +ngx.update_time() +local used_time = ngx.now() - start_time +ngx.say("matched res: ", res) +ngx.say("route count: ", route_count) +ngx.say("match times: ", match_times) +ngx.say("time used : ", used_time, " sec") +ngx.say("QPS : ", math.floor(match_times / used_time)) diff --git a/lib/resty/radixtree.lua b/lib/resty/radixtree.lua index c35979c7..72f3d3ec 100644 --- a/lib/resty/radixtree.lua +++ b/lib/resty/radixtree.lua @@ -118,6 +118,7 @@ ffi_cdef[[ void *radix_tree_search(void *t, void *it, const unsigned char *buf, size_t len); int radix_tree_prev(void *it, const unsigned char *buf, size_t len); + int radix_tree_up(void *it, const unsigned char *buf, size_t len); int radix_tree_stop(void *it); void *radix_tree_new_it(void *t); @@ -847,7 +848,7 @@ local function match_route(self, path, opts, args) end while true do - local idx = radix.radix_tree_prev(it, path, #path) + local idx = radix.radix_tree_up(it, path, #path) if idx <= 0 then break end diff --git a/src/easy_rax.c b/src/easy_rax.c index b3a56491..313966a0 100644 --- a/src/easy_rax.c +++ b/src/easy_rax.c @@ -166,6 +166,30 @@ radix_tree_prev(void *it, const unsigned char *buf, size_t len) } +int +radix_tree_up(void *it, const unsigned char *buf, size_t len) +{ + raxIterator *iter = it; + int res; + + while (1) { + res = raxUp(iter); + if (!res) { + return -1; + } + + if (iter->key_len > len || + memcmp(buf, iter->key, iter->key_len) != 0) { + continue; + } + + break; + } + + return (int)iter->data; +} + + int radix_tree_stop(void *it) { diff --git a/src/easy_rax.h b/src/easy_rax.h index 7c3f3e28..11ccd7b5 100644 --- a/src/easy_rax.h +++ b/src/easy_rax.h @@ -57,6 +57,7 @@ void *radix_tree_find(void *t, const unsigned char *buf, size_t len); void *radix_tree_search(void *t, void *it, const unsigned char *buf, size_t len); int radix_tree_prev(void *it, const unsigned char *buf, size_t len); int radix_tree_next(void *it, const unsigned char *buf, size_t len); +int radix_tree_up(void *it, const unsigned char *buf, size_t len); int radix_tree_stop(void *it); void *radix_tree_new_it(void *t); diff --git a/src/rax.c b/src/rax.c index bc3782af..03513fbf 100644 --- a/src/rax.c +++ b/src/rax.c @@ -1501,6 +1501,48 @@ int raxIteratorPrevStep(raxIterator *it, int noup) { } } + +int raxIteratorUpStep(raxIterator *it) { + if (it->flags & RAX_ITER_EOF) { + return 1; + } else if (it->flags & RAX_ITER_JUST_SEEKED) { + it->flags &= ~RAX_ITER_JUST_SEEKED; + return 1; + } + + /* Save key len, stack items and the node where we are currently + * so that on iterator EOF we can restore the current key and state. */ + size_t orig_key_len = it->key_len; + size_t orig_stack_items = it->stack.items; + raxNode *orig_node = it->node; + + while(1) { + /* Already on head? Can't go up, iteration finished. */ + if (it->node == it->rt->head) { + it->flags |= RAX_ITER_EOF; + it->stack.items = orig_stack_items; + it->key_len = orig_key_len; + it->node = orig_node; + return 1; + } + + it->node = raxStackPop(&it->stack); + + /* Adjust the current key to represent the node we are + * at. */ + int todel = it->node->iscompr ? it->node->size : 1; + raxIteratorDelChars(it,todel); + + /* Return the key: this could be the key we found scanning a new + * subtree, or if we did not find a new subtree to explore here, + * before giving up with this node, check if it's a key itself. */ + if (it->node->iskey) { + it->data = raxGetData(it->node); + return 1; + } + } +} + /* Seek an iterator at the specified element. * Return 0 if the seek failed for syntax error or out of memory. Otherwise * 1 is returned. When 0 is returned for out of memory, errno is set to @@ -1718,6 +1760,18 @@ int raxPrev(raxIterator *it) { return 1; } +int raxUp(raxIterator *it) { + if (!raxIteratorUpStep(it)) { + errno = ENOMEM; + return 0; + } + if (it->flags & RAX_ITER_EOF) { + errno = 0; + return 0; + } + return 1; +} + /* Compare the key currently pointed by the iterator to the specified * key according to the specified operator. Returns 1 if the comparison is * true, otherwise 0 is returned. */ diff --git a/src/rax.h b/src/rax.h index a2e7f985..803f23d5 100644 --- a/src/rax.h +++ b/src/rax.h @@ -200,6 +200,7 @@ void raxStart(raxIterator *it, rax *rt); int raxSeek(raxIterator *it, const char *op, unsigned char *ele, size_t len); int raxNext(raxIterator *it); int raxPrev(raxIterator *it); +int raxUp(raxIterator *it); int raxCompare(raxIterator *iter, const char *op, unsigned char *key, size_t key_len); void raxStop(raxIterator *it); int raxEOF(raxIterator *it);