SkillAgentSearch skills...

Sirix

SirixDB is an an embeddable, bitemporal, append-only database system and event store, storing immutable lightweight snapshots. It keeps the full history of each resource. Every commit stores a space-efficient snapshot through structural sharing. It is log-structured and never overwrites data. SirixDB uses a novel page-level versioning approach.

Install / Use

/learn @sirixdb/Sirix

README

<p align="center"><img src="https://raw.githubusercontent.com/sirixdb/sirix/master/Circuit Technology Logo.png"/></p> <h1 align="center">SirixDB - The Bitemporal Database System</h1> <h3 align="center">Query any revision as fast as the latest</h3> <p align="center"> <a href="https://github.com/sirixdb/sirix/actions"><img src="https://github.com/sirixdb/sirix/workflows/Java%20CI%20with%20Gradle/badge.svg" alt="CI Build Status"/></a> <a href="https://search.maven.org/search?q=g:io.sirix"><img src="https://img.shields.io/maven-central/v/io.sirix/sirix-core.svg" alt="Maven Central"/></a> <a href="http://makeapullrequest.com"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs Welcome"/></a> <a href="#contributors-"><img src="https://img.shields.io/badge/all_contributors-23-orange.svg?style=flat-square" alt="All Contributors"/></a> </p> <p align="center"> <a href="https://sirix.io/docs/index.html"><b>Documentation</b></a> · <a href="https://discord.gg/yC33wVpv7t"><b>Discord</b></a> · <a href="https://sirix.discourse.group/"><b>Forum</b></a> · <a href="https://github.com/sirixdb/sirixdb-web-gui"><b>Web UI</b></a> </p>

The Problem

You update a row in your database. The old value is gone.

To get history, you bolt on audit tables, change-data-capture, or event sourcing. Now you have two systems: one for current state, one for history. Querying the past means replaying events or scanning logs. Your "simple" audit requirement just became an infrastructure project.

Git solves this for files—but you can't query a Git repository. Event sourcing preserves history—but reconstructing past state means replaying from the beginning.

The Solution

SirixDB is a database where every revision is a first-class citizen. Not an afterthought. Not a log you replay.

// Query revision 1 - instant, not reconstructed
session.beginNodeReadOnlyTrx(1)

// Query by timestamp - which revision was current at 3am last Tuesday?
session.beginNodeReadOnlyTrx(Instant.parse("2024-01-15T03:00:00Z"))

// Both return the same thing: a readable snapshot, as fast as querying "now"

This works because SirixDB uses structural sharing: when you modify data, only changed pages are written. Unchanged data is shared between revisions via copy-on-write. Revision 1000 doesn't store 1000 copies—it stores the current state plus pointers to shared history.

The result:

  • Storage: O(changes per revision), not O(total size × revisions)
  • Read any page from any revision: O(N) page fragment reads, where N is the configurable snapshot window (default 3)
  • No event replay, no log scanning—direct page access

Bitemporal: Two Kinds of Time

Most databases (if they version at all) track one timeline: when data was written. SirixDB tracks two:

  • Transaction time: When was this committed? (system-managed)
  • Valid time: When was this true in the real world? (user-managed)

Why does this matter?

January 15: You record "Price = $100, valid from January 1"
January 20: You discover the price was actually $95 on January 1

After correction, you can ask:
  "What did we THINK the price was on Jan 16?"  →  $100 (transaction time)
  "What WAS the price on Jan 1?"                →  $95  (valid time)

Both questions have correct, different answers. Without bitemporal support, the correction destroys the audit trail.

Core Properties

  • Append-only storage: Data is never overwritten. New revisions write to new locations.
  • Structural sharing: Unchanged pages and nodes are referenced between revisions via copy-on-write.
  • Snapshot isolation: Readers see a consistent view; one writer per resource.
  • Embeddable: Single JAR, no external dependencies. Or run as REST server.

How Versioning Works

SirixDB stores data in a persistent tree structure where revisions share unchanged pages and nodes. Traditional databases overwrite data in place and use write-ahead logs for recovery. SirixDB takes a different approach:

Physical Storage: Append-Only Log

All data is written sequentially to an append-only log. Nothing is ever overwritten.

Physical Log (append-only, sequential writes)
┌────────────────────────────────────────────────────────────────────────┐
│ [R1:Root] [R1:P1] [R1:P2] [R2:Root] [R2:P1'] [R3:Root] [R3:P2'] ...    │
└────────────────────────────────────────────────────────────────────────┘
     t=0      t=1     t=2      t=3      t=4       t=5       t=6    → time

