-
Notifications
You must be signed in to change notification settings - Fork 486
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Alice Ryhl <[email protected]>
- Loading branch information
1 parent
b0edd09
commit 757de67
Showing
2 changed files
with
156 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
Copyright (c) 2020 Tokio Contributors | ||
|
||
Permission is hereby granted, free of charge, to any | ||
person obtaining a copy of this software and associated | ||
documentation files (the "Software"), to deal in the | ||
Software without restriction, including without | ||
limitation the rights to use, copy, modify, merge, | ||
publish, distribute, sublicense, and/or sell copies of | ||
the Software, and to permit persons to whom the Software | ||
is furnished to do so, subject to the following | ||
conditions: | ||
|
||
The above copyright notice and this permission notice | ||
shall be included in all copies or substantial portions | ||
of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | ||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | ||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,140 @@ | ||
# mini-redis | ||
|
||
`mini-redis` is a lightweight, idiomatic implementation of [Redis](https://redis.io) built with [tokio](https://tokio.rs). | ||
`mini-redis` is an incomplete, idiomatic implementation of a | ||
[Redis](https://redis.io) client and server built with | ||
[Tokio](https://tokio.rs). | ||
|
||
## Logging | ||
The intent of this project is to provide a larger example of writing a Tokio | ||
application. | ||
|
||
`mini-redis` uses [`tracing`](https://github.com/tokio-rs/tracing) to provide structured logs. Debug logs can be displayed by running: | ||
**Disclaimer** Don't even think about trying to use this in production... just | ||
don't. | ||
|
||
```console | ||
## Running | ||
|
||
The repository provides a server, client library, and some client executables | ||
for interacting with the server. | ||
|
||
Start the server: | ||
|
||
``` | ||
RUST_LOG=debug cargo run --bin server | ||
``` | ||
|
||
Logs will appear when commands are sent to the server from a client. | ||
The [`tracing`](https://github.com/tokio-rs/tracing) crate is used to provide structured logs. | ||
You can substitute `debug` with the desired [log level][level]. | ||
|
||
[level]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives | ||
|
||
Then, in a different terminal window, the various client [examples](examples) | ||
can be executed. For example: | ||
|
||
``` | ||
cargo run --example hello_world | ||
``` | ||
|
||
Additionally, a CLI client is provided to run arbitrary commands from the | ||
terminal. With the server running, the following works: | ||
|
||
``` | ||
cargo run --bin cli set foo bar | ||
cargo run --bin cli get foo | ||
``` | ||
|
||
## Supported commands | ||
|
||
`mini-redis` currently supports the following commands. | ||
|
||
* [GET](https://redis.io/commands/get) | ||
* [SET](https://redis.io/commands/set) | ||
* [PUBLISH](https://redis.io/commands/publish) | ||
* [SUBSCRIBE](https://redis.io/commands/subscribe) | ||
|
||
The Redis wire protocol specification can be found | ||
[here](https://redis.io/topics/protocol). | ||
|
||
|
||
## Tokio patterns | ||
|
||
The project demonstrates a number of useful patterns, including: | ||
|
||
### TCP server | ||
|
||
[`server.rs`](src/server.rs) starts a TCP server that accepts connections, | ||
and spawns a new task per connection. It gracefully handles `accept` errors. | ||
|
||
### Client library | ||
|
||
[`client.rs`](src/client.rs) shows how to model an asynchronous client. The | ||
various capabilities are exposed as `async` methods. | ||
|
||
### State shared across sockets | ||
|
||
The server maintains a [`Db`] instance that is accessible from all connected | ||
connections. The [`Db`] instance manages the key-value state as well as pub/sub | ||
capabilities. | ||
|
||
[`Db`]: src/db.rs | ||
|
||
### Framing | ||
|
||
[`connection.rs`](src/connection.rs) and [`frame.rs`](src/frame.rs) show how to | ||
idiomatically implement a wire protocol. The protocol is modeled using an | ||
intermediate representation, the `Frame` structure. `Connection` takes a | ||
`TcpStream` and exposes an API that sends and receives `Frame` values. | ||
|
||
### Graceful shutdown | ||
|
||
The server implements graceful shutdown. [`tokio::signal`] is used to listen for | ||
a SIGINT. Once the signal is received, shutdown begins. The server stops | ||
accepting new connections. Existing connections are notified to shutdown | ||
gracefully. In-flight work is completed, and the connection is closed. | ||
|
||
[`tokio::signal`]: https://docs.rs/tokio/*/tokio/signal/ | ||
|
||
### Concurrent connection limiting | ||
|
||
The server uses a [`Semaphore`] limits the maximum number of concurrent | ||
connections. Once the limit is reached, the server stops accepting new | ||
connections until an existing one terminates. | ||
|
||
[`Semaphore`]: https://docs.rs/tokio/*/tokio/sync/struct.Semaphore.html | ||
|
||
### Pub/Sub | ||
|
||
The server implements non-trivial pub/sub capability. The client may subscribe | ||
to multiple channels and update its subscription at any time. The server | ||
implements this using one [broadcast channel][broadcast] per channel and a | ||
[`StreamMap`] per connection. Clients are able to send subscription commands to | ||
the server to update the active subscriptions. | ||
|
||
[broadcast]: https://docs.rs/tokio/*/tokio/sync/broadcast/index.html | ||
[`StreamMap`]: https://docs.rs/tokio/*/tokio/stream/struct.StreamMap.html | ||
|
||
## Contributing | ||
|
||
Contributions to `mini-redis` are welcome. Keep in mind, the goal of the project | ||
is **not** to reach feature parity with real Redis, but to demonstrate | ||
asynchronous Rust patterns with Tokio. | ||
|
||
Commands or other features should only be added if doing so is useful to | ||
demonstrate a new pattern. | ||
|
||
Contributions should come with extensive comments targetted to new Tokio users. | ||
|
||
## FAQ | ||
|
||
#### Should I use this in production? | ||
|
||
No. | ||
|
||
## License | ||
|
||
This project is licensed under the [MIT license](LICENSE). | ||
|
||
### Contribution | ||
|
||
More documentation on enabling different log levels and filtering logs can be found [here](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives). | ||
Unless you explicitly state otherwise, any contribution intentionally submitted | ||
for inclusion in `mini-redis` by you, shall be licensed as MIT, without any | ||
additional terms or conditions. |