Implement a Transactional In-Memory Table
AddeparSoftware Engineer · Technical ScreenLast updated
Design an in-memory tabular data store that supports transactional modifications (create, update, delete, find-and-replace) with commit and rollback capabilities.
Problem Statement
Design an in-memory, relational-style table with a fixed schema of column names and a unique integer row ID. All write operations must occur within an active transaction. The table supports starting a transaction, committing changes, or rolling back to the exact state before the transaction began.
Implement the TransactionalTable class:
TransactionalTable(columns: list[str]): Initializes the table with a fixed list of column names.begin() -> bool: Begins a new transaction. ReturnsTrueif successfully started, orFalseif a transaction is already active (nested transactions are not supported).commit() -> bool: Commits all modifications made during the active transaction. ReturnsTrueon success, orFalseif there is no active transaction.rollback() -> bool: Discards all modifications made during the active transaction, reverting the table to its state at the time ofbegin(). ReturnsTrueon success, orFalseif there is no active transaction.insert_row(row_id: int, values: dict[str, str]) -> bool: Inserts a row with the givenrow_id. Unspecified columns should default to empty string"". ReturnsFalseif no transaction is active, ifrow_idalready exists, or ifvaluescontains column names not in the schema.update_cell(row_id: int, column: str, value: str) -> bool: Updates the specified cell. ReturnsFalseif no transaction is active, ifrow_iddoes not exist, or ifcolumnis not in the schema.delete_row(row_id: int) -> bool: Deletes the row with the givenrow_id. ReturnsFalseif no transaction is active or ifrow_iddoes not exist.find_and_replace(column: str, target: str, replacement: str) -> int: Replaces all occurrences oftargetwithreplacementin the givencolumn. Returns the number of cells modified. Returns-1if no transaction is active or ifcolumnis not in the schema.serialize() -> str: Returns a deterministic CSV-formatted string of the current table state (even outside a transaction). The first line isid,,,...matching the schema order. Subsequent lines contain the rows ordered byrow_idin ascending order.
Example
table = TransactionalTable(["name", "department"])
# Modifying outside transaction returns False
table.insert_row(1, {"name": "Alice", "department": "Eng"}) # False
table.begin() # True
table.insert_row(1, {"name": "Alice", "department": "Eng"}) # True
table.insert_row(2, {"name": "Bob", "department": "Eng"}) # True
table.find_and_replace("department", "Eng", "Engineering") # 2
table.commit() # True
table.begin() # True
table.update_cell(1, "department", "HR") # True
table.delete_row(2) # True
table.rollback() # True
print(table.serialize())
# Output:
# id,name,department
# 1,Alice,Engineering
# 2,Bob,Engineering
Constraints
- Number of columns = 1.
- Only one transaction can be active at any given time.
Hints
Hint 1
You can implement rollback either by snapshotting the committed state upon `begin()` or by recording an undo log (inverse operations) for every mutation.
Hint 2
Be sure to handle validation (checking schema columns and row existence) before making changes so failed operations do not corrupt transaction history.
Hint 3
Using an undo log is generally more memory-efficient than deep-copying the entire table when only a small fraction of rows are modified per transaction.
Follow-up questions
- How would you extend this design to support nested transactions (savepoints)?
- How would you adapt this data structure to support concurrent read and write transactions safely (e.g., via multi-version concurrency control)?
- If `find_and_replace` is called frequently across millions of rows, what indexing strategy would you use to avoid full-table scans?
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.