Stuck at WAIT with multiple commands #na2

Hi Dev,

I am stuck at stage: WAIT with multiple commands #na2. I’m not sure how to handle the the replicas who don’t respond with ACk.

I’ve attached logs and the relevant methods below. You can find the full source code here.

[tester::#NA2] Running tests for Stage #NA2 (Replication - WAIT with multiple commands)
[tester::#NA2] $ ./your_program.sh --port 6379
[tester::#NA2] Proceeding to create 3 replicas.
[tester::#NA2] [setup] Creating 3 replicas:
[tester::#NA2] [setup] 1. replica@6380 (Listening port = 6380)
[tester::#NA2] [setup] 2. replica@6381 (Listening port = 6381)
[tester::#NA2] [setup] 3. replica@6382 (Listening port = 6382)
[tester::#NA2] Creating replica@6380
[your_program] Redis server started on port 6379
[your_program] Running as master
[tester::#NA2] [handshake] [replica@6380] $ redis-cli PING
[tester::#NA2] [handshake] [replica@6380] Sent bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#NA2] [handshake] [replica@6380] Received bytes: "+PONG\r\n"
[tester::#NA2] [handshake] [replica@6380] Received RESP simple string: "PONG"
[tester::#NA2] [handshake] [replica@6380] Received "PONG"
[tester::#NA2] [handshake] [replica@6380] > REPLCONF listening-port 6380
[tester::#NA2] [handshake] [replica@6380] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n"
[your_program] Handling REPLCONF command: listening-port 6380
[your_program] Added replica on port 6380. Total replicas: 1
[tester::#NA2] [handshake] [replica@6380] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6380] Received RESP simple string: "OK"
[tester::#NA2] [handshake] [replica@6380] Received "OK"
[tester::#NA2] [handshake] [replica@6380] > REPLCONF capa psync2
[tester::#NA2] [handshake] [replica@6380] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[tester::#NA2] [handshake] [replica@6380] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6380] Received RESP simple string: "OK"
[your_program] Handling REPLCONF command: capa psync2
[tester::#NA2] [handshake] [replica@6380] Received "OK"
[tester::#NA2] [handshake] [replica@6380] > PSYNC ? -1
[tester::#NA2] [handshake] [replica@6380] Sent bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[tester::#NA2] [handshake] [replica@6380] Received bytes: "+FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0\r\n"
[tester::#NA2] [handshake] [replica@6380] Received RESP simple string: "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6380] Received "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6380] Reading RDB file...
[tester::#NA2] [handshake] [replica@6380] Received 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::#NA2] [handshake] [replica@6380] Received RDB file
[tester::#NA2] Creating replica@6381
[tester::#NA2] [handshake] [replica@6381] $ redis-cli PING
[tester::#NA2] [handshake] [replica@6381] Sent bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#NA2] [handshake] [replica@6381] Received bytes: "+PONG\r\n"
[tester::#NA2] [handshake] [replica@6381] Received RESP simple string: "PONG"
[tester::#NA2] [handshake] [replica@6381] Received "PONG"
[tester::#NA2] [handshake] [replica@6381] > REPLCONF listening-port 6381
[tester::#NA2] [handshake] [replica@6381] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6381\r\n"
[tester::#NA2] [handshake] [replica@6381] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6381] Received RESP simple string: "OK"
[your_program] Handling REPLCONF command: listening-port 6381
[your_program] Added replica on port 6381. Total replicas: 2
[tester::#NA2] [handshake] [replica@6381] Received "OK"
[tester::#NA2] [handshake] [replica@6381] > REPLCONF capa psync2
[tester::#NA2] [handshake] [replica@6381] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[tester::#NA2] [handshake] [replica@6381] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6381] Received RESP simple string: "OK"
[your_program] Handling REPLCONF command: capa psync2
[tester::#NA2] [handshake] [replica@6381] Received "OK"
[tester::#NA2] [handshake] [replica@6381] > PSYNC ? -1
[tester::#NA2] [handshake] [replica@6381] Sent bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[tester::#NA2] [handshake] [replica@6381] Received bytes: "+FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0\r\n"
[tester::#NA2] [handshake] [replica@6381] Received RESP simple string: "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6381] Received "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6381] Reading RDB file...
[tester::#NA2] [handshake] [replica@6381] Received 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::#NA2] [handshake] [replica@6381] Received RDB file
[tester::#NA2] Creating replica@6382
[tester::#NA2] [handshake] [replica@6382] $ redis-cli PING
[tester::#NA2] [handshake] [replica@6382] Sent bytes: "*1\r\n$4\r\nPING\r\n"
[tester::#NA2] [handshake] [replica@6382] Received bytes: "+PONG\r\n"
[tester::#NA2] [handshake] [replica@6382] Received RESP simple string: "PONG"
[tester::#NA2] [handshake] [replica@6382] Received "PONG"
[tester::#NA2] [handshake] [replica@6382] > REPLCONF listening-port 6382
[tester::#NA2] [handshake] [replica@6382] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6382\r\n"
[tester::#NA2] [handshake] [replica@6382] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6382] Received RESP simple string: "OK"
[your_program] Handling REPLCONF command: listening-port 6382
[your_program] Added replica on port 6382. Total replicas: 3
[tester::#NA2] [handshake] [replica@6382] Received "OK"
[tester::#NA2] [handshake] [replica@6382] > REPLCONF capa psync2
[tester::#NA2] [handshake] [replica@6382] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n"
[your_program] Handling REPLCONF command: capa psync2
[tester::#NA2] [handshake] [replica@6382] Received bytes: "+OK\r\n"
[tester::#NA2] [handshake] [replica@6382] Received RESP simple string: "OK"
[tester::#NA2] [handshake] [replica@6382] Received "OK"
[tester::#NA2] [handshake] [replica@6382] > PSYNC ? -1
[tester::#NA2] [handshake] [replica@6382] Sent bytes: "*3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n"
[tester::#NA2] [handshake] [replica@6382] Received bytes: "+FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0\r\n"
[tester::#NA2] [handshake] [replica@6382] Received RESP simple string: "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6382] Received "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[tester::#NA2] [handshake] [replica@6382] Reading RDB file...
[tester::#NA2] [handshake] [replica@6382] Received 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::#NA2] [handshake] [replica@6382] Received RDB file
[tester::#NA2] [test] [client] $ redis-cli SET foo 123
[tester::#NA2] [test] [client] Sent bytes: "*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n123\r\n"
[your_program] Command [SET, foo, 123] uses 31 bytes
[your_program] master offset: 31
[tester::#NA2] [test] [client] Received bytes: "+OK\r\n"
[tester::#NA2] [test] [client] Received RESP simple string: "OK"
[tester::#NA2] [test] [client] Received "OK"
[tester::#NA2] [test] [client] > WAIT 1 500
[tester::#NA2] [test] [client] Sent bytes: "*3\r\n$4\r\nWAIT\r\n$1\r\n1\r\n$3\r\n500\r\n"
[tester::#NA2] [test] Testing Replica: replica@6380
[tester::#NA2] [test] [replica@6380] Expecting "SET foo 123" to be propagated
[tester::#NA2] [test] [replica@6380] Received bytes: "*3\r\n+SET\r\n+foo\r\n+123\r\n"
[tester::#NA2] [test] [replica@6380] Received RESP array: ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6380] Received ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6380] Expecting "REPLCONF GETACK *" from Master
[tester::#NA2] [test] [replica@6380] Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#NA2] [test] [replica@6380] Received RESP array: ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6380] Received ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6380] Sending ACK to Master
[tester::#NA2] [test] [replica@6380] > REPLCONF ACK 22
[tester::#NA2] [test] [replica@6380] Sent bytes: "*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$2\r\n22\r\n"
[tester::#NA2] [test] Testing Replica: replica@6381
[tester::#NA2] [test] [replica@6381] Expecting "SET foo 123" to be propagated
[tester::#NA2] [test] [replica@6381] Received bytes: "*3\r\n+SET\r\n+foo\r\n+123\r\n"
[tester::#NA2] [test] [replica@6381] Received RESP array: ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6381] Received ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6381] Expecting "REPLCONF GETACK *" from Master
[your_program] Handling REPLCONF command: ACK 22
[your_program] Received ACK from replica
[your_program] Replica acknowledged offset: 22, Master offset: 31
[tester::#NA2] [test] [replica@6381] Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#NA2] [test] [replica@6381] Received RESP array: ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6381] Received ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6381] Not sending ACK to Master
[tester::#NA2] [test] Testing Replica: replica@6382
[tester::#NA2] [test] [replica@6382] Expecting "SET foo 123" to be propagated
[tester::#NA2] [test] [replica@6382] Received bytes: "*3\r\n+SET\r\n+foo\r\n+123\r\n"
[tester::#NA2] [test] [replica@6382] Received RESP array: ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6382] Received ["SET", "foo", "123"]
[tester::#NA2] [test] [replica@6382] Expecting "REPLCONF GETACK *" from Master
[tester::#NA2] [test] [replica@6382] Received bytes: "*3\r\n$8\r\nREPLCONF\r\n$6\r\nGETACK\r\n$1\r\n*\r\n"
[tester::#NA2] [test] [replica@6382] Received RESP array: ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6382] Received ["REPLCONF", "GETACK", "*"]
[tester::#NA2] [test] [replica@6382] Not sending ACK to Master
[tester::#NA2] [test] [client] Received bytes: ":0\r\n"
[tester::#NA2] [test] [client] Received RESP integer: 0
[tester::#NA2] Expected 1, got 0
[tester::#NA2] Test failed
[tester::#NA2] Terminating program
[tester::#NA2] Program terminated successfully
public void handleReplconf(String clientId, List<String> command, OutputStream out) throws IOException {
        if (command.size() < 3) {
            writeError(RedisConstants.ERR_WRONG_NUMBER_ARGS + " 'REPLCONF' command", out);
            return;
        }

        String arg1 = command.get(1);
        String arg2 = command.get(2);

        System.out.println("Handling REPLCONF command: " + arg1 + " " + arg2);

        switch (arg1) {
            case RedisConstants.LISTENING_PORT:
                serverConfig.addReplica(out, Integer.parseInt(arg2));
                writeSimpleString("OK", out);
                break;

            case RedisConstants.CAPABILITIES:
                writeSimpleString("OK", out);
                break;

            case RedisConstants.GETACK:
                String offset = String.valueOf(serverConfig.getReplicaOffset());

                writeArray(3, out);
                writeBulkString("REPLCONF", out);
                writeBulkString("ACK", out);
                writeBulkString(offset, out);

                int bytes = RespProtocol.calculateRespCommandBytes(command);
                serverConfig.setReplicaOffset(serverConfig.getReplicaOffset() + bytes);
                System.out.println("getack: " + command + " replica offset: " + serverConfig.getReplicaOffset());
                break;

            case RedisConstants.ACK:
                System.out.println("Received ACK from replica");
                int receivedReplicaOffset = Integer.parseInt(arg2);

                if(receivedReplicaOffset >= serverConfig.getMasterOffset()){
                    serverConfig.setUpToDateReplicas(serverConfig.getUpToDateReplicas() + 1);
                }

                System.out.println("Replica acknowledged offset: " + receivedReplicaOffset +
                        ", Master offset: " + serverConfig.getMasterOffset());
                break;
        }

    }
public void handleWait(String clientId, List<String> command, OutputStream out) throws IOException, InterruptedException {
        if (command.size() < 3) {
            writeError(RedisConstants.ERR_WRONG_NUMBER_ARGS + " 'WAIT' command", out);
            return;
        }

        if(!serverConfig.hasReplicas()){
            writeInteger(0, out);
            return;
        }

        serverConfig.setUpToDateReplicas(0);
        serverConfig.getAck();

        int minimumUpToDateReplica = Integer.parseInt(command.get(1));
        long duration = Long.parseLong(command.get(2));

        long startTime = System.currentTimeMillis();
        long endTime = startTime + duration;

        while(System.currentTimeMillis() < endTime) {
            if(serverConfig.getUpToDateReplicas() >= minimumUpToDateReplica) {
                System.out.println("wait res sent: " + serverConfig.getUpToDateReplicas());
                writeInteger(serverConfig.getUpToDateReplicas(), out);
                return;
            }
            Thread.sleep(1);
        }

        writeInteger(serverConfig.getUpToDateReplicas(), out);
    }

Would really appreciate your help!!

Thanks.

I think no need to handle explicitly, we have time duration for that. But my test is failing. The offset I’m receiving (22) from the first replica should be >= master offset (31) which is not in this case

am I calculating master offset incorrectly? i’m simply calculating bytes of commands received (SET in this case) and adding it to the master offset i.e. 0 + 31

Hey @vaibhavhapani, could you upload your code to GitHub and share the link? It will be much easier to debug if I can run it directly.

Hi @andy1li, I’ve shared the link in the issue description. Anyways, here you go - GitHub - vaibhavhapani/codecrafters-redis-java

@vaibhavhapani I tried running your code against the previous stages, but it’s actually no longer passing a previous stage #TU8 (Replication - WAIT with no commands).

Suggestions:

  1. Use our CLI to test against previous stages by running:
codecrafters test --previous
  1. Focus on fixing the early stages first, as later stages depend on them.

it was passing this stage, maybe because of latest changes it’s breaking. I’ll look into it. But I’m still not sure where it is going wrong in the current stage

Let me know once you’ve fixed the previous stage so I can take another look.

Sure, thank you, andy!!

1 Like

Hey, this is fixed now. Previous stages are working fine. #na2 is still failing.

@andy1li the problem is that I’m getting ACK 22 from the first replica and the master offset is 33 (bytes of the previous command SET foo 123) which is not matching, therefore I’m not counting that and the rest of the replicas don’t send ACK so eventually I’m responding with 0 up to date replicas

the test case expects me to respond with 1

Hi , I found the issue was in how I was propagating the commands to replicas.

for (OutputStream replicaOutputStream : replicas) {
                writeArray(command.size(), replicaOutputStream);
                for (String arg : command) writeSimpleString(arg, replicaOutputStream);
}

I was passing the command args as simple strings rather than bulk strings

:victory_hand:

1 Like

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