@peerbit/shared-log 16.0.25 → 16.0.27
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/index.d.ts +45 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +167 -26
- package/dist/src/index.js.map +1 -1
- package/dist/src/replication-info-v2-receive.d.ts +49 -4
- package/dist/src/replication-info-v2-receive.d.ts.map +1 -1
- package/dist/src/replication-info-v2-receive.js +272 -25
- package/dist/src/replication-info-v2-receive.js.map +1 -1
- package/dist/src/replication-info-v2-send.d.ts +27 -0
- package/dist/src/replication-info-v2-send.d.ts.map +1 -1
- package/dist/src/replication-info-v2-send.js +112 -0
- package/dist/src/replication-info-v2-send.js.map +1 -1
- package/package.json +16 -16
- package/src/index.ts +297 -34
- package/src/replication-info-v2-receive.ts +409 -31
- package/src/replication-info-v2-send.ts +164 -0
|
@@ -46,9 +46,31 @@ export type ReplicationInfoV2LocalCapabilityAdvertisement = {
|
|
|
46
46
|
firstAttempt?: Promise<void>;
|
|
47
47
|
};
|
|
48
48
|
type ReplicationInfoV2RemoteFullRearm = {
|
|
49
|
-
|
|
49
|
+
peerHash: string;
|
|
50
|
+
receiveEpoch: object | null;
|
|
51
|
+
receiverTransportSession: bigint;
|
|
52
|
+
nextAttemptAt: number;
|
|
53
|
+
attemptsStarted: number;
|
|
54
|
+
outstandingAttempts: number;
|
|
50
55
|
inFlight?: Promise<void>;
|
|
56
|
+
controller?: AbortController;
|
|
51
57
|
};
|
|
58
|
+
export type ReplicationInfoV2ReceiveDiagnostic = Readonly<{
|
|
59
|
+
state: "absent" | "current" | "stale";
|
|
60
|
+
/** Current-state classification; no historical packet/drop log is retained. */
|
|
61
|
+
reason: "state-absent" | "peer-session-mismatch" | "receive-epoch-mismatch" | "transport-session-mismatch" | "state-not-current" | "admission-pending" | "active" | "request-parked" | "request-in-flight" | "request-scheduled" | "awaiting-full" | "resync";
|
|
62
|
+
phase?: ReplicationInfoV2ReceivePhase;
|
|
63
|
+
requestState?: "idle" | "scheduled" | "in-flight" | "parked" | "admission-pending";
|
|
64
|
+
lastAppliedSequence?: string;
|
|
65
|
+
requestAttempts?: number;
|
|
66
|
+
capabilityAdvertisementAttempts: number;
|
|
67
|
+
capabilityAdvertisement: "absent" | "advertising" | "ready" | "stale";
|
|
68
|
+
remoteFullRearm: "idle" | "in-flight" | "cooldown" | "limited";
|
|
69
|
+
remoteFullRearmAttempts: number;
|
|
70
|
+
remoteFullRearmOutstanding: number;
|
|
71
|
+
remoteFullRearmGlobalOutstanding: number;
|
|
72
|
+
remoteFullRearmCooldownRemainingMs?: number;
|
|
73
|
+
}>;
|
|
52
74
|
export type ReplicationInfoV2LocalCapabilityRefresh = {
|
|
53
75
|
receiverTransportSession: bigint;
|
|
54
76
|
requestNotBeforeMs: number;
|
|
@@ -111,6 +133,9 @@ export type ReplicationInfoV2ReceiveDeps = {
|
|
|
111
133
|
requestRetryMs?: number;
|
|
112
134
|
maxRequestRetryMs?: number;
|
|
113
135
|
requestMaxAttempts?: number;
|
|
136
|
+
remoteFullRearmAttemptTimeoutMs?: number;
|
|
137
|
+
remoteFullRearmCooldownMs?: number;
|
|
138
|
+
maxRemoteFullRearmOutstandingGlobal?: number;
|
|
114
139
|
};
|
|
115
140
|
/**
|
|
116
141
|
* Authenticated receive grants and sender-authoritative ordering for
|
|
@@ -133,11 +158,16 @@ export declare class ReplicationInfoV2ReceiveCoordinator {
|
|
|
133
158
|
_localCapabilityContextBySession: WeakMap<object, ReplicationInfoV2LocalCapabilityContext>;
|
|
134
159
|
_localCapabilityAdvertisementsByPeer: Map<string, ReplicationInfoV2LocalCapabilityAdvertisement>;
|
|
135
160
|
_remoteFullRearmBySession: WeakMap<object, ReplicationInfoV2RemoteFullRearm>;
|
|
161
|
+
_remoteFullRearmsInFlight: Set<ReplicationInfoV2RemoteFullRearm>;
|
|
162
|
+
_remoteFullRearmOutstanding: Set<object>;
|
|
136
163
|
_reservedAdmissionsByPeer: Map<string, ReplicationInfoV2ReceiveAdmission>;
|
|
137
164
|
private readonly now;
|
|
138
165
|
private readonly requestRetryMs;
|
|
139
166
|
private readonly maxRequestRetryMs;
|
|
140
167
|
private readonly requestMaxAttempts;
|
|
168
|
+
private readonly remoteFullRearmAttemptTimeoutMs;
|
|
169
|
+
private readonly remoteFullRearmCooldownMs;
|
|
170
|
+
private readonly maxRemoteFullRearmOutstandingGlobal;
|
|
141
171
|
constructor(deps: ReplicationInfoV2ReceiveDeps);
|
|
142
172
|
resetForOpen(): void;
|
|
143
173
|
clearForClose(): void;
|
|
@@ -171,9 +201,14 @@ export declare class ReplicationInfoV2ReceiveCoordinator {
|
|
|
171
201
|
* stream that was lost while both directions otherwise remained current.
|
|
172
202
|
*
|
|
173
203
|
* This deliberately does not mutate the steady advertisement worker. One
|
|
174
|
-
* attempt is coalesced per PeerSession and bound to
|
|
175
|
-
*
|
|
176
|
-
*
|
|
204
|
+
* attempt is coalesced per exact PeerSession/receive generation and bound to
|
|
205
|
+
* its own deadline as well as the caller's signal. A cooldown avoids rotating
|
|
206
|
+
* a healthy in-flight challenge on every recovery tick. The remote rotates
|
|
207
|
+
* only when its receive state is active; later hints during resync only nudge
|
|
208
|
+
* that same bounded request generation. At most two transports that disregard
|
|
209
|
+
* abort remain outstanding for one exact session (64 across this coordinator's
|
|
210
|
+
* lifetime); reaching either cap stops new hints while the persisted-readiness
|
|
211
|
+
* gate remains fail closed.
|
|
177
212
|
*/
|
|
178
213
|
reAdvertiseLocalCapabilityForRemoteFull(properties: {
|
|
179
214
|
peerHash: string;
|
|
@@ -181,6 +216,16 @@ export declare class ReplicationInfoV2ReceiveCoordinator {
|
|
|
181
216
|
receiveEpoch: object | null;
|
|
182
217
|
signal: AbortSignal;
|
|
183
218
|
}): boolean;
|
|
219
|
+
/**
|
|
220
|
+
* Bounded, read-only state for persisted-readiness troubleshooting. This
|
|
221
|
+
* intentionally omits transport sessions, challenges, payloads, and maps.
|
|
222
|
+
*/
|
|
223
|
+
diagnosePeer(properties: {
|
|
224
|
+
peerHash: string;
|
|
225
|
+
peerSession?: object;
|
|
226
|
+
receiveEpoch?: object | null;
|
|
227
|
+
senderTransportSession?: bigint;
|
|
228
|
+
}): ReplicationInfoV2ReceiveDiagnostic;
|
|
184
229
|
private promoteLocalCapabilityAdvertisement;
|
|
185
230
|
/**
|
|
186
231
|
* Re-advertise one exact current recovery epoch from the stable membership
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replication-info-v2-receive.d.ts","sourceRoot":"","sources":["../../src/replication-info-v2-receive.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAA2B,MAAM,iBAAiB,CAAC;AAM9E,OAAO,EAKN,+BAA+B,EAC/B,KAAK,wBAAwB,EAC7B,sCAAsC,EACtC,+BAA+B,EAG/B,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"replication-info-v2-receive.d.ts","sourceRoot":"","sources":["../../src/replication-info-v2-receive.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,11 @@ const REQUIRED_SENDER_CAPABILITIES = SYNC_CAPABILITY_REPLICATION_INFO_V2_DECODE
|
|
|
8
8
|
const DEFAULT_REQUEST_RETRY_MS = 1_000;
|
|
9
9
|
const DEFAULT_MAX_REQUEST_RETRY_MS = 30_000;
|
|
10
10
|
const DEFAULT_REQUEST_MAX_ATTEMPTS = 7;
|
|
11
|
+
const DEFAULT_REMOTE_FULL_REARM_ATTEMPT_TIMEOUT_MS = 2_000;
|
|
12
|
+
const DEFAULT_REMOTE_FULL_REARM_COOLDOWN_MS = 5_000;
|
|
13
|
+
const MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION = 2;
|
|
14
|
+
const MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL = 64;
|
|
15
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
11
16
|
const MAX_U64 = (1n << 64n) - 1n;
|
|
12
17
|
const MAX_BACKOFF_EXPONENT = 20;
|
|
13
18
|
const bytesEqual = (left, right) => {
|
|
@@ -56,23 +61,38 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
56
61
|
_localCapabilityContextBySession;
|
|
57
62
|
_localCapabilityAdvertisementsByPeer;
|
|
58
63
|
_remoteFullRearmBySession;
|
|
64
|
+
_remoteFullRearmsInFlight;
|
|
65
|
+
_remoteFullRearmOutstanding;
|
|
59
66
|
_reservedAdmissionsByPeer;
|
|
60
67
|
now;
|
|
61
68
|
requestRetryMs;
|
|
62
69
|
maxRequestRetryMs;
|
|
63
70
|
requestMaxAttempts;
|
|
71
|
+
remoteFullRearmAttemptTimeoutMs;
|
|
72
|
+
remoteFullRearmCooldownMs;
|
|
73
|
+
maxRemoteFullRearmOutstandingGlobal;
|
|
64
74
|
constructor(deps) {
|
|
65
75
|
this.deps = deps;
|
|
66
76
|
this.now = deps.now ?? Date.now;
|
|
67
77
|
this.requestRetryMs = Math.max(1, deps.requestRetryMs ?? DEFAULT_REQUEST_RETRY_MS);
|
|
68
78
|
this.maxRequestRetryMs = Math.max(this.requestRetryMs, deps.maxRequestRetryMs ?? DEFAULT_MAX_REQUEST_RETRY_MS);
|
|
69
79
|
this.requestMaxAttempts = Math.max(1, Math.floor(deps.requestMaxAttempts ?? DEFAULT_REQUEST_MAX_ATTEMPTS));
|
|
80
|
+
this.remoteFullRearmAttemptTimeoutMs = Math.max(1, Math.min(MAX_TIMER_MS, Math.floor(deps.remoteFullRearmAttemptTimeoutMs ??
|
|
81
|
+
DEFAULT_REMOTE_FULL_REARM_ATTEMPT_TIMEOUT_MS)));
|
|
82
|
+
this.remoteFullRearmCooldownMs = Math.max(this.requestRetryMs, Math.min(MAX_TIMER_MS, Math.floor(deps.remoteFullRearmCooldownMs ??
|
|
83
|
+
DEFAULT_REMOTE_FULL_REARM_COOLDOWN_MS)));
|
|
84
|
+
// The injected value is a test seam that may only tighten this lifetime
|
|
85
|
+
// resource bound, never widen it.
|
|
86
|
+
this.maxRemoteFullRearmOutstandingGlobal = Math.min(MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL, Math.max(1, Math.floor(deps.maxRemoteFullRearmOutstandingGlobal ??
|
|
87
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL)));
|
|
70
88
|
this._receiveStates = new Map();
|
|
71
89
|
this._cutoverPeerSessions = new WeakSet();
|
|
72
90
|
this._localCapabilityReadyBySession = new WeakMap();
|
|
73
91
|
this._localCapabilityContextBySession = new WeakMap();
|
|
74
92
|
this._localCapabilityAdvertisementsByPeer = new Map();
|
|
75
93
|
this._remoteFullRearmBySession = new WeakMap();
|
|
94
|
+
this._remoteFullRearmsInFlight = new Set();
|
|
95
|
+
this._remoteFullRearmOutstanding = new Set();
|
|
76
96
|
this._reservedAdmissionsByPeer = new Map();
|
|
77
97
|
}
|
|
78
98
|
resetForOpen() {
|
|
@@ -83,9 +103,14 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
83
103
|
this._localCapabilityContextBySession = new WeakMap();
|
|
84
104
|
this._localCapabilityAdvertisementsByPeer = new Map();
|
|
85
105
|
this._remoteFullRearmBySession = new WeakMap();
|
|
106
|
+
this._remoteFullRearmsInFlight = new Set();
|
|
86
107
|
this._reservedAdmissionsByPeer = new Map();
|
|
87
108
|
}
|
|
88
109
|
clearForClose() {
|
|
110
|
+
for (const rearm of this._remoteFullRearmsInFlight ?? []) {
|
|
111
|
+
rearm.controller?.abort(new Error("Replication-info V2 receiver closed during remote Full rearm"));
|
|
112
|
+
}
|
|
113
|
+
this._remoteFullRearmsInFlight?.clear();
|
|
89
114
|
for (const advertisement of [
|
|
90
115
|
...(this._localCapabilityAdvertisementsByPeer?.values() ?? []),
|
|
91
116
|
]) {
|
|
@@ -114,10 +139,23 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
114
139
|
this._localCapabilityContextBySession.delete(state.peerSession);
|
|
115
140
|
this._cutoverPeerSessions.delete(state.peerSession);
|
|
116
141
|
}
|
|
142
|
+
if (!expectedSession) {
|
|
143
|
+
for (const rearm of this._remoteFullRearmsInFlight) {
|
|
144
|
+
if (rearm.peerHash === peerHash) {
|
|
145
|
+
rearm.controller?.abort(new Error("Replication-info V2 peer cleared during rearm"));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const rearmSession = expectedSession ?? state?.peerSession ?? advertisement?.peerSession;
|
|
150
|
+
if (rearmSession) {
|
|
151
|
+
this._remoteFullRearmBySession
|
|
152
|
+
.get(rearmSession)
|
|
153
|
+
?.controller?.abort(new Error("Replication-info V2 peer session cleared during rearm"));
|
|
154
|
+
this._remoteFullRearmBySession.delete(rearmSession);
|
|
155
|
+
}
|
|
117
156
|
if (expectedSession) {
|
|
118
157
|
this._localCapabilityReadyBySession.delete(expectedSession);
|
|
119
158
|
this._localCapabilityContextBySession.delete(expectedSession);
|
|
120
|
-
this._remoteFullRearmBySession.delete(expectedSession);
|
|
121
159
|
this._cutoverPeerSessions.delete(expectedSession);
|
|
122
160
|
}
|
|
123
161
|
}
|
|
@@ -388,9 +426,14 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
388
426
|
* stream that was lost while both directions otherwise remained current.
|
|
389
427
|
*
|
|
390
428
|
* This deliberately does not mutate the steady advertisement worker. One
|
|
391
|
-
* attempt is coalesced per PeerSession and bound to
|
|
392
|
-
*
|
|
393
|
-
*
|
|
429
|
+
* attempt is coalesced per exact PeerSession/receive generation and bound to
|
|
430
|
+
* its own deadline as well as the caller's signal. A cooldown avoids rotating
|
|
431
|
+
* a healthy in-flight challenge on every recovery tick. The remote rotates
|
|
432
|
+
* only when its receive state is active; later hints during resync only nudge
|
|
433
|
+
* that same bounded request generation. At most two transports that disregard
|
|
434
|
+
* abort remain outstanding for one exact session (64 across this coordinator's
|
|
435
|
+
* lifetime); reaching either cap stops new hints while the persisted-readiness
|
|
436
|
+
* gate remains fail closed.
|
|
394
437
|
*/
|
|
395
438
|
reAdvertiseLocalCapabilityForRemoteFull(properties) {
|
|
396
439
|
const context = this._localCapabilityContextBySession.get(properties.peerSession);
|
|
@@ -408,33 +451,69 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
408
451
|
return false;
|
|
409
452
|
}
|
|
410
453
|
const now = this.now();
|
|
454
|
+
const receiverTransportSession = ready.receiverTransportSession;
|
|
411
455
|
let rearm = this._remoteFullRearmBySession.get(properties.peerSession);
|
|
456
|
+
if (rearm &&
|
|
457
|
+
(rearm.peerHash !== properties.peerHash ||
|
|
458
|
+
rearm.receiveEpoch !== properties.receiveEpoch ||
|
|
459
|
+
rearm.receiverTransportSession !== receiverTransportSession)) {
|
|
460
|
+
rearm.controller?.abort(new Error("Replication-info V2 remote Full rearm generation changed"));
|
|
461
|
+
rearm = undefined;
|
|
462
|
+
}
|
|
412
463
|
if (rearm?.inFlight) {
|
|
413
464
|
return true;
|
|
414
465
|
}
|
|
415
|
-
if (rearm !== undefined &&
|
|
416
|
-
|
|
466
|
+
if (rearm !== undefined && now < rearm.nextAttemptAt) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
if ((rearm?.outstandingAttempts ?? 0) >=
|
|
470
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION ||
|
|
471
|
+
this._remoteFullRearmOutstanding.size >=
|
|
472
|
+
this.maxRemoteFullRearmOutstandingGlobal) {
|
|
417
473
|
return true;
|
|
418
474
|
}
|
|
419
475
|
if (!rearm) {
|
|
420
|
-
rearm = {
|
|
476
|
+
rearm = {
|
|
477
|
+
peerHash: properties.peerHash,
|
|
478
|
+
receiveEpoch: properties.receiveEpoch,
|
|
479
|
+
receiverTransportSession,
|
|
480
|
+
nextAttemptAt: now + this.remoteFullRearmCooldownMs,
|
|
481
|
+
attemptsStarted: 0,
|
|
482
|
+
outstandingAttempts: 0,
|
|
483
|
+
};
|
|
421
484
|
this._remoteFullRearmBySession.set(properties.peerSession, rearm);
|
|
422
485
|
}
|
|
423
486
|
else {
|
|
424
|
-
rearm.
|
|
425
|
-
}
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
487
|
+
rearm.nextAttemptAt = now + this.remoteFullRearmCooldownMs;
|
|
488
|
+
}
|
|
489
|
+
const attemptState = rearm;
|
|
490
|
+
const outstandingReservation = {};
|
|
491
|
+
attemptState.attemptsStarted = Math.min(MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL, attemptState.attemptsStarted + 1);
|
|
492
|
+
attemptState.outstandingAttempts++;
|
|
493
|
+
this._remoteFullRearmOutstanding.add(outstandingReservation);
|
|
494
|
+
const attemptController = new AbortController();
|
|
495
|
+
const operationSignal = attemptController.signal;
|
|
496
|
+
attemptState.controller = attemptController;
|
|
497
|
+
this._remoteFullRearmsInFlight.add(attemptState);
|
|
498
|
+
const sourceSignals = Array.from(new Set([context.lifecycleSignal, properties.signal]));
|
|
499
|
+
const onSourceAbort = (event) => {
|
|
500
|
+
const source = event.currentTarget;
|
|
501
|
+
attemptController.abort(source.reason);
|
|
502
|
+
};
|
|
503
|
+
for (const source of sourceSignals) {
|
|
504
|
+
source.addEventListener("abort", onSourceAbort, { once: true });
|
|
505
|
+
}
|
|
506
|
+
const attemptTimer = setTimeout(() => attemptController.abort(new Error("Replication-info V2 remote Full rearm attempt timed out")), this.remoteFullRearmAttemptTimeoutMs);
|
|
507
|
+
attemptTimer.unref?.();
|
|
508
|
+
let releasedOutstanding = false;
|
|
509
|
+
const releaseOutstanding = () => {
|
|
510
|
+
if (releasedOutstanding)
|
|
511
|
+
return;
|
|
512
|
+
releasedOutstanding = true;
|
|
513
|
+
this._remoteFullRearmOutstanding.delete(outstandingReservation);
|
|
514
|
+
attemptState.outstandingAttempts--;
|
|
435
515
|
};
|
|
436
|
-
|
|
437
|
-
.then(() => {
|
|
516
|
+
const refresh = Promise.resolve().then(() => {
|
|
438
517
|
if (operationSignal.aborted) {
|
|
439
518
|
throw operationSignal.reason;
|
|
440
519
|
}
|
|
@@ -446,7 +525,40 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
446
525
|
signal: operationSignal,
|
|
447
526
|
requestRemoteFullRearm: true,
|
|
448
527
|
});
|
|
449
|
-
})
|
|
528
|
+
});
|
|
529
|
+
void refresh.then(releaseOutstanding, releaseOutstanding);
|
|
530
|
+
let operation;
|
|
531
|
+
const detach = () => {
|
|
532
|
+
clearTimeout(attemptTimer);
|
|
533
|
+
operationSignal.removeEventListener("abort", detach);
|
|
534
|
+
for (const source of sourceSignals) {
|
|
535
|
+
source.removeEventListener("abort", onSourceAbort);
|
|
536
|
+
}
|
|
537
|
+
if (attemptState.inFlight === operation) {
|
|
538
|
+
this._remoteFullRearmsInFlight.delete(attemptState);
|
|
539
|
+
attemptState.inFlight = undefined;
|
|
540
|
+
attemptState.controller = undefined;
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
const raceWithAttemptSignal = (promise) => new Promise((resolve, reject) => {
|
|
544
|
+
const onAbort = () => {
|
|
545
|
+
operationSignal.removeEventListener("abort", onAbort);
|
|
546
|
+
reject(operationSignal.reason);
|
|
547
|
+
};
|
|
548
|
+
operationSignal.addEventListener("abort", onAbort, { once: true });
|
|
549
|
+
if (operationSignal.aborted) {
|
|
550
|
+
onAbort();
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
553
|
+
promise.then((value) => {
|
|
554
|
+
operationSignal.removeEventListener("abort", onAbort);
|
|
555
|
+
resolve(value);
|
|
556
|
+
}, (error) => {
|
|
557
|
+
operationSignal.removeEventListener("abort", onAbort);
|
|
558
|
+
reject(error);
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
operation = raceWithAttemptSignal(refresh)
|
|
450
562
|
.then(() => undefined)
|
|
451
563
|
.catch((error) => {
|
|
452
564
|
if (!operationSignal.aborted &&
|
|
@@ -456,17 +568,152 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
456
568
|
}
|
|
457
569
|
})
|
|
458
570
|
.finally(() => {
|
|
459
|
-
operationSignal.removeEventListener("abort", detach);
|
|
460
571
|
detach();
|
|
461
572
|
});
|
|
462
|
-
|
|
573
|
+
attemptState.inFlight = operation;
|
|
463
574
|
operationSignal.addEventListener("abort", detach, { once: true });
|
|
464
|
-
|
|
465
|
-
|
|
575
|
+
for (const source of sourceSignals) {
|
|
576
|
+
if (source.aborted) {
|
|
577
|
+
attemptController.abort(source.reason);
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
466
580
|
}
|
|
467
581
|
void operation;
|
|
468
582
|
return true;
|
|
469
583
|
}
|
|
584
|
+
/**
|
|
585
|
+
* Bounded, read-only state for persisted-readiness troubleshooting. This
|
|
586
|
+
* intentionally omits transport sessions, challenges, payloads, and maps.
|
|
587
|
+
*/
|
|
588
|
+
diagnosePeer(properties) {
|
|
589
|
+
const state = this._receiveStates.get(properties.peerHash);
|
|
590
|
+
const advertisement = this._localCapabilityAdvertisementsByPeer.get(properties.peerHash);
|
|
591
|
+
const session = properties.peerSession ??
|
|
592
|
+
state?.peerSession ??
|
|
593
|
+
advertisement?.peerSession;
|
|
594
|
+
const ready = session
|
|
595
|
+
? this._localCapabilityReadyBySession.get(session)
|
|
596
|
+
: undefined;
|
|
597
|
+
let capabilityAdvertisement = "absent";
|
|
598
|
+
if (ready && ready.peerHash === properties.peerHash) {
|
|
599
|
+
capabilityAdvertisement =
|
|
600
|
+
session !== undefined &&
|
|
601
|
+
this.deps.isPeerSessionCurrent(properties.peerHash, session) &&
|
|
602
|
+
this.deps.isReceiveEpochCurrent(properties.peerHash, ready.receiveEpoch) &&
|
|
603
|
+
ready.receiverTransportSession ===
|
|
604
|
+
this.deps.getReceiverTransportSession() &&
|
|
605
|
+
(properties.receiveEpoch === undefined ||
|
|
606
|
+
ready.receiveEpoch === properties.receiveEpoch)
|
|
607
|
+
? "ready"
|
|
608
|
+
: "stale";
|
|
609
|
+
}
|
|
610
|
+
else if (advertisement) {
|
|
611
|
+
capabilityAdvertisement =
|
|
612
|
+
advertisement.peerHash === properties.peerHash &&
|
|
613
|
+
advertisement.peerSession === session &&
|
|
614
|
+
(properties.receiveEpoch === undefined ||
|
|
615
|
+
advertisement.receiveEpoch === properties.receiveEpoch) &&
|
|
616
|
+
this.isLocalCapabilityAdvertisementGenerationCurrent(advertisement)
|
|
617
|
+
? "advertising"
|
|
618
|
+
: "stale";
|
|
619
|
+
}
|
|
620
|
+
const rearm = session
|
|
621
|
+
? this._remoteFullRearmBySession.get(session)
|
|
622
|
+
: undefined;
|
|
623
|
+
const now = this.now();
|
|
624
|
+
const rearmLimited = (rearm?.outstandingAttempts ?? 0) >=
|
|
625
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION ||
|
|
626
|
+
this._remoteFullRearmOutstanding.size >=
|
|
627
|
+
this.maxRemoteFullRearmOutstandingGlobal;
|
|
628
|
+
const rearmStatus = rearm?.inFlight
|
|
629
|
+
? "in-flight"
|
|
630
|
+
: rearmLimited
|
|
631
|
+
? "limited"
|
|
632
|
+
: rearm && now < rearm.nextAttemptAt
|
|
633
|
+
? "cooldown"
|
|
634
|
+
: "idle";
|
|
635
|
+
const common = {
|
|
636
|
+
capabilityAdvertisementAttempts: Math.min(MAX_BACKOFF_EXPONENT + 1, Math.max(0, advertisement?.attempts ?? 0)),
|
|
637
|
+
capabilityAdvertisement,
|
|
638
|
+
remoteFullRearm: rearmStatus,
|
|
639
|
+
remoteFullRearmAttempts: Math.min(MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL, Math.max(0, rearm?.attemptsStarted ?? 0)),
|
|
640
|
+
remoteFullRearmOutstanding: Math.min(MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION, Math.max(0, rearm?.outstandingAttempts ?? 0)),
|
|
641
|
+
remoteFullRearmGlobalOutstanding: Math.min(this.maxRemoteFullRearmOutstandingGlobal, this._remoteFullRearmOutstanding.size),
|
|
642
|
+
...(rearm && now < rearm.nextAttemptAt
|
|
643
|
+
? {
|
|
644
|
+
remoteFullRearmCooldownRemainingMs: Math.min(MAX_TIMER_MS, Math.max(0, rearm.nextAttemptAt - now)),
|
|
645
|
+
}
|
|
646
|
+
: {}),
|
|
647
|
+
};
|
|
648
|
+
if (!state) {
|
|
649
|
+
return Object.freeze({
|
|
650
|
+
state: "absent",
|
|
651
|
+
reason: "state-absent",
|
|
652
|
+
...common,
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
let status = "current";
|
|
656
|
+
let reason;
|
|
657
|
+
if (properties.peerSession !== undefined &&
|
|
658
|
+
state.peerSession !== properties.peerSession) {
|
|
659
|
+
status = "stale";
|
|
660
|
+
reason = "peer-session-mismatch";
|
|
661
|
+
}
|
|
662
|
+
else if (properties.receiveEpoch !== undefined &&
|
|
663
|
+
state.receiveEpoch !== properties.receiveEpoch) {
|
|
664
|
+
status = "stale";
|
|
665
|
+
reason = "receive-epoch-mismatch";
|
|
666
|
+
}
|
|
667
|
+
else if (properties.senderTransportSession !== undefined &&
|
|
668
|
+
state.senderTransportSession !== properties.senderTransportSession) {
|
|
669
|
+
status = "stale";
|
|
670
|
+
reason = "transport-session-mismatch";
|
|
671
|
+
}
|
|
672
|
+
else if (!this.isStateCurrent(state)) {
|
|
673
|
+
status = "stale";
|
|
674
|
+
reason = "state-not-current";
|
|
675
|
+
}
|
|
676
|
+
else if (state.reservedAdmission !== undefined ||
|
|
677
|
+
this._reservedAdmissionsByPeer.has(properties.peerHash)) {
|
|
678
|
+
reason = "admission-pending";
|
|
679
|
+
}
|
|
680
|
+
else if (state.phase === "active") {
|
|
681
|
+
reason = "active";
|
|
682
|
+
}
|
|
683
|
+
else if (state.requestParked) {
|
|
684
|
+
reason = "request-parked";
|
|
685
|
+
}
|
|
686
|
+
else if (state.requestInFlight !== undefined) {
|
|
687
|
+
reason = "request-in-flight";
|
|
688
|
+
}
|
|
689
|
+
else if (state.requestTimer !== undefined) {
|
|
690
|
+
reason = "request-scheduled";
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
reason = state.phase;
|
|
694
|
+
}
|
|
695
|
+
const requestState = state.reservedAdmission !== undefined ||
|
|
696
|
+
this._reservedAdmissionsByPeer.has(properties.peerHash)
|
|
697
|
+
? "admission-pending"
|
|
698
|
+
: state.requestParked
|
|
699
|
+
? "parked"
|
|
700
|
+
: state.requestInFlight !== undefined
|
|
701
|
+
? "in-flight"
|
|
702
|
+
: state.requestTimer !== undefined
|
|
703
|
+
? "scheduled"
|
|
704
|
+
: "idle";
|
|
705
|
+
return Object.freeze({
|
|
706
|
+
state: status,
|
|
707
|
+
reason,
|
|
708
|
+
phase: state.phase,
|
|
709
|
+
requestState,
|
|
710
|
+
...(state.lastSequence === undefined
|
|
711
|
+
? {}
|
|
712
|
+
: { lastAppliedSequence: state.lastSequence.toString() }),
|
|
713
|
+
requestAttempts: Math.min(this.requestMaxAttempts, Math.max(0, state.requestAttempts)),
|
|
714
|
+
...common,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
470
717
|
promoteLocalCapabilityAdvertisement(state) {
|
|
471
718
|
const ready = state.acknowledgedReady;
|
|
472
719
|
if (state.ready ||
|