@peerbit/shared-log 13.2.16 → 13.2.18
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 +7 -1
- package/dist/src/checked-prune.d.ts.map +1 -1
- package/dist/src/checked-prune.js +13 -3
- package/dist/src/checked-prune.js.map +1 -1
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +137 -34
- package/dist/src/index.js.map +1 -1
- package/package.json +15 -15
- package/src/checked-prune.ts +22 -3
- package/src/index.ts +188 -39
package/dist/src/index.js
CHANGED
|
@@ -1768,6 +1768,13 @@ let SharedLog = (() => {
|
|
|
1768
1768
|
// before a liveness eviction but reach the per-peer apply lane after it. Unlike
|
|
1769
1769
|
// message timestamps, these tokens never compare clocks from different peers.
|
|
1770
1770
|
_replicationInfoReceiveEpochByPeer;
|
|
1771
|
+
// Receive-side ownership plans may span lower-log joins that invoke user code.
|
|
1772
|
+
// Increment synchronously with leader-cache invalidation so the handler can
|
|
1773
|
+
// detect whether its pre-join plan needs one fresh post-persist audit.
|
|
1774
|
+
_receiveOwnershipRevision = 0;
|
|
1775
|
+
// Count ownership-changing range mutations from queue admission through
|
|
1776
|
+
// settlement, including mutations already pending when a receive starts.
|
|
1777
|
+
_receiveOwnershipMutationAdmissions = 0;
|
|
1771
1778
|
// Subscription callbacks can overlap because removing a replicator mutates the
|
|
1772
1779
|
// replication index asynchronously. Keep that lifecycle separate from message
|
|
1773
1780
|
// timestamps so a reconnect can synchronously revoke an older unsubscribe.
|
|
@@ -3778,8 +3785,13 @@ let SharedLog = (() => {
|
|
|
3778
3785
|
this.invalidateTopicSubscribersCache(this.topic, this.rpc.topic);
|
|
3779
3786
|
}
|
|
3780
3787
|
invalidateLeaderSelectionContextCache() {
|
|
3788
|
+
this._receiveOwnershipRevision++;
|
|
3781
3789
|
this._leaderSelectionContextCache = undefined;
|
|
3782
3790
|
}
|
|
3791
|
+
isReceiveOwnershipSnapshotStable(revision) {
|
|
3792
|
+
return (this._receiveOwnershipMutationAdmissions === 0 &&
|
|
3793
|
+
this._receiveOwnershipRevision === revision);
|
|
3794
|
+
}
|
|
3783
3795
|
canCacheLeaderSelectionContext(options) {
|
|
3784
3796
|
return options?.roleAge == null && options?.candidates == null;
|
|
3785
3797
|
}
|
|
@@ -5033,7 +5045,7 @@ let SharedLog = (() => {
|
|
|
5033
5045
|
let deleted = [];
|
|
5034
5046
|
let ownerHasRanges = false;
|
|
5035
5047
|
let mutationError;
|
|
5036
|
-
const mutationCommitted = await this.
|
|
5048
|
+
const mutationCommitted = await this.withReceiveOwnershipMutationQueue(async () => {
|
|
5037
5049
|
if (!ownsReplicationOwnershipLifecycle() ||
|
|
5038
5050
|
!ownsReplicationLifecycle() ||
|
|
5039
5051
|
!ownsSubscriptionEpoch() ||
|
|
@@ -5201,7 +5213,7 @@ let SharedLog = (() => {
|
|
|
5201
5213
|
}
|
|
5202
5214
|
removeReplicationRanges(ranges, from, options, replicationOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle()) {
|
|
5203
5215
|
this.throwIfReplicationOwnershipLifecycleInactive(replicationOwnershipLifecycleController);
|
|
5204
|
-
return this.
|
|
5216
|
+
return this.withReceiveOwnershipMutationQueue(() => this.removeReplicationRangesUnlocked(ranges, from, options), replicationOwnershipLifecycleController);
|
|
5205
5217
|
}
|
|
5206
5218
|
async removeReplicationRangesUnlocked(ranges, from, options) {
|
|
5207
5219
|
if (ranges.length === 0) {
|
|
@@ -5303,7 +5315,7 @@ let SharedLog = (() => {
|
|
|
5303
5315
|
return undefined;
|
|
5304
5316
|
}
|
|
5305
5317
|
this.throwIfReplicationOwnershipLifecycleInactive(replicationOwnershipLifecycleController);
|
|
5306
|
-
return this.
|
|
5318
|
+
return this.withReceiveOwnershipMutationQueue(() => this.addReplicationRangeUnlocked(ranges, from, options, replicationOwnershipLifecycleController), replicationOwnershipLifecycleController);
|
|
5307
5319
|
}
|
|
5308
5320
|
async addReplicationRangeUnlocked(ranges, from, { reset, checkDuplicates, timestamp: ts, rebalance, allowLegacyOrderedReplacementPairs, onConfirmedDurableStateChanged, shouldApply, } = {}, replicationOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle()) {
|
|
5309
5321
|
this.validateReplicationRangeAnnouncement(ranges);
|
|
@@ -7435,6 +7447,10 @@ let SharedLog = (() => {
|
|
|
7435
7447
|
return;
|
|
7436
7448
|
}
|
|
7437
7449
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
7450
|
+
const freshReceiveRoleAge = options?.freshReceiveOwnerAudit
|
|
7451
|
+
? await this.getDefaultMinRoleAge()
|
|
7452
|
+
: undefined;
|
|
7453
|
+
this.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
7438
7454
|
const plans = new Array(entries.length);
|
|
7439
7455
|
const leaderItems = [];
|
|
7440
7456
|
const leaderItemIndexes = [];
|
|
@@ -7443,7 +7459,9 @@ let SharedLog = (() => {
|
|
|
7443
7459
|
const entry = entries[i];
|
|
7444
7460
|
const replicas = options?.decodedReplicaCounts?.get(entry.hash) ??
|
|
7445
7461
|
decodeReplicas(entry).getValue(this);
|
|
7446
|
-
const reusablePlan = options?.
|
|
7462
|
+
const reusablePlan = options?.freshReceiveOwnerAudit
|
|
7463
|
+
? undefined
|
|
7464
|
+
: options?.reusableLeaderPlans?.get(entry.hash);
|
|
7447
7465
|
if (reusablePlan && reusablePlan.replicas === replicas) {
|
|
7448
7466
|
plans[i] = reusablePlan.plan;
|
|
7449
7467
|
reusableLeaderPlanHits++;
|
|
@@ -7452,7 +7470,9 @@ let SharedLog = (() => {
|
|
|
7452
7470
|
leaderItems.push({
|
|
7453
7471
|
entry,
|
|
7454
7472
|
replicas,
|
|
7455
|
-
options:
|
|
7473
|
+
options: options?.freshReceiveOwnerAudit
|
|
7474
|
+
? { roleAge: freshReceiveRoleAge, persist: false }
|
|
7475
|
+
: { roleAge: 0, persist: false },
|
|
7456
7476
|
});
|
|
7457
7477
|
leaderItemIndexes.push(i);
|
|
7458
7478
|
}
|
|
@@ -7502,6 +7522,7 @@ let SharedLog = (() => {
|
|
|
7502
7522
|
const loopStartedAt = syncProfileStart(options?.profile);
|
|
7503
7523
|
let enqueuedPrune = 0;
|
|
7504
7524
|
let cancelledLocalLeader = 0;
|
|
7525
|
+
let localLeaderResults = 0;
|
|
7505
7526
|
for (let i = 0; i < entries.length; i++) {
|
|
7506
7527
|
if (!this.isRepairLifecycleActive(ownershipLifecycleController)) {
|
|
7507
7528
|
continue;
|
|
@@ -7509,9 +7530,12 @@ let SharedLog = (() => {
|
|
|
7509
7530
|
const entry = entries[i];
|
|
7510
7531
|
const leaders = plans[i]?.leaders ?? new Map();
|
|
7511
7532
|
if (leaders.has(selfHash)) {
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7533
|
+
if (!options?.preserveExistingPruneOnLocalResult) {
|
|
7534
|
+
await this.cancelCheckedPruneForLocalLeader(entry.hash);
|
|
7535
|
+
this.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
7536
|
+
cancelledLocalLeader++;
|
|
7537
|
+
}
|
|
7538
|
+
localLeaderResults++;
|
|
7515
7539
|
continue;
|
|
7516
7540
|
}
|
|
7517
7541
|
if (this._checkedPrune.hasPendingDelete(entry.hash)) {
|
|
@@ -7534,7 +7558,7 @@ let SharedLog = (() => {
|
|
|
7534
7558
|
entries: entries.length,
|
|
7535
7559
|
count: enqueuedPrune,
|
|
7536
7560
|
messages: 1,
|
|
7537
|
-
details: { cancelledLocalLeader },
|
|
7561
|
+
details: { cancelledLocalLeader, localLeaderResults },
|
|
7538
7562
|
});
|
|
7539
7563
|
}
|
|
7540
7564
|
async pruneIndexedEntriesNoLongerLed(options, ownershipLifecycleController = this.captureReplicationOwnershipLifecycle()) {
|
|
@@ -7736,9 +7760,11 @@ let SharedLog = (() => {
|
|
|
7736
7760
|
const state = checkedPruneCoordinator.getRetry(hash) ??
|
|
7737
7761
|
{
|
|
7738
7762
|
attempts: 0,
|
|
7763
|
+
generation: 0,
|
|
7739
7764
|
entry: args.entry,
|
|
7740
7765
|
leaders: args.leaders,
|
|
7741
7766
|
};
|
|
7767
|
+
state.generation++;
|
|
7742
7768
|
state.entry = args.entry;
|
|
7743
7769
|
state.leaders = args.leaders;
|
|
7744
7770
|
if (state.timer)
|
|
@@ -7756,6 +7782,7 @@ let SharedLog = (() => {
|
|
|
7756
7782
|
const delayMs = Math.min(CHECKED_PRUNE_RETRY_MAX_DELAY_MS, 1_000 * 2 ** (attempt - 1) + jitterMs);
|
|
7757
7783
|
state.attempts = attempt;
|
|
7758
7784
|
const timer = setTimeout(() => {
|
|
7785
|
+
const generation = state.generation;
|
|
7759
7786
|
const run = async () => {
|
|
7760
7787
|
const st = checkedPruneCoordinator.getRetry(hash);
|
|
7761
7788
|
if (st !== state || state.timer !== timer || !isCurrent()) {
|
|
@@ -7764,6 +7791,7 @@ let SharedLog = (() => {
|
|
|
7764
7791
|
state.timer = undefined;
|
|
7765
7792
|
const isExactAttempt = () => isCurrent() &&
|
|
7766
7793
|
checkedPruneCoordinator.getRetry(hash) === state &&
|
|
7794
|
+
state.generation === generation &&
|
|
7767
7795
|
state.timer === undefined;
|
|
7768
7796
|
if (checkedPruneCoordinator.hasPendingDelete(hash))
|
|
7769
7797
|
return;
|
|
@@ -7800,21 +7828,27 @@ let SharedLog = (() => {
|
|
|
7800
7828
|
!checkedPruneCoordinator.hasPendingDelete(hash)) {
|
|
7801
7829
|
// A keep policy is terminal for this background prune. Do not
|
|
7802
7830
|
// retain a retry record with neither a timer nor pending work.
|
|
7803
|
-
checkedPruneCoordinator.clearRetry(hash
|
|
7831
|
+
checkedPruneCoordinator.clearRetry(hash, {
|
|
7832
|
+
state,
|
|
7833
|
+
generation,
|
|
7834
|
+
});
|
|
7804
7835
|
}
|
|
7805
7836
|
};
|
|
7806
7837
|
void run().catch((error) => {
|
|
7807
7838
|
if (isCurrent() && !isNotStartedError(error)) {
|
|
7808
7839
|
logger.error(error);
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
!
|
|
7840
|
+
if (checkedPruneCoordinator.getRetry(hash) === state &&
|
|
7841
|
+
state.generation === generation &&
|
|
7842
|
+
!state.timer &&
|
|
7812
7843
|
!checkedPruneCoordinator.hasPendingDelete(hash)) {
|
|
7813
7844
|
try {
|
|
7814
|
-
this.scheduleCheckedPruneRetry({ entry:
|
|
7845
|
+
this.scheduleCheckedPruneRetry({ entry: state.entry, leaders: state.leaders }, ownershipLifecycleController);
|
|
7815
7846
|
}
|
|
7816
7847
|
catch {
|
|
7817
|
-
checkedPruneCoordinator.clearRetry(hash
|
|
7848
|
+
checkedPruneCoordinator.clearRetry(hash, {
|
|
7849
|
+
state,
|
|
7850
|
+
generation,
|
|
7851
|
+
});
|
|
7818
7852
|
}
|
|
7819
7853
|
}
|
|
7820
7854
|
}
|
|
@@ -10380,6 +10414,8 @@ let SharedLog = (() => {
|
|
|
10380
10414
|
this._checkedPruneRemoveBlocksLocalRangeMutationAdmission = 0;
|
|
10381
10415
|
this._checkedPruneRemovalCallbackInvocationDepth = 0;
|
|
10382
10416
|
this._localReplicationRoleGeneration = 0;
|
|
10417
|
+
this._receiveOwnershipRevision = 0;
|
|
10418
|
+
this._receiveOwnershipMutationAdmissions = 0;
|
|
10383
10419
|
this._pruneRemovesClosing = false;
|
|
10384
10420
|
this._replicationRangeMutationFailure = undefined;
|
|
10385
10421
|
this.startRepairLifecycle();
|
|
@@ -10709,7 +10745,8 @@ let SharedLog = (() => {
|
|
|
10709
10745
|
continue;
|
|
10710
10746
|
}
|
|
10711
10747
|
if (checkedPruneLeaders.localLeader) {
|
|
10712
|
-
const
|
|
10748
|
+
const retryIdentity = checkedPruneCoordinator.getRetryIdentity(hash);
|
|
10749
|
+
const retry = retryIdentity?.state;
|
|
10713
10750
|
await this.cancelCheckedPruneForLocalLeader(hash, {
|
|
10714
10751
|
preserveRetry: retry != null,
|
|
10715
10752
|
});
|
|
@@ -10719,7 +10756,7 @@ let SharedLog = (() => {
|
|
|
10719
10756
|
if (retry) {
|
|
10720
10757
|
// A delayed confirmation of local ownership is terminal.
|
|
10721
10758
|
// Future ownership mutations will enqueue fresh work.
|
|
10722
|
-
checkedPruneCoordinator.clearRetry(hash);
|
|
10759
|
+
checkedPruneCoordinator.clearRetry(hash, retryIdentity);
|
|
10723
10760
|
}
|
|
10724
10761
|
else {
|
|
10725
10762
|
// A first positive view can be a transient membership
|
|
@@ -10760,6 +10797,10 @@ let SharedLog = (() => {
|
|
|
10760
10797
|
this.scheduleCheckedPruneRetry(value, pruneOwnershipLifecycleController);
|
|
10761
10798
|
}
|
|
10762
10799
|
catch {
|
|
10800
|
+
if (value.workToken != null &&
|
|
10801
|
+
checkedPruneCoordinator.isCandidateTokenCurrent(hash, value.workToken)) {
|
|
10802
|
+
checkedPruneCoordinator.invalidateCandidateToken(hash);
|
|
10803
|
+
}
|
|
10763
10804
|
checkedPruneCoordinator.clearRetry(hash);
|
|
10764
10805
|
}
|
|
10765
10806
|
}
|
|
@@ -11385,7 +11426,7 @@ let SharedLog = (() => {
|
|
|
11385
11426
|
}
|
|
11386
11427
|
async updateTimestampOfOwnedReplicationRanges(timestamp = +new Date()) {
|
|
11387
11428
|
const ownershipLifecycleController = this.captureReplicationOwnershipLifecycle();
|
|
11388
|
-
return this.
|
|
11429
|
+
return this.withReceiveOwnershipMutationQueue(async () => {
|
|
11389
11430
|
this.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
11390
11431
|
const all = await this.replicationIndex
|
|
11391
11432
|
.iterate({
|
|
@@ -13170,6 +13211,8 @@ let SharedLog = (() => {
|
|
|
13170
13211
|
if (!releasePeerReceiveLease) {
|
|
13171
13212
|
return;
|
|
13172
13213
|
}
|
|
13214
|
+
const receiveOwnershipRevision = this._receiveOwnershipRevision;
|
|
13215
|
+
const receiveOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle();
|
|
13173
13216
|
const receiveReplicationInfoReceiveEpoch = this.getReplicationInfoReceiveEpoch(receiveFromHash);
|
|
13174
13217
|
if (msg instanceof ResponseRoleMessage) {
|
|
13175
13218
|
msg = msg.toReplicationInfoMessage(); // migration
|
|
@@ -13377,6 +13420,7 @@ let SharedLog = (() => {
|
|
|
13377
13420
|
fromIsSelf,
|
|
13378
13421
|
syncProfile,
|
|
13379
13422
|
selection: await getRawPreparedReceiveSelection(heads, hashes),
|
|
13423
|
+
receiveOwnershipRevision,
|
|
13380
13424
|
}),
|
|
13381
13425
|
selectPreparedRawReceiveHashes: rawIsRepairHint
|
|
13382
13426
|
? undefined
|
|
@@ -13387,6 +13431,7 @@ let SharedLog = (() => {
|
|
|
13387
13431
|
fromIsSelf,
|
|
13388
13432
|
syncProfile,
|
|
13389
13433
|
selection: await getRawPreparedReceiveSelection(heads, hashes),
|
|
13434
|
+
receiveOwnershipRevision,
|
|
13390
13435
|
}),
|
|
13391
13436
|
});
|
|
13392
13437
|
if (materializedRawMessage === undefined) {
|
|
@@ -13972,6 +14017,7 @@ let SharedLog = (() => {
|
|
|
13972
14017
|
!isReplicating &&
|
|
13973
14018
|
!this.keep &&
|
|
13974
14019
|
!isRepairHint &&
|
|
14020
|
+
this.isReceiveOwnershipSnapshotStable(receiveOwnershipRevision) &&
|
|
13975
14021
|
receiveGroups.length > 0 &&
|
|
13976
14022
|
receiveGroups.every((group) => group.isLeader === false &&
|
|
13977
14023
|
group.fromIsLeader === false &&
|
|
@@ -14578,11 +14624,42 @@ let SharedLog = (() => {
|
|
|
14578
14624
|
confirmedHashes.add(hash);
|
|
14579
14625
|
}
|
|
14580
14626
|
const checkedPruneStartedAt = syncProfileStart(syncProfile);
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14627
|
+
const ownershipChangedDuringReceive = !this.isReceiveOwnershipSnapshotStable(receiveOwnershipRevision);
|
|
14628
|
+
if (ownershipChangedDuringReceive) {
|
|
14629
|
+
const freshAuditRevision = this._receiveOwnershipRevision;
|
|
14630
|
+
const armFreshAuditRetry = () => {
|
|
14631
|
+
for (const entry of admittedShallowEntries) {
|
|
14632
|
+
this.scheduleCheckedPruneRetry({ entry, leaders: new Map() }, receiveOwnershipLifecycleController);
|
|
14633
|
+
}
|
|
14634
|
+
};
|
|
14635
|
+
try {
|
|
14636
|
+
await this.pruneJoinedEntriesNoLongerLed(admittedShallowEntries, {
|
|
14637
|
+
decodedReplicaCounts: receiveReplicaCounts,
|
|
14638
|
+
freshReceiveOwnerAudit: true,
|
|
14639
|
+
preserveExistingPruneOnLocalResult: true,
|
|
14640
|
+
profile: syncProfile,
|
|
14641
|
+
}, receiveOwnershipLifecycleController);
|
|
14642
|
+
this.throwIfReplicationOwnershipLifecycleInactive(receiveOwnershipLifecycleController);
|
|
14643
|
+
if (!this.isReceiveOwnershipSnapshotStable(freshAuditRevision)) {
|
|
14644
|
+
armFreshAuditRetry();
|
|
14645
|
+
}
|
|
14646
|
+
}
|
|
14647
|
+
catch {
|
|
14648
|
+
// The lower-log and coordinate commits are already durable. A
|
|
14649
|
+
// sender retry will filter these hashes as present, so retain a
|
|
14650
|
+
// bounded local obligation instead of failing the admitted receive.
|
|
14651
|
+
this.throwIfReplicationOwnershipLifecycleInactive(receiveOwnershipLifecycleController);
|
|
14652
|
+
armFreshAuditRetry();
|
|
14653
|
+
}
|
|
14654
|
+
}
|
|
14655
|
+
else {
|
|
14656
|
+
await this.pruneJoinedEntriesNoLongerLed(admittedShallowEntries, {
|
|
14657
|
+
decodedReplicaCounts: receiveReplicaCounts,
|
|
14658
|
+
preserveExistingPruneOnLocalResult: true,
|
|
14659
|
+
reusableLeaderPlans: reusableCoordinatePlans,
|
|
14660
|
+
profile: syncProfile,
|
|
14661
|
+
}, receiveOwnershipLifecycleController);
|
|
14662
|
+
}
|
|
14586
14663
|
if (syncProfile) {
|
|
14587
14664
|
emitSyncProfileDuration(syncProfile, checkedPruneStartedAt, {
|
|
14588
14665
|
name: "sharedLog.receive.checkedPrune",
|
|
@@ -17059,13 +17136,16 @@ let SharedLog = (() => {
|
|
|
17059
17136
|
}
|
|
17060
17137
|
async tryFastDropPreparedRawReceive(properties) {
|
|
17061
17138
|
const backbone = this._nativeBackbone;
|
|
17139
|
+
const ownershipRevision = properties.receiveOwnershipRevision;
|
|
17062
17140
|
if (!backbone || !this.syncronizer.onReceivedEntryHashes) {
|
|
17063
17141
|
return false;
|
|
17064
17142
|
}
|
|
17065
17143
|
const receivePlanStartedAt = syncProfileStart(properties.syncProfile);
|
|
17066
17144
|
const selection = properties.selection ??
|
|
17067
17145
|
(await this.planNativePreparedRawReceiveSelection(properties));
|
|
17068
|
-
if (!selection ||
|
|
17146
|
+
if (!selection ||
|
|
17147
|
+
selection.retainedHashes.length > 0 ||
|
|
17148
|
+
!this.isReceiveOwnershipSnapshotStable(ownershipRevision)) {
|
|
17069
17149
|
return false;
|
|
17070
17150
|
}
|
|
17071
17151
|
if (properties.syncProfile) {
|
|
@@ -17094,6 +17174,9 @@ let SharedLog = (() => {
|
|
|
17094
17174
|
hashes: selection.droppedHashes,
|
|
17095
17175
|
from: properties.from,
|
|
17096
17176
|
});
|
|
17177
|
+
if (!this.isReceiveOwnershipSnapshotStable(ownershipRevision)) {
|
|
17178
|
+
return false;
|
|
17179
|
+
}
|
|
17097
17180
|
if (properties.syncProfile) {
|
|
17098
17181
|
emitSyncProfileDuration(properties.syncProfile, notifyStartedAt, {
|
|
17099
17182
|
name: "sharedLog.receive.notifySynchronizer",
|
|
@@ -17124,13 +17207,15 @@ let SharedLog = (() => {
|
|
|
17124
17207
|
return true;
|
|
17125
17208
|
}
|
|
17126
17209
|
async selectNativePreparedRawReceiveHashes(properties) {
|
|
17210
|
+
const ownershipRevision = properties.receiveOwnershipRevision;
|
|
17127
17211
|
if (!this.syncronizer.onReceivedEntryHashes) {
|
|
17128
17212
|
return undefined;
|
|
17129
17213
|
}
|
|
17130
17214
|
const receivePlanStartedAt = syncProfileStart(properties.syncProfile);
|
|
17131
17215
|
const selection = properties.selection ??
|
|
17132
17216
|
(await this.planNativePreparedRawReceiveSelection(properties));
|
|
17133
|
-
if (!selection
|
|
17217
|
+
if (!selection ||
|
|
17218
|
+
!this.isReceiveOwnershipSnapshotStable(ownershipRevision)) {
|
|
17134
17219
|
return undefined;
|
|
17135
17220
|
}
|
|
17136
17221
|
if (selection.droppedHashes.length === 0) {
|
|
@@ -17144,6 +17229,9 @@ let SharedLog = (() => {
|
|
|
17144
17229
|
hashes: selection.droppedHashes,
|
|
17145
17230
|
from: properties.from,
|
|
17146
17231
|
});
|
|
17232
|
+
if (!this.isReceiveOwnershipSnapshotStable(ownershipRevision)) {
|
|
17233
|
+
return undefined;
|
|
17234
|
+
}
|
|
17147
17235
|
emitSyncProfileDuration(properties.syncProfile, notifyStartedAt, {
|
|
17148
17236
|
name: "sharedLog.receive.notifySynchronizer",
|
|
17149
17237
|
component: "shared-log",
|
|
@@ -17639,7 +17727,7 @@ let SharedLog = (() => {
|
|
|
17639
17727
|
this._checkedPruneRemovalCallbackInvocationDepth--;
|
|
17640
17728
|
return result;
|
|
17641
17729
|
}
|
|
17642
|
-
withReplicationRangeMutationQueue(fn, replicationOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle()) {
|
|
17730
|
+
withReplicationRangeMutationQueue(fn, replicationOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle(), options) {
|
|
17643
17731
|
try {
|
|
17644
17732
|
this.throwIfReplicationOwnershipLifecycleInactive(replicationOwnershipLifecycleController);
|
|
17645
17733
|
}
|
|
@@ -17649,6 +17737,15 @@ let SharedLog = (() => {
|
|
|
17649
17737
|
if (this._replicationRangeMutationsClosing) {
|
|
17650
17738
|
return Promise.reject(new TerminalOperationNotStartedError("Replication range mutations are closing"));
|
|
17651
17739
|
}
|
|
17740
|
+
let releaseReceiveOwnershipMutationAdmission;
|
|
17741
|
+
if (options?.affectsReceiveOwnership) {
|
|
17742
|
+
this._receiveOwnershipMutationAdmissions++;
|
|
17743
|
+
this.invalidateLeaderSelectionContextCache();
|
|
17744
|
+
releaseReceiveOwnershipMutationAdmission = () => {
|
|
17745
|
+
this._receiveOwnershipMutationAdmissions--;
|
|
17746
|
+
this.invalidateLeaderSelectionContextCache();
|
|
17747
|
+
};
|
|
17748
|
+
}
|
|
17652
17749
|
const run = (this._replicationRangeMutationTail ?? Promise.resolve())
|
|
17653
17750
|
.catch(() => {
|
|
17654
17751
|
// A failed predecessor must not leave the queue permanently rejected.
|
|
@@ -17660,8 +17757,14 @@ let SharedLog = (() => {
|
|
|
17660
17757
|
this.throwIfReplicationOwnershipLifecycleInactive(replicationOwnershipLifecycleController);
|
|
17661
17758
|
return fn();
|
|
17662
17759
|
});
|
|
17663
|
-
|
|
17664
|
-
|
|
17760
|
+
const fencedRun = releaseReceiveOwnershipMutationAdmission
|
|
17761
|
+
? run.finally(releaseReceiveOwnershipMutationAdmission)
|
|
17762
|
+
: run;
|
|
17763
|
+
this._replicationRangeMutationTail = fencedRun.then(() => undefined, () => undefined);
|
|
17764
|
+
return fencedRun;
|
|
17765
|
+
}
|
|
17766
|
+
withReceiveOwnershipMutationQueue(fn, replicationOwnershipLifecycleController = this.captureReplicationOwnershipLifecycle()) {
|
|
17767
|
+
return this.withReplicationRangeMutationQueue(fn, replicationOwnershipLifecycleController, { affectsReceiveOwnership: true });
|
|
17665
17768
|
}
|
|
17666
17769
|
acquireReplicationRangeMutationTerminalFence() {
|
|
17667
17770
|
this._replicationRangeMutationsClosing = true;
|
|
@@ -18349,7 +18452,8 @@ let SharedLog = (() => {
|
|
|
18349
18452
|
for (const { hash } of admitted) {
|
|
18350
18453
|
const candidate = checkedPruneCoordinator.getRestartCandidate(hash);
|
|
18351
18454
|
const pending = checkedPruneCoordinator.getPendingDelete(hash);
|
|
18352
|
-
const
|
|
18455
|
+
const retryIdentity = checkedPruneCoordinator.getRetryIdentity(hash);
|
|
18456
|
+
const retry = retryIdentity?.state;
|
|
18353
18457
|
const hadQueuedCandidate = this.pruneDebouncedFn.has(hash);
|
|
18354
18458
|
const hadInFlightCandidate = checkedPruneCoordinator.hasCandidate(hash);
|
|
18355
18459
|
const shouldRestart = candidate != null &&
|
|
@@ -18384,7 +18488,7 @@ let SharedLog = (() => {
|
|
|
18384
18488
|
restartCandidates.push({
|
|
18385
18489
|
candidate,
|
|
18386
18490
|
reservation: checkedPruneCoordinator.reserveRestart(hash),
|
|
18387
|
-
|
|
18491
|
+
retryIdentity,
|
|
18388
18492
|
});
|
|
18389
18493
|
}
|
|
18390
18494
|
}
|
|
@@ -18411,13 +18515,12 @@ let SharedLog = (() => {
|
|
|
18411
18515
|
finally {
|
|
18412
18516
|
admission.barrier.resolve();
|
|
18413
18517
|
await admission.observedBarrier;
|
|
18414
|
-
for (const { candidate, reservation,
|
|
18518
|
+
for (const { candidate, reservation, retryIdentity, } of admission.restartCandidates) {
|
|
18415
18519
|
if (this._checkedPrune !== checkedPruneCoordinator ||
|
|
18416
18520
|
!this.isRepairLifecycleActive(ownershipLifecycleController)) {
|
|
18417
18521
|
checkedPruneCoordinator.cancelRestartReservation(candidate.hash, reservation);
|
|
18418
|
-
if (
|
|
18419
|
-
checkedPruneCoordinator.
|
|
18420
|
-
checkedPruneCoordinator.clearRetry(candidate.hash);
|
|
18522
|
+
if (retryIdentity) {
|
|
18523
|
+
checkedPruneCoordinator.clearRetry(candidate.hash, retryIdentity);
|
|
18421
18524
|
}
|
|
18422
18525
|
continue;
|
|
18423
18526
|
}
|