{"id":21071283,"url":"https://github.com/yisuschrist/codecrafters-redis-rust","last_synced_at":"2025-06-19T08:32:22.598Z","repository":{"id":230223230,"uuid":"778801611","full_name":"YisusChrist/codecrafters-redis-rust","owner":"YisusChrist","description":"Welcome to the Build your own Redis challenge!","archived":false,"fork":false,"pushed_at":"2024-03-31T16:13:20.000Z","size":133,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-20T21:58:10.521Z","etag":null,"topics":["codecrafters","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/YisusChrist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-28T12:39:06.000Z","updated_at":"2024-03-31T16:12:25.000Z","dependencies_parsed_at":"2024-11-19T18:51:31.902Z","dependency_job_id":"21725d9e-39ea-4e94-9da6-b17577edea91","html_url":"https://github.com/YisusChrist/codecrafters-redis-rust","commit_stats":null,"previous_names":["yisuschrist/codecrafters-redis-rust"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YisusChrist%2Fcodecrafters-redis-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YisusChrist%2Fcodecrafters-redis-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YisusChrist%2Fcodecrafters-redis-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/YisusChrist%2Fcodecrafters-redis-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/YisusChrist","download_url":"https://codeload.github.com/YisusChrist/codecrafters-redis-rust/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243514267,"owners_count":20303088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["codecrafters","rust"],"created_at":"2024-11-19T18:51:17.723Z","updated_at":"2025-03-14T02:43:34.866Z","avatar_url":"https://github.com/YisusChrist.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![progress-banner](https://backend.codecrafters.io/progress/redis/bbb1d029-ae01-4a52-8a51-6d18cdefdffc)](https://app.codecrafters.io/users/codecrafters-bot?r=2qF)\n\nThis is a starting point for Rust solutions to the\n[\"Build Your Own Redis\" Challenge](https://codecrafters.io/challenges/redis).\n\nIn this challenge, you'll build a toy Redis clone that's capable of handling\nbasic commands like `PING`, `SET` and `GET`. Along the way we'll learn about\nevent loops, the Redis protocol and more.\n\n**Note**: If you're viewing this repo on GitHub, head over to\n[codecrafters.io](https://codecrafters.io) to try the challenge.\n\n- [Introduction](#introduction)\n- [Repository Setup](#repository-setup)\n- [Passing the first stage](#passing-the-first-stage)\n- [Stage 2 \\\u0026 beyond](#stage-2--beyond)\n- [Functionalities implemented for each stage](#functionalities-implemented-for-each-stage)\n  - [Basic functionality](#basic-functionality)\n    - [Stage 1: Bind to a port](#stage-1-bind-to-a-port)\n      - [Your Task](#your-task)\n      - [Tests](#tests)\n      - [Notes](#notes)\n    - [Stage 2: Respond to PING](#stage-2-respond-to-ping)\n      - [Prerequisites](#prerequisites)\n      - [Your Task](#your-task-1)\n      - [Tests](#tests-1)\n      - [Notes](#notes-1)\n    - [Stage 3: Respond to multiple PINGs](#stage-3-respond-to-multiple-pings)\n      - [Your Task](#your-task-2)\n      - [Tests](#tests-2)\n      - [Notes](#notes-2)\n    - [Stage 4: Handle concurrent clients](#stage-4-handle-concurrent-clients)\n      - [Your Task](#your-task-3)\n      - [Tests](#tests-3)\n      - [Notes](#notes-3)\n    - [Stage 5: Implement the ECHO command](#stage-5-implement-the-echo-command)\n      - [Your Task](#your-task-4)\n      - [Tests](#tests-4)\n      - [Notes](#notes-4)\n    - [Stage 6: Implement the SET \\\u0026 GET commands](#stage-6-implement-the-set--get-commands)\n      - [Your Task](#your-task-5)\n      - [Tests](#tests-5)\n      - [Notes](#notes-5)\n    - [Stage 7: Expiry](#stage-7-expiry)\n      - [Your Task](#your-task-6)\n      - [Tests](#tests-6)\n      - [Notes](#notes-6)\n  - [Replication](#replication)\n    - [Stage 8: Configure listening port](#stage-8-configure-listening-port)\n      - [Your Task](#your-task-7)\n      - [Tests](#tests-7)\n      - [Notes](#notes-7)\n    - [Stage 9: The INFO command](#stage-9-the-info-command)\n      - [Your Task](#your-task-8)\n      - [The replication section](#the-replication-section)\n      - [Tests](#tests-8)\n      - [Notes](#notes-8)\n    - [Stage 10: The INFO command on a replica](#stage-10-the-info-command-on-a-replica)\n      - [Your Task](#your-task-9)\n      - [The `--replicaof` flag](#the---replicaof-flag)\n      - [Tests](#tests-9)\n      - [Notes](#notes-9)\n    - [Stage 11: Initial Replication ID and Offset](#stage-11-initial-replication-id-and-offset)\n      - [Your Task](#your-task-10)\n      - [The replication ID and offset](#the-replication-id-and-offset)\n      - [Tests](#tests-10)\n      - [Notes](#notes-10)\n    - [Stage 12: Send handshake (1/3)](#stage-12-send-handshake-13)\n      - [Your Task](#your-task-11)\n      - [Handshake](#handshake)\n      - [Tests](#tests-11)\n      - [Notes](#notes-11)\n    - [Stage 13: Send handshake (2/3)](#stage-13-send-handshake-23)\n      - [Your Task](#your-task-12)\n      - [Handshake (continued from previous stage)](#handshake-continued-from-previous-stage)\n      - [Tests](#tests-12)\n    - [Stage 14: Send handshake (3/3)](#stage-14-send-handshake-33)\n      - [Your Task](#your-task-13)\n      - [Handshake (continued from previous stage)](#handshake-continued-from-previous-stage-1)\n      - [Tests](#tests-13)\n    - [Stage 15: Receive handshake (1/2)](#stage-15-receive-handshake-12)\n      - [Your Task](#your-task-14)\n      - [Handshake (continued from previous stage)](#handshake-continued-from-previous-stage-2)\n      - [Tests](#tests-14)\n    - [Stage 16: Receive handshake (2/2)](#stage-16-receive-handshake-22)\n      - [Your Task](#your-task-15)\n      - [Handshake (continued from previous stage)](#handshake-continued-from-previous-stage-3)\n      - [Tests](#tests-15)\n    - [Stage 17: Empty RDB Transfer](#stage-17-empty-rdb-transfer)\n      - [Your Task](#your-task-16)\n      - [Full resynchronization](#full-resynchronization)\n      - [Tests](#tests-16)\n      - [Notes](#notes-12)\n    - [Stage 18: Single-replica propagation](#stage-18-single-replica-propagation)\n      - [Your Task](#your-task-17)\n      - [Command propagation](#command-propagation)\n      - [Replication connection](#replication-connection)\n      - [Tests](#tests-17)\n      - [Notes](#notes-13)\n    - [Stage 19: Multi Replica Command Propagation](#stage-19-multi-replica-command-propagation)\n      - [Your Task](#your-task-18)\n      - [Tests](#tests-18)\n    - [Stage 20: Command Processing](#stage-20-command-processing)\n      - [Your Task](#your-task-19)\n      - [Command processing](#command-processing)\n      - [Tests](#tests-19)\n\n# Introduction\n\nWelcome to the Build your own Redis challenge!\n\nRedis is an in-memory data structure store often used as a database, cache, message broker and streaming engine. In this challenge you'll build your own Redis server that is capable of serving basic commands, reading RDB files and more.\n\nAlong the way, you'll learn about TCP servers, the Redis Protocol and more.\n\n# Repository Setup\n\nWe've prepared a starter repository with some Rust code for you.\n\nStep 1: Clone the repository.\n\n```sh\ngit clone https://git.codecrafters.io/a6d6aeeafdfc7c25 codecrafters-redis-rust \u0026\u0026 cd codecrafters-redis-rust\n```\n\nStep 2: Push an empty commit.\n\n```sh\ngit commit --allow-empty -m 'test' \u0026\u0026 git push origin master\n```\n\nWhen you run the above command, the \"Listening for a git push\" message below will change, and the first stage will be activated.\n\n# Passing the first stage\n\nThe entry point for your Redis implementation is in `src/main.rs`. Study and\nuncomment the relevant code, and push your changes to pass the first stage:\n\n```sh\ngit add .\ngit commit -m \"pass 1st stage\" # any msg\ngit push origin master\n```\n\nThat's all!\n\n# Stage 2 \u0026 beyond\n\nNote: This section is for stages 2 and beyond.\n\n1. Ensure you have `cargo (1.54)` installed locally\n1. Run `./spawn_redis_server.sh` to run your Redis server, which is implemented\n   in `src/main.rs`. This command compiles your Rust project, so it might be\n   slow the first time you run it. Subsequent runs will be fast.\n1. Commit your changes and run `git push origin master` to submit your solution\n   to CodeCrafters. Test output will be streamed to your terminal.\n\n# Functionalities implemented for each stage\n\n## Basic functionality\n\nHere are the functionalities that you'll need to implement for each stage:\n\n### Stage 1: Bind to a port\n\n#### Your Task\n\nIn this stage, you'll implement a TCP server that listens on port 6379.\n\n[TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) is the underlying protocol used by protocols like HTTP, SSH and others you're probably familiar with. Redis clients \u0026 servers use TCP to communicate with each other.\n\nDon't worry if you're unfamiliar with the TCP protocol, or what Redis clients \u0026 servers are. You'll learn more about this in the next stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```sh\n$ ./spawn_redis_server.sh\n```\n\nIt'll then try to connect to your TCP server on port 6379. If the connection succeeds, you'll pass this stage.\n\n#### Notes\n\n- 6379 is the default port that Redis uses.\n- If you already have a Redis server running on your machine and listening on port 6379, you'll see a \"port already in use\" error when running your code. Try stopping the existing Redis server and running your code again.\n\n### Stage 2: Respond to PING\n\n#### Prerequisites\n\nBefore attempting this stage, we recommend familiarizing yourself with:\n\n- The TCP protocol\n- Rust's `std::net` module\n- How to write TCP servers in Rust\n\nOur interactive concepts can help with this:\n\n- [TCP: An Overview](https://app.codecrafters.io/concepts/tcp-overview) — Learn about the TCP protocol and how it works\n- [TCP Servers in Rust](https://app.codecrafters.io/concepts/rust-tcp-server) — Learn how to write TCP servers using Rust's std::net module\n\n#### Your Task\n\nIn this stage, you'll implement support for the [PING](https://redis.io/commands/ping) command.\n\nRedis clients communicate with Redis servers by sending \"[commands](https://redis.io/commands/)\". For each command, a Redis server sends a response back to the client. Commands and responses are both encoded using the [Redis protocol](https://redis.io/topics/protocol) (we'll learn more about this in later stages).\n\n[PING](https://redis.io/commands/ping/) is one of the simplest Redis commands. It's used to check whether a Redis server is healthy.\n\nThe response for the `PING` command is `+PONG\\r\\n`. This is the string \"PONG\" encoded using the [Redis protocol](https://redis.io/docs/reference/protocol-spec/).\n\nIn this stage, we'll cut corners by ignoring client input and hardcoding `+PONG\\r\\n` as a response. We'll learn to parse client input in later stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```sh\n$ ./spawn_redis_server.sh\n```\n\nIt'll then send a `PING` command to your server and expect a `+PONG\\r\\n` response.\n\n```sh\n$ redis-cli ping\n```\n\nYour server should respond with `+PONG\\r\\n`, which is \"PONG\" encoded as a [RESP simple string](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings).\n\n#### Notes\n\n- You can ignore the data that the tester sends you for this stage. We'll get to parsing client input in later stages. For now, you can just hardcode `+PONG\\r\\n` as the response.\n- You can also ignore handling multiple clients and handling multiple PING commands in the stage, we'll get to that in later stages.\n- The exact bytes your program will receive won't be just `ping`, you'll receive something like this: `\\*1\\r\\n$4\\r\\nping\\r\\n`, which is the Redis protocol encoding of the `PING` command. We'll learn more about this in later stages.\n\n### Stage 3: Respond to multiple PINGs\n\n#### Your Task\n\nIn this stage, you'll respond to multiple [PING](https://redis.io/commands/ping) commands sent by the same connection.\n\nA Redis server starts to listen for the next command as soon as it's done responding to the previous one. This allows Redis clients to send multiple commands using the same connection.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n$ ./spawn_redis_server.sh\n```\n\nIt'll then send two PING commands using the same connection:\n\n```bash\n$ echo -e \"ping\\nping\" | redis-cli\n```\n\nThe tester will expect to receive two `+PONG\\r\\n` responses.\n\nYou'll need to run a loop that reads input from a connection and sends a response back.\n\n#### Notes\n\n- Just like the previous stage, you can hardcode `+PONG\\r\\n` as the response for this stage. We'll get to parsing client input in later stages.\n- The two PING commands will be sent using the same connection. We'll get to handling multiple connections in later stages.\n\n### Stage 4: Handle concurrent clients\n\n#### Your Task\n\nIn this stage, you'll add support for multiple concurrent clients.\n\nIn addition to handling multiple commands from the same client, Redis servers are also designed to handle multiple clients at once.\n\nTo implement this, you'll need to either use threads, or, if you're feeling adventurous, an [Event Loop](https://en.wikipedia.org/wiki/Event_loop) (like the official Redis implementation does).\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n$ ./spawn_redis_server.sh\n```\n\nIt'll then send two PING commands concurrently using two different connections:\n\n```bash\n## These two will be sent concurrently so that we test your server's ability to handle concurrent clients.\n$ redis-cli ping\n$ redis-cli ping\n```\n\nThe tester will expect to receive two `+PONG\\r\\n` responses.\n\n#### Notes\n\n- Since the tester client _only_ sends the PING command at the moment, it's okay to ignore what the client sends and hardcode a response. We'll get to parsing client input in later stages.\n\n### Stage 5: Implement the ECHO command\n\n#### Your Task\n\nIn this stage, you'll add support for the [ECHO](https://redis.io/commands/echo) command.\n\n`ECHO` is a command like `PING` that's used for testing and debugging. It accepts a single argument and returns it back as a RESP bulk string.\n\n```bash\n$ redis-cli ping ## The command you implemented in previous stages\nPONG\n$ redis-cli echo hey ## The command you'll implement in this stage\nhey\n```\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n$ ./spawn_redis_server.sh\n```\n\nIt'll then send an `ECHO` command with an argument to your server:\n\n```bash\n$ redis-cli echo hey\n```\n\nThe tester will expect to receive `$3\\r\\nhey\\r\\n` as a response (that's the string `hey` encoded as a [RESP bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings).\n\n#### Notes\n\n- We suggest that you implement a proper Redis protocol parser in this stage. It'll come in handy in later stages.\n- Redis command names are case-insensitive, so `ECHO`, `echo` and `EcHo` are all valid commands.\n- The tester will send a random string as an argument to the `ECHO` command, so you won't be able to hardcode the response to pass this stage.\n- The exact bytes your program will receive won't be just `echo hey`, you'll receive something like this: `*2\\r\\n$4\\r\\necho\\r\\n$3\\r\\nhey\\r\\n`. That's `[\"echo\", \"hey\"]` encoded using the [Redis protocol](https://redis.io/docs/reference/protocol-spec/).\n- You can read more about how \"commands\" are handled in the Redis protocol [here](https://redis.io/docs/reference/protocol-spec/#sending-commands-to-a-redis-server).\n\n### Stage 6: Implement the SET \u0026 GET commands\n\n#### Your Task\n\nIn this stage, you'll add support for the [SET](https://redis.io/commands/set) \u0026 [GET](https://redis.io/commands/get) commands.\n\nThe `SET` command is used to set a key to a value. The `GET` command is used to retrieve the value of a key.\n\n```bash\n$ redis-cli set foo bar\nOK\n$ redis-cli get foo\nbar\n```\n\nThe `SET` command supports a number of extra options like `EX` (expiry time in seconds), `PX` (expiry time in milliseconds) and more. We won't cover these extra options in this stage. We'll get to them in later stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh\n```\n\nIt'll then send a `SET` command to your server:\n\n```bash\n$ redis-cli set foo bar\n```\n\nThe tester will expect to receive `+OK\\r\\n` as a response (that's the string `OK` encoded as a [RESP simple string](https://redis.io/docs/reference/protocol-spec/#resp-simple-strings)).\n\nThis command will be followed by a `GET` command:\n\n```bash\n$ redis-cli get foo\n```\n\nThe tester will expect to receive `$3\\r\\nbar\\r\\n` as a response (that's the string `bar` encoded as a [RESP bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings).\n\n#### Notes\n\n- If you implemented a proper Redis protocol parser in the previous stage, you should be able to reuse it in this stage.\n- Just like the previous stage, the values used for keys and values will be random, so you won't be able to hardcode the response to pass this stage.\n- If a key doesn't exist, the `GET` command should return a \"null bulk string\" (`$-1\\r\\n`). We won't explicitly test this in this stage, but you'll need it for the next stage (expiry).\n\n### Stage 7: Expiry\n\n#### Your Task\n\nIn this stage, you'll add support for setting a key with an expiry.\n\nThe expiry for a key can be provided using the \"PX\" argument to the [SET](https://redis.io/commands/set) command. The expiry is provided in milliseconds.\n\n```bash\n$ redis-cli set foo bar px 100 ## Sets the key \"foo\" to \"bar\" with an expiry of 100 milliseconds\nOK\n```\n\nAfter the key has expired, a `GET` command for that key should return a \"null bulk string\" (`$-1\\r\\n`).\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n$ ./spawn_redis_server.sh\n```\n\nIt'll then send a `SET` command to your server to set a key with an expiry:\n\n```bash\n$ redis-cli set foo bar px 100\n```\n\nIt'll then immediately send a `GET` command to retrieve the value:\n\n```bash\n$ redis-cli get foo\n```\n\nIt'll expect the response to be `bar` (encoded as a RESP bulk string).\n\nIt'll then wait for the key to expire and send another `GET` command:\n\n```bash\n$ sleep 0.2 \u0026\u0026 redis-cli get foo\n```\n\nIt'll expect the response to be `$-1\\r\\n` (a \"null bulk string\").\n\n#### Notes\n\n- Just like command names, command arguments are also case-insensitive. So `PX`, `px` and `pX` are all valid.\n- The keys, values and expiry times used in the tests will be random, so you won't be able to hardcode a response to pass this stage.\n\n## Replication\n\n### Stage 8: Configure listening port\n\n#### Your Task\n\nWelcome to the Replication extension!\n\nIn this extension, you'll extend your Redis server to support [leader-follower replication](https://redis.io/docs/management/replication/). You'll be able to run multiple Redis servers with one acting as the \"master\" and the others as \"replicas\". Changes made to the master will be automatically replicated to replicas.\n\nSince we'll need to run multiple instances of your Redis server at once, we can't run all of them on port 6379.\n\nIn this stage, you'll add support for starting the Redis server on a custom port. The port number will be passed to your program via the `--port` flag.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port 6380\n```\n\nIt'll then try to connect to your TCP server on the specified port number (`6380` in the example above). If the connection succeeds, you'll pass this stage.\n\n#### Notes\n\n- Your program still needs to pass the previous stages, so if `--port` isn't specified, you should default to port 6379.\n- The tester will pass a random port number to your program, so you can't hardcode the port number from the example above.\n- If your repository was created before 5th Oct 2023, it's possible that your `./spawn_redis_server.sh` script might not be passing arguments on to your program. You'll need to edit `./spawn_redis_server.sh` to fix this, check [this PR](https://github.com/codecrafters-io/build-your-own-redis/pull/89/files) for details.\n\n### Stage 9: The INFO command\n\n#### Your Task\n\nIn this stage, you'll add support for the [INFO](https://redis.io/commands/info/) command.\n\nThe `INFO` command returns information and statistics about a Redis server. In this stage, we'll add support for the `replication` section of the `INFO` command.\n\n#### The replication section\n\nWhen you run the `INFO` command against a Redis server, you'll see something like this:\n\n```bash\n$ redis-cli info replication\n# Replication\nrole:master\nconnected_slaves:0\nmaster_replid:8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb\nmaster_repl_offset:0\nsecond_repl_offset:-1\nrepl_backlog_active:0\nrepl_backlog_size:1048576\nrepl_backlog_first_byte_offset:0\nrepl_backlog_histlen:\n```\n\nThe reply to this command is a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings) where each line is a key value pair, separated by \":\".\n\nHere are what some of the important fields mean:\n\n- `role`: The role of the server (`master` or `slave`)\n- `connected_slaves`: The number of connected replicas\n- `master_replid`: The replication ID of the master (we'll get to this in later stages)\n- `master_repl_offset`: The replication offset of the master (we'll get to this in later stages)\n\nIn this stage, you'll only need to support the `role` key. We'll add support for other keys in later stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then send the `INFO` command with `replication` as an argument.\n\n```bash\n$ redis-cli -p \u003cPORT\u003e info replication\n```\n\nYour program should respond with a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings) where each line is a key value pair separated by `:`. The tester will only look for the `role` key, and assert that the value is `master`.\n\n#### Notes\n\n- In the response for the `INFO` command, you only need to support the `role` key for this stage. We'll add support for the other keys in later stages.\n- The `# Replication` heading in the response is optional, you can ignore it.\n- The response to `INFO` needs to be encoded as a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings).\n  - An example valid response would be `$11\\r\\nrole:master\\r\\n` (the string `role:master` encoded as a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings))\n- The `INFO` command can be used without any arguments, in which case it returns all sections available. In this stage, we'll always send `replication` as an argument to the `INFO` command, so you only need to support the `replication` section.\n\n### Stage 10: The INFO command on a replica\n\n#### Your Task\n\nIn this stage, you'll extend your [INFO](https://redis.io/commands/info/) command to run on a replica.\n\n#### The `--replicaof` flag\n\nBy default, a Redis server assumes the \"master\" role. When the `--replicaof` flag is passed, the server assumes the \"slave\" role instead.\n\nHere's an example usage of the `--replicaof` flag:\n\n```bash\n./spawn_redis_server.sh --port 6380 --replicaof localhost 6379\n```\n\nIn this example, we're starting a Redis server in replica mode. The server itself will listen for connections on port 6380, but it'll also connect to a master (another Redis server) running on localhost port 6379 and replicate all changes from the master.\n\nWe'll learn more about how this replication works in later stages. For now, we'll focus on adding support for the `--replicaof` flag, and extending the `INFO` command to support returning `role: slave` when the server is a replica.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e --replicaof \u003cMASTER_HOST\u003e \u003cMASTER_PORT\u003e\n```\n\nIt'll then send the `INFO` command with `replication` as an argument to your server.\n\n```bash\n$ redis-cli -p \u003cPORT\u003e info replication\n```\n\nYour program should respond with a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings) where each line is a key value pair separated by `:`. The tester will only look for the `role` key, and assert that the value is `slave`.\n\n#### Notes\n\n- Your program still needs to pass the previous stage tests, so if `--replicaof` isn't specified, you should default to the `master` role.\n- Just like the last stage, you only need to support the `role` key in the response for this stage. We'll add support for the other keys in later stages.\n- You don't need to actually connect to the master server specified via `--replicaof` in this stage. We'll get to that in later stages.\n\n### Stage 11: Initial Replication ID and Offset\n\n#### Your Task\n\nIn this stage, you'll extend your `INFO` command to return two additional values: `master_replid` and `master_repl_offset`.\n\n#### The replication ID and offset\n\nEvery Redis master has a replication ID: it is a large pseudo random string. This is set when the master is booted. Every time a master instance restarts from scratch, its replication ID is reset.\n\nEach master also maintains a \"replication offset\" corresponding to how many bytes of commands have been added to the replication stream. We'll learn more about this offset in later stages. For now, just know that the value starts from `0` when a master is booted and no replicas have connected yet.\n\nIn this stage, you'll initialize a replication ID and offset for your master:\n\n- The ID can be any pseudo random alphanumeric string of 40 characters.\n  - For the purposes of this challenge, you don't need to actually generate a random string, you can hardcode it instead.\n  - As an example, you can hardcode `8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb` as the replication ID.\n- The offset is to be 0.\n\nThese two values should be returned as part of the INFO command output, under the `master_replid` and `master_repl_offset` keys respectively.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh\n```\n\nIt'll then send the `INFO` command with `replication` as an argument to your server.\n\n```bash\n$ redis-cli info replication\n```\n\nYour program should respond with a [Bulk string](https://redis.io/docs/reference/protocol-spec/#bulk-strings) where each line is a key value pair separated by `:`. The tester will look for the following keys:\n\n- `master_replid`, which should be a 40 character alphanumeric string\n- `master_repl_offset`, which should be `0`\n\n#### Notes\n\n- Your code should still pass the previous stage tests, so the `role` key still needs to be returned\n\n### Stage 12: Send handshake (1/3)\n\n#### Your Task\n\nIn this stage, you'll implement part 1 of the handshake that happens when a replica connects to master.\n\n#### Handshake\n\nWhen a replica connects to a master, it needs to go through a handshake process before receiving updates from the master.\n\nThere are three parts to this handshake:\n\n- The replica sends a `PING` to the master (**This stage**)\n- The replica sends `REPLCONF` twice to the master (Next stages)\n- The replica sends `PSYNC` to the master (Next stages)\n\nWe'll learn more about `REPLCONF` and `PSYNC` in later stages. For now, we'll focus on the first part of the handshake: sending `PING` to the master.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e --replicaof \u003cMASTER_HOST\u003e \u003cMASTER_PORT\u003e\n```\n\nIt'll then assert that the replica connects to the master and sends the `PING` command.\n\n#### Notes\n\n- The `PING` command should be sent as a RESP Array, like this : `*1\\r\\n$4\\r\\nping\\r\\n`\n\n### Stage 13: Send handshake (2/3)\n\n#### Your Task\n\nIn this stage, you'll implement part 2 of the handshake that happens when a replica connects to master.\n\n#### Handshake (continued from previous stage)\n\nAs a recap, there are three parts to the handshake:\n\n- The replica sends a `PING` to the master (Previous stage)\n- The replica sends `REPLCONF` twice to the master (**This stage**)\n- The replica sends `PSYNC` to the master (Next stage)\n\nAfter receiving a response to `PING`, the replica then sends 2 [REPLCONF](https://redis.io/commands/replconf/) commands to the master.\n\nThe `REPLCONF` command is used to configure replication. Replicas will send this command to the master twice:\n\n- The first time, it'll be sent like this: `REPLCONF listening-port \u003cPORT\u003e`\n  - This is the replica notifying the master of the port it's listening on\n- The second time, it'll be sent like this: `REPLCONF capa psync2`\n  - This is the replica notifying the master of its capabilities (\"capa\" is short for \"capabilities\")\n  - You can safely hardcode these capabilities for now, we won't need to use them in this challenge.\n\nThese commands should be sent as RESP Arrays, so the exact bytes will look something like this:\n\n```bash\n# REPLCONF listening-port \u003cPORT\u003e\n*3\\r\\n$8\\r\\nREPLCONF\\r\\n$14\\r\\nlistening-port\\r\\n$4\\r\\n6380\\r\\n\n\n# REPLCONF capa psync2\n*3\\r\\n$8\\r\\nREPLCONF\\r\\n$4\\r\\ncapa\\r\\n$6\\r\\npsync2\\r\\n\n```\n\nFor both commands, the master will respond with `+OK\\r\\n` (\"OK\" encoded as a RESP Simple String).\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e --replicaof \u003cMASTER_HOST\u003e \u003cMASTER_PORT\u003e\n```\n\nIt'll then assert that the replica connects to the master and:\n\n- **(a)** sends the `PING` command\n- **(b)** sends the `REPLCONF` command with `listening-port` and `\u003cPORT\u003e` as arguments\n- **(c)** sends the `REPLCONF` command with `capa psync2` as arguments\n\n**Notes**\n\n- The response to `REPLCONF` will always be `+OK\\r\\n` (\"OK\" encoded as a RESP Simple String)\n\n### Stage 14: Send handshake (3/3)\n\n#### Your Task\n\nIn this stage, you'll implement part 3 of the handshake that happens when a replica connects to master.\n\n#### Handshake (continued from previous stage)\n\nAs a recap, there are three parts to the handshake:\n\n- The replica sends a `PING` to the master (Previous stages)\n- The replica sends `REPLCONF` twice to the master (Previous stages)\n- The replica sends `PSYNC` to the master (**This stage**)\n\nAfter receiving a response to the second `REPLCONF`, the replica then sends a [PSYNC](https://redis.io/commands/psync/) command to the master.\n\nThe `PSYNC` command is used to synchronize the state of the replica with the master. The replica will send this command to the master with two arguments:\n\n- The first argument is the replication ID of the master\n  - Since this is the first time the replica is connecting to the master, the replication ID will be `?` (a question mark)\n- The second argument is the offset of the master\n  - Since this is the first time the replica is connecting to the master, the offset will be `-1`\n\nSo the final command sent will be `PSYNC ? -1`.\n\nThis should be sent as a RESP Array, so the exact bytes will look something like this:\n\n```bash\n*3\\r\\n$5\\r\\nPSYNC\\r\\n$1\\r\\n?\\r\\n$2\\r\\n-1\\r\\n\n```\n\nThe master will respond with a [Simple string](https://redis.io/docs/reference/protocol-spec/#simple-strings) that looks like this:\n\n```bash\n+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n\n```\n\nYou can ignore the response for now, we'll get to handling it in later stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e --replicaof \u003cMASTER_HOST\u003e \u003cMASTER_PORT\u003e\n```\n\nIt'll then assert that the replica connects to the master and:\n\n- **(a)** sends `PING` command\n- **(b)** sends `REPLCONF listening-port \u003cPORT\u003e`\n- **(c)** sends `REPLCONF capa eof capa psync2`\n- **(d)** sends `PSYNC ? -1`\n\n### Stage 15: Receive handshake (1/2)\n\n#### Your Task\n\nIn this stage, we'll start implementing support for receiving a replication handshake as a master.\n\n#### Handshake (continued from previous stage)\n\nWe'll now implement the same handshake we did in the previous stages, but on the master instead of the replica.\n\nAs a recap, there are three parts to the handshake:\n\n- The master receives a `PING` from the replica\n  - Your Redis server already supports the `PING` command, so there's no additional work to do here\n- The master receives `REPLCONF` twice from the replica (**This stage**)\n- The master receives `PSYNC` from the replica (Next stage)\n\nIn this stage, you'll add support for receiving the `REPLCONF` command from the replica.\n\nYou'll receive `REPLCONF` twice from the replica. For the purposes of this challenge, you can safely ignore the arguments for both commands and just respond with `+OK\\r\\n` (\"OK\" encoded as a RESP Simple String).\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then send the following commands:\n\n1.  `PING` (expecting `+PONG\\r\\n` back)\n2.  `REPLCONF listening-port \u003cPORT\u003e` (expecting `+OK\\r\\n` back)\n3.  `REPLCONF capa eof capa psync2` (expecting `+OK\\r\\n` back)\n\n### Stage 16: Receive handshake (2/2)\n\n#### Your Task\n\nIn this stage, you'll add support for receiving the [`PSYNC`](https://redis.io/commands/psync/) command from the replica.\n\n#### Handshake (continued from previous stage)\n\nAs a recap, there are three parts to the handshake:\n\n- The master receives a `PING` from the replica (You've already implemented this)\n- The master receives `REPLCONF` twice from the replica (You've already implemented this)\n- The master receives `PSYNC` from the replica (**This stage**)\n\nAfter the replica sends `REPLCONF` twice, it'll send a `PSYNC ? -1` command to the master.\n\n- The first argument is `?`\n  - This is replication ID of the master, it is `?` because this is the first time the replica is connecting to the master.\n- The second argument is `-1`\n  - This is the replication offset, it is `-1` because this is the first time the replica is connecting to the master.\n\nThe final command you receive will look something like this:\n\n```bash\n*3\\r\\n$5\\r\\nPSYNC\\r\\n$1\\r\\n?\\r\\n$2\\r\\n-1\\r\\n\n```\n\n(That's `[\"PSYNC\", \"?\", \"-1\"]` encoded as a RESP Array)\n\nThe master needs to respond with `+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n` (\"FULLRESYNC 0\" encoded as a RESP Simple String). Here's what the response means:\n\n- `FULLRESYNC` means that the master cannot perform incremental replication with the replica, and will thus start a \"full\" resynchronization.\n- `\u003cREPL_ID\u003e` is the replication ID of the master. You've already set this in the \"Replication ID \u0026 Offset\" stage.\n  - As an example, you can hardcode `8371b4fb1155b71f4a04d3e1bc3e18c4a990aeeb` as the replication ID.\n- `0` is the replication offset of the master. You've already set this in the \"Replication ID \u0026 Offset\" stage.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then connect to your TCP server as a replica and execute the following commands:\n\n1.  `PING` (expecting `+PONG\\r\\n` back)\n2.  `REPLCONF listening-port \u003cPORT\u003e` (expecting `+OK\\r\\n` back)\n3.  `REPLCONF capa eof capa psync2` (expecting `+OK\\r\\n` back)\n4.  `PSYNC ? -1` (expecting `+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n` back)\n\n**Notes**:\n\n- In the response, `\u003cREPL_ID\u003e` needs to be replaced with the replication ID of the master which you've initialized in previous stages.\n\n### Stage 17: Empty RDB Transfer\n\n#### Your Task\n\nIn this stage, you'll add support for sending an empty RDB file to the replica. This is part of the \"full resynchronization\" process.\n\n#### Full resynchronization\n\nWhen a replica connects to a master for the first time, it sends a `PSYNC ? -1` command. This is the replica's way of telling the master that it doesn't have any data yet, and needs to be fully resynchronized.\n\nThe master acknowledges this by sending a `FULLRESYNC` response to the replica.\n\nAfter sending the `FULLRESYNC` response, the master will then send a RDB file of its current state to the replica. The replica is expected to load the file into memory, replacing its current state.\n\nFor the purposes of this challenge, you don't have to actually construct an RDB file. We'll assume that the master's database is always empty, and just hardcode an empty RDB file to send to the replica.\n\nYou can find the hex representation of an empty RDB file [here](https://github.com/codecrafters-io/redis-tester/blob/main/internal/assets/empty_rdb_hex.md).\n\nThe tester will accept any valid RDB file that is empty, you don't need to send the exact file above.\n\nThe file is sent using the following format:\n\n```bash\n$\u003clength_of_file\u003e\\r\\n\u003ccontents_of_file\u003e\n```\n\n(This is similar to how [Bulk Strings](https://redis.io/topics/protocol#resp-bulk-strings) are encoded, but without the trailing `\\r\\n`)\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then connect to your TCP server as a replica and execute the following commands:\n\n1.  `PING` (expecting `+PONG\\r\\n` back)\n2.  `REPLCONF listening-port \u003cPORT\u003e` (expecting `+OK\\r\\n` back)\n3.  `REPLCONF capa eof capa psync2` (expecting `+OK\\r\\n` back)\n4.  `PSYNC ? -1` (expecting `+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n` back)\n\nAfter receiving a response to the last command, the tester will expect to receive an empty RDB file from your server.\n\n#### Notes\n\n- The [RDB file link](https://github.com/codecrafters-io/redis-tester/blob/main/internal/assets/empty_rdb_hex.md) contains hex \u0026 base64 representations of the file. You need to decode these into binary contents before sending it to the replica.\n- The RDB file should be sent like this: `$\u003clength\u003e\\r\\n\u003ccontents\u003e`\n  - `\u003clength\u003e` is the length of the file in bytes\n  - `\u003ccontents\u003e` is the contents of the file\n  - Note that this is NOT a RESP bulk string, it doesn't contain a `\\r\\n` at the end\n- If you want to learn more about the RDB file format, read [this blog post](https://rdb.fnordig.de/file_format.html). This challenge has a separate extension dedicated to reading RDB files.\n\n### Stage 18: Single-replica propagation\n\n#### Your Task\n\nIn this stage, you'll add support for propagating write commands from a master to a single replica.\n\n#### Command propagation\n\nAfter the replication handshake is complete and the master has sent the RDB file to the replica, the master starts propagating commands to the replica.\n\nWhen a master receives a \"write\" command from a client, it propagates the command to the replica. The replica processes the command and updates its state. More on how this propagation works in the \"Replication connection\" section below.\n\nCommands like `PING`, `ECHO` etc. are not considered \"write\" commands, so they aren't propagated. Commands like `SET`, `DEL` etc. are considered \"write\" commands, so they are propagated.\n\n#### Replication connection\n\nCommand propagation happens over the replication connection. This is the same connection that was used for the handshake.\n\nPropagated commands are sent as RESP arrays. For example, if the master receives `SET foo bar` as a command from a client, it'll send `*3\\r\\n$3\\r\\nSET\\r\\n$3\\r\\nfoo\\r\\n$3\\r\\nbar\\r\\n` to all connected replicas over their respective replication connections.\n\nReplicas process commands received over the replication connection just like they would process commands received from a client, but with one difference: Replicas don't send responses back to the master. They just process the command silently and update their state.\n\nSimilarly, the master doesn't wait for a response from the replica when propagating commands. It just keeps sending commands as they come in.\n\nThere is one exception to this \"no response\" rule, the `REPLCONF GETACK` command. We'll learn about this in later stages.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then connect to your TCP server as a replica and execute the following commands:\n\n1.  `PING` (expecting `+PONG\\r\\n` back)\n2.  `REPLCONF listening-port \u003cPORT\u003e` (expecting `+OK\\r\\n` back)\n3.  `REPLCONF capa eof capa psync2` (expecting `+OK\\r\\n` back)\n4.  `PSYNC ? -1` (expecting `+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n` back)\n\nThe tester will then wait for your server to send an RDB file.\n\nOnce the RDB file is received, the tester will send series of write commands to your program (as a separate Redis client, not the replica).\n\n```bash\n$ redis-cli SET foo 1\n$ redis-cli SET bar 2\n$ redis-cli SET baz 3\n```\n\nIt'll then assert that these commands were propagated to the replica, in order. The tester will expect to receive these commands (encoded as RESP arrays) on the replication connection (the one used for the handshake).\n\n#### Notes\n\n- A true implementation would buffer the commands so that they can be sent to the replica after it loads the RDB file. For the purposes of this challenge, you can assume that the replica is ready to receive commands immediately after receiving the RDB file.\n\n### Stage 19: Multi Replica Command Propagation\n\n#### Your Task\n\nIn this stage, you'll extend your implementation to support propagating commands to multiple replicas.\n\n#### Tests\n\nThe tester will execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e\n```\n\nIt'll then start **multiple** replicas that connect to your server and execute the following commands:\n\n1.  `PING` (expecting `+PONG\\r\\n` back)\n2.  `REPLCONF listening-port \u003cPORT\u003e` (expecting `+OK\\r\\n` back)\n3.  `REPLCONF capa psync2` (expecting `+OK\\r\\n` back)\n4.  `PSYNC ? -1` (expecting `+FULLRESYNC \u003cREPL_ID\u003e 0\\r\\n` back)\n\nEach replica will expect to receive an RDB file from the master after the handshake is complete.\n\nIt'll then send `SET` commands to the master from a client (a separate Redis client, not the replicas).\n\n```bash\n$ redis-cli SET foo 1\n$ redis-cli SET bar 2\n$ redis-cli SET baz 3\n```\n\nIt'll then assert that each replica received those commands, in order.\n\n### Stage 20: Command Processing\n\n#### Your Task\n\nIn this stage you'll implement the processing of commands propagated to the replica from the master.\n\n#### Command processing\n\nAfter the replica receives a command from the master, it processes it and apply it to its own state. This will work exactly like a regular command sent by a client, except that the replica doesn't send a response back to the master.\n\nFor example, if the command `set foo 1` is propagated to the replica by a master, the replica must update its database to set the value of `foo` to `1`. Unlike commands from a regular client though, it must not reply with `+OK\\r\\n`.\n\n#### Tests\n\nTHe tester will spawn a Redis master, and it'll then execute your program like this:\n\n```bash\n./spawn_redis_server.sh --port \u003cPORT\u003e --replicaof \u003cMASTER_HOST\u003e \u003cMASTER_PORT\u003e\n```\n\nJust like in the previous stages, your replica should complete the handshake with the master and receive an empty RDB file.\n\nOnce the RDB file is received, the master will propagate a series of write commands to your program.\n\n```bash\nset foo 1 # propagated from master to replica\nset bar 2 # propagated from master to replica\nset baz 3 # propagated from master to replica\n\n```\n\nThe tester will then issue `get` commands to your program to check if the commands were processed correctly.\n\n```bash\n$ redis-cli GET foo # expecting `1` back\n$ redis-cli GET bar # expecting `2` back\n# ... and so on\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyisuschrist%2Fcodecrafters-redis-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyisuschrist%2Fcodecrafters-redis-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyisuschrist%2Fcodecrafters-redis-rust/lists"}