Giter VIP home page Giter VIP logo

mini-redis's Introduction

mini-redis

mini-redis is an incomplete, idiomatic implementation of a Redis client and server built with Tokio.

The intent of this project is to provide a larger example of writing a Tokio application.

Disclaimer Please don't use mini-redis in production. This project is intended to be a learning resource, and omits various parts of the Redis protocol because implementing them would not introduce any new concepts. We will not add new features because you need them in your project — use one of the fully featured alternatives instead.

Why Redis

The primary goal of this project is teaching Tokio. Doing this requires a project with a wide range of features with a focus on implementation simplicity. Redis, an in-memory database, provides a wide range of features and uses a simple wire protocol. The wide range of features allows demonstrating many Tokio patterns in a "real world" context.

The Redis wire protocol documentation can be found here.

The set of commands Redis provides can be found here.

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 mini-redis-server

The tracing crate is used to provide structured logs. You can substitute debug with the desired log level.

Then, in a different terminal window, the various client 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 mini-redis-cli set foo bar

cargo run --bin mini-redis-cli get foo

OpenTelemetry

If you are running many instances of your application (which is usually the case when you are developing a cloud service, for example), you need a way to get all of your trace data out of your host and into a centralized place. There are many options here, such as Prometheus, Jaeger, DataDog, Honeycomb, AWS X-Ray etc.

We leverage OpenTelemetry, because it's an open standard that allows for a single data format to be used for all the options mentioned above (and more). This eliminates the risk of vendor lock-in, since you can switch between providers if needed.

AWS X-Ray example

To enable sending traces to X-Ray, use the otel feature:

RUST_LOG=debug cargo run --bin mini-redis-server --features otel

This will switch tracing to use tracing-opentelemetry. You will need to have a copy of AWSOtelCollector running on the same host.

For demo purposes, you can follow the setup documented at https://github.com/aws-observability/aws-otel-collector/blob/main/docs/developers/docker-demo.md#run-a-single-aws-otel-collector-instance-in-docker

Supported commands

mini-redis currently supports the following commands.

The Redis wire protocol specification can be found here.

There is no support for persistence yet.

Tokio patterns

The project demonstrates a number of useful patterns, including:

TCP server

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 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.

Framing

connection.rs and 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.

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.

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 per channel and a StreamMap per connection. Clients are able to send subscription commands to the server to update the active subscriptions.

Using a std::sync::Mutex in an async application

The server uses a std::sync::Mutex and not a Tokio mutex to synchronize access to shared state. See db.rs for more details.

Testing asynchronous code that relies on time

In tests/server.rs, there are tests for key expiration. These tests depend on time passing. In order to make the tests deterministic, time is mocked out using Tokio's testing utilities.

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.

Contributions that only focus on clarifying and improving comments are very welcome.

License

This project is licensed under the MIT license.

Contribution

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.

mini-redis's People

Contributors

avinassh avatar bryangarza avatar carllerche avatar chienguo avatar darksonn avatar dependabot[bot] avatar dimbtp avatar everlastingbugstopper avatar gallir avatar happysalada avatar hodkinson avatar jxs avatar leshow avatar liukun4515 avatar logan272 avatar mdaverde avatar microyahoo avatar nomyfan avatar palango avatar qyuzh avatar robatipoor avatar shomitarai avatar sunt-ing avatar taiki-e avatar tisonkun avatar tony-x avatar tottoto avatar vilgotf avatar zjp-cn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mini-redis's Issues

theoretically bug in db.set method?

theoretically bug in db.set method when current expire equal previous.

Is this code Better?

        if let Some(prev) = prev {
            if let Some(when) = prev.expires_at {
                if expires_at.is_none() || when != expires_at.unwrap() {
                    state.expirations.remove(&(when, key));
                }
            }
        }

than

        if let Some(prev) = prev {
            if let Some(when) = prev.expires_at {
                // clear expiration
                state.expirations.remove(&(when, key));
            }
        }

