@peerbit/shared-log 16.0.26 → 16.0.28
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 +43 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +160 -31
- package/dist/src/index.js.map +1 -1
- package/dist/src/replication-info-v2-receive.d.ts +27 -0
- package/dist/src/replication-info-v2-receive.d.ts.map +1 -1
- package/dist/src/replication-info-v2-receive.js +135 -0
- 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 +15 -15
- package/src/index.ts +274 -43
- package/src/replication-info-v2-receive.ts +209 -0
- package/src/replication-info-v2-send.ts +164 -0
|
@@ -122,11 +122,46 @@ type ReplicationInfoV2RemoteFullRearm = {
|
|
|
122
122
|
receiveEpoch: object | null;
|
|
123
123
|
receiverTransportSession: bigint;
|
|
124
124
|
nextAttemptAt: number;
|
|
125
|
+
attemptsStarted: number;
|
|
125
126
|
outstandingAttempts: number;
|
|
126
127
|
inFlight?: Promise<void>;
|
|
127
128
|
controller?: AbortController;
|
|
128
129
|
};
|
|
129
130
|
|
|
131
|
+
export type ReplicationInfoV2ReceiveDiagnostic = Readonly<{
|
|
132
|
+
state: "absent" | "current" | "stale";
|
|
133
|
+
/** Current-state classification; no historical packet/drop log is retained. */
|
|
134
|
+
reason:
|
|
135
|
+
| "state-absent"
|
|
136
|
+
| "peer-session-mismatch"
|
|
137
|
+
| "receive-epoch-mismatch"
|
|
138
|
+
| "transport-session-mismatch"
|
|
139
|
+
| "state-not-current"
|
|
140
|
+
| "admission-pending"
|
|
141
|
+
| "active"
|
|
142
|
+
| "request-parked"
|
|
143
|
+
| "request-in-flight"
|
|
144
|
+
| "request-scheduled"
|
|
145
|
+
| "awaiting-full"
|
|
146
|
+
| "resync";
|
|
147
|
+
phase?: ReplicationInfoV2ReceivePhase;
|
|
148
|
+
requestState?:
|
|
149
|
+
| "idle"
|
|
150
|
+
| "scheduled"
|
|
151
|
+
| "in-flight"
|
|
152
|
+
| "parked"
|
|
153
|
+
| "admission-pending";
|
|
154
|
+
lastAppliedSequence?: string;
|
|
155
|
+
requestAttempts?: number;
|
|
156
|
+
capabilityAdvertisementAttempts: number;
|
|
157
|
+
capabilityAdvertisement: "absent" | "advertising" | "ready" | "stale";
|
|
158
|
+
remoteFullRearm: "idle" | "in-flight" | "cooldown" | "limited";
|
|
159
|
+
remoteFullRearmAttempts: number;
|
|
160
|
+
remoteFullRearmOutstanding: number;
|
|
161
|
+
remoteFullRearmGlobalOutstanding: number;
|
|
162
|
+
remoteFullRearmCooldownRemainingMs?: number;
|
|
163
|
+
}>;
|
|
164
|
+
|
|
130
165
|
export type ReplicationInfoV2LocalCapabilityRefresh = {
|
|
131
166
|
receiverTransportSession: bigint;
|
|
132
167
|
requestNotBeforeMs: number;
|
|
@@ -796,6 +831,7 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
796
831
|
receiveEpoch: properties.receiveEpoch,
|
|
797
832
|
receiverTransportSession,
|
|
798
833
|
nextAttemptAt: now + this.remoteFullRearmCooldownMs,
|
|
834
|
+
attemptsStarted: 0,
|
|
799
835
|
outstandingAttempts: 0,
|
|
800
836
|
};
|
|
801
837
|
this._remoteFullRearmBySession.set(properties.peerSession, rearm);
|
|
@@ -804,6 +840,10 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
804
840
|
}
|
|
805
841
|
const attemptState = rearm;
|
|
806
842
|
const outstandingReservation = {};
|
|
843
|
+
attemptState.attemptsStarted = Math.min(
|
|
844
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL,
|
|
845
|
+
attemptState.attemptsStarted + 1,
|
|
846
|
+
);
|
|
807
847
|
attemptState.outstandingAttempts++;
|
|
808
848
|
this._remoteFullRearmOutstanding.add(outstandingReservation);
|
|
809
849
|
|
|
@@ -916,6 +956,175 @@ export class ReplicationInfoV2ReceiveCoordinator {
|
|
|
916
956
|
return true;
|
|
917
957
|
}
|
|
918
958
|
|
|
959
|
+
/**
|
|
960
|
+
* Bounded, read-only state for persisted-readiness troubleshooting. This
|
|
961
|
+
* intentionally omits transport sessions, challenges, payloads, and maps.
|
|
962
|
+
*/
|
|
963
|
+
diagnosePeer(properties: {
|
|
964
|
+
peerHash: string;
|
|
965
|
+
peerSession?: object;
|
|
966
|
+
receiveEpoch?: object | null;
|
|
967
|
+
senderTransportSession?: bigint;
|
|
968
|
+
}): ReplicationInfoV2ReceiveDiagnostic {
|
|
969
|
+
const state = this._receiveStates.get(properties.peerHash);
|
|
970
|
+
const advertisement = this._localCapabilityAdvertisementsByPeer.get(
|
|
971
|
+
properties.peerHash,
|
|
972
|
+
);
|
|
973
|
+
const session =
|
|
974
|
+
properties.peerSession ??
|
|
975
|
+
state?.peerSession ??
|
|
976
|
+
advertisement?.peerSession;
|
|
977
|
+
const ready = session
|
|
978
|
+
? this._localCapabilityReadyBySession.get(session)
|
|
979
|
+
: undefined;
|
|
980
|
+
let capabilityAdvertisement: ReplicationInfoV2ReceiveDiagnostic["capabilityAdvertisement"] =
|
|
981
|
+
"absent";
|
|
982
|
+
if (ready && ready.peerHash === properties.peerHash) {
|
|
983
|
+
capabilityAdvertisement =
|
|
984
|
+
session !== undefined &&
|
|
985
|
+
this.deps.isPeerSessionCurrent(properties.peerHash, session) &&
|
|
986
|
+
this.deps.isReceiveEpochCurrent(
|
|
987
|
+
properties.peerHash,
|
|
988
|
+
ready.receiveEpoch,
|
|
989
|
+
) &&
|
|
990
|
+
ready.receiverTransportSession ===
|
|
991
|
+
this.deps.getReceiverTransportSession() &&
|
|
992
|
+
(properties.receiveEpoch === undefined ||
|
|
993
|
+
ready.receiveEpoch === properties.receiveEpoch)
|
|
994
|
+
? "ready"
|
|
995
|
+
: "stale";
|
|
996
|
+
} else if (advertisement) {
|
|
997
|
+
capabilityAdvertisement =
|
|
998
|
+
advertisement.peerHash === properties.peerHash &&
|
|
999
|
+
advertisement.peerSession === session &&
|
|
1000
|
+
(properties.receiveEpoch === undefined ||
|
|
1001
|
+
advertisement.receiveEpoch === properties.receiveEpoch) &&
|
|
1002
|
+
this.isLocalCapabilityAdvertisementGenerationCurrent(advertisement)
|
|
1003
|
+
? "advertising"
|
|
1004
|
+
: "stale";
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const rearm = session
|
|
1008
|
+
? this._remoteFullRearmBySession.get(session)
|
|
1009
|
+
: undefined;
|
|
1010
|
+
const now = this.now();
|
|
1011
|
+
const rearmLimited =
|
|
1012
|
+
(rearm?.outstandingAttempts ?? 0) >=
|
|
1013
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION ||
|
|
1014
|
+
this._remoteFullRearmOutstanding.size >=
|
|
1015
|
+
this.maxRemoteFullRearmOutstandingGlobal;
|
|
1016
|
+
const rearmStatus: ReplicationInfoV2ReceiveDiagnostic["remoteFullRearm"] =
|
|
1017
|
+
rearm?.inFlight
|
|
1018
|
+
? "in-flight"
|
|
1019
|
+
: rearmLimited
|
|
1020
|
+
? "limited"
|
|
1021
|
+
: rearm && now < rearm.nextAttemptAt
|
|
1022
|
+
? "cooldown"
|
|
1023
|
+
: "idle";
|
|
1024
|
+
const common = {
|
|
1025
|
+
capabilityAdvertisementAttempts: Math.min(
|
|
1026
|
+
MAX_BACKOFF_EXPONENT + 1,
|
|
1027
|
+
Math.max(0, advertisement?.attempts ?? 0),
|
|
1028
|
+
),
|
|
1029
|
+
capabilityAdvertisement,
|
|
1030
|
+
remoteFullRearm: rearmStatus,
|
|
1031
|
+
remoteFullRearmAttempts: Math.min(
|
|
1032
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_GLOBAL,
|
|
1033
|
+
Math.max(0, rearm?.attemptsStarted ?? 0),
|
|
1034
|
+
),
|
|
1035
|
+
remoteFullRearmOutstanding: Math.min(
|
|
1036
|
+
MAX_REMOTE_FULL_REARM_OUTSTANDING_PER_SESSION,
|
|
1037
|
+
Math.max(0, rearm?.outstandingAttempts ?? 0),
|
|
1038
|
+
),
|
|
1039
|
+
remoteFullRearmGlobalOutstanding: Math.min(
|
|
1040
|
+
this.maxRemoteFullRearmOutstandingGlobal,
|
|
1041
|
+
this._remoteFullRearmOutstanding.size,
|
|
1042
|
+
),
|
|
1043
|
+
...(rearm && now < rearm.nextAttemptAt
|
|
1044
|
+
? {
|
|
1045
|
+
remoteFullRearmCooldownRemainingMs: Math.min(
|
|
1046
|
+
MAX_TIMER_MS,
|
|
1047
|
+
Math.max(0, rearm.nextAttemptAt - now),
|
|
1048
|
+
),
|
|
1049
|
+
}
|
|
1050
|
+
: {}),
|
|
1051
|
+
};
|
|
1052
|
+
if (!state) {
|
|
1053
|
+
return Object.freeze({
|
|
1054
|
+
state: "absent" as const,
|
|
1055
|
+
reason: "state-absent" as const,
|
|
1056
|
+
...common,
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
let status: "current" | "stale" = "current";
|
|
1061
|
+
let reason: ReplicationInfoV2ReceiveDiagnostic["reason"];
|
|
1062
|
+
if (
|
|
1063
|
+
properties.peerSession !== undefined &&
|
|
1064
|
+
state.peerSession !== properties.peerSession
|
|
1065
|
+
) {
|
|
1066
|
+
status = "stale";
|
|
1067
|
+
reason = "peer-session-mismatch";
|
|
1068
|
+
} else if (
|
|
1069
|
+
properties.receiveEpoch !== undefined &&
|
|
1070
|
+
state.receiveEpoch !== properties.receiveEpoch
|
|
1071
|
+
) {
|
|
1072
|
+
status = "stale";
|
|
1073
|
+
reason = "receive-epoch-mismatch";
|
|
1074
|
+
} else if (
|
|
1075
|
+
properties.senderTransportSession !== undefined &&
|
|
1076
|
+
state.senderTransportSession !== properties.senderTransportSession
|
|
1077
|
+
) {
|
|
1078
|
+
status = "stale";
|
|
1079
|
+
reason = "transport-session-mismatch";
|
|
1080
|
+
} else if (!this.isStateCurrent(state)) {
|
|
1081
|
+
status = "stale";
|
|
1082
|
+
reason = "state-not-current";
|
|
1083
|
+
} else if (
|
|
1084
|
+
state.reservedAdmission !== undefined ||
|
|
1085
|
+
this._reservedAdmissionsByPeer.has(properties.peerHash)
|
|
1086
|
+
) {
|
|
1087
|
+
reason = "admission-pending";
|
|
1088
|
+
} else if (state.phase === "active") {
|
|
1089
|
+
reason = "active";
|
|
1090
|
+
} else if (state.requestParked) {
|
|
1091
|
+
reason = "request-parked";
|
|
1092
|
+
} else if (state.requestInFlight !== undefined) {
|
|
1093
|
+
reason = "request-in-flight";
|
|
1094
|
+
} else if (state.requestTimer !== undefined) {
|
|
1095
|
+
reason = "request-scheduled";
|
|
1096
|
+
} else {
|
|
1097
|
+
reason = state.phase;
|
|
1098
|
+
}
|
|
1099
|
+
const requestState: NonNullable<
|
|
1100
|
+
ReplicationInfoV2ReceiveDiagnostic["requestState"]
|
|
1101
|
+
> =
|
|
1102
|
+
state.reservedAdmission !== undefined ||
|
|
1103
|
+
this._reservedAdmissionsByPeer.has(properties.peerHash)
|
|
1104
|
+
? "admission-pending"
|
|
1105
|
+
: state.requestParked
|
|
1106
|
+
? "parked"
|
|
1107
|
+
: state.requestInFlight !== undefined
|
|
1108
|
+
? "in-flight"
|
|
1109
|
+
: state.requestTimer !== undefined
|
|
1110
|
+
? "scheduled"
|
|
1111
|
+
: "idle";
|
|
1112
|
+
return Object.freeze({
|
|
1113
|
+
state: status,
|
|
1114
|
+
reason,
|
|
1115
|
+
phase: state.phase,
|
|
1116
|
+
requestState,
|
|
1117
|
+
...(state.lastSequence === undefined
|
|
1118
|
+
? {}
|
|
1119
|
+
: { lastAppliedSequence: state.lastSequence.toString() }),
|
|
1120
|
+
requestAttempts: Math.min(
|
|
1121
|
+
this.requestMaxAttempts,
|
|
1122
|
+
Math.max(0, state.requestAttempts),
|
|
1123
|
+
),
|
|
1124
|
+
...common,
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
|
|
919
1128
|
private promoteLocalCapabilityAdvertisement(
|
|
920
1129
|
state: ReplicationInfoV2LocalCapabilityAdvertisement,
|
|
921
1130
|
): boolean {
|
|
@@ -55,6 +55,7 @@ type ApplicationConfirmationTarget = {
|
|
|
55
55
|
type ApplicationConfirmationWaiter = {
|
|
56
56
|
revision: bigint;
|
|
57
57
|
minPeers: number;
|
|
58
|
+
startedAt: number;
|
|
58
59
|
target?: ApplicationConfirmationTarget;
|
|
59
60
|
resolve: () => void;
|
|
60
61
|
reject: (error: unknown) => void;
|
|
@@ -63,6 +64,37 @@ type ApplicationConfirmationWaiter = {
|
|
|
63
64
|
onAbort?: () => void;
|
|
64
65
|
};
|
|
65
66
|
|
|
67
|
+
export type ReplicationInfoV2SendDiagnostic = Readonly<{
|
|
68
|
+
state: "absent" | "current" | "stale";
|
|
69
|
+
/** Current-state classification; no historical packet/drop log is retained. */
|
|
70
|
+
reason:
|
|
71
|
+
| "state-absent"
|
|
72
|
+
| "state-retiring"
|
|
73
|
+
| "peer-session-mismatch"
|
|
74
|
+
| "transport-session-mismatch"
|
|
75
|
+
| "destination-not-current"
|
|
76
|
+
| "destination-not-open"
|
|
77
|
+
| "ownership-inactive"
|
|
78
|
+
| "retry-backoff"
|
|
79
|
+
| "send-in-flight"
|
|
80
|
+
| "send-pending"
|
|
81
|
+
| "confirmation-in-flight"
|
|
82
|
+
| "latest-applied"
|
|
83
|
+
| "latest-unconfirmed";
|
|
84
|
+
established?: boolean;
|
|
85
|
+
suspended?: boolean;
|
|
86
|
+
currentRevision: string;
|
|
87
|
+
pendingRevision?: string;
|
|
88
|
+
inFlightRevision?: string;
|
|
89
|
+
inFlightSequence?: string;
|
|
90
|
+
appliedRevision?: string;
|
|
91
|
+
confirmationRevision?: string;
|
|
92
|
+
confirmationSequence?: string;
|
|
93
|
+
retryAttempts?: number;
|
|
94
|
+
confirmationWaiters: number;
|
|
95
|
+
oldestConfirmationAgeMs?: number;
|
|
96
|
+
}>;
|
|
97
|
+
|
|
66
98
|
export type ReplicationInfoV2ConfirmationOptions = {
|
|
67
99
|
/** Distinct current peers that must report durable application. Defaults to 1. */
|
|
68
100
|
minPeers?: number;
|
|
@@ -460,6 +492,7 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
|
|
|
460
492
|
const waiter: ApplicationConfirmationWaiter = {
|
|
461
493
|
revision: this._revision,
|
|
462
494
|
minPeers: properties.minPeers,
|
|
495
|
+
startedAt: Date.now(),
|
|
463
496
|
target: properties.target ? { ...properties.target } : undefined,
|
|
464
497
|
resolve,
|
|
465
498
|
reject,
|
|
@@ -488,6 +521,137 @@ export class ReplicationInfoV2SendCoordinator<R extends "u32" | "u64"> {
|
|
|
488
521
|
});
|
|
489
522
|
}
|
|
490
523
|
|
|
524
|
+
/**
|
|
525
|
+
* Bounded, read-only state for persisted-readiness troubleshooting. Opaque
|
|
526
|
+
* session/challenge values and peer maps are intentionally excluded.
|
|
527
|
+
*/
|
|
528
|
+
diagnosePeer(target: {
|
|
529
|
+
peerHash: string;
|
|
530
|
+
peerSession?: object;
|
|
531
|
+
receiverTransportSession?: bigint;
|
|
532
|
+
}): ReplicationInfoV2SendDiagnostic {
|
|
533
|
+
const state = this._sendStates.get(target.peerHash);
|
|
534
|
+
let matchingConfirmationCount = 0;
|
|
535
|
+
let oldestStartedAt: number | undefined;
|
|
536
|
+
for (const waiter of this._confirmations) {
|
|
537
|
+
if (
|
|
538
|
+
waiter.target?.peerHash !== target.peerHash ||
|
|
539
|
+
(target.peerSession !== undefined &&
|
|
540
|
+
waiter.target.peerSession !== target.peerSession) ||
|
|
541
|
+
(target.receiverTransportSession !== undefined &&
|
|
542
|
+
waiter.target.receiverTransportSession !==
|
|
543
|
+
target.receiverTransportSession)
|
|
544
|
+
) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
matchingConfirmationCount++;
|
|
548
|
+
oldestStartedAt =
|
|
549
|
+
oldestStartedAt === undefined
|
|
550
|
+
? waiter.startedAt
|
|
551
|
+
: Math.min(oldestStartedAt, waiter.startedAt);
|
|
552
|
+
}
|
|
553
|
+
const common = {
|
|
554
|
+
currentRevision: this._revision.toString(),
|
|
555
|
+
confirmationWaiters: Math.min(
|
|
556
|
+
this.maxConfirmationWaiters,
|
|
557
|
+
matchingConfirmationCount,
|
|
558
|
+
),
|
|
559
|
+
...(oldestStartedAt === undefined
|
|
560
|
+
? {}
|
|
561
|
+
: {
|
|
562
|
+
oldestConfirmationAgeMs: Math.min(
|
|
563
|
+
MAX_TIMER_MS,
|
|
564
|
+
Math.max(0, Date.now() - oldestStartedAt),
|
|
565
|
+
),
|
|
566
|
+
}),
|
|
567
|
+
};
|
|
568
|
+
if (!state) {
|
|
569
|
+
return Object.freeze({
|
|
570
|
+
state: this._retiringWorkersByPeer.has(target.peerHash)
|
|
571
|
+
? ("stale" as const)
|
|
572
|
+
: ("absent" as const),
|
|
573
|
+
reason: this._retiringWorkersByPeer.has(target.peerHash)
|
|
574
|
+
? ("state-retiring" as const)
|
|
575
|
+
: ("state-absent" as const),
|
|
576
|
+
...common,
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
let status: "current" | "stale" = "current";
|
|
581
|
+
let reason: ReplicationInfoV2SendDiagnostic["reason"];
|
|
582
|
+
if (
|
|
583
|
+
target.peerSession !== undefined &&
|
|
584
|
+
state.peerSession !== target.peerSession
|
|
585
|
+
) {
|
|
586
|
+
status = "stale";
|
|
587
|
+
reason = "peer-session-mismatch";
|
|
588
|
+
} else if (
|
|
589
|
+
target.receiverTransportSession !== undefined &&
|
|
590
|
+
state.receiverTransportSession !== target.receiverTransportSession
|
|
591
|
+
) {
|
|
592
|
+
status = "stale";
|
|
593
|
+
reason = "transport-session-mismatch";
|
|
594
|
+
} else if (!this.isDestinationCurrent(state)) {
|
|
595
|
+
status = "stale";
|
|
596
|
+
reason = "destination-not-current";
|
|
597
|
+
} else if (!this.isDestinationReady(state)) {
|
|
598
|
+
reason = "destination-not-open";
|
|
599
|
+
} else if (
|
|
600
|
+
!this.deps.isReplicationOwnershipLifecycleActive(
|
|
601
|
+
state.ownershipLifecycleController,
|
|
602
|
+
)
|
|
603
|
+
) {
|
|
604
|
+
reason = "ownership-inactive";
|
|
605
|
+
} else if (state.suspended || state.retryTimer !== undefined) {
|
|
606
|
+
reason = "retry-backoff";
|
|
607
|
+
} else if (state.applicationConfirmationRequest !== undefined) {
|
|
608
|
+
reason = "confirmation-in-flight";
|
|
609
|
+
} else if (state.inFlightRevision !== undefined) {
|
|
610
|
+
reason = "send-in-flight";
|
|
611
|
+
} else if (state.pending !== undefined) {
|
|
612
|
+
reason = "send-pending";
|
|
613
|
+
} else if (
|
|
614
|
+
state.appliedRevision !== undefined &&
|
|
615
|
+
state.appliedRevision >= this._revision
|
|
616
|
+
) {
|
|
617
|
+
reason = "latest-applied";
|
|
618
|
+
} else {
|
|
619
|
+
reason = "latest-unconfirmed";
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
return Object.freeze({
|
|
623
|
+
state: status,
|
|
624
|
+
reason,
|
|
625
|
+
established: state.established,
|
|
626
|
+
suspended: state.suspended,
|
|
627
|
+
...common,
|
|
628
|
+
...(state.pending === undefined
|
|
629
|
+
? {}
|
|
630
|
+
: { pendingRevision: state.pending.revision.toString() }),
|
|
631
|
+
...(state.inFlightRevision === undefined
|
|
632
|
+
? {}
|
|
633
|
+
: { inFlightRevision: state.inFlightRevision.toString() }),
|
|
634
|
+
...(state.inFlightSequence === undefined
|
|
635
|
+
? {}
|
|
636
|
+
: { inFlightSequence: state.inFlightSequence.toString() }),
|
|
637
|
+
...(state.appliedRevision === undefined
|
|
638
|
+
? {}
|
|
639
|
+
: { appliedRevision: state.appliedRevision.toString() }),
|
|
640
|
+
...(state.applicationConfirmationRequest === undefined
|
|
641
|
+
? {}
|
|
642
|
+
: {
|
|
643
|
+
confirmationRevision:
|
|
644
|
+
state.applicationConfirmationRequest.revision.toString(),
|
|
645
|
+
confirmationSequence:
|
|
646
|
+
state.applicationConfirmationRequest.sequence.toString(),
|
|
647
|
+
}),
|
|
648
|
+
retryAttempts: Math.min(
|
|
649
|
+
MAX_BACKOFF_EXPONENT + 1,
|
|
650
|
+
Math.max(0, state.retryAttempts),
|
|
651
|
+
),
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
|
|
491
655
|
/**
|
|
492
656
|
* Wait until the latest committed local replication revision is reported as
|
|
493
657
|
* durably applied by the configured number of current peers. Revisions newer
|