Skip to content

Commit 3be0480

Browse files
committed
perf(*): cache regex predicates with rc using router attribute
KAG-3182
1 parent aa56399 commit 3be0480

File tree

8 files changed

+131
-65
lines changed

8 files changed

+131
-65
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ concurrency:
1414
jobs:
1515
tests:
1616
name: Tests
17-
runs-on: ubuntu-20.04
17+
runs-on: ubuntu-24.04
1818

1919
strategy:
2020
matrix:

src/ast.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::schema::Schema;
22
use cidr::IpCidr;
33
use regex::Regex;
4-
use std::net::IpAddr;
4+
use std::{net::IpAddr, rc::Rc};
55

66
#[cfg(feature = "serde")]
77
use serde::{Deserialize, Serialize};
@@ -53,7 +53,7 @@ pub enum Value {
5353
IpAddr(IpAddr),
5454
Int(i64),
5555
#[cfg_attr(feature = "serde", serde(with = "serde_regex"))]
56-
Regex(Regex),
56+
Regex(Rc<Regex>),
5757
}
5858

5959
impl PartialEq for Value {
@@ -137,7 +137,7 @@ pub struct Predicate {
137137
mod tests {
138138
use super::*;
139139
use crate::parser::parse;
140-
use std::fmt;
140+
use std::{collections::HashMap, fmt};
141141

142142
impl fmt::Display for Expression {
143143
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -240,6 +240,7 @@ mod tests {
240240

241241
#[test]
242242
fn expr_op_and_prec() {
243+
let mut regex_cache = HashMap::new();
243244
let tests = vec![
244245
("a > 0", "(a > 0)"),
245246
("a in \"abc\"", "(a in \"abc\")"),
@@ -271,13 +272,14 @@ mod tests {
271272
),
272273
];
273274
for (input, expected) in tests {
274-
let result = parse(input).unwrap();
275+
let result = parse(input, &mut regex_cache).unwrap();
275276
assert_eq!(result.to_string(), expected);
276277
}
277278
}
278279

279280
#[test]
280281
fn expr_var_name_and_ip() {
282+
let mut regex_cache = HashMap::new();
281283
let tests = vec![
282284
// ipv4_literal
283285
("kong.foo in 1.1.1.1", "(kong.foo in 1.1.1.1)"),
@@ -298,13 +300,14 @@ mod tests {
298300
),
299301
];
300302
for (input, expected) in tests {
301-
let result = parse(input).unwrap();
303+
let result = parse(input, &mut regex_cache).unwrap();
302304
assert_eq!(result.to_string(), expected);
303305
}
304306
}
305307

306308
#[test]
307309
fn expr_regex() {
310+
let mut regex_cache = HashMap::new();
308311
let tests = vec![
309312
// regex_literal
310313
(
@@ -318,13 +321,14 @@ mod tests {
318321
),
319322
];
320323
for (input, expected) in tests {
321-
let result = parse(input).unwrap();
324+
let result = parse(input, &mut regex_cache).unwrap();
322325
assert_eq!(result.to_string(), expected);
323326
}
324327
}
325328

326329
#[test]
327330
fn expr_digits() {
331+
let mut regex_cache = HashMap::new();
328332
let tests = vec![
329333
// dec literal
330334
("kong.foo.foo7 == 123", "(kong.foo.foo7 == 123)"),
@@ -340,13 +344,14 @@ mod tests {
340344
("kong.foo.foo12 == -0123", "(kong.foo.foo12 == -83)"),
341345
];
342346
for (input, expected) in tests {
343-
let result = parse(input).unwrap();
347+
let result = parse(input, &mut regex_cache).unwrap();
344348
assert_eq!(result.to_string(), expected);
345349
}
346350
}
347351

348352
#[test]
349353
fn expr_transformations() {
354+
let mut regex_cache = HashMap::new();
350355
let tests = vec![
351356
// lower
352357
(
@@ -360,13 +365,14 @@ mod tests {
360365
),
361366
];
362367
for (input, expected) in tests {
363-
let result = parse(input).unwrap();
368+
let result = parse(input, &mut regex_cache).unwrap();
364369
assert_eq!(result.to_string(), expected);
365370
}
366371
}
367372

368373
#[test]
369374
fn expr_transformations_nested() {
375+
let mut regex_cache = HashMap::new();
370376
let tests = vec![
371377
// lower + lower
372378
(
@@ -390,35 +396,37 @@ mod tests {
390396
),
391397
];
392398
for (input, expected) in tests {
393-
let result = parse(input).unwrap();
399+
let result = parse(input, &mut regex_cache).unwrap();
394400
assert_eq!(result.to_string(), expected);
395401
}
396402
}
397403

398404
#[test]
399405
fn str_unicode_test() {
406+
let mut regex_cache = HashMap::new();
400407
let tests = vec![
401408
// cjk chars
402409
("t_msg in \"你好\"", "(t_msg in \"你好\")"),
403410
// 0xXXX unicode
404411
("t_msg in \"\u{4f60}\u{597d}\"", "(t_msg in \"你好\")"),
405412
];
406413
for (input, expected) in tests {
407-
let result = parse(input).unwrap();
414+
let result = parse(input, &mut regex_cache).unwrap();
408415
assert_eq!(result.to_string(), expected);
409416
}
410417
}
411418

412419
#[test]
413420
fn rawstr_test() {
421+
let mut regex_cache = HashMap::new();
414422
let tests = vec![
415423
// invalid escape sequence
416424
(r##"a == r#"/path/to/\d+"#"##, r#"(a == "/path/to/\d+")"#),
417425
// valid escape sequence
418426
(r##"a == r#"/path/to/\n+"#"##, r#"(a == "/path/to/\n+")"#),
419427
];
420428
for (input, expected) in tests {
421-
let result = parse(input).unwrap();
429+
let result = parse(input, &mut regex_cache).unwrap();
422430
assert_eq!(result.to_string(), expected);
423431
}
424432
}

src/ffi/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ pub unsafe extern "C" fn context_reset(context: &mut Context) {
158158
/// Violating any of the following constraints will result in undefined behavior:
159159
///
160160
/// - `context` must be a valid pointer returned by [`context_new`],
161-
/// must be passed to [`router_execute`] before calling this function,
162-
/// and must not be reset by [`context_reset`] before calling this function.
161+
/// must be passed to [`router_execute`] before calling this function,
162+
/// and must not be reset by [`context_reset`] before calling this function.
163163
/// - If `uuid_hex` is not `NULL`, `uuid_hex` must be valid to read and write for
164164
/// `16 * size_of::<u8>()` bytes, and it must be properly aligned.
165165
/// - If `matched_field` is not `NULL`,

src/ffi/expression.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::ffi::ERR_BUF_MAX_LEN;
33
use crate::schema::Schema;
44
use bitflags::bitflags;
55
use std::cmp::min;
6+
use std::collections::HashMap;
67
use std::ffi;
78
use std::os::raw::c_char;
89
use std::slice::from_raw_parts_mut;
@@ -163,7 +164,7 @@ pub unsafe extern "C" fn expression_validate(
163164
let errbuf = from_raw_parts_mut(errbuf, ERR_BUF_MAX_LEN);
164165

165166
// Parse the expression
166-
let result = parse(atc).map_err(|e| e.to_string());
167+
let result = parse(atc, &mut HashMap::new()).map_err(|e| e.to_string());
167168
if let Err(e) = result {
168169
let errlen = min(e.len(), *errbuf_len);
169170
errbuf[..errlen].copy_from_slice(&e.as_bytes()[..errlen]);

src/ffi/router.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ pub unsafe extern "C" fn router_free(router: *mut Router) {
8080
///
8181
/// - `router` must be a valid pointer returned by [`router_new`].
8282
/// - `uuid` must be a valid pointer to a C-style string, must be properly aligned,
83-
/// and must not have '\0' in the middle.
83+
/// and must not have '\0' in the middle.
8484
/// - `atc` must be a valid pointer to a C-style string, must be properly aligned,
85-
/// and must not have '\0' in the middle.
85+
/// and must not have '\0' in the middle.
8686
/// - `errbuf` must be valid to read and write for `errbuf_len * size_of::<u8>()` bytes,
87-
/// and it must be properly aligned.
87+
/// and it must be properly aligned.
8888
/// - `errbuf_len` must be valid to read and write for `size_of::<usize>()` bytes,
89-
/// and it must be properly aligned.
89+
/// and it must be properly aligned.
9090
#[no_mangle]
9191
pub unsafe extern "C" fn router_add_matcher(
9292
router: &mut Router,
@@ -135,7 +135,7 @@ pub unsafe extern "C" fn router_add_matcher(
135135
///
136136
/// - `router` must be a valid pointer returned by [`router_new`].
137137
/// - `uuid` must be a valid pointer to a C-style string, must be properly aligned,
138-
/// and must not have '\0' in the middle.
138+
/// and must not have '\0' in the middle.
139139
#[no_mangle]
140140
pub unsafe extern "C" fn router_remove_matcher(
141141
router: &mut Router,
@@ -165,8 +165,8 @@ pub unsafe extern "C" fn router_remove_matcher(
165165
///
166166
/// - `router` must be a valid pointer returned by [`router_new`].
167167
/// - `context` must be a valid pointer returned by [`context_new`],
168-
/// and must be reset by [`context_reset`] before calling this function
169-
/// if you want to reuse the same context for multiple matches.
168+
/// and must be reset by [`context_reset`] before calling this function
169+
/// if you want to reuse the same context for multiple matches.
170170
#[no_mangle]
171171
pub unsafe extern "C" fn router_execute(router: &Router, context: &mut Context) -> bool {
172172
router.execute(context)
@@ -180,9 +180,9 @@ pub unsafe extern "C" fn router_execute(router: &Router, context: &mut Context)
180180
///
181181
/// - `router`: a pointer to the [`Router`] object returned by [`router_new`].
182182
/// - `fields`: a pointer to an array of pointers to the field names
183-
/// (NOT C-style strings) that are actually used in the router, which will be filled in.
184-
/// if `fields` is `NULL`, this function will only return the number of fields used
185-
/// in the router.
183+
/// (NOT C-style strings) that are actually used in the router, which will be filled in.
184+
/// if `fields` is `NULL`, this function will only return the number of fields used
185+
/// in the router.
186186
/// - `fields_len`: a pointer to an array of the length of each field name.
187187
///
188188
/// # Lifetimes

0 commit comments

Comments
 (0)