TodoMVCC |
Demo Spec PostgreSQL XTDB |
TodoMVCC = like TodoMVC but for databases (not UIs!)
Developers building data-intensive applications often struggle with versioning, concurrency control, and maintaining consistency over time. Manual versioning schemes, transaction anomalies, and locking contention plague traditional approaches.
This project demonstrates these challenges using everyone's favorite example: a todo list.
Building reliable applications often means wrestling with:
What if there was a better way?
Most applications run on READ COMMITTED isolation by default, which allows various consistency anomalies. Let's see how these manifest in a simple todo app:
Two users editing the same todo simultaneously:
-- User A starts editing todo #123
BEGIN;
SELECT title FROM todos WHERE id = 123; -- "Buy groceries"
-- User B also starts editing the same todo
BEGIN;
SELECT title FROM todos WHERE id = 123; -- "Buy groceries"
-- User A updates the title
UPDATE todos SET title = 'Buy groceries and milk' WHERE id = 123;
COMMIT;
-- User B updates based on stale data
UPDATE todos SET title = 'Buy groceries and bread' WHERE id = 123;
COMMIT;
-- Result: User A's changes are lost!
In READ COMMITTED: User B's update overwrites User A's changes.
In SERIALIZABLE: One transaction would be aborted and retry with fresh data.
Maintaining a business constraint across multiple todos:
-- Rule: At most 3 todos can be marked "urgent" priority
-- Currently 2 urgent todos exist
-- Transaction A: Mark todo #456 as urgent
BEGIN;
SELECT COUNT(*) FROM todos WHERE priority = 'urgent'; -- Returns 2
-- User thinks: "OK, I can add one more"
UPDATE todos SET priority = 'urgent' WHERE id = 456;
-- Transaction B: Mark todo #789 as urgent
BEGIN;
SELECT COUNT(*) FROM todos WHERE priority = 'urgent'; -- Returns 2
-- User thinks: "OK, I can add one more"
UPDATE todos SET priority = 'urgent' WHERE id = 789;
-- Both transactions commit successfully
-- Result: 4 urgent todos! Business rule violated.
In READ COMMITTED: Both transactions see consistent snapshots but create inconsistent final state.
In SERIALIZABLE: One transaction would be aborted to maintain the constraint.
SERIALIZABLE isolation eliminates these anomalies by ensuring transactions appear to execute one at a time, even when running concurrently. For todo apps, this means:
For a deep dive into consistency models and isolation levels, check out Jepsen's Consistency Models - an excellent interactive guide to understanding how different databases handle consistency.
Key resources:
Manual versioning with locking-based concurrency control.
CREATE TABLE todos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT false,
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
version BIGINT NOT NULL DEFAULT 1
);
CREATE TABLE todos_history (
id UUID NOT NULL,
title TEXT NOT NULL,
completed BOOLEAN NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
version BIGINT NOT NULL,
txid BIGINT NOT NULL DEFAULT txid_current(),
PRIMARY KEY (id, version)
);
Built-in time dimensions with optimistic concurrency control.
-- Time travel query (built-in)
SELECT * FROM todos
FOR SYSTEM_TIME AS OF '2024-01-01T12:00:00Z'
WHERE completed = false;
-- No manual versioning needed!
INSERT INTO todos (id, title, completed)
VALUES (1, 'Learn XTDB', false);
XTDB implementation coming soon...
The demo will showcase side-by-side comparisons demonstrating:
🚧 Interactive demo coming soon...
Challenge | Traditional SQL | XTDB Bitemporal |
---|---|---|
Version Tracking | Complex application logic | Zero application code |
Concurrency | Deadlocks and timeouts | No locks, no contention |
Consistency | Race conditions possible | Perfect isolation |
Audit Trail | Manual triggers/tables | Built-in auditability |
Performance | Degradation with locking | Predictable characteristics |
Want to contribute an implementation? Check out the TodoMVCC Specification for guidelines on:
TodoMVCC is perfect for:
Built by XTDB | View on GitHub
TodoMVCC combines the familiar TodoMVC concept with Multi-Version Concurrency Control - because sometimes the best way to understand complex database concepts is through a simple, relatable example that every developer knows: a todo list.