Skip to content

Commit 849997e

Browse files
authored
Merge pull request #5 from linksplatform/issue-4-476fa2392aa2
feat: use official spacetimedb-sdk 2.0 with real SpacetimeDB server
2 parents 32aafd0 + 4c25e63 commit 849997e

112 files changed

Lines changed: 13413 additions & 734 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/rust-benchmark.yml

Lines changed: 89 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ name: Rust Benchmark
33
on:
44
push:
55
branches: [main, master]
6-
paths: ['rust/**', '.github/workflows/rust-benchmark.yml']
6+
paths: ['rust/**', 'spacetime-module/**', '.github/workflows/rust-benchmark.yml']
77
pull_request:
88
branches: [main, master]
9-
paths: ['rust/**', '.github/workflows/rust-benchmark.yml']
9+
paths: ['rust/**', 'spacetime-module/**', '.github/workflows/rust-benchmark.yml']
1010

1111
env:
1212
CARGO_TERM_COLOR: always
@@ -20,38 +20,74 @@ jobs:
2020
test:
2121
name: Test (${{ matrix.os }})
2222
runs-on: ${{ matrix.os }}
23+
timeout-minutes: 360
2324
strategy:
2425
fail-fast: false
2526
matrix:
26-
os: [ubuntu-latest, macos-latest, windows-latest]
27+
os: [ubuntu-latest, macos-latest]
2728
steps:
2829
- uses: actions/checkout@v4
2930

30-
- name: Setup Rust (nightly-2022-08-22)
31+
- name: Setup Rust (nightly)
3132
uses: dtolnay/rust-toolchain@master
3233
with:
33-
toolchain: nightly-2022-08-22
34+
toolchain: nightly
3435
components: rustfmt, clippy
36+
targets: wasm32-unknown-unknown
3537

3638
- name: Cache cargo registry
37-
uses: actions/cache@v4
39+
uses: Swatinem/rust-cache@v2
3840
with:
39-
path: |
40-
~/.cargo/registry
41-
~/.cargo/git
42-
rust/target
43-
key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }}
44-
restore-keys: |
45-
${{ runner.os }}-cargo-
41+
workspaces: rust -> target
42+
cache-on-failure: "true"
4643

4744
- name: Check formatting
4845
run: cargo fmt --all -- --check
4946

5047
- name: Run Clippy
5148
run: cargo clippy --all-targets
5249

50+
- name: Install SpacetimeDB CLI
51+
shell: bash
52+
run: |
53+
curl -sSf https://install.spacetimedb.com | sh -s -- -y
54+
echo "$HOME/.local/bin" >> $GITHUB_PATH
55+
working-directory: .
56+
57+
- name: Build SpacetimeDB module (WASM)
58+
run: cargo build --release --target wasm32-unknown-unknown
59+
working-directory: rust/spacetime-module
60+
61+
- name: Start SpacetimeDB server
62+
shell: bash
63+
run: |
64+
spacetime start &
65+
echo "Waiting for SpacetimeDB server to be ready..."
66+
for i in $(seq 1 30); do
67+
if curl -sf http://localhost:3000/ > /dev/null 2>&1; then
68+
echo "SpacetimeDB server is ready"
69+
break
70+
fi
71+
sleep 1
72+
done
73+
working-directory: .
74+
75+
- name: Publish SpacetimeDB module
76+
shell: bash
77+
run: |
78+
spacetime publish \
79+
--server http://localhost:3000 \
80+
--bin-path target/wasm32-unknown-unknown/release/spacetime_module.wasm \
81+
--yes \
82+
benchmark-links
83+
working-directory: rust/spacetime-module
84+
5385
- name: Run tests
54-
run: cargo test --release
86+
env:
87+
SPACETIMEDB_URI: http://localhost:3000
88+
SPACETIMEDB_DB: benchmark-links
89+
# Run tests sequentially to avoid parallel interference with shared SpacetimeDB state.
90+
run: cargo test -- --test-threads=1
5591

5692
benchmark:
5793
name: Benchmark
@@ -64,10 +100,11 @@ jobs:
64100
fetch-depth: 0
65101
token: ${{ secrets.GITHUB_TOKEN }}
66102

67-
- name: Setup Rust (nightly-2022-08-22)
103+
- name: Setup Rust (nightly)
68104
uses: dtolnay/rust-toolchain@master
69105
with:
70-
toolchain: nightly-2022-08-22
106+
toolchain: nightly
107+
targets: wasm32-unknown-unknown
71108

72109
- name: Setup Python
73110
uses: actions/setup-python@v5
@@ -78,15 +115,41 @@ jobs:
78115
run: pip install matplotlib numpy
79116

