Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
7e311cd
feat(storage): add the Postgres-to-LMDB migration seam
chappie-daemon Nov 12, 2026
3448639
feat(storage): read the migration's source from Postgres, one keyset …
chappie-daemon Nov 12, 2026
98d94d6
feat(storage): write the migration's rows into LMDB exactly as the so…
chappie-daemon Nov 12, 2026
f5bddc9
feat(cli): add the migrate pg-to-lmdb subcommand with a resumable man…
chappie-daemon Nov 12, 2026
94edd8f
test(cli): pin the migrate command's copy, resume, verify and throughput
chappie-daemon Nov 12, 2026
fecfdbf
test(storage): pin the seam's canonical projection and key bytes
chappie-daemon Nov 12, 2026
7bd1aef
test(storage): run the migration against the CI Postgres
chappie-daemon Nov 12, 2026
a1e2b8b
docs: record ADR 0012 for the Postgres-to-LMDB migration
chappie-daemon Nov 12, 2026
aa8660d
chore: add the migration tool's empty changeset
chappie-daemon Nov 12, 2026
71ef2a1
test(cli): state AC8's liveness split where the assertion reads
chappie-daemon Nov 12, 2026
b93dc9e
fix(storage): page invoices on their text id
chappie-daemon Nov 12, 2026
dae4d0e
feat(cli): refuse a target that already holds rows
chappie-daemon Nov 12, 2026
8c26b70
test(cli): measure the run against a target that sleeps
chappie-daemon Nov 12, 2026
a1c3583
fix(cli): refuse a manifest of another format
chappie-daemon Nov 12, 2026
11afb3e
fix(cli): refuse a batch size of zero in both entry points
chappie-daemon Nov 12, 2026
08baaaf
fix(cli): verify without creating a missing store
chappie-daemon Nov 12, 2026
73abd6d
docs: run the migration target in the parity instructions
chappie-daemon Nov 12, 2026
592add5
test(storage): page the invite-code cursor too
chappie-daemon Nov 12, 2026
2be1e8b
feat(cli): write the manifest before the first batch
chappie-daemon Nov 12, 2026
2d6b279
feat(storage): open an existing store read-only
chappie-daemon Nov 12, 2026
bb508d1
fix(cli): verify a store without creating one
chappie-daemon Nov 12, 2026
b43b6ee
docs: record the fresh manifest and the read-only verify
chappie-daemon Nov 12, 2026
54673c4
style: rustfmt the read-only opener and the resume test
chappie-daemon Nov 12, 2026
51d6bf9
refactor(storage): name the store's data file beside its directory
chappie-daemon Nov 12, 2026
6e63972
fix(cli): refuse a manifest that does not describe the nine tables
chappie-daemon Nov 12, 2026
ba41d97
test(cli): assert the seam's replaceable, outbox and status index writes
chappie-daemon Nov 12, 2026
aed4ecd
style: rustfmt the manifest check
chappie-daemon Nov 12, 2026
5abbba6
feat(cli): refuse a manifest that records progress over a missing store
chappie-daemon Nov 12, 2026
8d90867
docs: record the refusal a progressed manifest needs
chappie-daemon Nov 12, 2026
2bd48d9
fix(migrate): make the manifest durable and the checksum add carry
chappie-daemon Nov 12, 2026
6307de2
fix(lmdb): commit the read transaction that opens the databases
chappie-daemon Nov 12, 2026
f64fe2a
fix(migrate): ask about the store by its file, and pin the checksum
chappie-daemon Nov 12, 2026
255a09a
fix(migrate): refuse a store that lost the rows the manifest counts
chappie-daemon Nov 12, 2026
f34d762
fix(migrate): keep the manifest private and refuse a redirectable target
chappie-daemon Nov 12, 2026
8d80d97
fix(migrate): name the source, the store and the way back
chappie-daemon Nov 12, 2026
f5b720d
fix(migrate): drop the query string too when naming the source
chappie-daemon Nov 12, 2026
be82e5e
fix(migrate): name only the host and database in a source error
chappie-daemon Nov 12, 2026
201883d
fix(migrate): read the master only, and own the store directory
chappie-daemon Nov 12, 2026
2e1627f
fix(migrate): refuse a target owned by another user
chappie-daemon Nov 12, 2026
0fc8bca
test(migrate): pick a uid that is not the directory's owner
chappie-daemon Nov 12, 2026
7c4e287
fix(migrate): the data file's own metadata, and a source that answers…
chappie-daemon Nov 12, 2026
db16388
fix(storage): the read-only opener composes the store path through st…
chappie-daemon Nov 12, 2026
32df3c7
fix(migrate): one bounded connection attempt, and refuse a URI withou…
chappie-daemon Nov 12, 2026
95bcbd5
fix(migrate): refuse only the shape that breaks, and echo nothing
chappie-daemon Nov 12, 2026
b009127
test(migrate): pin the one shape the check refuses on purpose
chappie-daemon Nov 12, 2026
bb06dcc
fix(migrate): read the URI the way sqlx does, and say what the gate r…
chappie-daemon Nov 12, 2026
cfe1b23
fix(storage): build with no features, which is what CI checks
chappie-daemon Nov 12, 2026
3d4dc4a
docs(migrate): name the schemes the gate accepts, not bare URIs
chappie-daemon Nov 12, 2026
0066049
fix(migrate): judge the target after creating it, and refuse a swappa…
chappie-daemon Nov 13, 2026
4465130
Merge branch 'rewrite/main' into factory/029-pg-to-lmdb
cameri Nov 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .changeset/pg-to-lmdb-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
6 changes: 3 additions & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,12 @@ jobs:
-D clippy::todo -D clippy::unimplemented -D clippy::panic
- name: Tests
run: cargo test --workspace --all-features
# The two database-backed storage targets create and migrate their own scratch
# databases; the Cucumber half of the harness stays in scripts/storage-parity.sh.
# The database-backed storage targets create and migrate their own scratch databases; the
# Cucumber half of the harness stays in scripts/storage-parity.sh.
- name: Storage parity against Postgres
env:
PARITY_ADMIN_URL: postgres://postgres:postgres@localhost:5432/postgres
run: cargo test -p nostream-storage --test migrations --test parity -- --ignored --test-threads=1
run: cargo test -p nostream-storage --test migrations --test parity --test migration_pg -- --ignored --test-threads=1
- name: Storage builds without the Postgres driver
run: cargo check -p nostream-storage --no-default-features --all-targets
- name: Release build
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,7 @@ coverage-report/

