Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 33 additions & 42 deletions stage_descriptions/replication-15-yd3.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
In this stage, you'll extend your `REPLCONF GETACK` implementation to respond with the number of bytes of commands processed by the replica.

### ACKs (Recap)

As a recap, a master uses ACKs to verify that its replicas are in sync with it and haven't fallen behind. Each ACK contains an offset — the number of bytes of commands processed by the replica.

### Offset tracking

<details>
<summary>Click to expand/collapse</summary>
As we saw in previous stages, when a replica receives a command from the master, it processes it and updates its state. In addition to processing commands, the replica also keeps a running count of the number of bytes of commands it has processed.

This count is called the "offset". When a master sends a `REPLCONF GETACK` command to a replica, the replica is expected to respond with `REPLCONF ACK <offset>`. The returned `<offset>` should only include the number of bytes of commands processed **before** receiving the `REPLCONF GETACK` command.

As an example:

- Let's say a replica connects to a master and completes the handshake.
- The master then sends a `REPLCONF GETACK *` command.
- The replica should respond with `REPLCONF ACK 0`.
- The returned offset is 0 since no commands have been processed yet (before receiving the `REPLCONF GETACK` command)
- The master then sends `REPLCONF GETACK *` again.
- The replica should respond with `REPLCONF ACK 37`.
- The returned offset is 37 since the first `REPLCONF GETACK` command was processed, and it was 37 bytes long.
- The RESP encoding for the `REPLCONF GETACK` command looks like this: `*3\r\n$8\r\nreplconf\r\n$6\r\ngetack\r\n$1\r\n*\r\n` (that's 37 bytes long)
- The master then sends a `PING` command to the replica (masters do this periodically to notify replicas that the master is still alive).
- The replica must silently process the `PING` command and update its offset. It should not send a response back to the master.
- The master then sends `REPLCONF GETACK *` again (this is the third REPLCONF GETACK command received by the replica)
- The replica should respond with `REPLCONF ACK 88`.
- The returned offset is 88 (37 + 37 + 14)
- 37 for the first `REPLCONF GETACK` command
- 37 for the second `REPLCONF GETACK` command
- 14 for the `PING` command
- Note that the third `REPLCONF GETACK` command is not included in the offset, since the value should
only include the number of bytes of commands processed **before** receiving the current `REPLCONF GETACK` command.
- ... and so on

</details>
A replica keeps its offset updated by tracking the total byte size of every command received from its master. This includes both write commands (like `SET`, `DEL`) and non-write commands (like `PING`, `REPLCONF GETACK *`).

After processing the received command (e.g., `["SET", "foo", "bar]`), it adds the full RESP array byte length to its running offset.

An important rule for this process is that the offset should only include commands processed **before** the current `REPLCONF GETACK *` request.

For example:

- A replica connects, completes the handshake, and the master sends `REPLCONF GETACK *`.
- The replica responds with `REPLCONF ACK 0` since no commands had been processed before this request.
- Next, the master sends another `REPLCONF GETACK *`.
- The replica responds with `REPLCONF ACK 37`, because the previous `REPLCONF` command consumed 37 bytes.
- The master then sends a `PING` command.
- The replica silently processes it, increments its offset by 14, and sends no response.
- The next `REPLCONF GETACK *` arrives.
- The replica responds with `REPLCONF ACK 88` — that’s 37 (for the first `REPLCONF`), +37 (for the second `REPLCONF`), +14 (for the `PING`).

Notice that the current `GETACK` request itself is not included in the offset value.

### Tests

Expand All @@ -45,23 +38,21 @@ Just like in the previous stages, your replica should complete the handshake wit
The master will then propagate a series of commands to your replica. These commands will be interleaved with `REPLCONF GETACK *` commands.

```bash
REPLCONF getack * # expecting REPLCONF ACK 0, since 0 bytes have been processed
REPLCONF GETACK * # expect: REPLCONF ACK 0

ping # master sending a ping command to notify the replica that it's still alive
REPLCONF getack * # expecting REPLCONF ACK 51
# 51 = 37 (for the first REPLCONF command) + 14 (for the ping command)
PING # replica processes silently
REPLCONF GETACK * # expect: REPLCONF ACK 51
# 51 = 37 (first REPLCONF) + 14 (PING)

set foo 1 # propagated from master to replica
set bar 2 # propagated from master to replica
REPLCONF getack * # expecting REPLCONF ACK 146
# 146 = 51 + 37 (for the second REPLCONF command) + 29 (for the first set command) + 29 (for the second set command)
SET foo 1 # replica processes silently
SET bar 2 # replica processes silently
REPLCONF GETACK * # expect: REPLCONF ACK 146
# 146 = 51 + 37 (second REPLCONF) + 29 (SET foo) + 29 (SET bar)
```

Your replica must calculate and return the exact offset at each step in the `REPLCONF ACK <offset>` response. Your response should also be encoded as a [RESP array](https://redis.io/docs/latest/develop/reference/protocol-spec/#arrays).

### Notes

- The offset should only include the number of bytes of commands processed **before** receiving the current `REPLCONF GETACK` command.
- Although masters don't propagate `PING` commands when received from clients (since they aren't "write" commands),
they may send `PING` commands to replicas to notify replicas that the master is still alive.
- Replicas should update their offset to account for **all** commands propagated from the master, including `PING` and `REPLCONF` itself.
- The response should be encoded as a [RESP Array](https://redis.io/docs/latest/develop/reference/protocol-spec/#arrays), like
this: `*3\r\n$8\r\nREPLCONF\r\n$3\r\nACK\r\n$3\r\n154\r\n`.
- Although masters don't propagate `PING` commands when received from clients (since they aren't "write" commands), they may send `PING` commands to replicas to notify replicas that the master is still alive.
Loading