Skip to content

Commit edddbf8

Browse files
committed
Use Vec for PathRouter
Routes in path seemed to work with linear memory instead of needing the extra hash and tracking of prev_route_id, a Vec should work just fine while having the benefits of cache locality.
1 parent d8cd5ce commit edddbf8

File tree

2 files changed

+31
-55
lines changed

2 files changed

+31
-55
lines changed

axum/src/routing/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ macro_rules! panic_on_err {
5858
}
5959

6060
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
61-
pub(crate) struct RouteId(u32);
61+
pub(crate) struct RouteId(usize);
6262

6363
/// The router type for composing handlers and services.
6464
///

axum/src/routing/path_router.rs

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ use super::{
1414
};
1515

1616
pub(super) struct PathRouter<S> {
17-
routes: HashMap<RouteId, Endpoint<S>>,
17+
routes: Vec<Endpoint<S>>,
1818
node: Arc<Node>,
19-
prev_route_id: RouteId,
2019
v7_checks: bool,
2120
}
2221

@@ -71,11 +70,11 @@ where
7170
) -> Result<(), Cow<'static, str>> {
7271
validate_path(self.v7_checks, path)?;
7372

74-
let endpoint = if let Some((route_id, Endpoint::MethodRouter(prev_method_router))) = self
73+
if let Some((route_id, Endpoint::MethodRouter(prev_method_router))) = self
7574
.node
7675
.path_to_route_id
7776
.get(path)
78-
.and_then(|route_id| self.routes.get(route_id).map(|svc| (*route_id, svc)))
77+
.and_then(|route_id| self.routes.get(route_id.0).map(|svc| (*route_id, svc)))
7978
{
8079
// if we're adding a new `MethodRouter` to a route that already has one just
8180
// merge them. This makes `.route("/", get(_)).route("/", post(_))` work
@@ -84,15 +83,11 @@ where
8483
.clone()
8584
.merge_for_path(Some(path), method_router)?,
8685
);
87-
self.routes.insert(route_id, service);
88-
return Ok(());
86+
self.routes[route_id.0] = service;
8987
} else {
90-
Endpoint::MethodRouter(method_router)
91-
};
92-
93-
let id = self.next_route_id();
94-
self.set_node(path, id)?;
95-
self.routes.insert(id, endpoint);
88+
let endpoint = Endpoint::MethodRouter(method_router);
89+
self.new_route(path, endpoint)?;
90+
}
9691

9792
Ok(())
9893
}
@@ -102,7 +97,7 @@ where
10297
H: Handler<T, S>,
10398
T: 'static,
10499
{
105-
for (_, endpoint) in self.routes.iter_mut() {
100+
for endpoint in self.routes.iter_mut() {
106101
if let Endpoint::MethodRouter(rt) = endpoint {
107102
*rt = rt.clone().default_fallback(handler.clone());
108103
}
@@ -129,9 +124,7 @@ where
129124
) -> Result<(), Cow<'static, str>> {
130125
validate_path(self.v7_checks, path)?;
131126

132-
let id = self.next_route_id();
133-
self.set_node(path, id)?;
134-
self.routes.insert(id, endpoint);
127+
self.new_route(path, endpoint)?;
135128

136129
Ok(())
137130
}
@@ -143,21 +136,28 @@ where
143136
.map_err(|err| format!("Invalid route {path:?}: {err}"))
144137
}
145138

139+
fn new_route(&mut self, path: &str, endpoint: Endpoint<S>) -> Result<(), String> {
140+
let id = RouteId(self.routes.len());
141+
self.set_node(path, id)?;
142+
self.routes.push(endpoint);
143+
Ok(())
144+
}
145+
146146
pub(super) fn merge(&mut self, other: Self) -> Result<(), Cow<'static, str>> {
147147
let Self {
148148
routes,
149149
node,
150-
prev_route_id: _,
151150
v7_checks,
152151
} = other;
153152

154153
// If either of the two did not allow paths starting with `:` or `*`, do not allow them for the merged router either.
155154
self.v7_checks |= v7_checks;
156155

