I’m stuck on stage 11 of command replication with golang.
I’ve tried creating a separate connection on listening port and creating another handshake to this connection that will send replicated commands to all replicas. This approach replicated the commands fine but when I run codecrafters test I got
[replication-11] $ ./spawn_redis_server.sh --port 6379
[your_program] Server binded to port 6379...
[replication-11] replica: $ redis-cli PING
[your_program] Raw command: *1\r\n$4\r\nPING\r\n
[your_program] Received 14 bytes: ["PING"]
[replication-11] Received "PONG"
[replication-11] replica: $ redis-cli REPLCONF listening-port 6380
[your_program] Raw command: *3\r\n$8\r\nREPLCONF\r\n$14\r\nlistening-port\r\n$4\r\n6380\r\n
[your_program] Replica binded to port 6380...
[your_program] Received 49 bytes: ["REPLCONF" "listening-port" "6380"]
[replication-11] Received "OK"
[replication-11] replica: $ redis-cli REPLCONF capa psync2
[your_program] Raw command: *3\r\n$8\r\nREPLCONF\r\n$4\r\ncapa\r\n$6\r\npsync2\r\n
[your_program] Received 40 bytes: ["REPLCONF" "capa" "psync2"]
[replication-11] Received "OK"
[replication-11] replica: $ redis-cli PSYNC ? -1
[your_program] Raw command: *3\r\n$5\r\nPSYNC\r\n$1\r\n?\r\n$2\r\n-1\r\n
[replication-11] Received "FULLRESYNC 8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb 0"
[your_program] Received 30 bytes: ["PSYNC" "?" "-1"]
[replication-11] Received RDB file
[replication-11] client: $ redis-cli SET foo 123
[your_program] Raw command: *3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\n123\r\n
[your_program] Received 31 bytes: ["SET" "foo" "123"]
[replication-11] Received "OK"
[replication-11] client: $ redis-cli SET bar 456
[your_program] Raw command: *3\r\n$3\r\nSET\r\n$3\r\nbar\r\n$3\r\n456\r\n
[your_program] Received 31 bytes: ["SET" "bar" "456"]
[replication-11] Received "OK"
[replication-11] client: $ redis-cli SET baz 789
[your_program] Raw command: *3\r\n$3\r\nSET\r\n$3\r\nbaz\r\n$3\r\n789\r\n
[your_program] Received 31 bytes: ["SET" "baz" "789"]
[replication-11] Received "OK"
[replication-11] Sent 3 SET commands to master successfully.
[replication-11] replica: Expecting "SET foo 123" to be propagated
[replication-11] Received: "" (no content received)
[replication-11] ^ error
[replication-11] Error: Expected start of a new RESP2 value (either +, -, :, $ or *)
[replication-11] Test failed (try setting 'debug: true' in your codecrafters.yml to see more details)
I read some other posts about the same errors but I never understand what the error means or how I am supposed to replicate commands without beeing able to establish a connection from the master to the replica. I’m a noob in golang. I don’t have a specific chunk of code to show nor I ask for one. Just an explanation of the error and a description of what I am supposed to do. I’m sorry in advance if I’m expected to say anything I didn’t or I’m not able to understand something obvious.
@Souvlaki42 this is where the mistake is, instead of creating a new connection you need to re-use the original connection that the replica used when creating a handshake. After you’ve completed the handshake (i.e. sent the RDB file back), don’t throw that connection object away, instead find a way to store it and then use the same one for propagating commands.
Thanks for your reply. Just a little question. The connection object seems to be from replica to master. When I write on it, it writes to master, not the replica. I thought I was supposed to write commands from master to replicas. Isn’t that the case? Correct me if I’m being wrong here.
@Souvlaki42 You’re right that in this stage (Single-replica propagation) your master needs to write to replicas. TCP connections are two-way So when a replica connects to your master and performs the handshake, if you hold on to that connection and “write” to it from the master, you’d be writing to the replica.
I think what you’ve suggested could work but the reason it didn’t before neither it does now is because, I need a way to access the connection returned by the handshake inside master. Do you have any suggestions?
Hard to answer without seeing some code Mind sharing what you’ve currently got? Here’s how you can publish your code to GitHub: Publish to GitHub - CodeCrafters
You are right. Sorry for not providing it from the start of this post.
Here you go: My repo
(PS I’ve been trying to solve this stage for almost a week now, so your comments are really helpful for me to finally move on)
@Souvlaki42 this’d be the correct place to access the connection:
After “handling” psync and writing the response, that same connection object is what you’ll need to call Write on to propagate commands.
Looks like you’ve already got a replicas global here, instead of a channel you could use an array ([]net.Conn) and then append to that array from within handleConnection after receiving the psync command. That way all replica connections will be accessible from other parts of your program.
Note that you’ll need to find a way to prevent the defer connection.Close() statement within handleConnection from firing, else that’d close the connection when the handleConnection function exits.
Note: I’ve updated the title of this post to include the stage ID (#ZN8). You can learn about the stages rename here: Upcoming change: Stages overhaul.