mCaptcha Cache

Redis module that implements leaky bucket algorithm

[![dependency status](https://deps.rs/repo/github/mCaptcha/cache/status.svg)](https://deps.rs/repo/github/mCaptcha/cache) [![AGPL License](https://img.shields.io/badge/license-AGPL-blue.svg?style=flat-square)](http://www.gnu.org/licenses/agpl-3.0) [![Chat](https://img.shields.io/badge/matrix-+mcaptcha:matrix.batsense.net-purple?style=flat-square)](https://matrix.to/#/+mcaptcha:matrix.batsense.net)
## Features - [x] Timers for individual count - [x] Persistence through RDB - [ ] Persistence through AOF ## Motivation [mCaptcha](https://github.com/mCaptcha/mCaptcha) uses a [leaky- bucket](https://en.wikipedia.org/wiki/Leaky_bucket)-enabled counter to keep track of traffic/challenge requests. - At `t=0`(where `t` is time), if someone is visiting an mCaptcha-protected website, the counter for that website will be initialized and set to 1. - It should also automatically decrement(by 1) after a certain period, say `t=cooldown`. We call this cool down period and is constant for a website. - If at `t=x`(where `x ``` ## Benchmark **NOTE:** These benchmarks are for reference only. Do not depend upon them too much. When in doubt, please craft and run benchmarks that are better suited to your workload. To run benchmarks locally, launch Redis server with module loaded and: ```bash $ ./scripts/bench.sh ``` - platform: `Intel core i7-9750h` ```bash running set and get without pipelining SET: 86095.57 requests per second, p50=0.311 msec GET: 87519.70 requests per second, p50=0.311 msec mCaptcha cache without piplining MCAPTCHA_CACHE.COUNT mycounter 45: 85375.22 requests per second, p50=0.479 msec running set and get with pipelining SET: 822368.44 requests per second, p50=0.855 msec GET: 900090.06 requests per second, p50=0.775 msec mCaptcha cache with piplining MCAPTCHA_CACHE.COUNT mycounter 45: 274876.31 requests per second, p50=2.767 msec ``` ## Hacks I couldn't find any ways to persist timers to disk(`RDB`/`AOF`). So I'm using a dummy record(`mcaptcha:timer:*` see [Gotchas](#gotchas)) which will expire after an arbitrary time(see `POCKET_EXPIRY_OFFSET` in [`lib.rs`](./src/lib.rs)). When that expiry occurs, I derive the key of the pocket from the values that are passed to expiration event handlers and perform clean up of both the pocket and counters registered with the pocket. Ideally, I should be able to persist timers but I couldn't find ways to do that.