Apparent memory leak of spawned tasks

I believe there is some form of memory leak, and this was discussed some in the Discord channel #tokio-users recently. This graph should illustrate it pretty well:

Memory leak graph

The orange 6.2MB are a single allocation by tracing-subscriber, the green are RawTasks that are allocated via spawn, and the blue are something in broadcast. The workload is just running while true; do target/release/cli get k; done for a while (perhaps after setting a value for k, but I believe it doesn't actually matter).

As far as I can tell, the spawned tasks have actually completed. A different implementation (using watch instead of broadcast) fixes it. Another project using broadcast does not have a similar issue. My hunch is that there is some kind of reference cycle, maybe in part because the shutdown coordination is bidirectional, but I have not looked more closely yet.

Fails with Latest Rust

I am using Rust and Cargo 1.44.1. When installing mini-redis, I get a build error:

error[E0658]: use of unstable library feature 'renamed_spin_loop'
 --> /Users/jahred-love/.cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.9.2/src/spinwait.rs:9:5
  |
9 | use core::hint::spin_loop;
  |     ^^^^^^^^^^^^^^^^^^^^^
  |
  = note: see issue #55002 <https://github.com/rust-lang/rust/issues/55002> for more information

error[E0658]: use of unstable library feature 'renamed_spin_loop'
  --> /Users/jahred-love/.cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.9.2/src/spinwait.rs:16:9
   |
16 |         spin_loop()
   |         ^^^^^^^^^
   |
   = note: see issue #55002 <https://github.com/rust-lang/rust/issues/55002> for more information

   Compiling num_cpus v1.13.1
error[E0658]: `match` is not allowed in a `const fn`
   --> /Users/jahred-love/.cargo/registry/src/github.com-1ecc6299db9ec823/socket2-0.4.4/src/lib.rs:165:9
    |
165 | /         match address {
166 | |             SocketAddr::V4(_) => Domain::IPV4,
167 | |             SocketAddr::V6(_) => Domain::IPV6,
168 | |         }
    | |_________^
    |
    = note: see issue #49146 <https://github.com/rust-lang/rust/issues/49146> for more information

   Compiling atty v0.2.14
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0658`.
error: could not compile `parking_lot_core`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: aborting due to previous error

For more information about this error, try `rustc --explain E0658`.
error: could not compile `socket2`.

To learn more, run the command again with --verbose.
warning: build failed, waiting for other jobs to finish...
error: failed to compile `mini-redis v0.4.1`, intermediate artifacts can be found at `/var/folders/pz/g8nj0j791bzb4_7qn53833v80000gp/T/cargo-installG3dzIj`

Caused by:
  build failed

The `chat` example is empty

There is a chat.rs example file in the repository but it is empty:

#[tokio::main]
async fn main() {
    unimplemented!();
}

Why put an empty example file that contains nothing (genuine question)?

Bug: Cannot move variable from getter

In Shoutdown.rs the ownership is returning, however shouldn't the function return a borrow reference instead? I'm getting errors from the linter with the message "cannot move".

the original line :

pub(crate) fn is_shutdown(&self) -> bool {

what I think is correct [which may my thought is wrong]

pub(crate) fn is_shutdown(&self) -> &bool {
        &self.shutdown
    }

dtrace user stacks not generating

Hi,

I'm identifying useful metrics for powermetrics, dtrace, rust, and tokio. I've found tokio-metrics and other utilities, but I can't seem to get dtrace to work with mini-redis. Here is the interesting part about it, I can run the following command on another project using tokio for the PID[12345] selected.

$ sudo dtrace -x ustackframes=100 -n "profile-97 /pid == 12345 / { @[ustack()] = count(); } tick-60s { exit(0); }" -o user.stacks

Why am I opening this ticket here when the issue is with dtrace? I'd like to know, is this project doing anything sparsely different from the norm of writing rust code? If so, where is that sparsely different thing?

Question: steps to production from this project

I implement a lru cache based on this project. I know that this project isn't for production use. But what's the step missing for production usage? I know there're a few fix constants documented in the comments. Besides that, is there any good practice that does not exercise for this project to be ready for production usage? I'm new to tokio.

Looking at the flamegraph of the lru cache,
image
I notice that parsing the command takes a substantial time which might have room to optimize. Is there anything else that could be done better?

Initial benchmark results

REAL REDIS

redis-benchmark -t get,set -n 10000                                                                                                         ✔
====== SET ======
  10000 requests completed in 0.08 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
129870.13 requests per second

====== GET ======
  10000 requests completed in 0.07 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
138888.89 requests per second

MINI REDIS - SINGLE THREADED

redis-benchmark -t get,set -n 10000                                                                                                         ✔
====== SET ======
  10000 requests completed in 0.11 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.52% <= 105 milliseconds
99.59% <= 106 milliseconds
99.65% <= 107 milliseconds
99.73% <= 108 milliseconds
99.82% <= 109 milliseconds
99.94% <= 110 milliseconds
100.00% <= 110 milliseconds
90909.09 requests per second

====== GET ======
  10000 requests completed in 0.10 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.52% <= 101 milliseconds
99.60% <= 102 milliseconds
99.73% <= 103 milliseconds
99.91% <= 104 milliseconds
100.00% <= 104 milliseconds
96153.84 requests per second

MINI REDIS - THREADED

redis-benchmark -t get,set -n 10000                                                                                                         ✔
====== SET ======
  10000 requests completed in 0.09 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.57% <= 89 milliseconds
99.87% <= 90 milliseconds
100.00% <= 90 milliseconds
111111.11 requests per second

====== GET ======
  10000 requests completed in 0.11 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.57% <= 104 milliseconds
99.79% <= 105 milliseconds
100.00% <= 105 milliseconds
94339.62 requests per second

Values inserted into State::pub_sub HashMap are never removed, leaky.

e.insert(tx);

I'm working on my own project and find it hard to implement a pub_sub system that isn't either manually managing memory(an anti-rust patter IMHO) or forgetting about it altogether as this code does.

Edit/Replace:
I wrote what maybe a working solution:
https://gitlab.com/cheako/websuite-rs/-/blob/21e9c2e7e2bb31dd0e3f94cc5ae23a17ece8e2c0/naomi/src/lib.rs
I didn't use a mpsc for the locking here, because I didn't want to be sending messages in a Drop handler... What do you think?

I'm playing with some ideas, but nothing is working out:
tov/weak-table-rs#5
https://gitlab.com/cheako/websuite-rs/-/blob/77258e059853acf9b678049c8016d3545394d2f6/naomi/src/lib.rs#L69
https://gitlab.com/cheako/websuite-rs/-/blob/af387566968a48bb8a8cb574d1baf30eb953d141/naomi/src/lib.rs#L138

Another project struggling with this is feather a minecraft server:
https://github.com/feather-rs/feather/blob/e6927044246e258cd0529645429ae83b45a23628/server/chunk/src/chunk_manager.rs#L84

As such, solutions welcome.

Race condition in Drop of Db

The destructor of Db looks like this:

mini-redis/src/db.rs

Lines 249 to 257 in c3bc304

impl Drop for Db {
fn drop(&mut self) {
// If this is the last active `Db` instance, the background task must be
// notified to shut down.
//
// First, determine if this is the last `Db` instance. This is done by
// checking `strong_count`. The count will be 2. One for this `Db`
// instance and one for the handle held by the background task.
if Arc::strong_count(&self.shared) == 2 {

However if two Db instances are dropped at the same time, they may both see a strong count of three.

Add (optional) OpenTelemetry + Xray integration

This task is to set up the necessary code for shipping traces to AWS Xray (via OpenTelemetry). This will allow us to have a full example that we can point people to when they are looking to get started with Xray.

This additional code should be compiled only conditionally, and not enabled as a default.

The server test key_value_timeout has a race condition causing hang

For some reason this doesn't happen on a Linux VM, but my laptop reproduces it consistently.

This hangs almost straight away on my machine:
while cargo test key_value_timeout; do :; done

I added some prints and can see that when the test hangs, the background purge task was awakened at the time for the key to be purged, the key is purged, and then the request is made for the key, but it no longer exists as it just got purged. The test then hangs as read_exact is waiting for a longer response.

It seems to be related to the auto-advancing of the clock when paused, but I am unsure where to go from here to investigate further.

https://github.com/tokio-rs/tokio/blob/8f10d816131868030996b5079fbc632750e69332/tokio/src/time/clock.rs#L83-L84

Why itparsing is set to fail when frame is not array?

Can anyone explain why it should fail when frame is any variant except Array? I am trying to use this example as a sceleton for the other application that uses TCP sockets and I am getting a Simple frame that fails that condition.

pub(crate) fn new(frame: Frame) -> Result<Parse, ParseError> {
        let array = match frame {
            Frame::Array(array) => array,
            frame => return Err(format!("protocol error; expected array, got {:?}", frame).into()),
        };

        Ok(Parse {
            parts: array.into_iter(),
        })
    }

panic in VSCode terminal

Hi I wanted to follow the tutorial and installed miniredis server
cargo install mini-redis

then I ran the command mini-redis-server which resulted in panic.
The command worked fine in a normal terminal though.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Syntax(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
regex parse error:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1: (?x)
 2:                 ^(?P<global_level>(?i:trace|debug|info|warn|error|off|[0-5]))$ |
                                          ^
 3:                  #                 ^^^.
 4:                  #                     `note: we match log level names case-insensitively
 5:                 ^
 6:                 (?: # target name or span name
 7:                     (?P<target>[\w:-]+)|(?P<span>\[[^\]]*\])
 8:                 ){1,2}
 9:                 (?: # level or nothing
10:                     =(?P<level>(?i:trace|debug|info|warn|error|off|[0-5]))?
11:                      #          ^^^.
12:                      #              `note: we match log level names case-insensitively
13:                 )?
14:                 $
15:                 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: Unicode-aware case insensitivity matching is not available (make sure the unicode-case feature is enabled)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
)', /Users/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tracing-subscriber-0.2.25/src/filter/env/directive.rs:167:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

