How to Pass the Razorpay SDE-2 Machine Coding Round

Razorpay's 90-minute machine coding round is widely known as the most brutal filter in their SDE-2 hiring pipeline. Interviewers hand you a complex, ambiguous problem statement—think building an in-memory SQL-like database, a Splitwise clone, or a task scheduler. Then, you're expected to crank out fully functional, extensible, and thread-safe code before the clock hits zero. Algorithmic rounds might let you slide with pseudo-code, but machine coding demands a compilable, executable solution that gracefully handles edge cases. Let's break down the notoriously difficult in-memory database problem. We'll look at the exact architecture, concurrency models, and design patterns you'll need to show true senior-level engineering maturity.
The Razorpay SDE-2 Hiring Process
Before we write any code, you need to understand where this machine coding round fits into the broader Razorpay interview loop. The company indexes heavily on practical engineering skills. Pass the initial resume screen or recruiter call, and you'll face a rigorous sequence of technical evaluations.
| Interview Round | Duration | Core Focus | Key Expectations |
|---|---|---|---|
| 1. Machine Coding | 90-120 mins | Low-Level Design (LLD) & Execution | Working code, SOLID principles, concurrency, testability. |
| 2. System Design | 60 mins | High-Level Design (HLD) | Scalability, database choices, caching, API design, trade-offs. |
| 3. Technical Depth | 60 mins | Domain Knowledge & Past Projects | Deep dive into past architecture, debugging, framework internals. |
| 4. Hiring Manager | 45-60 mins | Behavioral & Culture Fit | Ownership, conflict resolution, alignment with Razorpay values. |
The Machine Coding Bar: Why Running Code is Just the Entry Ticket
If you're interviewing for an SDE-1 role, just getting the code to run and spit out the correct output might secure a pass. But for an SDE-2 candidate? Functional code is just the baseline. Razorpay interviewers evaluate your solution as if they were reviewing a PR for a production system. They want to see clear separation of concerns, meaning your data models sit completely decoupled from your business logic. Extensibility is also huge. If they ask you to add a new data type or a fresh constraint in the final 15 minutes, will you have to modify ten different files, or can you just snap in a single new class?
Thread safety is another massive factor, especially for a database problem. An in-memory database that corrupts data when two threads try inserting records simultaneously is fundamentally broken. You have to prove you understand locks, synchronization, and concurrent data structures. At the same time, you can't over-engineer the whole thing into a deadlock-prone mess.
The Problem Statement: Deconstructing the In-Memory SQL-Like Database
The prompt usually asks you to design and implement an in-memory database that lets users create tables, insert rows, and query data with specific filters. You'll need to support multiple data types (like String or Integer) and enforce column-level constraints. Think maximum length, value ranges, or mandatory fields.
Knocking this out in under 90 minutes means you have to identify the core entities right out of the gate. First, you need a Database class acting as a singleton or context manager to hold multiple Tables. Next, each Table requires a schema definition made up of Columns. Finally, you need a mechanism to store the actual Records (the rows) and enforce the rules defined by those Columns before any Record actually gets committed.
Designing the Domain Model: Tables, Schema-Defined Columns, and Records

