百科.dev
全部条目AI 编程趋势榜开源项目技术资讯提交条目
登录
< 返回工具列表
S

sirix

> 编程语言
开源

SirixDB 是一个可嵌入、双时段、只能追加的数据库系统和事件存储库,存储不可变的轻量级快照。它保存每个对象的完整历史,并支持事务性的数据修改。

1.2K stars0 点赞0 次浏览
访问官网GitHub

工具介绍

SirixDB 是一个可嵌入、双时段、只能追加的数据库系统和事件存储库,存储不可变的轻量级快照。它保存每个对象的完整历史,并支持事务性的数据修改。

SirixDB - The Bitemporal Database System

Query any revision as fast as the latest

Live Demo · Why SirixDB · Docs · Website · Discord · Forum · Web UI

Status: 1.0.0-beta — usable today and actively developed. The on-disk format and public APIs are stabilizing toward a 1.0 release; feedback from real use is exactly what we're looking for.


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 with sub-page versioning. Unchanged pages are shared between revisions via copy-on-write — and versioning continues below the page: a commit writes page fragments containing only the changed records, and the sliding-snapshot algorithm guarantees any page is reconstructible from at most N fragments. Block-level COW (ZFS-style) copies a whole page when one byte in it changes; delta-based systems make reads replay ever-growing diff chains. SirixDB pays neither cost. Revision 1000 doesn't store 1000 copies—it stores the current state plus pointers to shared history.

The result:

  • Storage: O(changed records per revision), not O(total size × revisions) — and not O(changed pages) either
  • 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: a single self-contained JAR (third-party dependencies shaded in) — embed it in-process, or run it as a REST server.

Performance

History is not a tax. Reading an old revision is a direct page lookup, not a replay — any revision reads as fast as the latest, and session-open cost is flat regardless of how much history exists (0.18 ms at 10,000 revisions).

A few measured receipts (we benchmark against ourselves and publish the losses, methodology in WHY-SIRIX.md and the linked comparison docs):

  • Concurrent reads under a committing writer — on a 12,800-revision database, 16 reader threads + 1 writer over REST went from 361 to 11,198 reads/s with reader p99 334 ms → 4.8 ms and zero errors, after fixing a page-lifecycle bug and an O(history) open cost (BENCHMARKS.md). The aged database now outruns the pre-fix fresh one.
  • Semantic diffs — node-level insert/update/delete between two revisions (with stable keys) in ~0.3 ms, not a text diff.
  • Analytics — the vectorized, fail-closed execution path runs the group-by/aggregate suite head-to-head with DuckDB 1.5.2 at 100M records: ahead on three of nine query shapes, within 1.1–2.5× on all others except count-distinct (~4.2×); the GraalVM native binary runs 7–17× faster than the JVM on warm analytical queries (COMPARISON_DUCKDB.md, NATIVE_IMAGE.md). The standalone query engine, brackit, beats jq several-fold on its own benchmark suite.
  • Honest loss vs PostgreSQL (COMPARISON_POSTGRES.md, re-run 2026-07) — PostgreSQL with a trigger-maintained history table still wins raw small-document ingest (1,093 vs 169 durable commits/s same-machine, both verified fsync-bound) and total storage (~2×, down from ~3× after recent storage work). SirixDB wins semantic diffs (0.58 ms node-level patch vs a top-level-only compare), now ties history listing, and offers sub-document time travel PostgreSQL doesn't have. Durability settings verified equivalent before measuring; the fsync floor of the box is published alongside the numbers.

Every fast path is fail-closed: a kernel only runs when the optimizer can prove the query's shape matches what it emits, and a differential suite requires byte-identical output against the general path. Wrong-but-fast is a bug class, not a setting.

How Versioning Works

Logical page structure of a resource with 3 revisions — read-only transactions (RTX) can open any revision, while a single write transaction (WTX) appends to the latest.

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.

  [Rev 1]           [Rev 2]         [Rev 3]
     │                 │               │
     ▼                 ▼               ▼
  [Root₁]           [Root₂]         [Root₃]
   │   │             │   │           │   │
   │   └──────────┐  │   └────────┐  │   └─────────┐
   ▼              ▼  ▼            ▼  ▼             ▼
┌──────┐        ┌──────┐        ┌──────┐        ┌──────┐
│  P1  │        │  P2  │        │ P1'  │        │ P2'  │
└──────┘        └──────┘        └──────┘        └──────┘
 Rev 1          Rev 1+2         Rev 2+3          Rev 3
                (shared)        (shared)