feel free to close this as won't fix so this issue at least serves for informational purpose :)

Benches for mini-redis

It would be great to provide an example of how to create idiomatic benchmarks (with criterion-rs or some other form) for a service/server like mini-redis - I've found very little info on that.

Confusing use of `notify`

Thank you for all the effort put into Tokio and the mini-redis demonstration project. As well as for making these open source.

Trying to understand Rust, we were confused by the use of the term notify to refer to a Receiver, specifically notify.recv() had us looking twice.

Some dictionaries have listen or collect or gather as antonyms for notify.

We think changing this usage of notify to one of the antonyms may be less puzzling?

Suggestion: logging option for `mini-redis-server` command

Hello,
I'm currently following up the tutorial.

How do you think about making some option to make log visible for server? When I run mini-redis-server command, seems it shows nothing while running(it works well though)...

It could be something like mini-redis-server --log-level info...

But if there is already a function, and only not been written in document, please let me know 🙏

updates?

mini-redis is used for learning async programming in Rust, but I feel like it needs to be updated.

Fails when install mini-redis with the latest rustc version

I am using Rust and Cargo 1.73.0 . When installing mini-redis, I get a build error:

error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/root/.vscode-server/bin/e7e037083ff4455cf320e344325dacb480062c3c/bin/remote-cli:/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin" VSLANG="1033" "cc" "-m64" "/tmp/rustcGWLqCB/symbols.o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70.build_script_build.f25fac906b0a6b23-cgu.0.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70.build_script_build.f25fac906b0a6b23-cgu.1.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70.build_script_build.f25fac906b0a6b23-cgu.2.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70.build_script_build.f25fac906b0a6b23-cgu.3.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70.2c7f59pgs6298tkj.rcgu.o" "-Wl,--as-needed" "-L" "/tmp/cargo-installf78Yjq/release/deps" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-6498d8891e016dca.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-3debdee1a9058d84.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-8339c5bd5cbc92bf.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-160ebcebb54c11ba.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-95c75789f1b65e37.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-7e8094f2d6258832.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-bac9783ef1b45db0.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-a1cd87df2f2d8e76.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-7fd06d468d7dba16.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-5ac19487656e05bf.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-c7c35d32cf825c11.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-c523f1571362e70b.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-85f17c92b770a911.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-598d3ba148dadcea.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-a58ec2dab545caa4.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-f9dda8cca149f0fc.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-7ba4c315dd7a3503.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-5ac2993e19124966.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-df2fb7f50dec519a.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/cargo-installf78Yjq/release/build/libc-3b0a2e386d160e70/build_script_build-3b0a2e386d160e70" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
  = note: /usr/bin/ld: final link failed: No space left on device
          collect2: error: ld returned 1 exit status
          

