chore(deps): LocalDb 0.2.0 — dereg cleanup, late-opt-in baselining, byte-budget replication

This commit is contained in:
Joseph Doherty
2026-08-14 22:22:18 -04:00
parent 312216ff2b
commit cca7f1786d
9 changed files with 288 additions and 69 deletions
+31 -11
View File
@@ -162,21 +162,41 @@ Each site has its own two-node cluster:
only the initiating half of a pair sets `PeerAddress` (one bidirectional stream, dialled by one
side); the passive half carries the key alone. A deliberately unreplicated node — site-b and
site-c on the rig — runs with no triggers at all and stops paying the per-write capture cost.
- **Stale-trigger cleanup is automatic** (LocalDb 0.2.0). A node with no replication configured does
not merely skip registration — at boot it calls `DeregisterReplicated` on all ten tables, dropping
any capture triggers an earlier build installed and pruning those tables' oplog and row-version
rows. It is idempotent, so a file that was never registered reports nothing to clean; when
something *was* cleaned the node logs it once at Information. Recreating the data volume is no
longer required to stop an in-place-upgraded node from capturing.
#### Turning replication ON for a site that has been running without it
Set the keys on **both** nodes and restart both. Two things to know before you do:
**Supported as of LocalDb 0.2.0.** Set the keys on **both** nodes and restart both (see the
stop-and-start-together rule below — this is a pair-wide change, not a rolling one). Existing rows
are carried across:
- **Existing rows are not baselined.** Capture is change-data-capture: rows written while the node
had no triggers were never recorded in `__localdb_row_version`, and LocalDb's snapshot resync
streams from that ledger, so it will not ship them. The pair converges on everything written
*after* the restart and stays silently divergent on everything before it. Start from a copy of one
node's database on both sides, or accept that only new writes converge.
- **A node upgraded in place keeps stale triggers.** The guard decides whether triggers are
*installed*, not whether existing ones are removed, and the library has no removal API yet. A
database file first created by a build that always registered keeps capturing until that lands.
Recreating the node's data volume clears it — which is what a schema-change redeploy does on the
docker rig, so the rig is unaffected.
- **Pre-existing rows are baselined automatically.** ScadaBridge registers every replicated table
with `baselineExistingRows: true`. Capture is change-data-capture, so rows written while the node
had no triggers appear in neither the oplog nor `__localdb_row_version` — and LocalDb's snapshot
resync streams from that ledger. Baselining seeds the ledger for those rows at the LWW floor
(HLC `0`, stamped with the node's own id) and flags a snapshot resync, so the peer actually
receives them. Copying one node's database onto the other beforehand is no longer necessary.
- **What the floor means for conflicts.** Every genuine HLC is a UTC millisecond shifted left 16
bits, so it is strictly greater than `0`: a baselined row loses to any real remote write of the
same key and wins only where the peer holds no version of that key at all. The one ambiguous case
is **both** nodes baselining the same key (e.g. both were restored from the same legacy file) —
both hold HLC `0` and the node-id tie-break decides. That is convergent but arbitrary as to which
content survives, so if the two files may disagree on a key, start both nodes from one node's
database.
- **Seeding is idempotent** (`ON CONFLICT DO NOTHING`), so a row that already has a genuine version
keeps it and no snapshot is flagged. Booting with baselining on every start is free after the
first.
Turning replication back **OFF** is likewise a both-nodes change: deregistration must be symmetric,
because the sync handshake compares the two nodes' registered-table digests fail-closed — a node
that drops a table its peer still replicates stops syncing with a schema-mismatch error rather than
diverging silently. Turning it on again later re-baselines, which is what makes the ledger prune on
deregistration safe.
### Site Pair Upgrades — stop and start BOTH nodes together