@peerbit/shared-log 16.0.28 → 16.0.30
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 +70 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +257 -42
- package/dist/src/index.js.map +1 -1
- package/dist/src/replication-info-v2-receive.d.ts.map +1 -1
- package/dist/src/replication-info-v2-receive.js +9 -2
- package/dist/src/replication-info-v2-receive.js.map +1 -1
- package/dist/src/replication-info-v2-send.d.ts +9 -2
- package/dist/src/replication-info-v2-send.d.ts.map +1 -1
- package/dist/src/replication-info-v2-send.js +67 -32
- package/dist/src/replication-info-v2-send.js.map +1 -1
- package/package.json +19 -19
- package/src/index.ts +267 -56
- package/src/replication-info-v2-receive.ts +13 -2
- package/src/replication-info-v2-send.ts +95 -42
package/dist/src/index.js
CHANGED
|
@@ -186,7 +186,7 @@ const emitAdvisorySyncProfileDuration = (profile, startedAt, event) => {
|
|
|
186
186
|
emitSyncProfileDuration(profile, startedAt, event);
|
|
187
187
|
}
|
|
188
188
|
catch {
|
|
189
|
-
//
|
|
189
|
+
// Advisory diagnostics must not change replication or lifecycle behavior.
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
192
|
const canUseOptionalNativeModuleImports = () => {
|
|
@@ -1964,7 +1964,7 @@ let SharedLog = (() => {
|
|
|
1964
1964
|
bumpSimpleFallbackPasses: () => {
|
|
1965
1965
|
this._repairMetrics["join-warmup"].simpleFallbackPasses += 1;
|
|
1966
1966
|
},
|
|
1967
|
-
sendEntriesSimple: (target, entries, options) => this.sendRepairEntriesWithTransport(target, entries, "simple", options),
|
|
1967
|
+
sendEntriesSimple: (target, entries, options) => this.sendRepairEntriesWithTransport(target, entries, "simple", options, "join-warmup"),
|
|
1968
1968
|
logError: (error) => logger.error(error),
|
|
1969
1969
|
});
|
|
1970
1970
|
}
|
|
@@ -3836,6 +3836,23 @@ let SharedLog = (() => {
|
|
|
3836
3836
|
current.peerSession === captured.peerSession);
|
|
3837
3837
|
};
|
|
3838
3838
|
try {
|
|
3839
|
+
if (!isPeerRoundCurrent())
|
|
3840
|
+
return;
|
|
3841
|
+
if (!this._v2Send.hasCurrentStateForPeer({
|
|
3842
|
+
peerHash: peer,
|
|
3843
|
+
peerSession: captured.peerSession,
|
|
3844
|
+
receiverTransportSession: captured.capabilitySession,
|
|
3845
|
+
})) {
|
|
3846
|
+
// Preflight can precede replacement or loss of the sender
|
|
3847
|
+
// stream. Delivery must recover its own exact current
|
|
3848
|
+
// binding before waiting for application confirmation.
|
|
3849
|
+
this._v2Receive.reAdvertiseLocalCapabilityForRemoteFull({
|
|
3850
|
+
peerHash: peer,
|
|
3851
|
+
peerSession: captured.peerSession,
|
|
3852
|
+
receiveEpoch: captured.receiveEpoch,
|
|
3853
|
+
signal: roundSignal,
|
|
3854
|
+
});
|
|
3855
|
+
}
|
|
3839
3856
|
await this._v2Send.confirmLatestForPeer({
|
|
3840
3857
|
peerHash: peer,
|
|
3841
3858
|
peerSession: captured.peerSession,
|
|
@@ -6840,47 +6857,88 @@ let SharedLog = (() => {
|
|
|
6840
6857
|
signal,
|
|
6841
6858
|
});
|
|
6842
6859
|
}
|
|
6843
|
-
async sendRepairEntriesWithTransport(target, entries, transport, options) {
|
|
6860
|
+
async sendRepairEntriesWithTransport(target, entries, transport, options, mode) {
|
|
6844
6861
|
const isStillCurrent = options?.isStillCurrent ?? (() => true);
|
|
6845
6862
|
if (!isStillCurrent()) {
|
|
6846
6863
|
return;
|
|
6847
6864
|
}
|
|
6848
6865
|
const unknownEntries = new Map();
|
|
6849
6866
|
const knownHashes = [];
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6867
|
+
const profile = this._logProperties?.sync?.profile;
|
|
6868
|
+
const startedAt = syncProfileStart(profile);
|
|
6869
|
+
const inputEntries = profile ? entries.size : 0;
|
|
6870
|
+
let selectedEntries = 0;
|
|
6871
|
+
let lastObservedCurrent = true;
|
|
6872
|
+
let outcome = "stale";
|
|
6873
|
+
try {
|
|
6874
|
+
for (const [hash, entry] of entries) {
|
|
6875
|
+
if ((options?.bypassRecentKnownPeers ||
|
|
6876
|
+
!this.isEntryRecentlyKnownByPeer(hash, target, RECENT_KNOWN_REPAIR_SUPPRESSION_MS)) &&
|
|
6877
|
+
(options?.bypassKnownPeers || !this.isEntryKnownByPeer(hash, target))) {
|
|
6878
|
+
unknownEntries.set(hash, entry);
|
|
6879
|
+
}
|
|
6880
|
+
else {
|
|
6881
|
+
knownHashes.push(hash);
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
// A custom synchronizer may mutate the Map once it receives it.
|
|
6885
|
+
if (profile)
|
|
6886
|
+
selectedEntries = unknownEntries.size;
|
|
6887
|
+
if (!isStillCurrent())
|
|
6888
|
+
return;
|
|
6889
|
+
this.clearRepairFrontierHashes(target, knownHashes);
|
|
6890
|
+
if (unknownEntries.size === 0) {
|
|
6891
|
+
outcome = "known-suppressed";
|
|
6892
|
+
return;
|
|
6893
|
+
}
|
|
6894
|
+
if (transport === "simple") {
|
|
6895
|
+
// Observe only checks the lower path already makes, without adding
|
|
6896
|
+
// lifecycle decisions or wrapping the disabled-profiling path.
|
|
6897
|
+
const dispatchIsStillCurrent = profile
|
|
6898
|
+
? () => (lastObservedCurrent = isStillCurrent())
|
|
6899
|
+
: isStillCurrent;
|
|
6900
|
+
// Fallback repair does not wait for the maybe-sync round trip.
|
|
6901
|
+
await this.pushRepairEntries(target, unknownEntries, dispatchIsStillCurrent, options?.signal);
|
|
6855
6902
|
}
|
|
6856
6903
|
else {
|
|
6857
|
-
|
|
6904
|
+
const syncEntries = this._logProperties?.sync?.priority
|
|
6905
|
+
? this._coordinates.materializeRepairDispatchEntries(unknownEntries)
|
|
6906
|
+
: unknownEntries;
|
|
6907
|
+
if (!isStillCurrent())
|
|
6908
|
+
return;
|
|
6909
|
+
await this.syncronizer.onMaybeMissingEntries({
|
|
6910
|
+
entries: syncEntries,
|
|
6911
|
+
targets: [target],
|
|
6912
|
+
signal: options?.signal,
|
|
6913
|
+
});
|
|
6858
6914
|
}
|
|
6915
|
+
outcome = !lastObservedCurrent
|
|
6916
|
+
? "stale"
|
|
6917
|
+
: options?.signal?.aborted
|
|
6918
|
+
? "cancelled"
|
|
6919
|
+
: "dispatched";
|
|
6859
6920
|
}
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
this.clearRepairFrontierHashes(target, knownHashes);
|
|
6864
|
-
if (unknownEntries.size === 0) {
|
|
6865
|
-
return;
|
|
6866
|
-
}
|
|
6867
|
-
if (transport === "simple") {
|
|
6868
|
-
// Fallback repair should not depend on the target completing the
|
|
6869
|
-
// RequestMaybeSync -> ResponseMaybeSync round trip.
|
|
6870
|
-
await this.pushRepairEntries(target, unknownEntries, isStillCurrent, options?.signal);
|
|
6871
|
-
return;
|
|
6921
|
+
catch (error) {
|
|
6922
|
+
outcome = "error";
|
|
6923
|
+
throw error;
|
|
6872
6924
|
}
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6925
|
+
finally {
|
|
6926
|
+
if (profile) {
|
|
6927
|
+
emitAdvisorySyncProfileDuration(profile, startedAt, {
|
|
6928
|
+
name: "sharedLog.repair.dispatch",
|
|
6929
|
+
component: "shared-log",
|
|
6930
|
+
entries: inputEntries,
|
|
6931
|
+
count: selectedEntries,
|
|
6932
|
+
targets: 1,
|
|
6933
|
+
details: {
|
|
6934
|
+
mode,
|
|
6935
|
+
transport,
|
|
6936
|
+
outcome,
|
|
6937
|
+
knownSuppressedEntries: knownHashes.length,
|
|
6938
|
+
},
|
|
6939
|
+
});
|
|
6940
|
+
}
|
|
6878
6941
|
}
|
|
6879
|
-
await this.syncronizer.onMaybeMissingEntries({
|
|
6880
|
-
entries: syncEntries,
|
|
6881
|
-
targets: [target],
|
|
6882
|
-
signal: options?.signal,
|
|
6883
|
-
});
|
|
6884
6942
|
}
|
|
6885
6943
|
async sendMaybeMissingEntriesNow(target, entries, options, repairLifecycleController = this._instanceLifecycle
|
|
6886
6944
|
?.ownershipLifecycleController) {
|
|
@@ -6938,7 +6996,7 @@ let SharedLog = (() => {
|
|
|
6938
6996
|
bypassRecentKnownPeers: bypassKnownPeerHints,
|
|
6939
6997
|
isStillCurrent: () => this.isRepairLifecycleActive(repairLifecycleController),
|
|
6940
6998
|
signal: repairLifecycleController.signal,
|
|
6941
|
-
})).catch((error) => logger.error(error));
|
|
6999
|
+
}, options.mode)).catch((error) => logger.error(error));
|
|
6942
7000
|
}
|
|
6943
7001
|
ensureRepairFrontierRunner(mode, target, retryScheduleMs, repairLifecycleController = this._instanceLifecycle
|
|
6944
7002
|
?.ownershipLifecycleController) {
|
|
@@ -7198,7 +7256,7 @@ let SharedLog = (() => {
|
|
|
7198
7256
|
bypassRecentKnownPeers: bypassKnownPeerHints,
|
|
7199
7257
|
isStillCurrent: () => this.isRepairLifecycleActive(repairLifecycleController),
|
|
7200
7258
|
signal: repairLifecycleController.signal,
|
|
7201
|
-
})).catch((error) => logger.error(error));
|
|
7259
|
+
}, options.mode)).catch((error) => logger.error(error));
|
|
7202
7260
|
};
|
|
7203
7261
|
const delayedJoinWarmupRetries = [];
|
|
7204
7262
|
retrySchedule.forEach((delayMs, index) => {
|
|
@@ -7303,6 +7361,18 @@ let SharedLog = (() => {
|
|
|
7303
7361
|
}
|
|
7304
7362
|
async runRepairSweep(repairLifecycleController = this._instanceLifecycle
|
|
7305
7363
|
?.ownershipLifecycleController) {
|
|
7364
|
+
const profile = this._logProperties?.sync?.profile;
|
|
7365
|
+
const startedAt = syncProfileStart(profile);
|
|
7366
|
+
const profileCounts = profile
|
|
7367
|
+
? {
|
|
7368
|
+
passes: 0,
|
|
7369
|
+
inputEntries: 0,
|
|
7370
|
+
nativePasses: 0,
|
|
7371
|
+
repairCandidates: 0,
|
|
7372
|
+
repairBatches: 0,
|
|
7373
|
+
outcome: "stale",
|
|
7374
|
+
}
|
|
7375
|
+
: undefined;
|
|
7306
7376
|
try {
|
|
7307
7377
|
while (this.isRepairLifecycleActive(repairLifecycleController)) {
|
|
7308
7378
|
if (!this.isRepairLifecycleActive(repairLifecycleController)) {
|
|
@@ -7334,8 +7404,12 @@ let SharedLog = (() => {
|
|
|
7334
7404
|
};
|
|
7335
7405
|
pruneStaleJoinWarmupPeers();
|
|
7336
7406
|
if (pendingModes.size === 0) {
|
|
7407
|
+
if (profileCounts)
|
|
7408
|
+
profileCounts.outcome = "completed";
|
|
7337
7409
|
return;
|
|
7338
7410
|
}
|
|
7411
|
+
if (profileCounts)
|
|
7412
|
+
profileCounts.passes += 1;
|
|
7339
7413
|
const optimisticGidPeersByMode = new Map();
|
|
7340
7414
|
const optimisticGidPeersConsumedByMode = new Map();
|
|
7341
7415
|
for (const mode of pendingModes) {
|
|
@@ -7406,6 +7480,10 @@ let SharedLog = (() => {
|
|
|
7406
7480
|
}
|
|
7407
7481
|
return;
|
|
7408
7482
|
}
|
|
7483
|
+
if (profileCounts) {
|
|
7484
|
+
profileCounts.repairCandidates += entries.size;
|
|
7485
|
+
profileCounts.repairBatches += 1;
|
|
7486
|
+
}
|
|
7409
7487
|
this.dispatchMaybeMissingEntries(target, entries, {
|
|
7410
7488
|
bypassRecentDedupe: true,
|
|
7411
7489
|
bypassKnownPeerHints: mode === "churn" ||
|
|
@@ -7456,6 +7534,10 @@ let SharedLog = (() => {
|
|
|
7456
7534
|
if ((this._nativeBackbone ?? this._nativeSharedLogState) &&
|
|
7457
7535
|
residentEntriesByHash &&
|
|
7458
7536
|
!this.hasCustomFindLeaders()) {
|
|
7537
|
+
if (profileCounts) {
|
|
7538
|
+
profileCounts.nativePasses += 1;
|
|
7539
|
+
profileCounts.inputEntries += residentEntriesByHash.size;
|
|
7540
|
+
}
|
|
7459
7541
|
const repairDispatchPlan = pruneStaleJoinWarmupPeers()
|
|
7460
7542
|
? await this.planResidentRepairDispatchBatch({
|
|
7461
7543
|
pendingModes,
|
|
@@ -7488,6 +7570,8 @@ let SharedLog = (() => {
|
|
|
7488
7570
|
!iterator.done() &&
|
|
7489
7571
|
pruneStaleJoinWarmupPeers()) {
|
|
7490
7572
|
const entries = await iterator.next(REPAIR_SWEEP_ENTRY_BATCH_SIZE);
|
|
7573
|
+
if (profileCounts)
|
|
7574
|
+
profileCounts.inputEntries += entries.length;
|
|
7491
7575
|
if (!this.isRepairLifecycleActive(repairLifecycleController)) {
|
|
7492
7576
|
return;
|
|
7493
7577
|
}
|
|
@@ -7602,6 +7686,8 @@ let SharedLog = (() => {
|
|
|
7602
7686
|
}
|
|
7603
7687
|
}
|
|
7604
7688
|
catch (error) {
|
|
7689
|
+
if (profileCounts)
|
|
7690
|
+
profileCounts.outcome = "error";
|
|
7605
7691
|
if (this.isRepairLifecycleActive(repairLifecycleController) &&
|
|
7606
7692
|
!isNotStartedError(error)) {
|
|
7607
7693
|
logger.error(`Repair sweep failed: ${error?.message ?? error}`);
|
|
@@ -7618,6 +7704,21 @@ let SharedLog = (() => {
|
|
|
7618
7704
|
void this.runRepairSweep(repairLifecycleController);
|
|
7619
7705
|
}
|
|
7620
7706
|
}
|
|
7707
|
+
if (profileCounts) {
|
|
7708
|
+
emitAdvisorySyncProfileDuration(profile, startedAt, {
|
|
7709
|
+
name: "sharedLog.placement.pass",
|
|
7710
|
+
component: "shared-log",
|
|
7711
|
+
entries: profileCounts.inputEntries,
|
|
7712
|
+
count: profileCounts.repairCandidates,
|
|
7713
|
+
details: {
|
|
7714
|
+
phase: "repair-sweep",
|
|
7715
|
+
outcome: profileCounts.outcome,
|
|
7716
|
+
passes: profileCounts.passes,
|
|
7717
|
+
nativePasses: profileCounts.nativePasses,
|
|
7718
|
+
repairBatches: profileCounts.repairBatches,
|
|
7719
|
+
},
|
|
7720
|
+
});
|
|
7721
|
+
}
|
|
7621
7722
|
}
|
|
7622
7723
|
}
|
|
7623
7724
|
async pruneDebouncedFnAddIfNotKeeping(args, ownershipLifecycleController = this.captureReplicationOwnershipLifecycle(), additionalCurrentCheck) {
|
|
@@ -14374,10 +14475,11 @@ let SharedLog = (() => {
|
|
|
14374
14475
|
const rawExistingStartedAt = syncProfileStart(syncProfile);
|
|
14375
14476
|
const rawExistingHashes = await this.log.hasMany(msg.heads.map((head) => head.hash));
|
|
14376
14477
|
if (syncProfile) {
|
|
14377
|
-
|
|
14478
|
+
emitAdvisorySyncProfileDuration(syncProfile, rawExistingStartedAt, {
|
|
14378
14479
|
name: "sharedLog.rawReceive.existingHeads",
|
|
14379
14480
|
component: "shared-log",
|
|
14380
14481
|
entries: msg.heads.length,
|
|
14482
|
+
count: rawExistingHashes.size,
|
|
14381
14483
|
messages: 1,
|
|
14382
14484
|
});
|
|
14383
14485
|
}
|
|
@@ -14694,10 +14796,11 @@ let SharedLog = (() => {
|
|
|
14694
14796
|
? undefined
|
|
14695
14797
|
: await this.log.hasMany(headHashes);
|
|
14696
14798
|
if (syncProfile) {
|
|
14697
|
-
|
|
14799
|
+
emitAdvisorySyncProfileDuration(syncProfile, existingStartedAt, {
|
|
14698
14800
|
name: "sharedLog.receive.existingHeads",
|
|
14699
14801
|
component: "shared-log",
|
|
14700
14802
|
entries: heads.length,
|
|
14803
|
+
count: existingHashes?.size,
|
|
14701
14804
|
messages: 1,
|
|
14702
14805
|
details: { rawMaterializedKnownMissing },
|
|
14703
14806
|
});
|
|
@@ -17264,6 +17367,23 @@ let SharedLog = (() => {
|
|
|
17264
17367
|
if (!continueWait())
|
|
17265
17368
|
return;
|
|
17266
17369
|
const recoveryTarget = confirmationRecoveryTarget;
|
|
17370
|
+
if (confirmationController && recoveryTarget) {
|
|
17371
|
+
if (this._peerSessions.current(peerHash) !==
|
|
17372
|
+
recoveryTarget.peerSession ||
|
|
17373
|
+
this._peerSessions.receiveEpoch(peerHash) !==
|
|
17374
|
+
recoveryTarget.receiveEpoch ||
|
|
17375
|
+
this._peerSyncCapabilitySessions.get(peerHash) !==
|
|
17376
|
+
recoveryTarget.capabilitySession ||
|
|
17377
|
+
!this.uniqueReplicators.has(peerHash)) {
|
|
17378
|
+
// Events can be coalesced while application confirmation waits.
|
|
17379
|
+
// Release the obsolete target on the recovery tick as well,
|
|
17380
|
+
// including loss of replicator eligibility within one session.
|
|
17381
|
+
// A temporary receive reservation keeps this same target alive;
|
|
17382
|
+
// the final readiness inspection still checks every admission gate.
|
|
17383
|
+
confirmationRecoveryTarget = undefined;
|
|
17384
|
+
confirmationController.abort(new AbortError("Persisted-receipt readiness target changed"));
|
|
17385
|
+
}
|
|
17386
|
+
}
|
|
17267
17387
|
this.nudgePersistedReceiptPeerReadiness(key, operationSignal, recoveryTarget && Date.now() >= recoveryTarget.notBefore
|
|
17268
17388
|
? recoveryTarget
|
|
17269
17389
|
: undefined);
|
|
@@ -20395,6 +20515,17 @@ let SharedLog = (() => {
|
|
|
20395
20515
|
warmupSessions.get(target);
|
|
20396
20516
|
const areJoinWarmupGenerationsCurrent = () => isOwnershipLifecycleCurrent() &&
|
|
20397
20517
|
[...warmupPeers].every(isCurrentJoinWarmupTarget);
|
|
20518
|
+
const profile = this._logProperties?.sync?.profile;
|
|
20519
|
+
const profileStartedAt = syncProfileStart(profile);
|
|
20520
|
+
const profileCounts = profile
|
|
20521
|
+
? {
|
|
20522
|
+
examinedEntries: 0,
|
|
20523
|
+
repairCandidates: 0,
|
|
20524
|
+
repairBatches: 0,
|
|
20525
|
+
pruneScan: false,
|
|
20526
|
+
outcome: "stale",
|
|
20527
|
+
}
|
|
20528
|
+
: undefined;
|
|
20398
20529
|
try {
|
|
20399
20530
|
const uncheckedDeliver = new Map();
|
|
20400
20531
|
const flushUncheckedDeliverTarget = (target) => {
|
|
@@ -20415,6 +20546,10 @@ let SharedLog = (() => {
|
|
|
20415
20546
|
: isWarmupTarget
|
|
20416
20547
|
? "join-warmup"
|
|
20417
20548
|
: "join-authoritative";
|
|
20549
|
+
if (profileCounts) {
|
|
20550
|
+
profileCounts.repairCandidates += entries.size;
|
|
20551
|
+
profileCounts.repairBatches += 1;
|
|
20552
|
+
}
|
|
20418
20553
|
this.dispatchMaybeMissingEntries(target, entries, {
|
|
20419
20554
|
bypassRecentDedupe: isWarmupTarget || forceFreshDelivery,
|
|
20420
20555
|
bypassKnownPeerHints: forceFreshDelivery ||
|
|
@@ -20453,6 +20588,8 @@ let SharedLog = (() => {
|
|
|
20453
20588
|
for await (const entryReplicated of toRebalance(immediateRebalanceChanges, this.entryCoordinatesIndex, this.recentlyRebalanced, {
|
|
20454
20589
|
forceFresh: forceFreshDelivery || useJoinWarmupFastPath,
|
|
20455
20590
|
})) {
|
|
20591
|
+
if (profileCounts)
|
|
20592
|
+
profileCounts.examinedEntries += 1;
|
|
20456
20593
|
if (!isOwnershipLifecycleCurrent() ||
|
|
20457
20594
|
(useJoinWarmupFastPath && !areJoinWarmupGenerationsCurrent())) {
|
|
20458
20595
|
break;
|
|
@@ -20649,6 +20786,8 @@ let SharedLog = (() => {
|
|
|
20649
20786
|
change.type === "removed" ||
|
|
20650
20787
|
change.type === "replaced"));
|
|
20651
20788
|
if (shouldRunLocalPruneScan) {
|
|
20789
|
+
if (profileCounts)
|
|
20790
|
+
profileCounts.pruneScan = true;
|
|
20652
20791
|
throwIfOwnershipLifecycleInactive();
|
|
20653
20792
|
// Adaptive range changes and fixed zero-width updates can make already-indexed
|
|
20654
20793
|
// local heads prunable even when the incremental rebalance scan misses them
|
|
@@ -20667,6 +20806,8 @@ let SharedLog = (() => {
|
|
|
20667
20806
|
return false;
|
|
20668
20807
|
}
|
|
20669
20808
|
}
|
|
20809
|
+
if (profileCounts)
|
|
20810
|
+
profileCounts.outcome = "completed";
|
|
20670
20811
|
return changed;
|
|
20671
20812
|
}
|
|
20672
20813
|
catch (error) {
|
|
@@ -20676,9 +20817,30 @@ let SharedLog = (() => {
|
|
|
20676
20817
|
if (isNotStartedError(error)) {
|
|
20677
20818
|
return false; // we are not started yet, so no changes
|
|
20678
20819
|
}
|
|
20820
|
+
if (profileCounts)
|
|
20821
|
+
profileCounts.outcome = "error";
|
|
20679
20822
|
logger.error(error.toString());
|
|
20680
20823
|
throw error;
|
|
20681
20824
|
}
|
|
20825
|
+
finally {
|
|
20826
|
+
if (profileCounts) {
|
|
20827
|
+
emitAdvisorySyncProfileDuration(profile, profileStartedAt, {
|
|
20828
|
+
name: "sharedLog.placement.pass",
|
|
20829
|
+
component: "shared-log",
|
|
20830
|
+
entries: profileCounts.examinedEntries,
|
|
20831
|
+
count: profileCounts.repairCandidates,
|
|
20832
|
+
details: {
|
|
20833
|
+
phase: "range-change",
|
|
20834
|
+
outcome: profileCounts.outcome,
|
|
20835
|
+
changes: changes.length,
|
|
20836
|
+
repairBatches: profileCounts.repairBatches,
|
|
20837
|
+
pruneScan: profileCounts.pruneScan,
|
|
20838
|
+
forceFreshDelivery,
|
|
20839
|
+
joinWarmupFastPath: useJoinWarmupFastPath,
|
|
20840
|
+
},
|
|
20841
|
+
});
|
|
20842
|
+
}
|
|
20843
|
+
}
|
|
20682
20844
|
}
|
|
20683
20845
|
async _onUnsubscription(evt) {
|
|
20684
20846
|
logger.trace(`Peer disconnected '${evt.detail.from.hashcode()}' from '${JSON.stringify(evt.detail.topics.map((x) => x))} '`);
|
|
@@ -20707,6 +20869,13 @@ let SharedLog = (() => {
|
|
|
20707
20869
|
await this.handleSubscriptionChange(evt.detail.from, evt.detail.topics, true, subscriptionEpoch, evt.detail.session);
|
|
20708
20870
|
}
|
|
20709
20871
|
async rebalanceParticipation(ownershipLifecycleController = this.captureReplicationOwnershipLifecycle(), rebalanceParticipationDebounced = this.rebalanceParticipationDebounced) {
|
|
20872
|
+
const profile = this._isAdaptiveReplicating
|
|
20873
|
+
? this._logProperties?.sync?.profile
|
|
20874
|
+
: undefined;
|
|
20875
|
+
const profileStartedAt = syncProfileStart(profile);
|
|
20876
|
+
const profileDetails = profile
|
|
20877
|
+
? { outcome: "stale", idleRemainingMs: 0 }
|
|
20878
|
+
: undefined;
|
|
20710
20879
|
// Stage 3: the lifecycle owns all three identity terms. `lifecycle` may
|
|
20711
20880
|
// go stale later; its deps late-bind to the host, so the debouncer term
|
|
20712
20881
|
// still reads the current host field, and the role term can disagree
|
|
@@ -20738,6 +20907,11 @@ let SharedLog = (() => {
|
|
|
20738
20907
|
}
|
|
20739
20908
|
if (this._isAdaptiveReplicating) {
|
|
20740
20909
|
if (this.shouldDelayAdaptiveRebalance()) {
|
|
20910
|
+
if (profileDetails) {
|
|
20911
|
+
profileDetails.outcome = "idle-deferred";
|
|
20912
|
+
profileDetails.idleRemainingMs = Math.max(0, this.adaptiveRebalanceIdleMs -
|
|
20913
|
+
(Date.now() - this._lastLocalAppendAt));
|
|
20914
|
+
}
|
|
20741
20915
|
if (isCurrent()) {
|
|
20742
20916
|
void rebalanceParticipationDebounced?.call();
|
|
20743
20917
|
}
|
|
@@ -20747,11 +20921,18 @@ let SharedLog = (() => {
|
|
|
20747
20921
|
const usedMemory = await this.getMemoryUsage();
|
|
20748
20922
|
if (!isCurrent())
|
|
20749
20923
|
return false;
|
|
20924
|
+
if (profileDetails) {
|
|
20925
|
+
profileDetails.storageUsedBytes = usedMemory;
|
|
20926
|
+
profileDetails.storageObjectiveBytes =
|
|
20927
|
+
this.replicationController.maxMemoryLimit;
|
|
20928
|
+
}
|
|
20750
20929
|
this.scheduleReplicationStatusRefreshForStorage(usedMemory);
|
|
20751
20930
|
let dynamicRange = await this.getDynamicRange();
|
|
20752
20931
|
if (!isCurrent())
|
|
20753
20932
|
return false;
|
|
20754
20933
|
if (!dynamicRange) {
|
|
20934
|
+
if (profileDetails)
|
|
20935
|
+
profileDetails.outcome = "not-permitted";
|
|
20755
20936
|
return; // not allowed to replicate
|
|
20756
20937
|
}
|
|
20757
20938
|
if (this.replicationController.maxMemoryLimit != null &&
|
|
@@ -20771,13 +20952,24 @@ let SharedLog = (() => {
|
|
|
20771
20952
|
const totalParticipation = await this.calculateTotalParticipation();
|
|
20772
20953
|
if (!isCurrent())
|
|
20773
20954
|
return false;
|
|
20955
|
+
const cpuUsage = this.cpuUsage?.value();
|
|
20956
|
+
const stepStartedAt = syncProfileStart(profile);
|
|
20774
20957
|
const newFactor = this.replicationController.step({
|
|
20775
20958
|
memoryUsage: usedMemory,
|
|
20776
20959
|
currentFactor: dynamicRange.widthNormalized,
|
|
20777
20960
|
totalFactor: totalParticipation, // TODO use this._totalParticipation when flakiness is fixed
|
|
20778
20961
|
peerCount: peersSize,
|
|
20779
|
-
cpuUsage
|
|
20962
|
+
cpuUsage,
|
|
20780
20963
|
});
|
|
20964
|
+
if (profileDetails) {
|
|
20965
|
+
profileDetails.preStepMs = stepStartedAt - profileStartedAt;
|
|
20966
|
+
profileDetails.stepMs = syncProfileStart(profile) - stepStartedAt;
|
|
20967
|
+
profileDetails.currentFactor = dynamicRange.widthNormalized;
|
|
20968
|
+
profileDetails.proposedFactor = newFactor;
|
|
20969
|
+
profileDetails.totalFactor = totalParticipation;
|
|
20970
|
+
profileDetails.controllerPeerCount = peersSize;
|
|
20971
|
+
profileDetails.cpuUsage = cpuUsage;
|
|
20972
|
+
}
|
|
20781
20973
|
const absoluteDifference = Math.abs(dynamicRange.widthNormalized - newFactor);
|
|
20782
20974
|
const relativeDifference = absoluteDifference /
|
|
20783
20975
|
Math.max(dynamicRange.widthNormalized, RECALCULATE_PARTICIPATION_RELATIVE_DENOMINATOR_FLOOR);
|
|
@@ -20805,8 +20997,11 @@ let SharedLog = (() => {
|
|
|
20805
20997
|
if (!isCurrent())
|
|
20806
20998
|
return false;
|
|
20807
20999
|
if (!canReplicate) {
|
|
21000
|
+
if (profileDetails)
|
|
21001
|
+
profileDetails.outcome = "not-permitted";
|
|
20808
21002
|
return false;
|
|
20809
21003
|
}
|
|
21004
|
+
const applyStartedAt = syncProfileStart(profile);
|
|
20810
21005
|
await this.startAnnounceReplicating([dynamicRange], {
|
|
20811
21006
|
checkDuplicates: false,
|
|
20812
21007
|
reset: false,
|
|
@@ -20814,6 +21009,10 @@ let SharedLog = (() => {
|
|
|
20814
21009
|
}, ownershipLifecycleController);
|
|
20815
21010
|
if (!isCurrent())
|
|
20816
21011
|
return false;
|
|
21012
|
+
if (profileDetails) {
|
|
21013
|
+
profileDetails.outcome = "apply-settled";
|
|
21014
|
+
profileDetails.applyMs = syncProfileStart(profile) - applyStartedAt;
|
|
21015
|
+
}
|
|
20817
21016
|
/* await this._updateRole(newRole, onRoleChange); */
|
|
20818
21017
|
if (isCurrent()) {
|
|
20819
21018
|
void rebalanceParticipationDebounced?.call();
|
|
@@ -20821,6 +21020,8 @@ let SharedLog = (() => {
|
|
|
20821
21020
|
return true;
|
|
20822
21021
|
}
|
|
20823
21022
|
else {
|
|
21023
|
+
if (profileDetails)
|
|
21024
|
+
profileDetails.outcome = "unchanged";
|
|
20824
21025
|
if (isCurrent()) {
|
|
20825
21026
|
void rebalanceParticipationDebounced?.call();
|
|
20826
21027
|
}
|
|
@@ -20829,13 +21030,27 @@ let SharedLog = (() => {
|
|
|
20829
21030
|
}
|
|
20830
21031
|
return false;
|
|
20831
21032
|
};
|
|
20832
|
-
|
|
20833
|
-
|
|
20834
|
-
|
|
21033
|
+
try {
|
|
21034
|
+
return await fn().catch((error) => {
|
|
21035
|
+
if (isNotStartedError(error) || isClosedStoreRace(error)) {
|
|
21036
|
+
if (profileDetails)
|
|
21037
|
+
profileDetails.outcome = "stale";
|
|
21038
|
+
return false;
|
|
21039
|
+
}
|
|
21040
|
+
if (profileDetails)
|
|
21041
|
+
profileDetails.outcome = "error";
|
|
21042
|
+
throw error;
|
|
21043
|
+
});
|
|
21044
|
+
}
|
|
21045
|
+
finally {
|
|
21046
|
+
if (profileDetails) {
|
|
21047
|
+
emitAdvisorySyncProfileDuration(profile, profileStartedAt, {
|
|
21048
|
+
name: "sharedLog.adaptive.rebalance",
|
|
21049
|
+
component: "shared-log",
|
|
21050
|
+
details: profileDetails,
|
|
21051
|
+
});
|
|
20835
21052
|
}
|
|
20836
|
-
|
|
20837
|
-
});
|
|
20838
|
-
return resp;
|
|
21053
|
+
}
|
|
20839
21054
|
}
|
|
20840
21055
|
getDynamicRangeOffset() {
|
|
20841
21056
|
const options = this._logProperties
|