80117
- name: Cache cargo registry
81-
uses: actions/cache@v4
118+
uses: Swatinem/rust-cache@v2
82119
with:
83-
path: |
84-
~/.cargo/registry
85-
~/.cargo/git
86-
rust/target
87-
key: ubuntu-cargo-bench-${{ hashFiles('rust/Cargo.lock') }}
88-
restore-keys: |
89-
ubuntu-cargo-bench-
120+
workspaces: rust -> target
121+
cache-on-failure: "true"
122+
123+
- name: Install SpacetimeDB CLI
124+
run: |
125+
curl -sSf https://install.spacetimedb.com | sh -s -- -y
126+
echo "$HOME/.local/bin" >> $GITHUB_PATH
127+
working-directory: .
128+
129+
- name: Build SpacetimeDB module (WASM)
130+
run: cargo build --release --target wasm32-unknown-unknown
131+
working-directory: rust/spacetime-module
132+
133+
- name: Start SpacetimeDB server
134+
run: |
135+
spacetime start &
136+
for i in $(seq 1 30); do
137+
if curl -sf http://localhost:3000/ > /dev/null 2>&1; then
138+
echo "SpacetimeDB server is ready"
139+
break
140+
fi
141+
sleep 1
142+
done
143+
working-directory: .
144+
145+
- name: Publish SpacetimeDB module
146+
run: |
147+
spacetime publish \
148+
--server http://localhost:3000 \
149+
--bin-path target/wasm32-unknown-unknown/release/spacetime_module.wasm \
150+
--yes \
151+
benchmark-links
152+
working-directory: rust/spacetime-module
90153

91154
- name: Build benchmark
92155
run: cargo build --release
@@ -95,6 +158,8 @@ jobs:
95158
env:
96159
BENCHMARK_LINK_COUNT: 1000
97160
BACKGROUND_LINK_COUNT: 3000
161+
SPACETIMEDB_URI: http://localhost:3000
162+
SPACETIMEDB_DB: benchmark-links
98163
run: cargo bench --bench bench -- --output-format bencher | tee out.txt
99164

100165
- name: Generate charts