# Rust
/target/

# A migration target is the dataset: `--target .` writes it here, and this repository is public.
/lmdb/
/migration-manifest.json
10 changes: 6 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,19 @@ cargo test --workspace --all-features
cargo build --workspace --all-features --release
```

CI additionally runs the two database-backed storage tests ("Storage parity against Postgres")
CI additionally runs the three database-backed storage tests ("Storage parity against Postgres")
against a `postgres:16-alpine` service, and they are `#[ignore]`d so a checkout without a database still passes
`cargo test --workspace`:

```
cargo test -p nostream-storage --test migrations --test parity -- --ignored --test-threads=1
cargo test -p nostream-storage --test migrations --test parity --test migration_pg \
-- --ignored --test-threads=1
```

`PARITY_ADMIN_URL` names the administrative database (CI sets
`postgres://postgres:postgres@localhost:5432/postgres`); the targets create, migrate and
drop their own scratch databases. `scripts/storage-parity.sh` runs both plus the
drop their own scratch databases — `migration_pg` seeds one and copies it into a temporary LMDB
store. `scripts/storage-parity.sh` runs all three plus the
TypeScript Cucumber suite against the sqlx-migrated schema — the complete local oracle. The
LMDB arm of that oracle needs no database: `cargo test -p nostream-storage --test parity_lmdb
-- --nocapture` replays the same fixture on a temporary store and runs inside the fifth
Expand Down Expand Up @@ -88,7 +90,7 @@ resolver 3:
| `nostream-relay` | connections, wire protocol, handlers, rate limiters, live dispatch, NIP-77 engine (the acceptor lives in `nostreamd`) |
| `nostream-services` | payment processors and the invoice lifecycle, operator notifications, the web-of-trust graph, Tor, the scheduler and its workers, event import, NIP-66 monitors (#865) |
| `nostream-admin` | admin API and auth |
| `nostream-cli` | operator command line (`nostream-cli config validate`, `nostream-cli import`) |
| `nostream-cli` | operator command line (`nostream-cli config validate`, `nostream-cli import`, `nostream-cli migrate pg-to-lmdb`) |
| `nostreamd` | the daemon binary: runtime, telemetry, signals, the services composition root and the worker supervisor |

- Every crate manifest repeats `version.workspace = true`, `edition.workspace = true`,
Expand Down
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/nostream-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ path = "src/main.rs"
[dependencies]
clap.workspace = true
anyhow = { workspace = true }
hex.workspace = true
nostream-config.workspace = true
nostream-core.workspace = true
nostream-services.workspace = true
nostream-storage.workspace = true
serde.workspace = true
serde_json.workspace = true
serde_yaml.workspace = true
sha2.workspace = true
thiserror.workspace = true
tokio.workspace = true

[dev-dependencies]
chrono.workspace = true
heed.workspace = true
tempfile.workspace = true

[lints]
Expand Down
Loading
Loading