Versioned Key-Value Store with Nested Transactions (Begin, Commit, Rollback)
xAISoftware Engineer · OnsiteLast updated
This question evaluates understanding of transactional state management, nested transactions, visibility semantics for set/delete operations, and efficient in-memory data-structure manipulation.
Implement an in-memory versioned key-value database that supports transactional writes with three transaction-control operations: begin (start a transaction), commit, and rollback. Transactions may be nested: a begin issued while another transaction is open starts a new inner transaction layered on top of it.
Implement the class VersionedKVStore:
VersionedKVStore()— initializes an empty store with no open transactions.void set(String key, int value)— setskeytovaluein the current context: the innermost open transaction if one exists, otherwise the permanent store.int get(String key)— returns the value ofkeyas currently visible: the innermost open transaction is consulted first, then each enclosing transaction from inner to outer, then the permanent store. Returns-1if the key is absent, or if the most recent visible operation on it is a deletion.void delete(String key)— deleteskeyin the current context. Inside a transaction, the deletion shadows any value from outer transactions or the permanent store (sogetreturns-1), but takes permanent effect only if committed. Deleting a key that is not visible is a no-op in effect (subsequentgetstill returns-1).void begin()— opens a new transaction, nested inside the current innermost transaction if one is open.boolean commit()— if no transaction is open, returnsfalse. Otherwise merges all changes (sets and deletions) of the innermost open transaction into its parent transaction — or into the permanent store if it is the outermost — closes that transaction, and returnstrue.boolean rollback()— if no transaction is open, returnsfalse. Otherwise discards all changes made in the innermost open transaction, closes it, and returnstrue.
Reads and writes issued outside any transaction apply directly and permanently to the store.
Example
Input:
["VersionedKVStore", "set", "get", "begin", "set", "get", "begin", "delete", "get", "rollback", "get", "commit", "get", "rollback", "get"]
[[], ["a", 1], ["a"], [], ["a", 2], ["a"], [], ["a"], ["a"], [], ["a"], [], ["a"], [], ["a"]]
Output:
[null, null, 1, null, null, 2, null, null, -1, true, 2, true, 2, false, 2]
Explanation:
set("a", 1)— no transaction open, written permanently.get("a")returns1.begin()opens transaction T1;set("a", 2)inside T1;get("a")returns2.begin()opens nested transaction T2;delete("a")inside T2;get("a")returns-1(the deletion in T2 shadows the outer value).rollback()discards T2 and returnstrue;get("a")returns2again (T1's write is intact).commit()merges T1 into the permanent store and returnstrue;get("a")returns2.rollback()returnsfalse— no transaction is open;get("a")still returns2.
Constraints
- At most
10^5operations in total. - Keys are non-empty lowercase strings of length at most
20. 0 <= value <= 10^9- Transaction nesting depth will not exceed
10^3.
Performance requirement
set and delete should run in O(1) average time. get may be O(d) in the worst case, where d is the current nesting depth (an O(1)-average get is possible with a more advanced design and is a nice discussion point). commit and rollback should cost time proportional to the number of keys modified in the innermost transaction — not the size of the whole store.
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.