Stuck on Redis Stage #LA7 in Rust

I’m stuck on Stage 6.

I have successfully implemented the SET and GET commands locally and can use them with the official resdis cli, but the tests are failing. I had no issues with the Python version.

Here are my logs:

[stage-6] Running tests for Stage #6: Implement the SET & GET commands
[stage-6] $ ./spawn_redis_server.sh
[your_program] Logs from your program will appear here!
[stage-6] Setting key apple to mango
[stage-6] $ redis-cli SET apple mango
[stage-6] Sent bytes: "*3\r\n$3\r\nSET\r\n$5\r\napple\r\n$5\r\nmango\r\n"
[stage-6] Received bytes: "+OK\r\n"
[stage-6] Received RESP value: "OK"
[your_program] accepted new connection
[your_program] handling connection
[your_program] received value: Array([BulkString(Some("SET")), BulkString(Some("apple")), BulkString(Some("mango"))])
[your_program] args [BulkString(Some("apple")), BulkString(Some("mango"))]
[your_program] Sending value SimpleString("OK")
[stage-6] Received "OK"
[stage-6] Getting key apple
[stage-6] $ redis-cli GET apple
[stage-6] Sent bytes: "*2\r\n$3\r\nGET\r\n$5\r\napple\r\n"
[stage-6] Received bytes: "+OK\r\n"
[stage-6] Received RESP value: "OK"
[stage-6] Expected "mango", got "OK"
[stage-6] Test failed
[stage-6] Terminating program
[your_program] received value: Array([BulkString(Some("SET")), BulkString(Some("apple")), BulkString(Some("mango"))])
[your_program] args [BulkString(Some("apple")), BulkString(Some("mango"))]
[your_program] Sending value SimpleString("OK")
[stage-6] Program terminated successfully

The logs of the test show that a get command is set, but my application gets another set command that is identical to the previous set command.

[07:15:25] 🐟 hwm@zebra in [Python 3.11.8] via 🦀 v1.75.0 on  master [!] ~/myspace/codecrafters-redis-rust 
❯ redis-cli set foo bar
OK

[07:15:44] 🐟 hwm@zebra in [Python 3.11.8] via 🦀 v1.75.0 on  master [!] ~/myspace/codecrafters-redis-rust 
❯ redis-cli get foo
"bar"

And the application logs for the manual test.

Logs from your program will appear here!
accepted new connection
handling connection
received value: Array([BulkString(Some("set")), BulkString(Some("foo")), BulkString(Some("bar"))])
args [BulkString(Some("foo")), BulkString(Some("bar"))]
Sending value SimpleString("OK")
accepted new connection
handling connection
received value: Array([BulkString(Some("get")), BulkString(Some("foo"))])
get args [BulkString(Some("foo"))]
Sending value BulkString(Some("bar"))

And here’s a snippet of my code:

    println!("handling connection");
    loop {
        let value = response_handler.read_value().await.unwrap();
        let response = if let Some(value) = value {
            println!("received value: {:?}", value);
            // println!("received value ser: {}", value.serialize());
            let (command, args) = extract_command(value).unwrap();

            match command.to_lowercase().as_str() {
                "ping" => Value::SimpleString("PONG".to_string()),

                "echo" => args.first().unwrap().clone(),

                "set" => run_set_command(args).await,
                "get" => run_get_command(args).await,

                c => panic!("Cannot handle command {}", c),
            }
        } else {
            break;
        };

        println!("Sending value {:?}", response);

        response_handler.write_value(response).await.unwrap();
    }

I have no idea why I have a different behaviour in the test and locally and what else I can try

@hwmrocker is it possible that you aren’t clear a buffer after reading the first command? That could explain why the same command is returned when you read again.

Hard to tell is that’s the case without seeing what response_handler is and how read_value() is implemented.

The reason this is different from the local test listed above could be that SET key value and GET key are sent on the same connection, not different connections.

Ah, that is a good point. This could be the reason.

The issue was that I didn’t advance the input buffer after the command. I could replicate this locally with

echo -e "set foo bar\nget foo" | redis-cli

Note: I’ve updated the title of this post to include the stage ID (#LA7). You can learn about the stages rename here: Upcoming change: Stages overhaul.