

R3 – High-performance URL router library in C - pedro93
https://github.com/c9s/r3

======
sjtgraham
Wow! My eyes popped out for a second when I saw my name there in the README. I
wrote an alternative router for Rails
([https://github.com/stevegraham/rails/pull/1](https://github.com/stevegraham/rails/pull/1))
because I wanted to be able to generate links to parent and child resources
automatically by reflecting on the routing table. I think this would be a
useful feature for Hypermedia APIs. I'm currently working on implementing this
in a project called Restafarian
([https://github.com/stevegraham/restafarian/blob/master/examp...](https://github.com/stevegraham/restafarian/blob/master/examples.md)).
I couldn't see a way to do this with Journey (The existing Rails router) which
is a deterministic finite state automaton, so I wrote one using a modified
trie structure where the nodes also have a reference to their parent. It also
happened to be a bit faster, which was a nice bonus, but it looks like they've
made some changes to bring it to nearly the same performance characteristics.

~~~
pedro93
Hi! your implementation is inspiring to me. so I mixed some other ideas to
implement this (for fun and experimentation).

this router library can be used for different purpose (outside of URL
dispatching), although we don't gain so much performance from the point of
view of each single request.

------
pstrateman
Is that seriously a performance issue for any real webapp?

~~~
evmar
(Pre-disclaimer: I think it's great that the author spent some time
benchmarking and hacking, and I don't mean for this comment to tear down their
work, but rather I'm just answering the above question which was also the
first thing that came to my mind when I saw this.)

The slowest URL router benchmarked there[1] does 10462.0 runs per second,
which is just under 0.1ms per run.

I'm not sure what performance is expected of Rails handlers but the first
stackoverflow thread[2] that came up on a simple Google search had twitter
doing 600 req/s across 180 instances which comes to 300ms per request.

By that math, the slowest URL router costs 0.033% of the request overhead.

Caveat: 300ms/req is slower than you'd like for an interactive website; real
websites may have more complicated routing tables than this benchmark.
Counter-caveat: 0.1ms is not enough to matter pretty much anywhere except for
the stock market.

[1]:
[https://github.com/c9s/r3#benchmark](https://github.com/c9s/r3#benchmark)

[2]: [http://stackoverflow.com/questions/373098/whats-the-
average-...](http://stackoverflow.com/questions/373098/whats-the-average-
requests-per-second-for-a-production-web-application)

~~~
pushrax
In addition, if you were to replace the Rails router with a Ruby trie
implementation, it would be even faster. (not that this is encouraged)

~~~
sjtgraham
I wrote the trie implementation referenced in the benchmarks. I didn't do it
for speed, I did it because I couldn't add the router functionality I needed
using the existing underlying implementation.

~~~
pushrax
Cool, nice work! I didn't actually look at the benchmark and was just making
(perhaps poor) assumptions. I'd imagine it does come with a nice little
performance boost though?

------
nwmcsween
Please don't use autotools, this is a prime example of why you shouldn't use
autotools as the whole of autotools within the project is larger than the
project, an alternative is a simple shell configure to check in env. A few
other issues that I don't understand is why you made strndiff / strdiff,
str_repeat, str_split it is the same as strncmp / strcmp, strcpy, strtok you
just duplicated libc for some reason.

~~~
pedro93
The behavior of (strndiff / strdiff) is different from strncmp or strcmp.
strn?cmp does not return the offset. they are different functions.

and in order to ship this package to deb, deploy to different platform, use
autotools to test C features is a requirement. (we used to build the project
with cmake before we use autotools)

~~~
nwmcsween
Reading it again strdiff is the same as strspn, but your's doesn't actually
handle c strings and reads past null. You can do feature tests yourself
without pulling in the whole autotools mess: [http://git.musl-
libc.org/cgit/musl/tree/configure](http://git.musl-
libc.org/cgit/musl/tree/configure)

~~~
pedro93
Thanks! that helps!

------
z0r
This is the kind of stuff Ragel would be a good fit for.

------
martinml
See also: [http://nikic.github.io/2014/02/18/Fast-request-routing-
using...](http://nikic.github.io/2014/02/18/Fast-request-routing-using-
regular-expressions.html)