Rev 2 modified only P1 (writing P1') and still shares P2 with Rev 1; Rev 3 modified only P2 (writing P2') and still shares P1' with Rev 2 — matching the physical log above.

Page Versioning Strategies

How page versions are stored is configurable per resource:

Strategy Page fragments per read Write cost Notes
FULL 1 full page per change fastest reads, largest storage
INCREMENTAL up to N−1 diffs small diffs + periodic full snapshot write spikes at snapshot points
DIFFERENTIAL 2 diffs grow between snapshots bounded reads, uneven writes
SLIDING_SNAPSHOT (default) ≤ N (default 3) small diffs, out-of-window records rescued into the newest fragment no full-snapshot spikes, best balance

Modifying data copies only the affected pages (copy-on-write); unchanged pages are referenced from the new revision, and the old revision remains intact and queryable. Storage cost is O(changed records) per revision. Read cost: opening a revision is O(1) by number, O(log R) by timestamp; each page read combines at most N fragments. The full strategy walkthrough is in docs/ARCHITECTURE.md.

Quick Start

Platform support: Linux, macOS, and Windows are CI-tested on every pull request. Linux additionally gets native binaries and the Docker images; known limitations are listed in docs/KNOWN_LIMITATIONS.md.

Using the CLI (Native Binaries)

SirixDB provides two CLI tools, both available as instant-startup native binaries:

Binary Module Description
sirix-cli sirix-kotlin-cli Full-featured CLI for database operations
sirix-shell sirix-query Interactive JSONiq/XQuery shell

Build native binaries with GraalVM:

# Build both CLIs as native binaries (requires GraalVM with native-image)
./gradlew :sirix-kotlin-cli:nativeCompile  # produces: sirix-cli
./gradlew :sirix-query:nativeCompile       # produces: sirix-shell

# Or run via JAR
./gradlew :sirix-kotlin-cli:run --args="-l /tmp/mydb create"

The whole create/update/time-travel loop from the shell (-l names the database path):

sirix-cli -l /tmp/mydb create json -r myresource -d '{"name": "Alice", "role": "admin"}'
sirix-cli -l /tmp/mydb update -r myresource '{"team": "engineering"}' -im as-first-child
sirix-cli -l /tmp/mydb query  -r myresource '$$.name'   # $$ is the document root
sirix-cli -l /tmp/mydb query  -r myresource -rev 1      # query a previous revision
sirix-cli -l /tmp/mydb resource-history myresource

sirix-shell is a JSONiq/XQuery REPL over the same data (jn:store(...), jn:doc(...) — multi-line queries, empty line executes, Control-D exits).

Using the REST API

Start SirixDB and its bundled OAuth2 provider (Keycloak) with Docker:

git clone https://github.com/sirixdb/sirix.git
cd sirix
docker compose up

This starts the REST server on http://localhost:9443 plus a Keycloak instance seeded with demo users admin/admin and viewer/viewer. All endpoints are OAuth2-protected:

TOKEN=$(curl -s -X POST http://localhost:9443/token \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin","grant_type":"password"}' | jq -r .access_token)

curl -X PUT http://localhost:9443/mydb/myresource \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"Alice","role":"admin"}'

curl http://localhost:9443/mydb/myresource -H "Authorization: Bearer $TOKEN"

For local development, auth.mode=none (docker run -e SIRIX_AUTH_MODE=none ...) skips Keycloak entirely (loud warning, admin-for-all). → docs/QUICKSTART.md walks the whole loop — create, query, commit, time-travel read, diff — with verified commands; the REST API documentation has the full endpoint reference.

Security note: the bundled Keycloak realm, demo users, client secret, and self-signed TLS certificate are for local development only — see docs/operations.md before any public deployment.

Using the MCP Server (for AI Agents)

SirixDB ships a native Model Context Protocol server, so AI agents (Claude, Cursor, Windsurf, or any MCP client) can talk to it directly. Because every revision is copy-on-write, agents get O(1) disposable snapshots, time-travel reads, and structural diffs for free — branch, experime

Issues· 0 开放

查看全部 Issues在 GitHub 打开

暂无开放 Issues,或尚未同步最近议题。

> 标签

Javacomparisoncoroutinesdiffdiff-algorithm

暂无评论,来聊聊你的看法吧

> 工具信息

发布日期2026年8月1日
最后更新2026年9月17日
分类编程语言
定价开源

> 相关工具

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言