README.md

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Benchmark comparing [SpacetimeDB 2](https://github.com/clockworklabs/SpacetimeDB) vs [Doublets](https://github.com/linksplatform/doublets-rs) performance for basic CRUD operations with links.
44

5-
SpacetimeDB is benchmarked via its SQLite storage backend (the same engine SpacetimeDB 2 uses internally). Doublets is benchmarked with its in-memory (volatile) storage variants.
5+
SpacetimeDB is benchmarked using the official `spacetimedb-sdk` Rust crate connected to a running SpacetimeDB 2.0 server. Doublets is benchmarked with both in-memory (volatile) and file-backed (non-volatile) storage variants.
66

77
## Benchmark Operations
88

@@ -18,16 +18,18 @@ SpacetimeDB is benchmarked via its SQLite storage backend (the same engine Space
1818

1919
## Backends Benchmarked
2020

21-
### SpacetimeDB (SQLite backend)
22-
- **SpacetimeDB Memory**in-memory SQLite with B-tree indexes on `id`, `source`, `target`
21+
### SpacetimeDB
22+
- **SpacetimeDB**connects to a running SpacetimeDB 2.0 server via the official `spacetimedb-sdk` Rust crate; uses the `links` table defined in the `spacetime-module` WebAssembly module
2323

24-
SpacetimeDB 2 uses SQLite as its underlying data store for persistent tables. This benchmark measures the performance of SpacetimeDB's storage layer (SQLite + WAL mode) for link CRUD operations.
24+
The benchmark uses the official SpacetimeDB Rust client SDK, calling reducers to mutate data and reading from the client-side subscription cache.
2525

2626
### Doublets
2727
- **Doublets United Volatile** — in-memory store; links stored as contiguous `(index, source, target)` units
2828
- **Doublets Split Volatile** — in-memory store; separate data and index memory regions
29+
- **Doublets United NonVolatile** — file-backed store; same contiguous layout but memory-mapped to a single file; data persists to disk
30+
- **Doublets Split NonVolatile** — file-backed store; separate data and index files; both memory-mapped; data persists to disk
2931

30-
Doublets is a custom in-memory doublet link data structure with O(1) lookup by id and O(log n + k) traversal by source/target using balanced tree indexes.
32+
Doublets uses a recursive-less size-balanced tree for O(1) lookup by id and O(log n + k) traversal by source/target. The file-backed variants use `memmap2` for memory-mapped file I/O, flushing changes to disk on drop via `sync_all()`. See [`rust/doublets-patched/PATCHES.md`](rust/doublets-patched/PATCHES.md) for why a local patched copy is used instead of the published crates.io version.
3133

3234
## Benchmark Background
3335

@@ -44,15 +46,17 @@ Each benchmark iteration pre-populates the database with background links to sim
4446

4547
## Operation Complexity
4648

47-
| Operation | SpacetimeDB (SQLite) | Doublets United | Doublets Split |
49+
| Operation | SpacetimeDB | Doublets United | Doublets Split |
4850
|---|---|---|---|
49-
| Create | O(log n) + disk I/O | O(log n) | O(log n) |
50-
| Delete | O(log n) + disk I/O | O(log n) | O(log n) |
51-
| Update | O(log n) + disk I/O | O(log n) | O(log n) |
52-
| Query All | O(n) + disk I/O | O(n) | O(n) |
53-
| Query by Id | O(log n) | O(1) | O(1) |
54-
| Query by Source | O(log n + k) | O(log n + k) | O(log n + k) |
55-
| Query by Target | O(log n + k) | O(log n + k) | O(log n + k) |
51+
| Create | O(log n) + network | O(log n) | O(log n) |
52+
| Delete | O(log n) + network | O(log n) | O(log n) |
53+
| Update | O(log n) + network | O(log n) | O(log n) |
54+
| Query All | O(n) cache read | O(n) | O(n) |
55+
| Query by Id | O(n) cache scan | O(1) | O(1) |
56+
| Query by Source | O(n) cache scan | O(log n + k) | O(log n + k) |
57+
| Query by Target | O(n) cache scan | O(log n + k) | O(log n + k) |
58+
59+
The algorithmic complexity is the same for volatile and non-volatile Doublets variants. The non-volatile variants have additional I/O overhead due to memory-mapped file writes (flushed to disk on drop).
5660

5761
## Related Benchmarks
5862

@@ -64,18 +68,33 @@ Each benchmark iteration pre-populates the database with background links to sim
6468

6569
### Prerequisites
6670

67-
- Rust nightly-2022-08-22 (see `rust/rust-toolchain.toml`)
71+
- Rust nightly (see `rust/rust-toolchain.toml`)
72+
- SpacetimeDB CLI: `curl -sSf https://install.spacetimedb.com | sh`
73+
74+
### Start SpacetimeDB server and publish module
75+
76+
```bash
77+
# Start the local SpacetimeDB server
78+
spacetime start &
79+
80+
# Build and publish the links module
81+
spacetime build --project-path spacetime-module
82+
spacetime publish --project-path spacetime-module benchmark-links
83+
```
6884

6985
### Run benchmarks
7086

7187
```bash
7288
cd rust
7389

7490
# Full benchmark run (1000 links, 3000 background)
75-
cargo bench --bench bench -- --output-format bencher | tee out.txt
91+
SPACETIMEDB_URI=http://localhost:3000 SPACETIMEDB_DB=benchmark-links \
92+
cargo bench --bench bench -- --output-format bencher | tee out.txt
7693

7794
# Quick benchmark run (CI scale)
78-
BENCHMARK_LINK_COUNT=10 BACKGROUND_LINK_COUNT=100 cargo bench --bench bench
95+
BENCHMARK_LINK_COUNT=10 BACKGROUND_LINK_COUNT=100 \
96+
SPACETIMEDB_URI=http://localhost:3000 SPACETIMEDB_DB=benchmark-links \
97+
cargo bench --bench bench
7998

8099
# Generate charts from results
81100
python3 out.py
@@ -85,7 +104,7 @@ python3 out.py
85104

86105
```bash
87106
cd rust
88-
cargo test --release
107+
SPACETIMEDB_URI=http://localhost:3000 SPACETIMEDB_DB=benchmark-links cargo test
89108
```
90109

91110
### Code quality
@@ -100,14 +119,21 @@ cargo clippy --all-targets
100119

101120
```
102121
.
122+
├── spacetime-module/ # SpacetimeDB WASM module (links table + reducers)
123+
│ ├── Cargo.toml
124+
│ └── src/
125+
│ └── lib.rs # Table definition and reducers using `spacetimedb` crate
103126
├── rust/
104127
│ ├── Cargo.toml # Package manifest with pinned dependencies
128+
│ ├── doublets-patched/ # Local patches to doublets-rs for modern nightly compatibility
129+
│ │ └── PATCHES.md # Documents why patches are needed and what was changed
105130
│ ├── rust-toolchain.toml # Pinned Rust nightly toolchain
106131
│ ├── rustfmt.toml # Rust formatting config
107132
│ ├── out.py # Chart generation script (matplotlib)
108133
│ ├── src/
109134
│ │ ├── lib.rs # Links trait, constants (BENCHMARK_LINK_COUNT, BACKGROUND_LINK_COUNT)
110-
│ │ ├── spacetimedb_impl.rs # SpacetimeDB SQLite client (implements Links)
135+
│ │ ├── module_bindings/ # spacetimedb-sdk client bindings for the links module
136+
│ │ ├── spacetimedb_impl.rs # SpacetimeDB SDK client (implements Links)
111137
│ │ ├── doublets_impl.rs # Doublets store adapters (implements Links)
112138
│ │ ├── exclusive.rs # Exclusive<T> wrapper for interior mutability
113139
│ │ ├── fork.rs # Fork<B> — benchmark iteration isolation
@@ -116,7 +142,7 @@ cargo clippy --all-targets
116142
│ │ ├── spacetimedb_benched.rs # Benched impl for SpacetimeDB
117143
│ │ └── doublets_benched.rs # Benched impls for Doublets stores
118144
│ └── benches/
119-
│ └── bench.rs # Criterion benchmark suite (7 operations x 3 backends)
145+
│ └── bench.rs # Criterion benchmark suite (7 operations x 5 backends)
120146
└── .github/
121147
└── workflows/
122148
└── rust-benchmark.yml # CI: test on 3 OS + benchmark + chart generation

changelog.d/20260224_spacetimedb_vs_doublets_benchmark.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@ bump: minor
44

55
### Added
66

7-
- **SpacetimeDB 2 vs Doublets benchmark** (`rust/`): New Rust benchmark suite comparing SpacetimeDB's SQLite backend against Doublets in-memory link stores for basic CRUD operations, following best practices from the Neo4j and PostgreSQL comparison benchmarks.
7+
- **SpacetimeDB 2 vs Doublets benchmark** (`rust/`): New Rust benchmark suite comparing SpacetimeDB 2.0 against Doublets in-memory link stores for basic CRUD operations.
88

99
- **7 benchmark operations**: Create, Delete, Update, Query All, Query by Id, Query by Source, Query by Target
10-
- **3 backends**: SpacetimeDB Memory (SQLite/WAL), Doublets United Volatile, Doublets Split Volatile
10+
- **3 backends**: SpacetimeDB 2.0 (via official `spacetimedb-sdk` Rust crate), Doublets United Volatile, Doublets Split Volatile
1111
- **Configurable scale**: `BENCHMARK_LINK_COUNT` and `BACKGROUND_LINK_COUNT` environment variables
1212
- **Criterion harness**: Uses criterion 0.3.6 with custom `iter_custom` timing to exclude setup/teardown from measurements
1313
- **Fork/unfork lifecycle**: Each iteration starts from a clean database state with pre-populated background links
1414

15-
- **`rust/src/lib.rs`**: `Links` trait as the shared interface for both SpacetimeDB and Doublets backends; `Benched` trait for benchmark lifecycle management.
15+
- **`spacetime-module/`**: SpacetimeDB WebAssembly module using the official `spacetimedb` Rust crate, defining the `links` table and CRUD reducers.
1616

17-
- **`rust/src/spacetimedb_impl.rs`**: SpacetimeDB SQLite client implementing the `Links` trait using the same schema and indexes that SpacetimeDB 2 uses internally.
17+
- **`rust/src/module_bindings/`**: Client-side SDK bindings for the links module (equivalent to `spacetime generate --lang rust` output).
18+
19+
- **`rust/src/spacetimedb_impl.rs`**: SpacetimeDB 2.0 implementation using the official `spacetimedb-sdk` Rust crate. Connects to a running SpacetimeDB server, subscribes to the links table, and calls reducers for CRUD operations.
1820

1921
- **`rust/src/doublets_impl.rs`**: Doublets store adapters implementing the `Links` trait for both United Volatile and Split Volatile storage layouts.
2022

2123
- **`rust/benches/bench.rs`**: Criterion benchmark suite with 21 benchmark functions (7 operations × 3 backends).
2224

2325
- **`rust/out.py`**: Python script for generating comparison charts (linear and log scale PNG) and a Markdown results table from benchmark output.
2426

25-
- **`.github/workflows/rust-benchmark.yml`**: GitHub Actions CI workflow that runs tests on Ubuntu/macOS/Windows and generates benchmark charts on push to main.
27+
- **`.github/workflows/rust-benchmark.yml`**: GitHub Actions CI workflow that installs the SpacetimeDB CLI, starts a local server, publishes the module, runs tests on Ubuntu/macOS/Windows, and generates benchmark charts on push to main.
2628

2729
- **Updated `README.md`**: Benchmark description, operation complexity table, and usage instructions.

0 commit comments

Comments
 (0)