PracHub
QuestionsCoachesLearningGuidesInterview Prep

Quick Overview

This question evaluates a candidate's ability to design a data structure that layers transactional state over a committed base, testing skills in nested scope management and state isolation. It probes practical application of stack-based rollback logic and efficient in-memory data modeling, a common way coding interviews assess system design at the data-structure level.

  • medium
  • Anthropic
  • Coding & Algorithms
  • Software Engineer

In-Memory Key-Value Database with Nested Transactions

Company: Anthropic

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

# In-Memory Key-Value Database with Nested Transactions Implement an in-memory key-value store whose keys and values are strings, supporting basic reads and writes plus **nested transactions** (a transaction started inside another transaction). The database is driven by a list of commands and returns one line of output per command that produces a result. Your function receives `commands: List[List[str]]` (each command is a list of tokens) and returns `List[str]` (the outputs, in order). Implement these commands: - `["SET", key, value]` — associate `value` with `key`. Produces no output. - `["GET", key]` — return the current value of `key`, or the literal string `"NULL"` if the key is not set. - `["DELETE", key]` — remove `key`. Produces no output. Deleting a missing key is a no-op. - `["COUNT", value]` — return, as a string, how many keys currently map to `value`. - `["BEGIN"]` — open a new transaction. Transactions may be nested arbitrarily deep; a `BEGIN` inside an open transaction starts a child transaction. Produces no output. - `["COMMIT"]` — permanently apply **all** changes made since the outermost `BEGIN`, closing every open transaction. If no transaction is open, return `"NO TRANSACTION"`. - `["ROLLBACK"]` — discard the changes made in the **innermost** currently-open transaction and close only that transaction. If no transaction is open, return `"NO TRANSACTION"`. ## Semantics - Reads (`GET`, `COUNT`) always reflect the state visible inside the current (innermost) transaction, layered over its parents and the committed base state. - A `SET`/`DELETE` inside a transaction is visible to reads within that transaction and its descendants, but must not affect the committed state until `COMMIT`. - `ROLLBACK` undoes only the innermost transaction's writes; the enclosing transaction (or base state) is restored to what it was before that innermost `BEGIN`. - `COMMIT` flattens every open transaction's writes into the committed base state at once. ## Constraints - `1 <= len(commands) <= 10^5`. - Keys and values are non-empty strings of length up to 100 with no spaces. - `COUNT` should run efficiently (do not scan all keys on every call if it can be avoided). ## Example Input: ``` [ ["SET", "a", "10"], ["GET", "a"], ["BEGIN"], ["SET", "a", "20"], ["BEGIN"], ["DELETE", "a"], ["GET", "a"], ["ROLLBACK"], ["GET", "a"], ["COMMIT"], ["GET", "a"] ] ``` Output: ``` ["10", "NULL", "20", "20"] ``` Explanation: `GET a` is `10`, then after the nested `DELETE` it is `NULL`; the inner `ROLLBACK` restores `a=20`; `COMMIT` makes `a=20` permanent, and the final `GET a` returns `20`.

Quick Answer: This question evaluates a candidate's ability to design a data structure that layers transactional state over a committed base, testing skills in nested scope management and state isolation. It probes practical application of stack-based rollback logic and efficient in-memory data modeling, a common way coding interviews assess system design at the data-structure level.

Implement an in-memory key-value store whose keys and values are strings, supporting basic reads and writes plus nested transactions (a transaction started inside another transaction). The database is driven by a list of commands and returns one line of output per command that produces a result. Your function receives `commands: List[List[str]]` (each command is a list of tokens) and returns `List[str]` (the outputs, in order). Implement these commands: - `["SET", key, value]` — associate `value` with `key`. Produces no output. - `["GET", key]` — return the current value of `key`, or the literal string `"NULL"` if the key is not set. - `["DELETE", key]` — remove `key`. Produces no output. Deleting a missing key is a no-op. - `["COUNT", value]` — return, as a string, how many keys currently map to `value`. - `["BEGIN"]` — open a new transaction. Transactions may be nested arbitrarily deep; a `BEGIN` inside an open transaction starts a child transaction. Produces no output. - `["COMMIT"]` — permanently apply all changes made since the outermost `BEGIN`, closing every open transaction. If no transaction is open, return `"NO TRANSACTION"`. - `["ROLLBACK"]` — discard the changes made in the innermost currently-open transaction and close only that transaction. If no transaction is open, return `"NO TRANSACTION"`. Semantics: - Reads (`GET`, `COUNT`) always reflect the state visible inside the current (innermost) transaction, layered over its parents and the committed base state. - A `SET`/`DELETE` inside a transaction is visible to reads within that transaction and its descendants, but must not affect the committed state until `COMMIT`. - `ROLLBACK` undoes only the innermost transaction's writes; the enclosing transaction (or base state) is restored to what it was before that innermost `BEGIN`. - `COMMIT` flattens every open transaction's writes into the committed base state at once. Constraints: - `1 <= len(commands) <= 10^5`. - Keys and values are non-empty strings of length up to 100 with no spaces. - `COUNT` should run efficiently (do not scan all keys on every call if it can be avoided). Example: Input: `[["SET","a","10"],["GET","a"],["BEGIN"],["SET","a","20"],["BEGIN"],["DELETE","a"],["GET","a"],["ROLLBACK"],["GET","a"],["COMMIT"],["GET","a"]]` Output: `["10","NULL","20","20"]` The first `GET a` is `10`; after the nested `DELETE` it is `NULL`; the inner `ROLLBACK` restores `a=20`; `COMMIT` makes `a=20` permanent, and the final `GET a` returns `20`.

