@peerbit/shared-log 13.2.24 → 13.2.25
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/dist/src/checked-prune.d.ts +12 -0
- package/dist/src/checked-prune.d.ts.map +1 -1
- package/dist/src/checked-prune.js +33 -0
- package/dist/src/checked-prune.js.map +1 -1
- package/dist/src/coordinate-persistence.d.ts +211 -0
- package/dist/src/coordinate-persistence.d.ts.map +1 -0
- package/dist/src/coordinate-persistence.js +1133 -0
- package/dist/src/coordinate-persistence.js.map +1 -0
- package/dist/src/errors.d.ts +1 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +19 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +127 -133
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1400 -4269
- package/dist/src/index.js.map +1 -1
- package/dist/src/instance-lifecycle.d.ts +117 -0
- package/dist/src/instance-lifecycle.d.ts.map +1 -0
- package/dist/src/instance-lifecycle.js +254 -0
- package/dist/src/instance-lifecycle.js.map +1 -0
- package/dist/src/join-warmup.d.ts +86 -0
- package/dist/src/join-warmup.d.ts.map +1 -0
- package/dist/src/join-warmup.js +351 -0
- package/dist/src/join-warmup.js.map +1 -0
- package/dist/src/native-write-through-block-store.d.ts +123 -0
- package/dist/src/native-write-through-block-store.d.ts.map +1 -0
- package/dist/src/native-write-through-block-store.js +989 -0
- package/dist/src/native-write-through-block-store.js.map +1 -0
- package/dist/src/peer-session.d.ts +117 -0
- package/dist/src/peer-session.d.ts.map +1 -0
- package/dist/src/peer-session.js +259 -0
- package/dist/src/peer-session.js.map +1 -0
- package/dist/src/replication-announcement.d.ts +116 -0
- package/dist/src/replication-announcement.d.ts.map +1 -0
- package/dist/src/replication-announcement.js +515 -0
- package/dist/src/replication-announcement.js.map +1 -0
- package/dist/src/replicator-liveness.d.ts +59 -0
- package/dist/src/replicator-liveness.d.ts.map +1 -0
- package/dist/src/replicator-liveness.js +304 -0
- package/dist/src/replicator-liveness.js.map +1 -0
- package/dist/src/sync/dispatch-lifecycle.d.ts +48 -0
- package/dist/src/sync/dispatch-lifecycle.d.ts.map +1 -0
- package/dist/src/sync/dispatch-lifecycle.js +141 -0
- package/dist/src/sync/dispatch-lifecycle.js.map +1 -0
- package/dist/src/sync/factory.d.ts +29 -0
- package/dist/src/sync/factory.d.ts.map +1 -0
- package/dist/src/sync/factory.js +87 -0
- package/dist/src/sync/factory.js.map +1 -0
- package/dist/src/sync/pending-sync-store.d.ts +105 -0
- package/dist/src/sync/pending-sync-store.d.ts.map +1 -0
- package/dist/src/sync/pending-sync-store.js +877 -0
- package/dist/src/sync/pending-sync-store.js.map +1 -0
- package/dist/src/sync/rateless-iblt.d.ts +4 -1
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +102 -106
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/dist/src/sync/simple.d.ts +10 -41
- package/dist/src/sync/simple.d.ts.map +1 -1
- package/dist/src/sync/simple.js +259 -952
- package/dist/src/sync/simple.js.map +1 -1
- package/dist/src/sync/sync-peer-state.d.ts +16 -0
- package/dist/src/sync/sync-peer-state.d.ts.map +1 -0
- package/dist/src/sync/sync-peer-state.js +82 -0
- package/dist/src/sync/sync-peer-state.js.map +1 -0
- package/package.json +9 -9
- package/src/checked-prune.ts +35 -0
- package/src/coordinate-persistence.ts +1796 -0
- package/src/errors.ts +21 -0
- package/src/index.ts +4014 -7858
- package/src/instance-lifecycle.ts +351 -0
- package/src/join-warmup.ts +507 -0
- package/src/native-write-through-block-store.ts +1170 -0
- package/src/peer-session.ts +336 -0
- package/src/replication-announcement.ts +744 -0
- package/src/replicator-liveness.ts +439 -0
- package/src/sync/dispatch-lifecycle.ts +230 -0
- package/src/sync/factory.ts +154 -0
- package/src/sync/pending-sync-store.ts +1085 -0
- package/src/sync/rateless-iblt.ts +122 -132
- package/src/sync/simple.ts +334 -1144
- package/src/sync/sync-peer-state.ts +107 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
// One PeerSession per peer connection-epoch. The session instance IS the
|
|
2
|
+
// opaque subscription-epoch token formerly stored by SharedLog: every `===`
|
|
3
|
+
// epoch comparison keeps working because tokens were always compared by
|
|
4
|
+
// identity and never inspected. Compound predicates now live on
|
|
5
|
+
// isCurrent()/isActive()/isReceiveAdmissionOpen().
|
|
6
|
+
|
|
7
|
+
export type PeerSessionKind = "opening" | "departing";
|
|
8
|
+
|
|
9
|
+
export type PeerSessionPhase =
|
|
10
|
+
| "opening" // subscribe transition; reconnect barrier not yet completed
|
|
11
|
+
| "open" // reconnect barrier completed (replication-info unblocked)
|
|
12
|
+
| "departing" // created by an unsubscribe epoch-advance, fencing the old connection
|
|
13
|
+
| "superseded"; // a newer session replaced this one (terminal)
|
|
14
|
+
|
|
15
|
+
export type PeerSessionDeps = {
|
|
16
|
+
// Late-bound readers into state that stays physically on SharedLog in
|
|
17
|
+
// stage 2. Delegating closures — NOT bound method refs — so sinon spies
|
|
18
|
+
// installed on the SharedLog instance keep intercepting (same constraint
|
|
19
|
+
// as the stage-1 coordinators).
|
|
20
|
+
isReplicationLifecycleActive: (
|
|
21
|
+
controller: AbortController | undefined,
|
|
22
|
+
) => boolean;
|
|
23
|
+
getReplicationLifecycleController: () => AbortController | undefined;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type PeerReceiveAdmissionOptions = {
|
|
27
|
+
allowReplicationInfoBlocked?: boolean;
|
|
28
|
+
allowCleanupGate?: boolean;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export class PeerSession {
|
|
32
|
+
readonly peerHash: string;
|
|
33
|
+
readonly kind: PeerSessionKind;
|
|
34
|
+
// The lifecycle controller live at rotation. All current seams pair the
|
|
35
|
+
// epoch check with a lifecycle check against a controller captured in the
|
|
36
|
+
// same synchronous window as the epoch advance; capturing it here
|
|
37
|
+
// reproduces that pairing exactly.
|
|
38
|
+
readonly replicationLifecycleController: AbortController | undefined;
|
|
39
|
+
phase: PeerSessionPhase;
|
|
40
|
+
// Diagnostics only in stage 2: the destructive removal funnel observed a
|
|
41
|
+
// committed replicator removal under this connection-epoch.
|
|
42
|
+
replicatorRemoved = false;
|
|
43
|
+
// Reconnect-barrier WINDOW sub-state (stage-3 home of the legacy
|
|
44
|
+
// _subscriptionOpeningEpochByPeer map entry, whose value was always this
|
|
45
|
+
// session). True exactly while the barrier window is open: set when
|
|
46
|
+
// handleSubscriptionChange starts the opening barrier (same synchronous
|
|
47
|
+
// window as the rotation that made this session current), cleared in the
|
|
48
|
+
// barrier's `finally` — including the barrier-throw path — where the map
|
|
49
|
+
// entry used to be deleted. Deliberately NOT derived from
|
|
50
|
+
// `phase === "opening"`: phase is "opening" from rotate() — BEFORE the
|
|
51
|
+
// barrier starts — and stays "opening" forever if the barrier throws
|
|
52
|
+
// (markOpen never runs), which would wrongly keep granting the opening
|
|
53
|
+
// lease bypasses that today's window drops.
|
|
54
|
+
openingBarrierActive = false;
|
|
55
|
+
readonly createdAt = Date.now(); // diagnostics only
|
|
56
|
+
|
|
57
|
+
constructor(
|
|
58
|
+
private readonly registry: PeerSessionRegistry,
|
|
59
|
+
peerHash: string,
|
|
60
|
+
kind: PeerSessionKind,
|
|
61
|
+
replicationLifecycleController: AbortController | undefined,
|
|
62
|
+
) {
|
|
63
|
+
this.peerHash = peerHash;
|
|
64
|
+
this.kind = kind;
|
|
65
|
+
this.replicationLifecycleController = replicationLifecycleController;
|
|
66
|
+
this.phase = kind;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** ≡ former SharedLog.isCurrentSubscriptionEpoch(this.peerHash, this). */
|
|
70
|
+
isCurrent(): boolean {
|
|
71
|
+
return this.registry.current(this.peerHash) === this;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Barrier window opens — ≡ the legacy
|
|
75
|
+
* `_subscriptionOpeningEpochByPeer.set(peerHash, thisSession)`. */
|
|
76
|
+
beginOpeningBarrier(): void {
|
|
77
|
+
this.openingBarrierActive = true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Barrier window closes — ≡ the legacy identity-guarded
|
|
81
|
+
* `_subscriptionOpeningEpochByPeer.delete(peerHash)`. Unconditional:
|
|
82
|
+
* the map guard only avoided clobbering a NEWER peer-keyed entry, and
|
|
83
|
+
* per-session flags cannot collide (a newer barrier flags its own,
|
|
84
|
+
* already-rotated session). */
|
|
85
|
+
finishOpeningBarrier(): void {
|
|
86
|
+
this.openingBarrierActive = false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** ≡ ownsReplicationLifecycle() && ownsSubscriptionEpoch() with both
|
|
90
|
+
* captured at the epoch-advance. */
|
|
91
|
+
isActive(): boolean {
|
|
92
|
+
return (
|
|
93
|
+
this.isCurrent() &&
|
|
94
|
+
this.registry.deps.isReplicationLifecycleActive(
|
|
95
|
+
this.replicationLifecycleController,
|
|
96
|
+
)
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** ≡ former SharedLog.isPeerReceiveAdmissionOpen(peerHash,
|
|
101
|
+
* this.replicationLifecycleController, this, options). */
|
|
102
|
+
isReceiveAdmissionOpen(options?: PeerReceiveAdmissionOptions): boolean {
|
|
103
|
+
return this.registry.isReceiveAdmissionOpen(
|
|
104
|
+
this.peerHash,
|
|
105
|
+
this,
|
|
106
|
+
this.replicationLifecycleController,
|
|
107
|
+
options,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class PeerSessionRegistry {
|
|
113
|
+
// The per-peer session map (formerly _subscriptionEpochByPeer; renamed
|
|
114
|
+
// once the last raw-token comparison in index.ts was gone — the values
|
|
115
|
+
// ARE the legacy epoch tokens, compared by identity and never inspected).
|
|
116
|
+
// The rename retires the map's fence-ratchet baseline entry: session
|
|
117
|
+
// identity is the mechanism the ratchet drains fences INTO, not a fence.
|
|
118
|
+
sessions!: Map<string, PeerSession>;
|
|
119
|
+
// Moved from SharedLog (fence B2, same name — the sanctioned file-to-file
|
|
120
|
+
// ratchet move). Local receive generations fence replication-info handlers
|
|
121
|
+
// that were admitted before a liveness eviction but reach the per-peer
|
|
122
|
+
// apply lane after it. Per-PEER, not per-session, on purpose: the token
|
|
123
|
+
// advances at removeReplicator, where the session does NOT rotate (the
|
|
124
|
+
// peer stays subscribed), and it must also fence a peer that never had a
|
|
125
|
+
// session. Unlike sessions this map IS cleared at _close (see
|
|
126
|
+
// clearReceiveEpochsForClose) and replaced at open.
|
|
127
|
+
_replicationInfoReceiveEpochByPeer!: Map<string, object>;
|
|
128
|
+
// Moved from SharedLog (fence B6, same name — the sanctioned file-to-file
|
|
129
|
+
// ratchet move). Refcount of in-flight destructive peer cleanups: while
|
|
130
|
+
// non-zero, receive admission for the peer is closed and prune final
|
|
131
|
+
// confirmations ignore the peer. Per-PEER, not per-session, on purpose:
|
|
132
|
+
// the gate is held across removeReplicator's awaited lanes while a
|
|
133
|
+
// reconnect may rotate the session; a fresh session with a zero gate
|
|
134
|
+
// would reopen receive admission mid-drain. The map instance is replaced
|
|
135
|
+
// only at open (resetForOpen) and cleared in place at _close.
|
|
136
|
+
_receiveCleanupGateByPeer!: Map<string, number>;
|
|
137
|
+
// Moved from SharedLog (fence B5, same name). Peers whose replication-info
|
|
138
|
+
// is fenced: added when a departure/unsubscribe rotation or a reconnect
|
|
139
|
+
// barrier starts, removed only when an opening barrier commits. Per-PEER,
|
|
140
|
+
// not per-session, on purpose (same reasoning as B2/B6 above): the block
|
|
141
|
+
// is set under one session (the departing rotation) and cleared under a
|
|
142
|
+
// LATER one (the opening barrier), so its lifetime deliberately spans
|
|
143
|
+
// session identities; readers (prune final-confirmation filter,
|
|
144
|
+
// announcement repair targeting, pruneOfflineReplicators) ask about peers
|
|
145
|
+
// that may have no session at all; and the `??`-fallback rotation in
|
|
146
|
+
// handleSubscriptionChange rotates WITHOUT touching blocked state — a
|
|
147
|
+
// per-session flag would silently reset it there. Replaced only at open
|
|
148
|
+
// (resetForOpen); deliberately NOT cleared at _close, matching the legacy
|
|
149
|
+
// host field site-for-site. Kept as a public field so existing tests can
|
|
150
|
+
// keep instrumenting the raw Set instance (events.spec.ts spies on its
|
|
151
|
+
// `delete`).
|
|
152
|
+
_replicationInfoBlockedPeers!: Set<string>;
|
|
153
|
+
|
|
154
|
+
constructor(readonly deps: PeerSessionDeps) {
|
|
155
|
+
this.resetForOpen();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** open()-time re-init: REPLACE the map instances, matching today's
|
|
159
|
+
* `= new Map()` re-inits (index.ts ctor / open).
|
|
160
|
+
* The session map is intentionally NOT cleared at _close — tokens must
|
|
161
|
+
* stay current across close so a late continuation's epoch check resolves
|
|
162
|
+
* exactly as it does today (close-safety comes from the paired
|
|
163
|
+
* lifecycle-controller check, not the epoch). There is NO clearForClose()
|
|
164
|
+
* for sessions; the receive-epoch map, by contrast, IS cleared at close. */
|
|
165
|
+
resetForOpen(): void {
|
|
166
|
+
this.sessions = new Map();
|
|
167
|
+
this._replicationInfoReceiveEpochByPeer = new Map();
|
|
168
|
+
this._receiveCleanupGateByPeer = new Map();
|
|
169
|
+
this._replicationInfoBlockedPeers = new Set();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** ≡ the legacy `this._replicationInfoBlockedPeers.add(peerHash)` (host
|
|
173
|
+
* Set, fence B5). */
|
|
174
|
+
blockReplicationInfo(peerHash: string): void {
|
|
175
|
+
this._replicationInfoBlockedPeers.add(peerHash);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** ≡ the legacy `this._replicationInfoBlockedPeers.delete(peerHash)`. */
|
|
179
|
+
unblockReplicationInfo(peerHash: string): void {
|
|
180
|
+
this._replicationInfoBlockedPeers.delete(peerHash);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** ≡ the legacy `this._replicationInfoBlockedPeers.has(peerHash)`. */
|
|
184
|
+
isReplicationInfoBlocked(peerHash: string): boolean {
|
|
185
|
+
return this._replicationInfoBlockedPeers.has(peerHash);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** _close counterpart of the legacy
|
|
189
|
+
* `this._replicationInfoReceiveEpochByPeer?.clear()`: a receive-epoch
|
|
190
|
+
* capture held across close must compare against null, never against a
|
|
191
|
+
* surviving token. Sessions deliberately survive close (see
|
|
192
|
+
* resetForOpen); the paired membership-lifecycle term at every
|
|
193
|
+
* receive-epoch check site makes the ordering unobservable either way. */
|
|
194
|
+
clearReceiveEpochsForClose(): void {
|
|
195
|
+
this._replicationInfoReceiveEpochByPeer.clear();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** _close counterpart of the legacy
|
|
199
|
+
* `this._receiveCleanupGateByPeer?.clear()`: an in-place clear (NOT a
|
|
200
|
+
* map replacement) so an in-flight removal's captured release still
|
|
201
|
+
* drains the instance it incremented — see acquireReceiveCleanupGate. */
|
|
202
|
+
clearCleanupGatesForClose(): void {
|
|
203
|
+
this._receiveCleanupGateByPeer.clear();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** ≡ removeReplicator's inline `blockPeerReceiveAdmission` +
|
|
207
|
+
* release-in-`finally` pair (fence B6). Acquire captures the CURRENT
|
|
208
|
+
* gate-map instance and increments once; the returned release is
|
|
209
|
+
* idempotent and decrements the captured map, deleting the entry at 0.
|
|
210
|
+
* The map-instance capture is load-bearing: close/reopen replaces the
|
|
211
|
+
* map (resetForOpen), and a late release must drain the exact map it
|
|
212
|
+
* incremented — a release against a fresh open's map would corrupt that
|
|
213
|
+
* open's refcounts. The `?? 1` mirrors the legacy release: an entry
|
|
214
|
+
* cleared at _close decrements to 0 and stays deleted. */
|
|
215
|
+
acquireReceiveCleanupGate(peerHash: string): () => void {
|
|
216
|
+
const gates = this._receiveCleanupGateByPeer;
|
|
217
|
+
gates.set(peerHash, (gates.get(peerHash) ?? 0) + 1);
|
|
218
|
+
let released = false;
|
|
219
|
+
return () => {
|
|
220
|
+
if (released) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
released = true;
|
|
224
|
+
const remaining = (gates.get(peerHash) ?? 1) - 1;
|
|
225
|
+
if (remaining > 0) {
|
|
226
|
+
gates.set(peerHash, remaining);
|
|
227
|
+
} else {
|
|
228
|
+
gates.delete(peerHash);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** ≡ the legacy `(this._receiveCleanupGateByPeer.get(peer) ?? 0) === 0`
|
|
234
|
+
* read (receive-admission term and prune final-confirmation filter). */
|
|
235
|
+
isReceiveCleanupGateOpen(peerHash: string): boolean {
|
|
236
|
+
return (this._receiveCleanupGateByPeer.get(peerHash) ?? 0) === 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** ≡ legacy SharedLog.advanceReplicationInfoReceiveEpoch. Advances
|
|
240
|
+
* WITHOUT rotating the session — the recovery fence must survive
|
|
241
|
+
* removeReplicator, where the peer stays subscribed. */
|
|
242
|
+
advanceReceiveEpoch(peerHash: string): object {
|
|
243
|
+
const next = {};
|
|
244
|
+
this._replicationInfoReceiveEpochByPeer.set(peerHash, next);
|
|
245
|
+
return next;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/** ≡ legacy SharedLog.getReplicationInfoReceiveEpoch (`?? null`). */
|
|
249
|
+
receiveEpoch(peerHash: string): object | null {
|
|
250
|
+
return this._replicationInfoReceiveEpochByPeer.get(peerHash) ?? null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** ≡ legacy SharedLog.isCurrentReplicationInfoReceiveEpoch. */
|
|
254
|
+
isReceiveEpochCurrent(peerHash: string, epoch: object | null): boolean {
|
|
255
|
+
return this.receiveEpoch(peerHash) === epoch;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
current(peerHash: string): PeerSession | null {
|
|
259
|
+
return this.sessions.get(peerHash) ?? null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** null is a VALID current value: a peer that never subscribed has no
|
|
263
|
+
* session, and the former host predicate admitted
|
|
264
|
+
* isCurrent(peer, null) === true. Preserved exactly. */
|
|
265
|
+
isCurrent(peerHash: string, session: object | null): boolean {
|
|
266
|
+
return this.current(peerHash) === session;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** The only creation point. Supersedes (never deletes) the previous
|
|
270
|
+
* session — per-peer entries are never removed, matching today's map. */
|
|
271
|
+
rotate(peerHash: string, kind: PeerSessionKind): PeerSession {
|
|
272
|
+
const previous = this.sessions.get(peerHash);
|
|
273
|
+
if (previous) {
|
|
274
|
+
previous.phase = "superseded";
|
|
275
|
+
}
|
|
276
|
+
const next = new PeerSession(
|
|
277
|
+
this,
|
|
278
|
+
peerHash,
|
|
279
|
+
kind,
|
|
280
|
+
this.deps.getReplicationLifecycleController(),
|
|
281
|
+
);
|
|
282
|
+
this.sessions.set(peerHash, next);
|
|
283
|
+
return next;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Reconnect barrier completed. Identity-guarded phase mark; no-op when
|
|
287
|
+
* the expected token was superseded meanwhile. */
|
|
288
|
+
markOpen(peerHash: string, expectedSession: object): void {
|
|
289
|
+
const current = this.sessions.get(peerHash);
|
|
290
|
+
if (
|
|
291
|
+
current !== undefined &&
|
|
292
|
+
current === expectedSession &&
|
|
293
|
+
current.kind === "opening"
|
|
294
|
+
) {
|
|
295
|
+
current.phase = "open";
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/** Destructive removal committed for this peer. Mirrors the removal
|
|
300
|
+
* funnel's epoch scoping: an epoch-scoped removal only stamps the
|
|
301
|
+
* session it was scoped to — a reconnect during the removal's awaited
|
|
302
|
+
* lanes must not inherit the stamp. Undefined = unscoped removal,
|
|
303
|
+
* which stamps the current session as before; null scopes to "peer had
|
|
304
|
+
* no session at capture", so a session created meanwhile is never
|
|
305
|
+
* stamped. */
|
|
306
|
+
noteReplicatorRemoved(
|
|
307
|
+
peerHash: string,
|
|
308
|
+
expectedSession?: object | null,
|
|
309
|
+
): void {
|
|
310
|
+
const current = this.sessions.get(peerHash);
|
|
311
|
+
if (
|
|
312
|
+
current &&
|
|
313
|
+
(expectedSession === undefined || current === expectedSession)
|
|
314
|
+
) {
|
|
315
|
+
current.replicatorRemoved = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Preserves the former SharedLog.isPeerReceiveAdmissionOpen predicate term
|
|
320
|
+
* for term. `session` may be null (pre-session peer). */
|
|
321
|
+
isReceiveAdmissionOpen(
|
|
322
|
+
peerHash: string,
|
|
323
|
+
session: object | null,
|
|
324
|
+
replicationLifecycleController: AbortController | undefined,
|
|
325
|
+
options?: PeerReceiveAdmissionOptions,
|
|
326
|
+
): boolean {
|
|
327
|
+
return (
|
|
328
|
+
this.deps.isReplicationLifecycleActive(replicationLifecycleController) &&
|
|
329
|
+
this.isCurrent(peerHash, session) &&
|
|
330
|
+
(options?.allowReplicationInfoBlocked === true ||
|
|
331
|
+
!this.isReplicationInfoBlocked(peerHash)) &&
|
|
332
|
+
(options?.allowCleanupGate === true ||
|
|
333
|
+
this.isReceiveCleanupGateOpen(peerHash))
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|