Design and implement an in-memory key–value store that supports transactions and nested transactional blocks. Your system must process a stream of commands and print results where applicable. Required commands and behavior:
(
-
SET
<key>
<value>
: Assign value to key in the current context; the assignment should shadow any prior value of the same key in outer contexts.
(
-
GET
<key>
: Print the current value for key, or NULL if the key has no value in any active context.
(
-
BEGIN: Start a new transactional block; changes after this belong to the new inner transaction.
(
-
ROLLBACK: Discard all changes made in the most recent active transaction and revert to the parent context; if no active transaction exists, print NO TRANSACTION.
(
-
COMMIT: Merge all open transactions into the base state and end all transactions; if no active transaction exists, print NO TRANSACTION. Requirements: Support arbitrarily nested transactions; ensure that reads respect the most recent assignment within the active stack of contexts; handle reassignments of keys that existed before a transaction as well as keys introduced inside a transaction; define and justify the time/space complexity of each command for up to tens of thousands of operations. Provide a brief discussion comparing an explicit stack-based approach versus a recursive approach to represent nested transactions, and justify your implementation choice. Include a few example interactions demonstrating BEGIN/SET/GET/ROLLBACK/COMMIT behavior and edge cases (e.g., GET on unknown key, ROLLBACK/COMMIT with no open transaction).