In-Memory Key-Value Store with Nested Transactions
Otter.AiSoftware Engineer · Technical ScreenLast updated
This problem tests the ability to implement a nested transactional key-value store using stack-based state management and scope shadowing.
Problem Statement
Design an in-memory key-value store that supports nested transactions. The store should handle basic set, get, and delete operations, along with begin, commit, and rollback commands to manage transaction scopes.
Requirements
set(key, value): Sets the value for a key in the current active transaction scope.get(key): Returns the value for the key. If the key exists in the current scope, return that value. Otherwise, traverse up to parent scopes to find the value. ReturnNoneif the key is not found in any scope.delete(key): Effectively hides the key in the current scope. Anygetrequest for this key should returnNone.begin(): Starts a new nested transaction scope.commit(): Merges the current transaction scope into the parent scope. If there is no parent scope, the changes persist at the global level.rollback(): Discards all changes made in the current transaction scope.
Signature
class TransactionalStore:
def __init__(self):
pass
def set(self, key, value):
pass
def get(self, key):
pass
def delete(self, key):
pass
def begin(self):
pass
def commit(self):
pass
def rollback(self):
pass
Examples
Example 1:
store = TransactionalStore()
store.set("a", 1)
print(store.get("a")) # Output: 1
store.begin()
store.set("a", 2)
print(store.get("a")) # Output: 2
store.rollback()
print(store.get("a")) # Output: 1
Constraints
- Use a stack-based approach to represent the hierarchy of transaction states.
- Ensure
getoperations run efficiently relative to the number of active transactions.
Hints
Hint 1
Consider maintaining a list of dictionaries (or hash maps), where each dictionary represents an isolated scope of the current transaction.
Hint 2
For 'set' and 'delete', always modify the dictionary at the top of the stack.
Hint 3
For 'get', search from the top of the stack downwards; if you find a tombstone (marker for deletion), return None immediately.
Follow-up questions
- How would you modify your implementation to ensure the global (base) state is never lost if an error occurs?
- What is the time complexity of the 'get' operation in the worst case, and can you optimize it?
- How would you handle thread-safety if multiple users were calling 'begin' and 'commit' concurrently?
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.