@peerbit/shared-log 16.0.2 → 16.0.3
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/coordinate-persistence.d.ts +18 -1
- package/dist/src/coordinate-persistence.d.ts.map +1 -1
- package/dist/src/coordinate-persistence.js +61 -4
- package/dist/src/coordinate-persistence.js.map +1 -1
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +261 -200
- package/dist/src/index.js.map +1 -1
- package/package.json +8 -8
- package/src/coordinate-persistence.ts +66 -5
- package/src/index.ts +345 -257
package/dist/src/index.js
CHANGED
|
@@ -1518,8 +1518,23 @@ let SharedLog = (() => {
|
|
|
1518
1518
|
};
|
|
1519
1519
|
for (const coordinate of intent.coordinates) {
|
|
1520
1520
|
rollback.hashes.add(coordinate.hash);
|
|
1521
|
-
|
|
1522
|
-
|
|
1521
|
+
// Same hold-counted row shape the coordinator's own
|
|
1522
|
+
// snapshot writes: one hold per hash, released by the
|
|
1523
|
+
// settle after the replay consumes the token below.
|
|
1524
|
+
// RELIES ON `intent.coordinates` HOLDING UNIQUE HASHES —
|
|
1525
|
+
// it is built from the token's `hashes` Set (see
|
|
1526
|
+
// setNativeStrictDurableTransactionOperation). Holds are
|
|
1527
|
+
// taken per element here but released per unique hash by
|
|
1528
|
+
// the settle, so a duplicate would take two and release
|
|
1529
|
+
// one and retain that row forever. That is the safe
|
|
1530
|
+
// direction (a retained row, never a fail-open rollback),
|
|
1531
|
+
// but keep the source a Set.
|
|
1532
|
+
const row = mutationGenerations.get(coordinate.hash);
|
|
1533
|
+
const generation = (row?.generation ?? 0) + 1;
|
|
1534
|
+
mutationGenerations.set(coordinate.hash, {
|
|
1535
|
+
generation,
|
|
1536
|
+
holds: (row?.holds ?? 0) + 1,
|
|
1537
|
+
});
|
|
1523
1538
|
rollback.generations.set(coordinate.hash, generation);
|
|
1524
1539
|
if (coordinate.value) {
|
|
1525
1540
|
const number = (value) => (this.domain.resolution === "u32"
|
|
@@ -1537,6 +1552,9 @@ let SharedLog = (() => {
|
|
|
1537
1552
|
}
|
|
1538
1553
|
}
|
|
1539
1554
|
await this._coordinates.rollbackNativeBackboneCoordinateAppendDurably("", rollback);
|
|
1555
|
+
// The replay fabricated these generations itself one turn
|
|
1556
|
+
// earlier and has now consumed them, so the rows are dead.
|
|
1557
|
+
this._coordinates.settleResidentCoordinateSnapshot(rollback);
|
|
1540
1558
|
}
|
|
1541
1559
|
for (const document of intent.documents) {
|
|
1542
1560
|
this.restoreNativeBackboneDocument({
|
|
@@ -7081,10 +7099,15 @@ let SharedLog = (() => {
|
|
|
7081
7099
|
return rollbackLowerPublication(error);
|
|
7082
7100
|
}
|
|
7083
7101
|
if (!result) {
|
|
7102
|
+
// Abandon arm: the token was minted but nothing downstream can
|
|
7103
|
+
// roll it back from here.
|
|
7104
|
+
this._coordinates.settleResidentCoordinateSnapshot(lowerPublicationRollback?.coordinateEntries);
|
|
7084
7105
|
return this.completeNativeStrictDurableTransaction(nativeStrictTransaction).then(() => undefined);
|
|
7085
7106
|
}
|
|
7086
7107
|
return mapMaybePromise(result, async (prepared) => {
|
|
7087
7108
|
if (!prepared) {
|
|
7109
|
+
// Abandon arm: same shape as the `!result` arm above.
|
|
7110
|
+
this._coordinates.settleResidentCoordinateSnapshot(lowerPublicationRollback?.coordinateEntries);
|
|
7088
7111
|
await this.completeNativeStrictDurableTransaction(nativeStrictTransaction);
|
|
7089
7112
|
return undefined;
|
|
7090
7113
|
}
|
|
@@ -7105,6 +7128,9 @@ let SharedLog = (() => {
|
|
|
7105
7128
|
}
|
|
7106
7129
|
try {
|
|
7107
7130
|
await this._coordinates.rollbackNativeBackboneCoordinateAppendDurably(prepared.appendFacts.hash, lowerPublicationRollback?.coordinateEntries);
|
|
7131
|
+
// Terminal: this is the last rollback consumer for the
|
|
7132
|
+
// token. A throw above leaves the row, which is safe.
|
|
7133
|
+
this._coordinates.settleResidentCoordinateSnapshot(lowerPublicationRollback?.coordinateEntries);
|
|
7108
7134
|
for (const document of lowerPublicationRollback?.documents ?? []) {
|
|
7109
7135
|
this.restoreNativeBackboneDocument(document);
|
|
7110
7136
|
}
|
|
@@ -7164,6 +7190,12 @@ let SharedLog = (() => {
|
|
|
7164
7190
|
catch (error) {
|
|
7165
7191
|
return rollback(error);
|
|
7166
7192
|
}
|
|
7193
|
+
// Success seam. The last await inside the protected try is the
|
|
7194
|
+
// finalizer acknowledge; `finish()` is synchronous, so no async
|
|
7195
|
+
// boundary separates the catch above from this statement and
|
|
7196
|
+
// `rollback` can no longer fire. Nothing downstream rolls back
|
|
7197
|
+
// (the retire below only warns), so the token is terminal here.
|
|
7198
|
+
this._coordinates.settleResidentCoordinateSnapshot(lowerPublicationRollback?.coordinateEntries);
|
|
7167
7199
|
this.applyPreparedAppendFactsWithDeferredCoordinateDeletes(prepared.appendFacts, prepared.removed, prepared.materializeEntry, { removedHashes: prepared.removedHashes });
|
|
7168
7200
|
try {
|
|
7169
7201
|
await this.completeNativeStrictDurableTransaction(nativeStrictTransaction);
|
|
@@ -7466,6 +7498,10 @@ let SharedLog = (() => {
|
|
|
7466
7498
|
}
|
|
7467
7499
|
return mapMaybePromise(result, async (prepared) => {
|
|
7468
7500
|
if (!prepared || !backboneAppend) {
|
|
7501
|
+
// Abandon arm: the token was minted inside
|
|
7502
|
+
// `prepareBackboneAppend` and nothing downstream of
|
|
7503
|
+
// this return can roll it back.
|
|
7504
|
+
this._coordinates.settleResidentCoordinateSnapshot(nativeCoordinateRollback);
|
|
7469
7505
|
await this.completeNativeStrictDurableTransaction(nativeStrictTransaction);
|
|
7470
7506
|
return undefined;
|
|
7471
7507
|
}
|
|
@@ -7533,6 +7569,8 @@ let SharedLog = (() => {
|
|
|
7533
7569
|
}
|
|
7534
7570
|
try {
|
|
7535
7571
|
await this._coordinates.rollbackNativeBackboneCoordinateAppendDurably(prepared.appendFacts.hash, rollbackCoordinateEntries);
|
|
7572
|
+
// Terminal: last rollback consumer for the token.
|
|
7573
|
+
this._coordinates.settleResidentCoordinateSnapshot(rollbackCoordinateEntries);
|
|
7536
7574
|
}
|
|
7537
7575
|
catch (rollbackError) {
|
|
7538
7576
|
rollbackFailures.push(rollbackError);
|
|
@@ -7594,6 +7632,10 @@ let SharedLog = (() => {
|
|
|
7594
7632
|
catch (error) {
|
|
7595
7633
|
return rollback(error);
|
|
7596
7634
|
}
|
|
7635
|
+
// Success seam: the finalizer acknowledge above is the last
|
|
7636
|
+
// await inside the protected try, so `rollback` can no
|
|
7637
|
+
// longer fire and the retire below only warns.
|
|
7638
|
+
this._coordinates.settleResidentCoordinateSnapshot(rollbackCoordinateEntries);
|
|
7597
7639
|
this.applyPreparedAppendFactsWithDeferredCoordinateDeletes(prepared.appendFacts, prepared.removed, prepared.materializeEntry, {
|
|
7598
7640
|
forgetNativeCoordinates: false,
|
|
7599
7641
|
removedHashes: prepared.removedHashes,
|
|
@@ -8148,6 +8190,8 @@ let SharedLog = (() => {
|
|
|
8148
8190
|
throw error;
|
|
8149
8191
|
}
|
|
8150
8192
|
if (!appended || !backboneAppends) {
|
|
8193
|
+
// Abandon arm: no consumer downstream of this return.
|
|
8194
|
+
this._coordinates.settleResidentCoordinateSnapshot(batchCoordinateRollback);
|
|
8151
8195
|
await this.completeNativeStrictDurableTransaction(nativeStrictTransaction);
|
|
8152
8196
|
this.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
8153
8197
|
return undefined;
|
|
@@ -8170,6 +8214,8 @@ let SharedLog = (() => {
|
|
|
8170
8214
|
}
|
|
8171
8215
|
try {
|
|
8172
8216
|
await this._coordinates.rollbackNativeBackboneCoordinateAppendDurably(appended.appendFacts[0]?.hash ?? "", batchCoordinateRollback);
|
|
8217
|
+
// Terminal: last rollback consumer for the batch token.
|
|
8218
|
+
this._coordinates.settleResidentCoordinateSnapshot(batchCoordinateRollback);
|
|
8173
8219
|
}
|
|
8174
8220
|
catch (rollbackError) {
|
|
8175
8221
|
rollbackFailures.push(rollbackError);
|
|
@@ -8260,6 +8306,9 @@ let SharedLog = (() => {
|
|
|
8260
8306
|
catch (error) {
|
|
8261
8307
|
return rollbackBatch(error);
|
|
8262
8308
|
}
|
|
8309
|
+
// Success seam: `rollbackBatch` has exactly one call site (the catch
|
|
8310
|
+
// above), and everything from here on escapes without any rollback.
|
|
8311
|
+
this._coordinates.settleResidentCoordinateSnapshot(batchCoordinateRollback);
|
|
8263
8312
|
this.throwIfReplicationOwnershipLifecycleInactive(ownershipLifecycleController);
|
|
8264
8313
|
const appendCommits = [];
|
|
8265
8314
|
for (let i = 0; i < coordinateRows.length; i++) {
|
|
@@ -12925,221 +12974,233 @@ let SharedLog = (() => {
|
|
|
12925
12974
|
const nativeReceiveCoordinateBatch = canUsePreparedAppendFacts
|
|
12926
12975
|
? this._coordinates.createBackboneOnlyReceiveCoordinateBatch(reusableCoordinatePersistItems)
|
|
12927
12976
|
: undefined;
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
!
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12977
|
+
try {
|
|
12978
|
+
const nativePreparedJoinCommit = canUsePreparedAppendFacts
|
|
12979
|
+
? this._coordinates.createNativeBackbonePreparedJoinCommit(nativeReceiveCoordinateBatch, (batch) => {
|
|
12980
|
+
nativePreparedCoordinateBatch = batch;
|
|
12981
|
+
}, nativeCommitVerifyHashes, nativeCommitVerifyAllHashes, syncProfile, (committedHashes) => {
|
|
12982
|
+
nativePreparedCommittedHashes = new Set(committedHashes);
|
|
12983
|
+
})
|
|
12984
|
+
: undefined;
|
|
12985
|
+
const finishNativePreparedCoordinates = async (properties) => {
|
|
12986
|
+
if (!properties.nativePreparedCommitted ||
|
|
12987
|
+
!nativePreparedCoordinateBatch) {
|
|
12988
|
+
return;
|
|
12989
|
+
}
|
|
12990
|
+
try {
|
|
12991
|
+
nativeBackboneOnlyPersistedHashes =
|
|
12992
|
+
await this._coordinates.finishBackboneOnlyReceiveCoordinateBatch(nativePreparedCoordinateBatch, syncProfile);
|
|
12993
|
+
nativePreparedCoordinatesFinished = true;
|
|
12994
|
+
}
|
|
12995
|
+
catch (error) {
|
|
12996
|
+
this._coordinates.rollbackBackboneOnlyReceiveCoordinateBatch(nativePreparedCoordinateBatch);
|
|
12997
|
+
throw error;
|
|
12998
|
+
}
|
|
12999
|
+
};
|
|
13000
|
+
const preparedAppendCanValidateAppend = canAppendAlreadyValidated ||
|
|
13001
|
+
(nativeCommitCanValidateAppend && !!nativePreparedJoinCommit);
|
|
13002
|
+
if (!preparedAppendCanValidateAppend) {
|
|
13003
|
+
canUsePreparedAppendFacts = false;
|
|
12948
13004
|
}
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
|
|
12954
|
-
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
? nativeCommitVerifyAllHashes
|
|
12958
|
-
? !!this._nativeBackbone?.graph
|
|
12959
|
-
.commitVerifiedAllPreparedRawReceiveJoinBatch ||
|
|
12960
|
-
!!this._nativeBackbone?.graph
|
|
13005
|
+
const nativePreparedJoinCommitValidatesPlan = !!nativePreparedJoinCommit &&
|
|
13006
|
+
(nativeCommitVerifyHashes && nativeCommitVerifyHashes.length > 0
|
|
13007
|
+
? nativeCommitVerifyAllHashes
|
|
13008
|
+
? !!this._nativeBackbone?.graph
|
|
13009
|
+
.commitVerifiedAllPreparedRawReceiveJoinBatch ||
|
|
13010
|
+
!!this._nativeBackbone?.graph
|
|
13011
|
+
.commitVerifiedPreparedRawReceiveJoinBatch
|
|
13012
|
+
: !!this._nativeBackbone?.graph
|
|
12961
13013
|
.commitVerifiedPreparedRawReceiveJoinBatch
|
|
12962
13014
|
: !!this._nativeBackbone?.graph
|
|
12963
|
-
.
|
|
12964
|
-
|
|
12965
|
-
|
|
12966
|
-
|
|
12967
|
-
|
|
12968
|
-
|
|
12969
|
-
|
|
12970
|
-
|
|
12971
|
-
|
|
12972
|
-
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
__peerbitProfile: syncProfile,
|
|
12995
|
-
});
|
|
12996
|
-
}
|
|
12997
|
-
// A recursive lower-log join can resolve successfully while declining
|
|
12998
|
-
// an individual top-level entry (for example, when one of its parents
|
|
12999
|
-
// is temporarily unavailable). The public Log.join() API intentionally
|
|
13000
|
-
// does not expose that per-entry result, so make local index presence the
|
|
13001
|
-
// authority before publishing any SharedLog-side effects. A successful
|
|
13002
|
-
// prepared-facts batch is atomic and already proves every input hash.
|
|
13003
|
-
const admittedHashes = joinedPreparedFacts
|
|
13004
|
-
? new Set(allToMergeHashes)
|
|
13005
|
-
: await this.log.hasMany(allToMergeHashes);
|
|
13006
|
-
admittedMergeHashes = admittedHashes;
|
|
13007
|
-
const admittedShallowEntries = admittedHashes.size === allToMergeShallowEntries.length
|
|
13008
|
-
? allToMergeShallowEntries
|
|
13009
|
-
: allToMergeShallowEntries.filter((entry) => admittedHashes.has(entry.hash));
|
|
13010
|
-
if (!joinedPreparedFacts) {
|
|
13011
|
-
reusableCoordinatePersistItems =
|
|
13012
|
-
reusableCoordinatePersistItems.filter((item) => admittedHashes.has(item.entry.hash));
|
|
13013
|
-
coordinatePersistFallbackEntries =
|
|
13014
|
-
coordinatePersistFallbackEntries.filter((entry) => admittedHashes.has(entry.hash));
|
|
13015
|
-
}
|
|
13016
|
-
const reusableCoordinatePersistItemCount = reusableCoordinatePersistItems.length;
|
|
13017
|
-
if (syncProfile) {
|
|
13018
|
-
emitSyncProfileDuration(syncProfile, lowerLogJoinStartedAt, {
|
|
13019
|
-
name: "sharedLog.receive.lowerLogJoin",
|
|
13020
|
-
component: "shared-log",
|
|
13021
|
-
entries: allToMerge.length,
|
|
13022
|
-
messages: 1,
|
|
13023
|
-
details: {
|
|
13024
|
-
hashOnlyEntryAdded,
|
|
13025
|
-
batchHashOnlyEntryAdded,
|
|
13026
|
-
programOnChange,
|
|
13027
|
-
joinedPreparedFacts,
|
|
13028
|
-
admittedEntries: admittedHashes.size,
|
|
13029
|
-
nativePreparedCoordinatesFinished,
|
|
13030
|
-
},
|
|
13031
|
-
});
|
|
13032
|
-
}
|
|
13033
|
-
const coordinatePersistStartedAt = syncProfileStart(syncProfile);
|
|
13034
|
-
if (nativePreparedCoordinatesFinished) {
|
|
13035
|
-
// The lower-log prepared receive transaction already finished
|
|
13036
|
-
// the native coordinate mirror/journal after entry-index commit.
|
|
13037
|
-
}
|
|
13038
|
-
else if (nativePreparedCoordinateBatch) {
|
|
13039
|
-
try {
|
|
13040
|
-
nativeBackboneOnlyPersistedHashes =
|
|
13041
|
-
await this._coordinates.finishBackboneOnlyReceiveCoordinateBatch(nativePreparedCoordinateBatch, syncProfile);
|
|
13015
|
+
.commitPreparedRawReceiveJoinBatch);
|
|
13016
|
+
const trustedLowerLog = this.log;
|
|
13017
|
+
// With a program-level onChange consumer the hash-only
|
|
13018
|
+
// sink is not used: the lower-log join dispatches the
|
|
13019
|
+
// change event (lazy entry views over the prepared raw
|
|
13020
|
+
// facts) so per-entry consumers observe every commit.
|
|
13021
|
+
const joinOnAppendHashes = programOnChange
|
|
13022
|
+
? undefined
|
|
13023
|
+
: onAppendHashes;
|
|
13024
|
+
const joinedPreparedFacts = canUsePreparedAppendFacts &&
|
|
13025
|
+
(await trustedLowerLog.joinPreparedAppendFactsBatch(preparedAppendFacts, {
|
|
13026
|
+
__peerbitEntriesAlreadyMissing: true,
|
|
13027
|
+
__peerbitCanAppendAlreadyValidated: true,
|
|
13028
|
+
__peerbitDeferIndexWrite: true,
|
|
13029
|
+
__peerbitOnAppendHashes: joinOnAppendHashes,
|
|
13030
|
+
__peerbitProfile: syncProfile,
|
|
13031
|
+
__peerbitNativePreparedJoinCommit: nativePreparedJoinCommit,
|
|
13032
|
+
__peerbitNativePreparedJoinCommitValidatesPlan: nativePreparedJoinCommitValidatesPlan,
|
|
13033
|
+
__peerbitOnPreparedJoinCommitted: nativePreparedJoinCommit
|
|
13034
|
+
? finishNativePreparedCoordinates
|
|
13035
|
+
: undefined,
|
|
13036
|
+
}));
|
|
13037
|
+
if (!joinedPreparedFacts) {
|
|
13038
|
+
await trustedLowerLog.join(materializeAllToMergeEntries(), {
|
|
13039
|
+
__peerbitBatchIndependent: true,
|
|
13040
|
+
__peerbitEntriesAlreadyMissing: true,
|
|
13041
|
+
__peerbitCanAppendAlreadyValidated: fallbackCanAppendAlreadyValidated,
|
|
13042
|
+
__peerbitDeferIndexWrite: true,
|
|
13043
|
+
__peerbitOnAppendHashes: joinOnAppendHashes,
|
|
13044
|
+
__peerbitProfile: syncProfile,
|
|
13045
|
+
});
|
|
13042
13046
|
}
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13047
|
+
// A recursive lower-log join can resolve successfully while declining
|
|
13048
|
+
// an individual top-level entry (for example, when one of its parents
|
|
13049
|
+
// is temporarily unavailable). The public Log.join() API intentionally
|
|
13050
|
+
// does not expose that per-entry result, so make local index presence the
|
|
13051
|
+
// authority before publishing any SharedLog-side effects. A successful
|
|
13052
|
+
// prepared-facts batch is atomic and already proves every input hash.
|
|
13053
|
+
const admittedHashes = joinedPreparedFacts
|
|
13054
|
+
? new Set(allToMergeHashes)
|
|
13055
|
+
: await this.log.hasMany(allToMergeHashes);
|
|
13056
|
+
admittedMergeHashes = admittedHashes;
|
|
13057
|
+
const admittedShallowEntries = admittedHashes.size === allToMergeShallowEntries.length
|
|
13058
|
+
? allToMergeShallowEntries
|
|
13059
|
+
: allToMergeShallowEntries.filter((entry) => admittedHashes.has(entry.hash));
|
|
13060
|
+
if (!joinedPreparedFacts) {
|
|
13061
|
+
reusableCoordinatePersistItems =
|
|
13062
|
+
reusableCoordinatePersistItems.filter((item) => admittedHashes.has(item.entry.hash));
|
|
13063
|
+
coordinatePersistFallbackEntries =
|
|
13064
|
+
coordinatePersistFallbackEntries.filter((entry) => admittedHashes.has(entry.hash));
|
|
13046
13065
|
}
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13056
|
-
|
|
13066
|
+
const reusableCoordinatePersistItemCount = reusableCoordinatePersistItems.length;
|
|
13067
|
+
if (syncProfile) {
|
|
13068
|
+
emitSyncProfileDuration(syncProfile, lowerLogJoinStartedAt, {
|
|
13069
|
+
name: "sharedLog.receive.lowerLogJoin",
|
|
13070
|
+
component: "shared-log",
|
|
13071
|
+
entries: allToMerge.length,
|
|
13072
|
+
messages: 1,
|
|
13073
|
+
details: {
|
|
13074
|
+
hashOnlyEntryAdded,
|
|
13075
|
+
batchHashOnlyEntryAdded,
|
|
13076
|
+
programOnChange,
|
|
13077
|
+
joinedPreparedFacts,
|
|
13078
|
+
admittedEntries: admittedHashes.size,
|
|
13079
|
+
nativePreparedCoordinatesFinished,
|
|
13080
|
+
},
|
|
13081
|
+
});
|
|
13082
|
+
}
|
|
13083
|
+
const coordinatePersistStartedAt = syncProfileStart(syncProfile);
|
|
13084
|
+
if (nativePreparedCoordinatesFinished) {
|
|
13085
|
+
// The lower-log prepared receive transaction already finished
|
|
13086
|
+
// the native coordinate mirror/journal after entry-index commit.
|
|
13087
|
+
}
|
|
13088
|
+
else if (nativePreparedCoordinateBatch) {
|
|
13089
|
+
try {
|
|
13090
|
+
nativeBackboneOnlyPersistedHashes =
|
|
13091
|
+
await this._coordinates.finishBackboneOnlyReceiveCoordinateBatch(nativePreparedCoordinateBatch, syncProfile);
|
|
13092
|
+
}
|
|
13093
|
+
catch (error) {
|
|
13094
|
+
this._coordinates.rollbackBackboneOnlyReceiveCoordinateBatch(nativePreparedCoordinateBatch);
|
|
13095
|
+
throw error;
|
|
13057
13096
|
}
|
|
13058
13097
|
}
|
|
13059
|
-
|
|
13060
|
-
|
|
13061
|
-
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
})));
|
|
13070
|
-
}
|
|
13071
|
-
if (syncProfile) {
|
|
13072
|
-
emitSyncProfileDuration(syncProfile, coordinatePersistStartedAt, {
|
|
13073
|
-
name: "sharedLog.receive.coordinatePersist",
|
|
13074
|
-
component: "shared-log",
|
|
13075
|
-
entries: entriesToPersist.length,
|
|
13076
|
-
messages: 1,
|
|
13077
|
-
details: {
|
|
13078
|
-
reusedLeaderPlans: reusableCoordinatePersistItemCount,
|
|
13079
|
-
nativeBackboneOnly: nativeBackboneOnlyPersistedHashes?.size ?? 0,
|
|
13080
|
-
},
|
|
13081
|
-
});
|
|
13082
|
-
}
|
|
13083
|
-
for (const hash of admittedHashes) {
|
|
13084
|
-
confirmedHashes.add(hash);
|
|
13085
|
-
}
|
|
13086
|
-
const checkedPruneStartedAt = syncProfileStart(syncProfile);
|
|
13087
|
-
const ownershipChangedDuringReceive = !this.isReceiveOwnershipSnapshotStable(receiveOwnershipRevision);
|
|
13088
|
-
if (ownershipChangedDuringReceive) {
|
|
13089
|
-
const freshAuditRevision = this._instanceLifecycle?._receiveOwnershipRevision ?? 0;
|
|
13090
|
-
const armFreshAuditRetry = () => {
|
|
13091
|
-
for (const entry of admittedShallowEntries) {
|
|
13092
|
-
this.scheduleCheckedPruneRetry({ entry, leaders: new Map() }, receiveOwnershipLifecycleController);
|
|
13098
|
+
else {
|
|
13099
|
+
nativeBackboneOnlyPersistedHashes =
|
|
13100
|
+
await this._coordinates.persistBackboneOnlyReceiveCoordinateBatch(reusableCoordinatePersistItems);
|
|
13101
|
+
}
|
|
13102
|
+
if (nativeBackboneOnlyPersistedHashes &&
|
|
13103
|
+
nativeBackboneOnlyPersistedHashes.size > 0) {
|
|
13104
|
+
for (let i = reusableCoordinatePersistItems.length - 1; i >= 0; i--) {
|
|
13105
|
+
if (nativeBackboneOnlyPersistedHashes.has(reusableCoordinatePersistItems[i].entry.hash)) {
|
|
13106
|
+
reusableCoordinatePersistItems.splice(i, 1);
|
|
13107
|
+
}
|
|
13093
13108
|
}
|
|
13094
|
-
}
|
|
13095
|
-
|
|
13109
|
+
}
|
|
13110
|
+
if (reusableCoordinatePersistItems.length > 0) {
|
|
13111
|
+
await this._coordinates.persistCoordinatesBatch(reusableCoordinatePersistItems);
|
|
13112
|
+
}
|
|
13113
|
+
if (coordinatePersistFallbackEntries.length > 0) {
|
|
13114
|
+
await this.planEntryLeaderBatch(coordinatePersistFallbackEntries.map((entry) => ({
|
|
13115
|
+
entry,
|
|
13116
|
+
replicas: receiveReplicaCounts.get(entry.hash) ??
|
|
13117
|
+
decodeReplicas(entry).getValue(this),
|
|
13118
|
+
options: { roleAge: 0, persist: {} },
|
|
13119
|
+
})));
|
|
13120
|
+
}
|
|
13121
|
+
if (syncProfile) {
|
|
13122
|
+
emitSyncProfileDuration(syncProfile, coordinatePersistStartedAt, {
|
|
13123
|
+
name: "sharedLog.receive.coordinatePersist",
|
|
13124
|
+
component: "shared-log",
|
|
13125
|
+
entries: entriesToPersist.length,
|
|
13126
|
+
messages: 1,
|
|
13127
|
+
details: {
|
|
13128
|
+
reusedLeaderPlans: reusableCoordinatePersistItemCount,
|
|
13129
|
+
nativeBackboneOnly: nativeBackboneOnlyPersistedHashes?.size ?? 0,
|
|
13130
|
+
},
|
|
13131
|
+
});
|
|
13132
|
+
}
|
|
13133
|
+
for (const hash of admittedHashes) {
|
|
13134
|
+
confirmedHashes.add(hash);
|
|
13135
|
+
}
|
|
13136
|
+
const checkedPruneStartedAt = syncProfileStart(syncProfile);
|
|
13137
|
+
const ownershipChangedDuringReceive = !this.isReceiveOwnershipSnapshotStable(receiveOwnershipRevision);
|
|
13138
|
+
if (ownershipChangedDuringReceive) {
|
|
13139
|
+
const freshAuditRevision = this._instanceLifecycle?._receiveOwnershipRevision ?? 0;
|
|
13140
|
+
const armFreshAuditRetry = () => {
|
|
13141
|
+
for (const entry of admittedShallowEntries) {
|
|
13142
|
+
this.scheduleCheckedPruneRetry({ entry, leaders: new Map() }, receiveOwnershipLifecycleController);
|
|
13143
|
+
}
|
|
13144
|
+
};
|
|
13145
|
+
try {
|
|
13146
|
+
await this.pruneJoinedEntriesNoLongerLed(admittedShallowEntries, {
|
|
13147
|
+
decodedReplicaCounts: receiveReplicaCounts,
|
|
13148
|
+
freshReceiveOwnerAudit: true,
|
|
13149
|
+
preserveExistingPruneOnLocalResult: true,
|
|
13150
|
+
profile: syncProfile,
|
|
13151
|
+
}, receiveOwnershipLifecycleController);
|
|
13152
|
+
this.throwIfReplicationOwnershipLifecycleInactive(receiveOwnershipLifecycleController);
|
|
13153
|
+
if (!this.isReceiveOwnershipSnapshotStable(freshAuditRevision)) {
|
|
13154
|
+
armFreshAuditRetry();
|
|
13155
|
+
}
|
|
13156
|
+
}
|
|
13157
|
+
catch {
|
|
13158
|
+
// The lower-log and coordinate commits are already durable. A
|
|
13159
|
+
// sender retry will filter these hashes as present, so retain a
|
|
13160
|
+
// bounded local obligation instead of failing the admitted receive.
|
|
13161
|
+
this.throwIfReplicationOwnershipLifecycleInactive(receiveOwnershipLifecycleController);
|
|
13162
|
+
armFreshAuditRetry();
|
|
13163
|
+
}
|
|
13164
|
+
}
|
|
13165
|
+
else {
|
|
13096
13166
|
await this.pruneJoinedEntriesNoLongerLed(admittedShallowEntries, {
|
|
13097
13167
|
decodedReplicaCounts: receiveReplicaCounts,
|
|
13098
|
-
freshReceiveOwnerAudit: true,
|
|
13099
13168
|
preserveExistingPruneOnLocalResult: true,
|
|
13169
|
+
reusableLeaderPlans: reusableCoordinatePlans,
|
|
13100
13170
|
profile: syncProfile,
|
|
13101
13171
|
}, receiveOwnershipLifecycleController);
|
|
13102
|
-
this.throwIfReplicationOwnershipLifecycleInactive(receiveOwnershipLifecycleController);
|
|
13103
|
-
if (!this.isReceiveOwnershipSnapshotStable(freshAuditRevision)) {
|
|
13104
|
-
armFreshAuditRetry();
|
|
13105
|
-
}
|
|
13106
13172
|
}
|
|
13107
|
-
|
|
13108
|
-
|
|
13109
|
-
|
|
13110
|
-
|
|
13111
|
-
|
|
13112
|
-
|
|
13173
|
+
if (syncProfile) {
|
|
13174
|
+
emitSyncProfileDuration(syncProfile, checkedPruneStartedAt, {
|
|
13175
|
+
name: "sharedLog.receive.checkedPrune",
|
|
13176
|
+
component: "shared-log",
|
|
13177
|
+
entries: allToMerge.length,
|
|
13178
|
+
messages: 1,
|
|
13179
|
+
});
|
|
13113
13180
|
}
|
|
13181
|
+
for (const plan of joinPlans) {
|
|
13182
|
+
plan.toDelete
|
|
13183
|
+
?.filter((entry) => admittedMergeHashes.has(entry.hash))
|
|
13184
|
+
.map((entry) => this.pruneDebouncedFnAddIfNotKeeping({
|
|
13185
|
+
key: entry.hash,
|
|
13186
|
+
value: {
|
|
13187
|
+
entry,
|
|
13188
|
+
leaders: plan.leaders,
|
|
13189
|
+
},
|
|
13190
|
+
}));
|
|
13191
|
+
}
|
|
13192
|
+
this.rebalanceParticipationDebounced?.call();
|
|
13114
13193
|
}
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
|
|
13118
|
-
|
|
13119
|
-
|
|
13120
|
-
|
|
13121
|
-
|
|
13122
|
-
|
|
13123
|
-
|
|
13124
|
-
emitSyncProfileDuration(syncProfile, checkedPruneStartedAt, {
|
|
13125
|
-
name: "sharedLog.receive.checkedPrune",
|
|
13126
|
-
component: "shared-log",
|
|
13127
|
-
entries: allToMerge.length,
|
|
13128
|
-
messages: 1,
|
|
13129
|
-
});
|
|
13130
|
-
}
|
|
13131
|
-
for (const plan of joinPlans) {
|
|
13132
|
-
plan.toDelete
|
|
13133
|
-
?.filter((entry) => admittedMergeHashes.has(entry.hash))
|
|
13134
|
-
.map((entry) => this.pruneDebouncedFnAddIfNotKeeping({
|
|
13135
|
-
key: entry.hash,
|
|
13136
|
-
value: {
|
|
13137
|
-
entry,
|
|
13138
|
-
leaders: plan.leaders,
|
|
13139
|
-
},
|
|
13140
|
-
}));
|
|
13194
|
+
finally {
|
|
13195
|
+
// Settle seam for the receive token. Every consumer that can
|
|
13196
|
+
// roll it back runs inline before control leaves this block: the
|
|
13197
|
+
// prepared-join callback resolves during the join await, and the
|
|
13198
|
+
// late finish/rollback arm runs above. This `finally` is what
|
|
13199
|
+
// closes the abandon arms (no prepared-join commit, a declined
|
|
13200
|
+
// native commit, a downgrade to the plain join) without having
|
|
13201
|
+
// to enumerate them.
|
|
13202
|
+
this._coordinates.settleResidentCoordinateSnapshot(nativeReceiveCoordinateBatch?.rollbackCoordinateEntries);
|
|
13141
13203
|
}
|
|
13142
|
-
this.rebalanceParticipationDebounced?.call();
|
|
13143
13204
|
}
|
|
13144
13205
|
for (const plan of joinPlans) {
|
|
13145
13206
|
if (!plan.maybeDelete) {
|