Skip to content

Commit 43f0a4e

Browse files
committed
fixup! perf(*): cache regex predicates with rc using router attribute
switch Rc to Arc and add static assertions
1 parent 2a270cf commit 43f0a4e

File tree

3 files changed

+24
-15
lines changed

3 files changed

+24
-15
lines changed

src/ast.rs

Lines changed: 2 additions & 2 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, rc::Rc};
4+
use std::{net::IpAddr, sync::Arc};
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(Rc<Regex>),
56+
Regex(Arc<Regex>),
5757
}
5858

5959
impl PartialEq for Value {

src/parser.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use pest::Parser;
1313
use regex::Regex;
1414
use std::collections::HashMap;
1515
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
16-
use std::rc::Rc;
16+
use std::sync::Arc;
1717

1818
type ParseResult<T> = Result<T, ParseError<Rule>>;
1919

@@ -66,7 +66,7 @@ impl ATCParser {
6666
fn parse_matcher(
6767
&mut self,
6868
source: &str,
69-
regex_cache: &mut HashMap<String, Rc<Regex>>,
69+
regex_cache: &mut HashMap<String, Arc<Regex>>,
7070
) -> ParseResult<Expression> {
7171
let pairs = ATCParser::parse(Rule::matcher, source)?;
7272
let expr_pair = pairs.peek().unwrap().into_inner().peek().unwrap();
@@ -212,7 +212,7 @@ fn parse_int_literal(pair: Pair<Rule>) -> ParseResult<i64> {
212212
#[allow(clippy::result_large_err)] // it's fine as parsing is not the hot path
213213
fn parse_predicate(
214214
pair: Pair<Rule>,
215-
regex_cache: &mut HashMap<String, Rc<Regex>>,
215+
regex_cache: &mut HashMap<String, Arc<Regex>>,
216216
) -> ParseResult<Predicate> {
217217
let mut pairs = pair.into_inner();
218218
let lhs = parse_lhs(pairs.next().unwrap())?;
@@ -236,7 +236,7 @@ fn parse_predicate(
236236
None => {
237237
let r = Regex::new(&s).into_parse_result(&rhs_pair)?;
238238

239-
let rc = Rc::new(r);
239+
let rc = Arc::new(r);
240240

241241
regex_cache.insert(s, rc.clone());
242242
rc
@@ -302,7 +302,7 @@ fn parse_binary_operator(pair: Pair<Rule>) -> BinaryOperator {
302302
fn parse_parenthesised_expression(
303303
pair: Pair<Rule>,
304304
pratt: &PrattParser<Rule>,
305-
regex_cache: &mut HashMap<String, Rc<Regex>>,
305+
regex_cache: &mut HashMap<String, Arc<Regex>>,
306306
) -> ParseResult<Expression> {
307307
let mut pairs = pair.into_inner();
308308
let pair = pairs.next().unwrap();
@@ -321,7 +321,7 @@ fn parse_parenthesised_expression(
321321
fn parse_term(
322322
pair: Pair<Rule>,
323323
pratt: &PrattParser<Rule>,
324-
regex_cache: &mut HashMap<String, Rc<Regex>>,
324+
regex_cache: &mut HashMap<String, Arc<Regex>>,
325325
) -> ParseResult<Expression> {
326326
let pairs = pair.into_inner();
327327
let inner_rule = pairs.peek().unwrap();
@@ -343,7 +343,7 @@ fn parse_term(
343343
fn parse_expression(
344344
pair: Pair<Rule>,
345345
pratt: &PrattParser<Rule>,
346-
regex_cache: &mut HashMap<String, Rc<Regex>>,
346+
regex_cache: &mut HashMap<String, Arc<Regex>>,
347347
) -> ParseResult<Expression> {
348348
let pairs = pair.into_inner();
349349
pratt
@@ -364,7 +364,7 @@ fn parse_expression(
364364
#[allow(clippy::result_large_err)] // it's fine as parsing is not the hot path
365365
pub fn parse(
366366
source: &str,
367-
regex_cache: &mut HashMap<String, Rc<Regex>>,
367+
regex_cache: &mut HashMap<String, Arc<Regex>>,
368368
) -> ParseResult<Expression> {
369369
ATCParser::new().parse_matcher(source, regex_cache)
370370
}

src/router.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::schema::Schema;
66
use crate::semantics::{FieldCounter, Validate};
77
use regex::Regex;
88
use std::collections::{BTreeMap, HashMap};
9-
use std::rc::Rc;
9+
use std::sync::Arc;
1010
use uuid::Uuid;
1111

1212
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -17,7 +17,7 @@ pub struct Router<'a> {
1717
schema: &'a Schema,
1818
matchers: BTreeMap<MatcherKey, Expression>,
1919
pub fields: HashMap<String, usize>,
20-
regex_cache: HashMap<String, Rc<Regex>>,
20+
regex_cache: HashMap<String, Arc<Regex>>,
2121
}
2222

2323
fn release_cache(expr: &Expression, router: &mut Router) {
@@ -30,10 +30,10 @@ fn release_cache(expr: &Expression, router: &mut Router) {
3030
LogicalExpression::Not(r) => release_cache(r, router),
3131
},
3232
Expression::Predicate(p) => {
33-
if let Value::Regex(rc) = &p.rhs {
34-
if Rc::strong_count(rc) == 2 {
33+
if let Value::Regex(arc) = &p.rhs {
34+
if Arc::strong_count(arc) == 2 {
3535
// about to be dropped and the only Rc left is in the map
36-
router.regex_cache.remove(rc.as_str());
36+
router.regex_cache.remove(arc.as_str());
3737
}
3838
}
3939
}
@@ -170,4 +170,13 @@ mod tests {
170170
ctx.add_value("http.path", "/not-dev".to_owned().into());
171171
router.try_match(&ctx).ok_or(()).expect_err("should fail");
172172
}
173+
174+
// Router might be used in async context therefore we need to assert that it implements Send and Sync traits.
175+
fn _assert_send<T: Send>() {}
176+
fn _assert_sync<T: Sync>() {}
177+
178+
fn _assertions() {
179+
_assert_send::<Router>();
180+
_assert_sync::<Router>();
181+
}
173182
}

0 commit comments

Comments
 (0)