157-
for (id, route) in routes {
156+
for (id, route) in routes.into_iter().enumerate() {
157+
let route_id = RouteId(id);
158158
let path = node
159159
.route_id_to_path
160-
.get(&id)
160+
.get(&route_id)
161161
.expect("no path for route id. This is a bug in axum. Please file an issue");
162162

163163
match route {
@@ -179,15 +179,15 @@ where
179179
let Self {
180180
routes,
181181
node,
182-
prev_route_id: _,
183182
// Ignore the configuration of the nested router
184183
v7_checks: _,
185184
} = router;
186185

187-
for (id, endpoint) in routes {
186+
for (id, endpoint) in routes.into_iter().enumerate() {
187+
let route_id = RouteId(id);
188188
let inner_path = node
189189
.route_id_to_path
190-
.get(&id)
190+
.get(&route_id)
191191
.expect("no path for route id. This is a bug in axum. Please file an issue");
192192

193193
let path = path_for_nested_route(prefix, inner_path);
@@ -259,16 +259,12 @@ where
259259
let routes = self
260260
.routes
261261
.into_iter()
262-
.map(|(id, endpoint)| {
263-
let route = endpoint.layer(layer.clone());
264-
(id, route)
265-
})
262+
.map(|endpoint| endpoint.layer(layer.clone()))
266263
.collect();
267264

268265
Self {
269266
routes,
270267
node: self.node,
271-
prev_route_id: self.prev_route_id,
272268
v7_checks: self.v7_checks,
273269
}
274270
}
@@ -292,16 +288,12 @@ where
292288
let routes = self
293289
.routes
294290
.into_iter()
295-
.map(|(id, endpoint)| {
296-
let route = endpoint.layer(layer.clone());
297-
(id, route)
298-
})
291+
.map(|endpoint| endpoint.layer(layer.clone()))
299292
.collect();
300293

301294
Self {
302295
routes,
303296
node: self.node,
304-
prev_route_id: self.prev_route_id,
305297
v7_checks: self.v7_checks,
306298
}
307299
}
@@ -314,21 +306,17 @@ where
314306
let routes = self
315307
.routes
316308
.into_iter()
317-
.map(|(id, endpoint)| {
318-
let endpoint: Endpoint<S2> = match endpoint {
319-
Endpoint::MethodRouter(method_router) => {
320-
Endpoint::MethodRouter(method_router.with_state(state.clone()))
321-
}
322-
Endpoint::Route(route) => Endpoint::Route(route),
323-
};
324-
(id, endpoint)
309+
.map(|endpoint| match endpoint {
310+
Endpoint::MethodRouter(method_router) => {
311+
Endpoint::MethodRouter(method_router.with_state(state.clone()))
312+
}
313+
Endpoint::Route(route) => Endpoint::Route(route),
325314
})
326315
.collect();
327316

328317
PathRouter {
329318
routes,
330319
node: self.node,
331-
prev_route_id: self.prev_route_id,
332320
v7_checks: self.v7_checks,
333321
}
334322
}
@@ -366,7 +354,7 @@ where
366354

367355
let endpoint = self
368356
.routes
369-
.get(&id)
357+
.get(id.0)
370358
.expect("no route for id. This is a bug in axum. Please file an issue");
371359

372360
let req = Request::from_parts(parts, body);
@@ -382,24 +370,13 @@ where
382370
Err(MatchError::NotFound) => Err((Request::from_parts(parts, body), state)),
383371
}
384372
}
385-
386-
fn next_route_id(&mut self) -> RouteId {
387-
let next_id = self
388-
.prev_route_id
389-
.0
390-
.checked_add(1)
391-
.expect("Over `u32::MAX` routes created. If you need this, please file an issue.");
392-
self.prev_route_id = RouteId(next_id);
393-
self.prev_route_id
394-
}
395373
}
396374

397375
impl<S> Default for PathRouter<S> {
398376
fn default() -> Self {
399377
Self {
400378
routes: Default::default(),
401379
node: Default::default(),
402-
prev_route_id: RouteId(0),
403380
v7_checks: true,
404381
}
405382
}
@@ -419,7 +396,6 @@ impl<S> Clone for PathRouter<S> {
419396
Self {
420397
routes: self.routes.clone(),
421398
node: self.node.clone(),
422-
prev_route_id: self.prev_route_id,
423399
v7_checks: self.v7_checks,
424400
}
425401
}

0 commit comments

Comments
 (0)