Transactional Key-Value Store
Nested transactions and rollback boundaries
Nested commit closes one boundary; it does not make a change durable outside every enclosing transaction. A committed child merges into its immediate parent, so an outer rollback must still undo it. A stack of full value-map snapshots is a simple correct design for small data.
std::vector<std::map<std::string,std::string>> views(1);
// begin copies views.back(); rollback discards only the top view.An overlay design can reduce copying, but deletion needs a tombstone distinct from absence: otherwise lookup falls through to a deleted parent value. Empty strings are actual stored values and cannot serve as absence markers. Use optional string results. Return snapshots by value and sorted map keys for deterministic prefix views. Invalid commit/rollback at depth zero must preserve both data and depth. Copying a full view costs O(number of keys), a deliberate tradeoff for an auditable first implementation.
C++ contract conventions: numeric values use signed Int (long long); all inputs and intermediate arithmetic are within its representable range. Opt<T> means std::optional<T> and absence is std::nullopt; Vec<T> means std::vector<T>. Invalid documented arguments throw std::invalid_argument. Inputs passed by const reference remain caller owned. Returned containers and records own their contents. Calls use the declared C++ parameter types. Implicit conversions performed by the caller are outside the runtime validation contract. Unless a lesson states otherwise, string ordering is lexicographic over Unicode code points (Text) or UTF-8 identifiers (std::string).
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.