Let's break down the best data structures for this specific domain. Your Database class should maintain a concurrent hash map that maps table names to Table objects. Relying on a ConcurrentHashMap here guarantees that if two different threads try creating tables at the exact same time, your database's internal state won't get corrupted.
Inside the Table class itself, you need to store both the schema and the data. The schema can just be a List of Column objects. Every Column object will encapsulate its name, its data type, and a list of constraints. When it comes to the actual data storage within the Table, a Map that ties a unique primary key (like an auto-incrementing integer or a UUID) to a Record object is going to be highly efficient. A Record, in this context, is simply a wrapper around a Map of column names to their respective values.
- Database: ConcurrentHashMap<String, Table>
- Table: List<Column> schema, ConcurrentHashMap<String, Record> rows
- Column: String name, Type type, List<Constraint> constraints
- Record: String id, Map<String, Object> values
Type-Safe Validations: Implementing Extensible Constraints via the Strategy Pattern
Candidates constantly fall into the trap of writing massive if-else blocks inside their insert method just to validate data. They'll check if a string is too long, then check if an integer is out of bounds, and finally verify if a field is null. This completely violates the Open-Closed Principle. If your interviewer suddenly asks you to add a 'RegexMatch' constraint, you'd be forced to rip open and modify the core insertion logic.
Instead, lean on the Strategy Pattern. Define a ValidationConstraint interface with a single method: validate(Object value). From there, you can create concrete implementations like StringLengthConstraint, IntRangeConstraint, and NotNullConstraint. When you define a Column, simply pass it a list of these constraints.
During an insert operation, the Table iterates through the provided values, looks up the corresponding Column, and fires validate() on every single constraint attached to it. If any constraint throws a ValidationException, you abort the entire insert operation. This approach makes your system incredibly extensible. Adding a brand-new constraint type requires absolutely zero changes to your existing Table or Column classes.
Thread-Safety & Concurrency: Applying Fine-Grained ReadWriteLocks
Handling concurrency correctly is what truly separates SDE-2 candidates from the rest of the pack. Rely on standard HashMaps without any synchronization, and your database will immediately fail under concurrent load. On the flip side, if you just lazily slap a synchronized keyword on the entire insert and read methods, you'll create a massive bottleneck. Only one thread will be able to do anything at a time, which completely ruins the performance benefits of building an in-memory system.
Your best bet for a 90-minute interview is Table-level locking using a ReentrantReadWriteLock. Databases naturally lean read-heavy. A ReadWriteLock lets multiple threads grab the read lock simultaneously, meaning concurrent SELECT queries can execute in parallel without getting in each other's way. But when a thread needs to INSERT or UPDATE, it has to acquire the exclusive write lock. This guarantees no other reads or writes can touch that specific table until the mutation finishes.
Optimizing Queries: Adding Indexing Support for Low-Latency Filtering
Once you have basic insertion and retrieval working, the interviewer will probably ask you to implement filtering—like finding all users where age = 25. The naive approach is a full table scan. You'd iterate through all records in the Table's map, check the age column, and return any matches. That's an O(N) operation, and frankly, it's completely unacceptable for a database.
To speed things up, you need to implement Indexing. In this context, an index is just a secondary data structure. You can tack an IndexManager onto your Table class to maintain a Map<String, Map<Object, List<String>>>. The first key represents the column name being indexed. The second key holds the actual value (like 25). Finally, the value is a list of Record IDs that contain that specific data.
When a new record comes in, you validate the constraints and then update the index map in O(1) time. Later, when a query runs filtering by an indexed column, you bypass the full table scan entirely. Instead, you perform an O(1) lookup in the index map to grab the exact Record IDs and fetch them instantly. Just make absolutely sure your write lock covers the index update so you avoid nasty dirty reads.
Common SDE-2 Interview Questions for this Problem
How do I handle concurrent transactions and rollbacks in an in-memory database?
Building full ACID transactions with rollbacks during a 90-minute round is generally out of scope, but you still need to know how to discuss it intelligently. You'd want to explain the concept of a Write-Ahead Log (WAL) or describe maintaining a snapshot of the record state before any mutations happen. For an in-memory setup, you could design a transaction context that clones the affected records and applies mutations directly to those clones. You'd only swap the pointers in the main concurrent map once a commit operation fires. If an error pops up, you just discard the clones, which effectively gives you a clean rollback.
What data structure should I use to implement a highly efficient range query?
If the interviewer presses you for a range query (like finding ages between 20 and 30), a standard HashMap index falls flat since it only handles exact matches. You should tell them you'd swap out the inner index map for a TreeMap or a Skip List. A TreeMap (which implements a Red-Black tree under the hood in Java) keeps keys perfectly sorted. That lets you find the lower bound in O(log N) time and sequentially traverse right up to the upper bound, making range queries incredibly fast.
How do I ensure the database schema can be dynamically altered without downtime?
Schema evolution is a classic senior-level curveball. If you want to alter a table—say, adding a new column—without causing downtime, you can't just lock the entire table for the duration of the migration, especially if it holds millions of rows. In a real-world system, you'd use a strategy similar to online schema migration tools. You create a new table with the updated schema, start mirroring new writes to both tables, backfill the old data in small chunks, and finally swap the table pointers atomically. For this coding round, you'll just explain the concept verbally rather than trying to write it all out.
How AcePrompt Helps You Live-Refactor LLD Patterns Under Pressure
Passing the Razorpay machine coding round takes a lot more than just memorizing design patterns. You have to recall and implement them flawlessly while a timer aggressively ticks down and an interviewer scrutinizes your screen. Forgetting the exact syntax for a ReentrantReadWriteLock or struggling to cleanly structure your Strategy pattern interfaces can easily burn 20 precious minutes. That kind of delay leaves you with an incomplete, failing solution.
This is exactly where AcePrompt AI steps in as your ultimate unfair advantage. Working as a real-time AI interview copilot, AcePrompt listens directly to the live conversation. When the interviewer suddenly pivots and asks, 'How would you add an index for range queries?', AcePrompt instantly processes the audio and displays structured, tailored suggestions right on your screen. It helps you recall those exact TreeMap implementation details and concurrency trade-offs. You end up communicating like a seasoned architect and writing flawless code, even under intense pressure.
Frequently asked questions
What programming language is best for the Razorpay machine coding round?
Java and C++ are usually the top picks because of their robust, built-in concurrency utilities—think ReentrantReadWriteLock and ConcurrentHashMap. Their strong typing also naturally fits LLD problems. That said, Python and Go are perfectly acceptable choices if you're highly proficient and can quickly spin up thread-safe structures.
Do I need to write a SQL parser for the in-memory database?
No. Unless they explicitly ask for it, don't waste time parsing strings. You're better off building clean, object-oriented APIs—like a Database class with a createTable method—to interact with your system. Just make sure to clarify this with your interviewer before you start coding.
Is having fully working code mandatory to pass?
For an SDE-2 role, absolutely. A partially working solution with decent design might get an SDE-1 candidate through, but the expectations are higher here. SDE-2 candidates need to deliver a fully functional, executable program that handles edge cases and concurrency correctly before the timer runs out.
How should I manage my time during the 90-minute round?
Dedicate your first 10 to 15 minutes to clarifying requirements and mapping out your class structures, especially your domain models. Then, spend about 60 minutes writing the core logic. You'll want to focus on the happy path and critical concurrency locks right away. Finally, reserve the last 15 minutes for writing driver code, running tests, and squashing any bugs.
Related comparisons
See AcePrompt in action
Watch how AcePrompt supports a real technical round - structured answers, tuned to your resume, in real time.
Stop freezing under pressure. Let AcePrompt AI guide your live interviews with real-time, structured answers.
Get started