Branching & Time Travel
Branching & Time Travel
HeliosDB-Lite provides Git-like branching for databases and point-in-time queries with AS OF TIMESTAMP. Branches are copy-on-write, creating instant snapshots with minimal storage overhead.
Prerequisites
- HeliosDB-Lite v3.5 or later with
time_travel_enabled = true(enabled by default) - Access to the SQL shell (REPL, PostgreSQL wire protocol, or REST API)
Part A — Time Travel
Step 1 — Create a Table and Insert Data
CREATE TABLE accounts ( id INT PRIMARY KEY, name TEXT, balance FLOAT8);
INSERT INTO accounts VALUES (1, 'Alice', 1000.00);INSERT INTO accounts VALUES (2, 'Bob', 2000.00);Every committed transaction creates a versioned snapshot. HeliosDB stores
version keys with the pattern v:{table}:{row_id}:{timestamp} so historical
states can be reconstructed.
Step 2 — Record a Timestamp, Then Modify Data
Note the current time, then perform some changes:
-- Remember this timestamp (e.g., '2025-03-26 10:00:00')SELECT NOW();
UPDATE accounts SET balance = 500.00 WHERE id = 1;UPDATE accounts SET balance = 3000.00 WHERE id = 2;Step 3 — Query Current State
SELECT * FROM accounts; id | name | balance----+-------+--------- 1 | Alice | 500.00 2 | Bob | 3000.00Step 4 — Query Historical State with AS OF TIMESTAMP
Retrieve the data as it existed before the updates:
SELECT * FROM accounts AS OF TIMESTAMP '2025-03-26 10:00:00'; id | name | balance----+-------+--------- 1 | Alice | 1000.00 2 | Bob | 2000.00The query reads from the versioned snapshot closest to the specified timestamp without modifying any data.
Step 5 — AS OF Variants
HeliosDB supports three AS OF targets:
-- By wall-clock timestampSELECT * FROM accounts AS OF TIMESTAMP '2025-03-26 10:00:00';
-- By internal transaction IDSELECT * FROM accounts AS OF TRANSACTION 42;
-- By System Change Number (Oracle-compatible)SELECT * FROM accounts AS OF SCN 1000;Step 6 — Snapshot Metadata
Query system views to see available snapshots:
SELECT * FROM helios_snapshots; timestamp | transaction_id | scn | wall_clock_time | gc_eligible--------------+----------------+------+--------------------------+------------ 1711451200 | 1 | 1 | 2025-03-26T09:00:00Z | true 1711454800 | 5 | 5 | 2025-03-26T10:00:00Z | truePart B — Branching
Step 7 — Create a Branch
Create a named branch from the current state:
CREATE BRANCH dev AS OF NOW;This captures a point-in-time snapshot. The branch uses copy-on-write storage: it shares all existing data with the parent and only stores new or modified keys.
You can also branch from a historical point:
CREATE BRANCH rollback_point AS OF TIMESTAMP '2025-03-26 10:00:00';Step 8 — Work on a Branch
Switch to a branch context to read and write data in isolation. Branch operations are available through the REST API, embedded Rust API, or programmatic access:
-- Via REST APIPOST /api/v1/query{ "sql": "INSERT INTO accounts VALUES (3, 'Charlie', 500.00)", "branch": "dev"}
-- Via embedded Rust APIdb.execute_on_branch("dev", "INSERT INTO accounts VALUES (3, 'Charlie', 500.00)")?;Changes on the dev branch are isolated. Querying the main branch still shows
only Alice and Bob.
Step 9 — Branch Isolation
Each branch maintains its own view of the data:
-- On branch 'dev':SELECT * FROM accounts; id | name | balance----+---------+--------- 1 | Alice | 500.00 2 | Bob | 3000.00 3 | Charlie | 500.00
-- On main:SELECT * FROM accounts; id | name | balance----+-------+--------- 1 | Alice | 500.00 2 | Bob | 3000.00Step 10 — Merge a Branch
Merge changes from one branch into another:
MERGE BRANCH dev INTO main;HeliosDB supports multiple merge strategies:
| Strategy | Behavior |
|---|---|
Auto | Prefer source branch on conflicts |
Manual | Fail on any conflict |
Theirs | Always prefer source branch changes |
Ours | Always prefer target branch changes |
MERGE BRANCH dev INTO main WITH (strategy = 'manual');If conflicts are detected with the Manual strategy, the merge fails and
reports which keys conflict.
Step 11 — Drop a Branch
DROP BRANCH dev;DROP BRANCH IF EXISTS rollback_point;Dropping a branch marks it as Dropped and frees copy-on-write storage that
is no longer referenced.
Tips and Troubleshooting
- Time travel requires versioning: The
time_travel_enabledsetting must betrue(the default). Without it, historical versions are not retained.
[storage]time_travel_enabled = true-
Garbage collection: Old snapshots are garbage-collected periodically. If you need to query very old timestamps, ensure GC retention is configured long enough. Snapshots marked
gc_eligible = truewill eventually be reclaimed. -
Storage overhead: Time travel and branching store additional version keys. For write-heavy workloads, monitor disk usage and tune GC frequency.
-
Branch naming: Branch names are case-sensitive strings. Use short, descriptive names like
dev,staging, orexperiment-42. -
Performance: AS OF queries have less than 2x overhead compared to current-time queries. The snapshot manager caches recent lookups in an LRU cache for fast access.
-
Concurrent branches: Multiple branches can be active simultaneously. Each branch tracks its own set of modified keys independently.