Redis Challenge #YD3

The variability in this test case is quite odd.

I can run the same command two in a row and receive two different outputs. I just dont understand what is happening nor how it is testing.

I have print statements that will voluntarily show and not show. Can someone give me an explanation as how to this test works? As a matter of fact they are failing in two different places. It is bewildering.

codecrafters test

[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#YD3] [test] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$1\r\n0\r\n"
[tester::#YD3] [test] master: Received RESP array: ["REPLCONF", "ACK", "0"]
[your_program] INITIAL REQUEST: *3
[your_program] $8
[your_program] REPLCONF
[your_program] $6
[your_program] GETACK
[your_program] $1
[your_program] *
[your_program] 
[your_program] REPL_CONF_INITIAL_OFFSET PRE: 0
[your_program] REPL_CONF_INITIAL_OFFSET AFTER: 37
[tester::#YD3] [test] Received ["REPLCONF", "ACK", "0"]
[tester::#YD3] [propagation] master: > PING
[tester::#YD3] [propagation] master: Sent bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#YD3] [test] master: > REPLCONF GETACK *
[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[your_program] INITIAL REQUEST: *1
[your_program] $4
[your_program] PING
[your_program] *3
[your_program] $8
[your_program] REPLCONF
[your_program] $6
[your_program] GETACK
[your_program] $1
[your_program] *
[your_program] 
[your_program] REPL_CONF_INITIAL_OFFSET PRE: 37
[your_program] REPL_CONF_INITIAL_OFFSET AFTER: 88
[tester::#YD3] [test] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$2\r\n37\r\n"
[tester::#YD3] [test] master: Received RESP array: ["REPLCONF", "ACK", "37"]
[tester::#YD3] Expected argument #2 to be "51", got "37"
[tester::#YD3] Test failed
[tester::#YD3] Terminating program
[tester::#YD3] Program terminated successfully```

subsequent codecrafters test 


[tester::#YD3] [handshake] master: Waiting for replica to initiate handshake with "PING" command

[tester::#YD3] [handshake] master: Received bytes: "*1\r\n$4\r\nPING\r\n"

[tester::#YD3] [handshake] master: Received RESP array: ["PING"]

[tester::#YD3] [handshake] Received ["PING"]

[tester::#YD3] [handshake] master: Sent "PONG"

[tester::#YD3] [handshake] master: Sent bytes: "+PONG\r\n"

[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF listening-port 6380" command

[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n"

[tester::#YD3] [handshake] master: Received RESP array: ["REPLCONF", "listening-port", "6380"]

[tester::#YD3] [handshake] Received ["REPLCONF", "listening-port", "6380"]

[tester::#YD3] [handshake] master: Sent "OK"

[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"

[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF capa" command

[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"

[tester::#YD3] [handshake] master: Received RESP array: ["REPLCONF", "capa", "psync2"]

[tester::#YD3] [handshake] Received ["REPLCONF", "capa", "psync2"]

[tester::#YD3] [handshake] master: Sent "OK"

[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"

[tester::#YD3] [handshake] master: Waiting for replica to send "PSYNC" command

[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"

[tester::#YD3] [handshake] master: Received RESP array: ["PSYNC", "?", "-1"]

[tester::#YD3] [handshake] Received ["PSYNC", "?", "-1"]

[tester::#YD3] [handshake] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"

[tester::#YD3] [handshake] master: Sent bytes: "+FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0\r\n"

[tester::#YD3] [handshake] Sending RDB file...

[tester::#YD3] [handshake] master: Sent bytes: "$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\b\xbce\xfa\bused-mem°\xc4\x10\x00\xfa\baof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2"

[tester::#YD3] [handshake] Sent RDB file.

[tester::#YD3] [test] master: > REPLCONF GETACK *

[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"

[tester::#YD3] Received: "" (no content received)

[tester::#YD3] ^ error

[tester::#YD3] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)

[tester::#YD3] Test failed

[tester::#YD3] Terminating program

[tester::#YD3] Program terminated successfully```



Is there an explanation? It is incredibly tough to debug without inconsistent outputs from the test cases.

Hey @gimmy1, there might be multiple issues at play. Here’re the first ones that I encountered:

  1. #HD5 (Replication - Multi-replica propagation)

Looks like PINGs are being propagated when they shouldn’t be.

Deleting this block should fix it:


  1. Running tests for Stage #XV6 (Replication - ACKs with no commands)

I tried printing the handshake responses from the master:

You can see that not only handshake responses but also subsequent commands are being ignored:

Suggestions:

  1. Make sure your replica can handle multiple commands received in a single read.
  2. Focus on fixing the early stages first, as later stages depend on them.

Tip:

You can use our CLI to test against previous stages by running:

codecrafters test --previous

Closing this thread due to inactivity. If you still need assistance, feel free to reopen or start a new discussion!

Hello @andy1li

Appreciate your response.

Can you please explain how the master, through your tests, invoke this command? I would like to re-create the flow locally without running the tests. How the master is triggered to send a REPLCONF GETACK 1

Is there a way to test one test instead of the suite? Because running each test makes it quite difficult to understand what is happening at times.

The tests are also not consistent and it is confusing to understand which is the right way to handle it.

These are two subsequent codecrafters test calls. For YD3, notice these two failures.

[tester::#YD3] Master is running on port 6379
[tester::#YD3] $ ./your_program.sh --port 6380 --replicaof "localhost 6379"
[tester::#YD3] [handshake] master: Waiting for replica to initiate handshake with "PING" command
[tester::#YD3] [handshake] master: Received bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#YD3] [handshake] master: Received RESP array: ["PING"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["PING"]
[tester::#YD3] [handshake] 
[your_program] SENDING COMMAND: *1
[your_program] $4
[your_program] PING
[your_program] 
[tester::#YD3] [handshake] master: Sent "PONG"
[tester::#YD3] [handshake] master: Sent bytes: "+PONG\r\n"
[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF listening-port 6380" command
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n"
[tester::#YD3] [handshake] master: Received RESP array: [
[tester::#YD3] [handshake]   "REPLCONF",
[tester::#YD3] [handshake]   "listening-port",
[tester::#YD3] [handshake]   "6380"
[tester::#YD3] [handshake] ]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received [
[tester::#YD3] [handshake]   "REPLCONF",
[tester::#YD3] [handshake]   "listening-port",
[tester::#YD3] [handshake]   "6380"
[tester::#YD3] [handshake] ]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] master: Sent "OK"
[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"
[your_program] THIS is the RESPONSE: b'+PONG\r\n'
[your_program] SENDING COMMAND: *3
[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF capa" command
[your_program] $8
[your_program] REPLCONF
[your_program] $14
[your_program] listening-port
[your_program] $4
[your_program] 6380
[your_program] 
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[tester::#YD3] [handshake] master: Received RESP array: ["REPLCONF", "capa", "psync2"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["REPLCONF", "capa", "psync2"]
[tester::#YD3] [handshake] 
[your_program] THIS is the RESPONSE: b'+OK\r\n'
[your_program] SENDING COMMAND: *3
[your_program] $8
[your_program] REPLCONF
[your_program] $4
[your_program] capa
[your_program] $6
[your_program] psync2
[your_program] 
[tester::#YD3] [handshake] master: Sent "OK"
[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"
[tester::#YD3] [handshake] master: Waiting for replica to send "PSYNC" command
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[tester::#YD3] [handshake] master: Received RESP array: ["PSYNC", "?", "-1"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["PSYNC", "?", "-1"]
[tester::#YD3] [handshake] 
[your_program] THIS is the RESPONSE: b'+OK\r\n'
[your_program] SENDING COMMAND: *3
[your_program] $5
[your_program] PSYNC
[your_program] $1
[your_program] ?
[your_program] $2
[your_program] -1
[your_program] 
[tester::#YD3] [handshake] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"
[tester::#YD3] [handshake] master: Sent bytes: "+FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0\r\n"
[tester::#YD3] [handshake] Sending RDB file...
[tester::#YD3] [handshake] master: Sent bytes: "$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\b\xbce\xfa\bused-mem°\xc4\x10\x00\xfa\baof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2"
[tester::#YD3] [handshake] Sent RDB file.
[tester::#YD3] [test] master: > REPLCONF GETACK *
[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[your_program] THIS is the RESPONSE: b'+FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0\r\n$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\x08\xbce\xfa\x08used-mem\xc2\xb0\xc4\x10\x00\xfa\x08aof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n'
[tester::#YD3] Received: "" (no content received)
[tester::#YD3]            ^ error
[tester::#YD3] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[tester::#YD3] Test failed
[tester::#YD3] Terminating program
[tester::#YD3] Program terminated successfully

this is the second call

[tester::#YD3] Running tests for Stage #YD3 (Replication - ACKs with commands)
[tester::#YD3] Master is running on port 6379
[tester::#YD3] $ ./your_program.sh --port 6380 --replicaof "localhost 6379"
[tester::#YD3] [handshake] master: Waiting for replica to initiate handshake with "PING" command
[your_program] SENDING COMMAND: *1
[your_program] $4
[your_program] PING
[your_program] 
[tester::#YD3] [handshake] master: Received bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#YD3] [handshake] master: Received RESP array: ["PING"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["PING"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] master: Sent "PONG"
[tester::#YD3] [handshake] master: Sent bytes: "+PONG\r\n"
[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF listening-port 6380" command
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n"
[tester::#YD3] [handshake] master: Received RESP array: [
[tester::#YD3] [handshake]   "REPLCONF",
[tester::#YD3] [handshake]   "listening-port",
[tester::#YD3] [handshake]   "6380"
[tester::#YD3] [handshake] ]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received [
[tester::#YD3] [handshake]   "REPLCONF",
[tester::#YD3] [handshake]   "listening-port",
[tester::#YD3] [handshake]   "6380"
[tester::#YD3] [handshake] ]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] master: Sent "OK"
[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"
[tester::#YD3] [handshake] master: Waiting for replica to send "REPLCONF capa" command
[your_program] THIS is the RESPONSE: +PONG
[your_program] 
[your_program] THIS is the COMMANDS: []
[your_program] THIS is the initial_request 
[your_program] SENDING COMMAND: *3
[your_program] $8
[your_program] REPLCONF
[your_program] $14
[your_program] listening-port
[your_program] $4
[your_program] 6380
[your_program] 
[your_program] THIS is the RESPONSE: +OK
[your_program] 
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[tester::#YD3] [handshake] master: Received RESP array: ["REPLCONF", "capa", "psync2"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["REPLCONF", "capa", "psync2"]
[tester::#YD3] [handshake] 
[your_program] THIS is the COMMANDS: []
[your_program] THIS is the initial_request 
[your_program] SENDING COMMAND: *3
[your_program] $8
[your_program] REPLCONF
[your_program] $4
[your_program] capa
[your_program] $6
[your_program] psync2
[your_program] 
[tester::#YD3] [handshake] master: Sent "OK"
[tester::#YD3] [handshake] master: Sent bytes: "+OK\r\n"
[tester::#YD3] [handshake] master: Waiting for replica to send "PSYNC" command
[tester::#YD3] [handshake] master: Received bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[your_program] THIS is the RESPONSE: +OK
[your_program] 
[tester::#YD3] [handshake] master: Received RESP array: ["PSYNC", "?", "-1"]
[tester::#YD3] [handshake] 
[tester::#YD3] [handshake] Received ["PSYNC", "?", "-1"]
[tester::#YD3] [handshake] 
[your_program] THIS is the COMMANDS: []
[your_program] THIS is the initial_request 
[your_program] SENDING COMMAND: *3
[your_program] $5
[your_program] PSYNC
[your_program] $1
[your_program] ?
[your_program] $2
[your_program] -1
[your_program] 
[tester::#YD3] [handshake] master: Sent "FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0"
[tester::#YD3] [handshake] master: Sent bytes: "+FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0\r\n"
[tester::#YD3] [handshake] Sending RDB file...
[tester::#YD3] [handshake] master: Sent bytes: "$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\b\xbce\xfa\bused-mem°\xc4\x10\x00\xfa\baof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2"
[tester::#YD3] [handshake] Sent RDB file.
[tester::#YD3] [test] master: > REPLCONF GETACK *
[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#YD3] [test] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$1\r\n0\r\n"
[tester::#YD3] [test] master: Received RESP array: ["REPLCONF", "ACK", "0"]
[tester::#YD3] [test] 
[your_program] THIS is the RESPONSE: +FULLRESYNC 75cd7bc10c49047e0d163660f3b90625b1af31dc 0
[your_program] 
[your_program] THIS is the COMMANDS: []
[your_program] THIS is the initial_request 
[your_program] RDATA IS: b'$88\r\nREDIS0011\xfa\tredis-ver\x057.2.0\xfa\nredis-bits\xc0@\xfa\x05ctime\xc2m\x08\xbce\xfa\x08used-mem\xc2\xb0\xc4\x10\x00\xfa\x08aof-base\xc0\x00\xff\xf0n;\xfe\xc0\xffZ\xa2*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n'
[your_program] LEN INITIAL REQUEST: 113
[your_program] REPL_CONF_INITIAL_OFFSET PRE: 0
[your_program] INITIAL REQUEST AFTER PRC: $8
[your_program] REPLCONF
[your_program] $6
[your_program] GETACK
[your_program] $1
[your_program] *
[your_program] 
[your_program] REPL_CONF_INITIAL_OFFSET POST: 33
[your_program] WHATS THE RESPONSE: b'*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$1\r\n0\r\n'
[tester::#YD3] [test] Received ["REPLCONF", "ACK", "0"]
[tester::#YD3] [test] 
[tester::#YD3] [propagation] master: > PING
[tester::#YD3] [propagation] master: Sent bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#YD3] [test] master: > REPLCONF GETACK *
[tester::#YD3] [test] master: Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#YD3] [test] master: Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$2\r\n33\r\n"
[tester::#YD3] [test] master: Received RESP array: ["REPLCONF", "ACK", "33"]
[tester::#YD3] [test] 
[tester::#YD3] Expected argument #2 to be "51", got "33"
[tester::#YD3] Test failed
[tester::#YD3] Terminating program
[your_program] RDATA IS: b'*1\r\n$4\r\nPING\r\n*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n'
[your_program] LEN INITIAL REQUEST: 51
[your_program] REPL_CONF_INITIAL_OFFSET PRE: 33
[your_program] INITIAL REQUEST AFTER PRC: $8
[your_program] REPLCONF
[your_program] $6
[your_program] GETACK
[your_program] $1
[your_program] *
[your_program] 
[your_program] REPL_CONF_INITIAL_OFFSET POST: 66
[your_program] WHATS THE RESPONSE: b'*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$2\r\n33\r\n'
[tester::#YD3] Program terminated successfully```

Can you explain why this occurs? Two same calls and two different failures. Can you give me an exact detail of how the Master will be used to send a call to the Slave? Does it come from the redis-cli to the Master to the Slave. Or is there another way? Because it seems there are two distinct ways the message is being relayed to the Slave.

Thank you

@gimmy1 There is no guarantee that a single read from a TCP connection will contain just one command.

Your replica should be able to handle multiple commands received in a single read:


Can you please explain how the master, through your tests, invoke this command?

Here’s the tester code for stage #YD3:

Let me know if you’d like further clarification!

Hey man, i’m not confused whether or not there will be multiple commands or a single command within one read. I’m more confused on the consistency of the test and what I can expect from the test.

For example, in my code i have an initial handshake code which sends the 4 commands and ignores the response, this was done on purpose. You pointed out that it was being ignored, OK. I added code to handle this scenario. But in another test case I can see that that value is not being ignored because it seems it is being sent through a redis-cli to the master and then to the slave. this is my second connection, my while True after the for command in commands.

I passed the test, I wanted an explanation what I could expect. I appreciate your swift response, @andy1li

There is definitely some odd behavior. Some submissions pass and move me on to the next round, while others dont pass me through. :man_shrugging:

@gimmy1 Glad to hear it’s working now! :tada:

Sorry if I misunderstood earlier. AFAIK, the only inconsistency or non-deterministic behavior is that a single read may or may not contain multiple commands.

For example, in my code i have an initial handshake code which sends the 4 commands and ignores the response, this was done on purpose.

When those responses were ignored, REPLCONF ACK * could be ignored along with them. However, the tester still expected your response but received nothing:

But in another test case I can see that that value is not being ignored because it seems it is being sent through a redis-cli to the master and then to the slave.

That test case likely passed not because of the way commands were passed around, but due to chance that every read happened to contain only one command.

Namely, even if the code did not handle the multiple-command case, it would still work in the single-command case when it’s lucky.

There is definitely some odd behavior.

Totally understand. These non-deterministic cases can be tricky. Let me know if you run into other issues!

@gimmy1 Just a heads-up: your recent submissions didn’t pass our flaky test, which meant the results were still non-deterministic.

Suggestion:

Use our CLI to test against previous stages by running:

codecrafters test --previous

You might need to run it multiple times to catch an unlucky run.

Just FYI:

  • Lucky run

  • Unlucky run

Alright, guess we can close this thread.

Have a good one.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.