Skip to content
MediumStateful DesignPython 3

Transactional KV Store

Implement nested in-memory transactions with read-your-writes, tombstones, commit, and rollback.

40m3 sample tests9 hidden tests

Implement TransactionalKV, an in-memory key/value store with . An explicit must hide a lower-layer value after a transactional delete.

Requirements

  • set(key, value) writes a value.
  • get(key) returns the visible value or None.
  • None is a valid stored value and must shadow lower layers, even though get can't distinguish it from absence.
  • delete(key) removes the visible value.
  • Deleting a missing key is harmless.
  • begin() opens a transaction layer.
  • commit() merges the current transaction into its parent layer or the base store.
  • rollback() discards the current transaction.
  • Both control operations close only the innermost layer. An inner commit can still be undone by rolling back its parent.
  • Reads inside a transaction must see writes and deletes from that transaction first.
  • Deleting a key inside a transaction must hide lower-layer values until rollback or commit.
  • Calling commit() or rollback() without an active transaction raises ValueError.

Example

Nested layers should make deletion and rollback observable:

OperationVisible modelReason
Base set("model", "fast")"fast"Base value exists.
Outer begin(); delete("model")NoneTombstone hides the base value.
Inner begin(); set("model", "strong")"strong"Inner write shadows the tombstone.
Inner rollback()NoneOuter deletion becomes visible again.
Outer rollback()"fast"Base value was never deleted.

The smaller example below demonstrates the write-and-rollback path:

python
1store = TransactionalKV() 2store.set("model", "fast") 3store.begin() 4store.set("model", "strong") 5assert store.get("model") == "strong" 6store.rollback() 7assert store.get("model") == "fast"

Constraints

  • Keep it single-process and in memory, with sequential calls and one shared transaction stack.
  • Treat values as opaque references. Transactions track set and delete; they don't undo in-place mutations to returned objects.
  • Preserve nested transaction semantics.
  • Don't use a database library.
  • Distinguish a missing layer entry from an explicit deletion marker.

Editor