Constraints

  • 1 <= len(commands) <= 10^5
  • Keys and values are non-empty strings of length up to 100 with no spaces.
  • GET on an unset key returns the literal string "NULL".
  • COMMIT / ROLLBACK with no open transaction returns "NO TRANSACTION".
  • COUNT should be efficient and not rescan all keys on every call.

Examples

Input: [["SET","a","10"],["GET","a"],["BEGIN"],["SET","a","20"],["BEGIN"],["DELETE","a"],["GET","a"],["ROLLBACK"],["GET","a"],["COMMIT"],["GET","a"]]

Expected Output: ["10","NULL","20","20"]

Explanation: GET a=10; after the nested DELETE it is NULL; the inner ROLLBACK restores a=20; COMMIT flattens a=20 into base; final GET a=20.

Input: [["COMMIT"]]

Expected Output: ["NO TRANSACTION"]

Explanation: COMMIT with no open transaction reports NO TRANSACTION.

Input: [["ROLLBACK"]]

Expected Output: ["NO TRANSACTION"]

Explanation: ROLLBACK with no open transaction reports NO TRANSACTION.

Input: [["SET","a","x"],["SET","b","x"],["SET","c","y"],["COUNT","x"],["COUNT","y"],["COUNT","z"],["DELETE","a"],["COUNT","x"]]

Expected Output: ["2","1","0","1"]

Explanation: Two keys map to x and one to y; z has none; after deleting a only b still maps to x.

Input: [["BEGIN"],["SET","k","1"],["BEGIN"],["SET","k","2"],["COMMIT"],["GET","k"],["ROLLBACK"]]

Expected Output: ["2","NO TRANSACTION"]

Explanation: COMMIT flattens both nested transactions so k=2 is permanent; the later ROLLBACK finds no open transaction.

Input: [["SET","a","x"],["BEGIN"],["SET","b","x"],["COUNT","x"],["ROLLBACK"],["COUNT","x"],["GET","b"]]

Expected Output: ["2","1","NULL"]

Explanation: Inside the transaction two keys map to x; ROLLBACK undoes the SET b so COUNT x drops back to 1 and b is unset.

Input: []

Expected Output: []

Explanation: No commands produce no output.

Input: [["GET","missing"],["DELETE","missing"],["GET","missing"]]

Expected Output: ["NULL","NULL"]

Explanation: Reading an unset key returns NULL; deleting a missing key is a no-op.

Input: [["SET","a","1"],["BEGIN"],["SET","a","2"],["SET","a","3"],["DELETE","a"],["ROLLBACK"],["GET","a"]]

Expected Output: ["1"]

Explanation: Multiple writes within one transaction are all undone in reverse by a single ROLLBACK, restoring a=1.

Input: [["SET","a","1"],["BEGIN"],["SET","a","2"],["BEGIN"],["SET","a","3"],["COMMIT"],["GET","a"]]

Expected Output: ["3"]

Explanation: COMMIT flattens every open transaction at once, so the innermost value a=3 becomes permanent.

Hints

  1. Keep one flat dictionary that represents the currently-visible state (committed base plus all open transactions applied), so GET is a single lookup.
  2. Maintain a value -> count map that you update on every SET/DELETE, so COUNT is O(1) instead of scanning every key.
  3. For each open transaction keep an undo log: before each write, record the key's previous value (or that it was absent). ROLLBACK replays that log in reverse; COMMIT just discards all logs since the visible state already holds the changes.
  4. Because only the innermost transaction's writes are recorded in its own log, ROLLBACK naturally restores the enclosing transaction (or base) state before that BEGIN.
Last updated: Jul 1, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Banking System Simulation - Anthropic (medium)
  • LRU Cache - Anthropic (medium)
  • Account Balance with Expiring Grants - Anthropic (medium)
  • Path Resolution with Symbolic Links - Anthropic (medium)
  • Time-Based Key-Value Store - Anthropic (medium)