I recently completed the interview process with Databricks and wanted to share my experience. While I ultimately decided not to move forward due to a leveling mismatch, it was genuinely one of the most professional, challenging, and well-structured interview loops I've been through. Here’s a breakdown for anyone preparing.
This was a single, in-depth DSA problem focused on practical application.
The first onsite round presented a complex, custom data structure problem.
ref_string and a src_string. The src_string is represented as a "cover"—a list of index pairs pointing to substrings within the ref_string. The task was to implement a delete(cover, index) function that removes a character at a logical index from the src_string and returns a new, valid cover.ref_string. The task was to ensure the delete function now returned a maximal cover.Knowing I had to perform well here, I was focused and ready.
(time, cost, row, col, current_mode), to correctly explore paths and account for the switching penalty. I solved both optimally and felt the concerns from the previous round were now resolved.This was an intense and highly practical round focused on low-level design and concurrency.
The Challenge: Design and implement a thread-safe EventWriter class. Multiple threads would call appendEvent() to write small data buffers to a single file. The key constraints were: high throughput, low latency, and durability (the function must only return after the data is confirmed to be on disk).
The Deep Dive & My Solution: This was a grilling session where a full C++ implementation was expected. My approach evolved as we discussed trade-offs:
appendEvent function, which calls write() followed by fsync() for every event. I explained this would have terrible throughput due to high lock contention and the massive overhead of calling fsync for every small write.producers) add events to a thread-safe in-memory buffer (e.g., a locked queue). A single, dedicated background thread (consumer) is responsible for writing to the file.write() call, followed by a single fsync(). This drastically improves throughput by amortizing the expensive system calls.appendEvent call needs to block until its specific event is durable. To solve this, I used std::promise and std::future. When a producer thread submits an event, it also creates a promise and passes the corresponding future back to the caller (or waits on it internally). The consumer thread, after successfully calling fsync() on a batch, iterates through the events in that batch and fulfills their associated promises. This unblocks the waiting producer threads, guaranteeing durability before they return.The discussion covered mutexes, condition variables, batching strategies, thread pools, and the critical role of fsync. The interviewer was satisfied with the robust and layered solution.
This was one of the best HM conversations I've ever had. It was a masterclass in behavioral interviewing.
This format tests for consistency and depth far better than scattered, unrelated questions. The round concluded with an excellent, transparent overview of the team's work and vision.
I was thrilled to receive an offer for a Level 4 Software Engineer position. The compensation was very strong and was competitive with an L5 offer I held from another company.
However, Databricks has a general policy of not increasing levels for lateral hires, and my goal was to secure an L5 role. Due to this leveling expectation mismatch, I respectfully decided not to move forward.
Despite my decision, I can't speak highly enough of the process. It was rigorous, fair, and a true test of a senior engineer's skills.