error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/root/.vscode-server/bin/e7e037083ff4455cf320e344325dacb480062c3c/bin/remote-cli:/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin" VSLANG="1033" "cc" "-m64" "/tmp/rustcsqz30r/symbols.o" "/tmp/cargo-installf78Yjq/release/build/proc-macro2-1427096048b90dcd/build_script_build-1427096048b90dcd.build_script_build.77c4db90c142e1f3-cgu.0.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/proc-macro2-1427096048b90dcd/build_script_build-1427096048b90dcd.build_script_build.77c4db90c142e1f3-cgu.1.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/proc-macro2-1427096048b90dcd/build_script_build-1427096048b90dcd.build_script_build.77c4db90c142e1f3-cgu.2.rcgu.o" "/tmp/cargo-installf78Yjq/release/build/proc-macro2-1427096048b90dcd/build_script_build-1427096048b90dcd.14zvc5gmntw8d8kv.rcgu.o" "-Wl,--as-needed" "-L" "/tmp/cargo-installf78Yjq/release/deps" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-6498d8891e016dca.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-3debdee1a9058d84.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-8339c5bd5cbc92bf.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-160ebcebb54c11ba.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-95c75789f1b65e37.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-7e8094f2d6258832.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-bac9783ef1b45db0.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-a1cd87df2f2d8e76.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-7fd06d468d7dba16.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-5ac19487656e05bf.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-c7c35d32cf825c11.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-c523f1571362e70b.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-85f17c92b770a911.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-598d3ba148dadcea.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-a58ec2dab545caa4.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-f9dda8cca149f0fc.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-7ba4c315dd7a3503.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-5ac2993e19124966.rlib" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-df2fb7f50dec519a.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/tmp/cargo-installf78Yjq/release/build/proc-macro2-1427096048b90dcd/build_script_build-1427096048b90dcd" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
  = note: /usr/bin/ld: final link failed: No space left on device
          collect2: error: ld returned 1 exit status
          

error: could not compile `libc` (build script) due to previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `proc-macro2` (build script) due to previous error
error: failed to compile `mini-redis v0.4.1`, intermediate artifacts can be found at `/tmp/cargo-installf78Yjq`.
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.

Add "supporting to write unit test" as usage target.

Golang has miniredis package which define itself as a "Pure Go Redis test server, used in Go unittests". This is very useful, so why don't we make one for Rust?

Detailed use case would be to spawn in-process Redis server on random port for every #[tokio::test] functions and access it via real Redis client.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.