Logical Structure: Persistent Trie

Each revision has a root node in a trie. Unchanged pages are shared via references.

Revision Roots                    Page Trie (persistent, copy-on-write)
      │
      ▼
   [Rev 3] ─────────────────┬─────────────────┐
      │                     │                 │
   [Rev 2] ────────┬────────┤                 │
      │            │        │                 │
   [Rev 1] ───┐    │        │                 │
              │    │        │                 │
              ▼    ▼        ▼                 ▼
           [Root₁][Root₂][Root₃]          [Pages...]
              │      │      │
              ▼      ▼      ▼
            ┌───────────────────────────────────────┐
            │           Shared Page Pool            │
            │  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐      │
            │  │ P1  │ │ P1' │ │ P2  │ │ P2' │ ...  │
            │  └──▲──┘ └──▲──┘ └──▲──┘ └──▲──┘      │
            │     │      │       │       │          │
            │   R1,R2    R3    R1,R3    R2          │
            │  (shared)       (shared)              │
            └───────────────────────────────────────┘

Page Versioning Strategies

SirixDB supports multiple strategies for storing page versions, configurable per resource:

┌──────────────────────────────────────────────────────────────────────────────┐
│ FULL: Each page stores complete data                                         │
│                                                                              │
│   Rev1: [████████]  Rev2: [████████]  Rev3: [████████]                       │
│         (full)            (full)            (full)                           │
│                                                                              │
│   + Fast reads (no reconstruction)                                           │
│   - High storage cost                                                        │
├──────────────────────────────────────────────────────────────────────────────┤
│ INCREMENTAL: Diffs from previous revision + periodic full snapshots          │
│                                                                              │
│   Rev1: [████████]  Rev2: [Δ←1]  Rev3: [Δ←2]  Rev4: [████████]              │
│         (full)       (diff)       (diff)       (full snapshot)              │
│                                                                              │
│   Rev5: [Δ←4]  Rev6: [Δ←5]  Rev7: [████████]  ...                           │
│         (diff)       (diff)       (full snapshot)                           │
│                                                                              │
│   Full snapshot written every N revisions (N = configurable window)          │
│   + Bounded read cost (max N-1 diffs between full snapshots)                 │
│   + Compact diffs (each diff is against previous revision only)              │
│   - Read cost grows linearly within each window                              │
├──────────────────────────────────────────────────────────────────────────────┤
│ DIFFERENTIAL: Diffs from reference snapshot + periodic full snapshots        │
│                                                                              │
│   Rev1: [████████]  Rev2: [Δ←1]  Rev3: [████████]  Rev4: [Δ←3]              │
│         (full)       (diff)       (full snapshot)    (diff)                 │
│                                                                              │
│   Rev5: [Δ←3]  Rev6: [████████]  Rev7: [Δ←6]  ...                           │
│         (diff)       (full snapshot)    (diff)                              │
│                                                                              │
│   Full snapshot every N revisions; diffs reference the last snapshot         │
│   + Bounded read cost (max 1 diff to apply)                                  │
│   - Diffs grow larger as they diverge from last snapshot                     │
├──────────────────────────────────────────────────────────────────────────────┤
│ SLIDING SNAPSHOT: Incremental diffs within a sliding window of size N       │
│                                                                              │
│   Rev1: [████████]  Rev2: [Δ←1]  Rev3: [Δ←2]  Rev4: [Δ←3 + R1 copy]        │
│         (full)       (diff)       (diff)       (diff + out-of-window        │
│                                                 records from Rev1)          │
│         ◄──────── window N=3 ──────────►                                    │
│                      ◄──────── window N=3 ──────────►                       │
│                                                                              │
│   As the window slides forward, records from pages that fall out of         │
│   the window are copied into the newest diff page, ensuring any             │
│   revision can be reconstructed from at most N page fragments.              │
│                                                                              │
│   + Bounded read cost (max N page fragments to combine)                      │
│   + No unbounded diff growth (out-of-window data is always rescued)         │
│   = Best balance of storage vs read performance                              │
└──────────────────────────────────────────────────────────────────────────────┘

When you modify data:

  1. Only the affected pages are copied and modified (copy-on-write)
  2. Unchanged pages are referenced from the new revision
  3. The old revision remains

Related Skills

View on GitHub
GitHub Stars1.2k
CategoryData
Updated12h ago
Forks248

Languages

Java

Security Score

100/100

Audited on Mar 19, 2026

No findings