@quereus/sync 3.2.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -7
- package/dist/src/clock/hlc.d.ts +43 -3
- package/dist/src/clock/hlc.d.ts.map +1 -1
- package/dist/src/clock/hlc.js +60 -10
- package/dist/src/clock/hlc.js.map +1 -1
- package/dist/src/create-sync-module.d.ts +46 -9
- package/dist/src/create-sync-module.d.ts.map +1 -1
- package/dist/src/create-sync-module.js +11 -8
- package/dist/src/create-sync-module.js.map +1 -1
- package/dist/src/index.d.ts +10 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/metadata/basis-lifecycle.d.ts +180 -0
- package/dist/src/metadata/basis-lifecycle.d.ts.map +1 -0
- package/dist/src/metadata/basis-lifecycle.js +211 -0
- package/dist/src/metadata/basis-lifecycle.js.map +1 -0
- package/dist/src/metadata/change-log.d.ts +1 -1
- package/dist/src/metadata/change-log.d.ts.map +1 -1
- package/dist/src/metadata/change-log.js +6 -6
- package/dist/src/metadata/change-log.js.map +1 -1
- package/dist/src/metadata/column-version.d.ts +14 -5
- package/dist/src/metadata/column-version.d.ts.map +1 -1
- package/dist/src/metadata/column-version.js +22 -12
- package/dist/src/metadata/column-version.js.map +1 -1
- package/dist/src/metadata/index.d.ts +2 -0
- package/dist/src/metadata/index.d.ts.map +1 -1
- package/dist/src/metadata/index.js +2 -0
- package/dist/src/metadata/index.js.map +1 -1
- package/dist/src/metadata/keys.d.ts +52 -2
- package/dist/src/metadata/keys.d.ts.map +1 -1
- package/dist/src/metadata/keys.js +99 -14
- package/dist/src/metadata/keys.js.map +1 -1
- package/dist/src/metadata/peer-state.d.ts +1 -1
- package/dist/src/metadata/peer-state.js +5 -5
- package/dist/src/metadata/quarantine.d.ts +90 -0
- package/dist/src/metadata/quarantine.d.ts.map +1 -0
- package/dist/src/metadata/quarantine.js +167 -0
- package/dist/src/metadata/quarantine.js.map +1 -0
- package/dist/src/metadata/schema-migration.d.ts +1 -1
- package/dist/src/metadata/schema-migration.js +7 -7
- package/dist/src/metadata/schema-version.d.ts +1 -1
- package/dist/src/metadata/schema-version.js +7 -7
- package/dist/src/metadata/tombstones.d.ts +26 -9
- package/dist/src/metadata/tombstones.d.ts.map +1 -1
- package/dist/src/metadata/tombstones.js +42 -19
- package/dist/src/metadata/tombstones.js.map +1 -1
- package/dist/src/sql/basis-lifecycle-tvf.d.ts +34 -0
- package/dist/src/sql/basis-lifecycle-tvf.d.ts.map +1 -0
- package/dist/src/sql/basis-lifecycle-tvf.js +101 -0
- package/dist/src/sql/basis-lifecycle-tvf.js.map +1 -0
- package/dist/src/sync/admission.d.ts +81 -0
- package/dist/src/sync/admission.d.ts.map +1 -0
- package/dist/src/sync/admission.js +94 -0
- package/dist/src/sync/admission.js.map +1 -0
- package/dist/src/sync/change-applicator.d.ts +65 -2
- package/dist/src/sync/change-applicator.d.ts.map +1 -1
- package/dist/src/sync/change-applicator.js +493 -68
- package/dist/src/sync/change-applicator.js.map +1 -1
- package/dist/src/sync/change-grouping.d.ts +43 -0
- package/dist/src/sync/change-grouping.d.ts.map +1 -0
- package/dist/src/sync/change-grouping.js +103 -0
- package/dist/src/sync/change-grouping.js.map +1 -0
- package/dist/src/sync/events.d.ts +159 -1
- package/dist/src/sync/events.d.ts.map +1 -1
- package/dist/src/sync/events.js +50 -0
- package/dist/src/sync/events.js.map +1 -1
- package/dist/src/sync/manager.d.ts +87 -0
- package/dist/src/sync/manager.d.ts.map +1 -1
- package/dist/src/sync/protocol.d.ts +174 -11
- package/dist/src/sync/protocol.d.ts.map +1 -1
- package/dist/src/sync/protocol.js +4 -1
- package/dist/src/sync/protocol.js.map +1 -1
- package/dist/src/sync/snapshot-stream.d.ts.map +1 -1
- package/dist/src/sync/snapshot-stream.js +89 -19
- package/dist/src/sync/snapshot-stream.js.map +1 -1
- package/dist/src/sync/snapshot.d.ts.map +1 -1
- package/dist/src/sync/snapshot.js +63 -44
- package/dist/src/sync/snapshot.js.map +1 -1
- package/dist/src/sync/store-adapter.d.ts +117 -15
- package/dist/src/sync/store-adapter.d.ts.map +1 -1
- package/dist/src/sync/store-adapter.js +247 -91
- package/dist/src/sync/store-adapter.js.map +1 -1
- package/dist/src/sync/sync-context.d.ts +44 -1
- package/dist/src/sync/sync-context.d.ts.map +1 -1
- package/dist/src/sync/sync-context.js +26 -0
- package/dist/src/sync/sync-context.js.map +1 -1
- package/dist/src/sync/sync-manager-impl.d.ts +247 -13
- package/dist/src/sync/sync-manager-impl.d.ts.map +1 -1
- package/dist/src/sync/sync-manager-impl.js +788 -193
- package/dist/src/sync/sync-manager-impl.js.map +1 -1
- package/package.json +6 -6
|
@@ -4,18 +4,29 @@
|
|
|
4
4
|
* Coordinates CRDT metadata tracking and sync operations.
|
|
5
5
|
* Delegates to focused sub-modules for snapshot, streaming, and change application.
|
|
6
6
|
*/
|
|
7
|
-
import type { KVStore
|
|
8
|
-
import type {
|
|
7
|
+
import type { KVStore } from '@quereus/store';
|
|
8
|
+
import type { Database, LensDeploymentSnapshot } from '@quereus/quereus';
|
|
9
|
+
import type { GetTableSchemaCallback, TransactionCommitSource } from '../create-sync-module.js';
|
|
9
10
|
import { HLCManager, type HLC } from '../clock/hlc.js';
|
|
10
11
|
import { type SiteId } from '../clock/site.js';
|
|
11
12
|
import { ColumnVersionStore } from '../metadata/column-version.js';
|
|
12
13
|
import { TombstoneStore } from '../metadata/tombstones.js';
|
|
13
14
|
import { SchemaMigrationStore } from '../metadata/schema-migration.js';
|
|
14
15
|
import { ChangeLogStore } from '../metadata/change-log.js';
|
|
16
|
+
import { QuarantineStore } from '../metadata/quarantine.js';
|
|
17
|
+
import { BasisLifecycleStore, type BasisTableLifecycleRecord } from '../metadata/basis-lifecycle.js';
|
|
15
18
|
import type { SyncManager, SnapshotCheckpoint } from './manager.js';
|
|
16
|
-
import type { SyncConfig, ChangeSet, ApplyResult, Snapshot, SnapshotChunk, SnapshotProgress, ApplyToStoreCallback } from './protocol.js';
|
|
19
|
+
import type { SyncConfig, ChangeSet, ApplyResult, Snapshot, SnapshotChunk, SnapshotProgress, ApplyToStoreCallback, DropLocalTableCallback, UnknownTableDisposition } from './protocol.js';
|
|
17
20
|
import { SyncEventEmitterImpl } from './events.js';
|
|
18
21
|
import type { SyncContext } from './sync-context.js';
|
|
22
|
+
/**
|
|
23
|
+
* Guard a transaction's running `opSeq` against the uint32 bound. `opSeq` is
|
|
24
|
+
* serialized as a big-endian uint32 in the HLC comparison key, so a fact count
|
|
25
|
+
* exceeding {@link MAX_OPSEQ} would silently wrap and corrupt ordering — throw
|
|
26
|
+
* instead. Practically unreachable (4 billion facts in one transaction); the
|
|
27
|
+
* write side telemeters the throw via an error sync-state event.
|
|
28
|
+
*/
|
|
29
|
+
export declare function assertOpSeqInRange(opSeq: number): void;
|
|
19
30
|
/**
|
|
20
31
|
* Implementation of SyncManager.
|
|
21
32
|
*
|
|
@@ -31,45 +42,268 @@ export declare class SyncManagerImpl implements SyncManager, SyncContext {
|
|
|
31
42
|
private readonly peerStates;
|
|
32
43
|
readonly changeLog: ChangeLogStore;
|
|
33
44
|
readonly schemaMigrations: SchemaMigrationStore;
|
|
45
|
+
readonly quarantine: QuarantineStore;
|
|
46
|
+
readonly basisLifecycle: BasisLifecycleStore;
|
|
34
47
|
readonly syncEvents: SyncEventEmitterImpl;
|
|
35
48
|
readonly applyToStore?: ApplyToStoreCallback;
|
|
36
49
|
private readonly getTableSchema?;
|
|
37
|
-
|
|
38
|
-
private
|
|
50
|
+
/** Reclaim-by-name callback for the eviction sweep; absent ⇒ sweep is a no-op. */
|
|
51
|
+
private readonly dropLocalTable?;
|
|
52
|
+
private readonly lastBasisHash;
|
|
53
|
+
private unknownTableIgnored;
|
|
54
|
+
private unknownTableQuarantined;
|
|
55
|
+
private unknownTableForwarded;
|
|
56
|
+
private unknownTableRelayed;
|
|
57
|
+
private readonly unknownTableByTable;
|
|
39
58
|
private constructor();
|
|
40
59
|
/**
|
|
41
60
|
* Create a new SyncManager, initializing or loading site identity.
|
|
42
61
|
*
|
|
43
62
|
* @param kv - KV store for sync metadata
|
|
44
|
-
* @param
|
|
63
|
+
* @param transactionSource - Engine transaction-commit source for local change
|
|
64
|
+
* capture (a `Database`, or any `onTransactionCommit` emitter). When provided,
|
|
65
|
+
* sync subscribes to `onTransactionCommit` and records CRDT metadata for each
|
|
66
|
+
* committed local transaction — one HLC per transaction. Pass `undefined` for a
|
|
67
|
+
* relay-only deployment (e.g. a coordinator) that captures no local DML.
|
|
45
68
|
* @param config - Sync configuration
|
|
46
69
|
* @param syncEvents - Sync event emitter for UI integration
|
|
47
70
|
* @param applyToStore - Optional callback for applying remote changes to the store
|
|
48
71
|
* @param getTableSchema - Optional callback for getting table schema by name
|
|
72
|
+
* @param dropLocalTable - Optional reclaim-by-name callback for the basis-table
|
|
73
|
+
* eviction sweep; when absent (e.g. a relay-only coordinator) the sweep is a no-op.
|
|
49
74
|
*/
|
|
50
|
-
static create(kv: KVStore,
|
|
75
|
+
static create(kv: KVStore, transactionSource: TransactionCommitSource | undefined, config: SyncConfig, syncEvents: SyncEventEmitterImpl, applyToStore?: ApplyToStoreCallback, getTableSchema?: GetTableSchemaCallback, dropLocalTable?: DropLocalTableCallback): Promise<SyncManagerImpl>;
|
|
51
76
|
getSiteId(): SiteId;
|
|
52
77
|
getCurrentHLC(): HLC;
|
|
53
78
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
79
|
+
* Basis-membership oracle for unknown-table detection. `getTableSchema(s,t)
|
|
80
|
+
* === undefined` ⇒ the table is outside the local basis. When no oracle was
|
|
81
|
+
* provided (e.g. a relay-only coordinator), detection is inert: every table
|
|
82
|
+
* reports in-basis and the store adapter's defensive throw governs.
|
|
83
|
+
*/
|
|
84
|
+
isTableInBasis(schema: string, table: string): boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Current column names for an in-basis table via the `getTableSchema` oracle, or
|
|
87
|
+
* `undefined` when the table is outside the basis (oracle returns nothing) OR no
|
|
88
|
+
* oracle was wired. Backs the drain path's basis gate + schema-drift filter (see
|
|
89
|
+
* {@link SyncContext.getTableColumnNames}). The no-oracle `undefined` makes drain
|
|
90
|
+
* a clean no-op on a relay-only coordinator, exactly as detection is inert there.
|
|
56
91
|
*/
|
|
57
|
-
|
|
92
|
+
getTableColumnNames(schema: string, table: string): readonly string[] | undefined;
|
|
58
93
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
94
|
+
* Accumulate unknown-table disposition stats (called by the apply path after a
|
|
95
|
+
* diverted group is successfully admitted).
|
|
61
96
|
*/
|
|
62
|
-
|
|
97
|
+
recordUnknownTable(disposition: UnknownTableDisposition, schema: string, table: string, changeCount: number): void;
|
|
98
|
+
getUnknownTableStats(): {
|
|
99
|
+
ignored: number;
|
|
100
|
+
quarantined: number;
|
|
101
|
+
forwarded: number;
|
|
102
|
+
relayed: number;
|
|
103
|
+
byTable: Map<string, number>;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Record one logical schema's lens deployment over its basis, recomputing the
|
|
107
|
+
* durable per-basis-table lifecycle classification (`docs/migration.md`
|
|
108
|
+
* § 2 Converge). See {@link SyncManager.recordLensDeployment}.
|
|
109
|
+
*
|
|
110
|
+
* The snapshot is scoped to ONE logical schema, so this schema's directly-mapped
|
|
111
|
+
* contribution is stored per-schema (`mappedBy`) and the aggregate state ORs all
|
|
112
|
+
* schemas — a basis table stays `directly-mapped` until the last mapper drops it.
|
|
113
|
+
* The classification is a pure function of `(snapshot, basis schema)`, both
|
|
114
|
+
* reachable from `db`: the directly-mapped set is the union of every table
|
|
115
|
+
* snapshot's `relationBacking` keys (plus deferred surrogate-split members), and
|
|
116
|
+
* the basis membership / derivation sources come from enumerating the basis
|
|
117
|
+
* schema's tables.
|
|
118
|
+
*/
|
|
119
|
+
recordLensDeployment(db: Database, logicalSchemaName: string, snapshot: LensDeploymentSnapshot): Promise<void>;
|
|
120
|
+
getBasisTableLifecycle(): Promise<BasisTableLifecycleRecord[]>;
|
|
121
|
+
/**
|
|
122
|
+
* Reclaim the local storage of every detached basis table that has been quiet
|
|
123
|
+
* past its effective retention horizon (`docs/migration.md` § 4 Contract).
|
|
124
|
+
* Host-driven (like {@link pruneTombstones} / {@link pruneQuarantine}) — the
|
|
125
|
+
* host schedules it; the library adds no timer. Returns the number of tables
|
|
126
|
+
* evicted.
|
|
127
|
+
*
|
|
128
|
+
* No-op when no `dropLocalTable` reclaim callback is wired (e.g. a relay-only
|
|
129
|
+
* coordinator with no store). For each evictable record it re-reads the record
|
|
130
|
+
* and re-checks eligibility immediately before dropping — guarding against a
|
|
131
|
+
* concurrent re-deploy that re-mapped the table between the scan and the drop —
|
|
132
|
+
* then drops the storage, emits `onBasisTableEvicted`, and clears the record. A
|
|
133
|
+
* `dropLocalTable` throw leaves the record in place to retry next sweep (the
|
|
134
|
+
* drop is idempotent).
|
|
135
|
+
*/
|
|
136
|
+
evictExpiredBasisTables(now?: number): Promise<number>;
|
|
137
|
+
/**
|
|
138
|
+
* Record CRDT metadata for one committed local transaction.
|
|
139
|
+
*
|
|
140
|
+
* Driven by the engine's `onTransactionCommit` group — the authoritative
|
|
141
|
+
* "one transaction = one HLC" boundary. The clock is ticked exactly **once**;
|
|
142
|
+
* every fact of the transaction shares that base `(wallTime, counter, siteId)`
|
|
143
|
+
* and differs only in `opSeq` (a contiguous, 0-based sub-order). DDL is recorded
|
|
144
|
+
* before DML so migrations sort below the same transaction's data facts
|
|
145
|
+
* (docs/sync.md § DDL Application Order). All metadata for the transaction —
|
|
146
|
+
* schema migrations, column versions, tombstones, change-log entries, and the
|
|
147
|
+
* HLC clock state — lands in a single KV batch.
|
|
148
|
+
*/
|
|
149
|
+
private handleTransactionCommit;
|
|
150
|
+
/**
|
|
151
|
+
* Record one local schema-change event as a migration. Allocates an `opSeq`
|
|
152
|
+
* (via `nextHlc`) only when the event maps to a tracked migration, so
|
|
153
|
+
* unsupported object types consume no sub-order. `versionCounters` carries the
|
|
154
|
+
* running per-table schema version across this transaction's migrations.
|
|
155
|
+
*/
|
|
156
|
+
private recordSchemaMigration;
|
|
157
|
+
/**
|
|
158
|
+
* Record one local data-change event: a tombstone (delete) or the changed
|
|
159
|
+
* column versions (insert/update). Each recorded fact consumes one `opSeq`.
|
|
160
|
+
*/
|
|
161
|
+
private recordDataEvent;
|
|
63
162
|
private recordColumnVersions;
|
|
163
|
+
/**
|
|
164
|
+
* Extract changes for a peer as **one {@link ChangeSet} per source
|
|
165
|
+
* transaction** (grouped by HLC identity `(wallTime, counter, siteId)`),
|
|
166
|
+
* bounded at transaction granularity by `config.batchSize`. A transaction is
|
|
167
|
+
* never split across ChangeSets and two transactions are never merged, so a
|
|
168
|
+
* consumer that advances `lastSyncHLC = ChangeSet.hlc` always lands on a real
|
|
169
|
+
* commit boundary (docs/sync.md § Transaction-Based Change Grouping → Read side).
|
|
170
|
+
*/
|
|
64
171
|
getChangesSince(peerSiteId: SiteId, sinceHLC?: HLC): Promise<ChangeSet[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Delta extraction: facts after `sinceHLC`, in change-log (HLC) order, bounded
|
|
174
|
+
* at **scan time** to whole transactions whose cumulative data-change count
|
|
175
|
+
* reaches `batchSize`.
|
|
176
|
+
*
|
|
177
|
+
* The change-log scan is keyed by `(wallTime, counter, siteId, opSeq)`, so a
|
|
178
|
+
* transaction's facts arrive contiguously and transactions arrive in commit
|
|
179
|
+
* order. That lets us stop scanning as soon as enough WHOLE transactions have
|
|
180
|
+
* accumulated, instead of draining the entire iterator into memory and letting
|
|
181
|
+
* {@link buildTransactionChangeSets} truncate afterward (the pre-
|
|
182
|
+
* `sync-getchangessince-bounded-extraction` behavior, where `batchSize` capped
|
|
183
|
+
* the response but not the scan). The bound here mirrors that grouping step
|
|
184
|
+
* exactly — whole transactions accumulate until the cumulative data-change count
|
|
185
|
+
* reaches `batchSize`, never splitting a transaction — so the grouped response
|
|
186
|
+
* is byte-identical; only the scan footprint shrinks.
|
|
187
|
+
*
|
|
188
|
+
* LOAD-BEARING INVARIANT: boundary detection keys off `logEntry.hlc`, but the
|
|
189
|
+
* grouper keys off the *resolved* version's HLC ({@link resolveLogEntry} returns
|
|
190
|
+
* `cv.hlc` / `tombstone.hlc`). These agree only when each non-null-resolving log
|
|
191
|
+
* entry's HLC equals its resolved version's HLC, which holds for BOTH entry types
|
|
192
|
+
* because each is deduped on overwrite — at most one entry survives per key, and
|
|
193
|
+
* its HLC equals the current version's:
|
|
194
|
+
* - COLUMN: an overwrite deletes the prior `(pk, column)` entry (see
|
|
195
|
+
* {@link recordColumnVersions} and `commitChangeMetadata`), so the survivor's
|
|
196
|
+
* HLC is the current `cv.hlc`.
|
|
197
|
+
* - DELETE: a newer tombstone deletes the prior `pk` delete entry (see
|
|
198
|
+
* {@link recordDataEvent} and `commitChangeMetadata`), so a
|
|
199
|
+
* delete→reinsert→delete key reuse no longer leaves a stale entry that
|
|
200
|
+
* re-attributes to a later tombstone HLC; the survivor's HLC is the current
|
|
201
|
+
* `tombstone.hlc`.
|
|
202
|
+
*
|
|
203
|
+
* The overwrite dedup above covers entries written across SEPARATE writes/applies
|
|
204
|
+
* (each later one sees the prior committed version). The apply path additionally
|
|
205
|
+
* collapses in-batch repeats: two versions of one key inside a single
|
|
206
|
+
* `applyChanges` call resolve against the SAME pre-batch prior version, so neither
|
|
207
|
+
* sees the other — `commitChangeMetadata` keeps only the max-HLC winner per key and
|
|
208
|
+
* writes a single entry, preserving the invariant regardless of how many versions
|
|
209
|
+
* of a key were batched.
|
|
210
|
+
*
|
|
211
|
+
* (Schema migrations are still fully scanned by {@link collectSchemaMigrations};
|
|
212
|
+
* the `sm:` range is not HLC-ordered, but migrations are few and the grouping
|
|
213
|
+
* step drops any that sort past the bounded fact watermark.)
|
|
214
|
+
*/
|
|
215
|
+
private collectChangesSince;
|
|
216
|
+
/**
|
|
217
|
+
* Resolve a change-log entry to the live {@link Change} it references, or
|
|
218
|
+
* `null` when the underlying column version / tombstone is gone — a stale log
|
|
219
|
+
* entry (e.g. a column overwritten, or a row deleted after the entry was
|
|
220
|
+
* written). The authoritative HLC and value come from the current version, not
|
|
221
|
+
* the log key.
|
|
222
|
+
*/
|
|
223
|
+
private resolveLogEntry;
|
|
224
|
+
/**
|
|
225
|
+
* Full extraction (initial sync / delta-from-zero): every column version and
|
|
226
|
+
* tombstone not originating from the peer. Ordering is owned by
|
|
227
|
+
* {@link buildTransactionChangeSets}, so no pre-sort is needed here.
|
|
228
|
+
*
|
|
229
|
+
* Unlike {@link collectChangesSince}, this path cannot early-exit at scan time:
|
|
230
|
+
* the `cv:`/`tb:` scans are keyed by table/pk, NOT by HLC, so transactions are
|
|
231
|
+
* interleaved arbitrarily and no transaction boundary is reachable without a
|
|
232
|
+
* full scan + sort. It is left unbounded because it is the from-zero path: a
|
|
233
|
+
* large initial range is expected to be served by a snapshot rather than this
|
|
234
|
+
* delta path (docs/sync.md).
|
|
235
|
+
*/
|
|
65
236
|
private collectAllChanges;
|
|
237
|
+
/**
|
|
238
|
+
* Collect forwardable held changes to re-offer to a peer — the outbound half of
|
|
239
|
+
* the `store-and-forward` unknown-table disposition. Source is
|
|
240
|
+
* {@link QuarantineStore.listForwardable}: straggler changes this peer held
|
|
241
|
+
* because it has retired the table, marked forwardable. Each is re-offered with
|
|
242
|
+
* its ORIGINAL `hlc` + `siteId` (the straggler's fact, not a new local one) — the
|
|
243
|
+
* identity that makes the relay loop-free and convergent across hops with NO
|
|
244
|
+
* per-table peer-membership oracle (none exists): a peer that already holds the
|
|
245
|
+
* change re-holds it idempotently (HLC-keyed) and the per-peer watermark stops
|
|
246
|
+
* re-send after one exchange.
|
|
247
|
+
*
|
|
248
|
+
* Two filters, mirroring {@link collectChangesSince} / {@link collectAllChanges}:
|
|
249
|
+
* - **Echo exclusion** — drop a change whose origin (`change.hlc.siteId`) is the
|
|
250
|
+
* peer itself, so a straggler's fact is never echoed back to its own author.
|
|
251
|
+
* - **Watermark filter** — when `sinceHLC` is defined (delta path), keep only
|
|
252
|
+
* `compareHLC(change.hlc, sinceHLC) > 0`. REQUIRED: the consumer advances its
|
|
253
|
+
* per-peer `lastSyncHLC` to `max(returned ChangeSet.hlc)`, so a round that
|
|
254
|
+
* returned a forwarded change with HLC ≤ the watermark would REGRESS it and
|
|
255
|
+
* trigger a re-scan/re-deliver flood. Filtering `> sinceHLC` keeps the merged
|
|
256
|
+
* response a safe contiguous prefix — exactly the change-log contract. When
|
|
257
|
+
* `sinceHLC` is undefined (from-zero / {@link collectAllChanges} path) there is
|
|
258
|
+
* no lower bound, so all (origin ≠ peer) are kept.
|
|
259
|
+
*
|
|
260
|
+
* Accepted limitation (documented intent, not a defect): a straggler whose change
|
|
261
|
+
* is causally older than the holder's sync recency with a peer (`HLC ≤ sinceHLC`)
|
|
262
|
+
* is NOT relayed via this delta path — the same scalar-watermark limitation the
|
|
263
|
+
* base delta layer already has. store-and-forward targets the transitional
|
|
264
|
+
* uneven-retirement window, where the straggler's writes are recent enough to
|
|
265
|
+
* exceed holder watermarks; quarantine already prevents write loss outside it.
|
|
266
|
+
*
|
|
267
|
+
* Snapshot carve-out: forwardable entries are DELTA-ONLY. The snapshot collectors
|
|
268
|
+
* scan only `cv:`/`tb:`/`sm:` (never `qt:`), since a snapshot transfers the
|
|
269
|
+
* offering peer's OWN basis and a forwarded change is for a table that peer does
|
|
270
|
+
* not have.
|
|
271
|
+
*
|
|
272
|
+
* Full horizon-bounded scan (no early-exit), paralleling {@link collectAllChanges}:
|
|
273
|
+
* the forwardable set is bounded by the retention horizon and is EMPTY — so this
|
|
274
|
+
* is zero-cost — in the no-straggler case.
|
|
275
|
+
*/
|
|
276
|
+
private collectForwardableChanges;
|
|
277
|
+
/**
|
|
278
|
+
* Collect schema migrations after `sinceHLC` not originating from the peer.
|
|
279
|
+
* Each migration shares its transaction's base HLC, so the grouping step
|
|
280
|
+
* rejoins it with that transaction's data facts (or forms a DDL-only ChangeSet).
|
|
281
|
+
*
|
|
282
|
+
* The `sm:` range is keyed by `{schema}.{table}:{version}`, not by HLC, so this
|
|
283
|
+
* scan cannot early-exit the way {@link collectChangesSince} does — it is drained
|
|
284
|
+
* in full even when the fact side stops early. That is acceptable because
|
|
285
|
+
* migrations are few, and {@link buildTransactionChangeSets} drops any migration
|
|
286
|
+
* that sorts past the bounded fact watermark (its DDL-only group falls beyond the
|
|
287
|
+
* `batchSize` cut), so over-scanning here costs work but never correctness. A
|
|
288
|
+
* peer with a pathological volume of un-synced DDL is the one case this leaves
|
|
289
|
+
* unbounded; see the bounded-extraction ticket's handoff.
|
|
290
|
+
*/
|
|
291
|
+
private collectSchemaMigrations;
|
|
66
292
|
applyChanges(changes: ChangeSet[]): Promise<ApplyResult>;
|
|
293
|
+
drainHeldChanges(schema?: string, table?: string): Promise<number>;
|
|
67
294
|
canDeltaSync(peerSiteId: SiteId, sinceHLC: HLC): Promise<boolean>;
|
|
68
295
|
getSnapshot(): Promise<Snapshot>;
|
|
69
296
|
applySnapshot(snapshot: Snapshot): Promise<void>;
|
|
70
297
|
updatePeerSyncState(peerSiteId: SiteId, hlc: HLC): Promise<void>;
|
|
71
298
|
getPeerSyncState(peerSiteId: SiteId): Promise<HLC | undefined>;
|
|
72
299
|
pruneTombstones(): Promise<number>;
|
|
300
|
+
/**
|
|
301
|
+
* GC quarantined out-of-basis straggler changes past the retention horizon —
|
|
302
|
+
* the quarantine sibling of {@link pruneTombstones}, keyed off the same
|
|
303
|
+
* `retentionHorizonMs`. A held change older than the horizon was already
|
|
304
|
+
* outside the delivery guarantee.
|
|
305
|
+
*/
|
|
306
|
+
pruneQuarantine(): Promise<number>;
|
|
73
307
|
getEventEmitter(): SyncEventEmitterImpl;
|
|
74
308
|
getSnapshotStream(chunkSize?: number): AsyncIterable<SnapshotChunk>;
|
|
75
309
|
applySnapshotStream(chunks: AsyncIterable<SnapshotChunk>, onProgress?: (progress: SnapshotProgress) => void): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-manager-impl.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-manager-impl.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"sync-manager-impl.d.ts","sourceRoot":"","sources":["../../../src/sync/sync-manager-impl.ts"],"names":[],"mappings":"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"}
|