@peerbit/shared-log 16.0.24 → 16.0.25
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/exchange-heads.d.ts +8 -0
- package/dist/src/exchange-heads.d.ts.map +1 -1
- package/dist/src/exchange-heads.js +8 -0
- package/dist/src/exchange-heads.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +71 -11
- package/dist/src/index.js.map +1 -1
- package/dist/src/replication-info-v2-receive.d.ts +23 -0
- package/dist/src/replication-info-v2-receive.d.ts.map +1 -1
- package/dist/src/replication-info-v2-receive.js +91 -0
- package/dist/src/replication-info-v2-receive.js.map +1 -1
- package/dist/src/replication-info-v2-send.d.ts +6 -0
- package/dist/src/replication-info-v2-send.d.ts.map +1 -1
- package/dist/src/replication-info-v2-send.js +13 -0
- package/dist/src/replication-info-v2-send.js.map +1 -1
- package/package.json +13 -13
- package/src/exchange-heads.ts +9 -0
- package/src/index.ts +97 -14
- package/src/replication-info-v2-receive.ts +122 -0
- package/src/replication-info-v2-send.ts +16 -0
package/dist/src/index.js
CHANGED
|
@@ -55,7 +55,7 @@ import { CoordinatePersistenceCoordinator, combineCoordinateDeleteHashes, isProm
|
|
|
55
55
|
import { CPUUsageIntervalLag } from "./cpu.js";
|
|
56
56
|
import { debouncedAccumulatorMap, } from "./debounce.js";
|
|
57
57
|
import { CompatibilityModeRetiredError, NativeDurableCommitError, NoPeersError, PersistedDeliveryError, isNotStartedError, } from "./errors.js";
|
|
58
|
-
import { EXCHANGE_HEADS_REPAIR_HINT, EntryWithRefs, ExchangeHeadsMessage, MAX_RAW_EXCHANGE_MESSAGE_SIZE, RawEntryWithRefs, RawExchangeHeadsMessage, RequestIPrune, RequestIPruneV2, ResponseIPrune, ResponseIPruneV2, SYNC_CAPABILITY_PERSISTED_ENTRY_RECEIPTS, SYNC_CAPABILITY_RAW_EXCHANGE_HEADS, SYNC_CAPABILITY_REPLICATION_INFO_V2_APPLY, SYNC_CAPABILITY_REPLICATION_INFO_V2_CONFIRM, SYNC_CAPABILITY_REPLICATION_INFO_V2_DECODE, SYNC_CAPABILITY_REPLICATION_INFO_V2_SEND, StashBackedRawExchangeHeadsMessage, SyncCapabilitiesMessage, collectRawExchangeHeadSendPlan, createExchangeHeadsMessages, createRawExchangeHeadsMessages, getExchangeHeadHash, getPreparedRawExchangeGid, getPreparedRawExchangeHashNumber, getPreparedRawExchangeHeadAppendFacts, getPreparedRawExchangeHeadGid, getPreparedRawExchangeHeadRequestedReplicas, getPreparedRawExchangeHeadShallowEntry, getPreparedRawExchangeHeadSignatureVerified, getPreparedRawExchangeNext, getPreparedRawExchangeRequestedReplicas, getPreparedRawExchangeTimestamp, getRawExchangeHeadByteLength, getRawExchangeHeadStashIndexes, initExchangeHeadEntry, isPreparedRawEntryWithRefs, isStashBackedRawExchangeHeadsMessage, materializeVerifiedRawExchangeHeadsMessage, } from "./exchange-heads.js";
|
|
58
|
+
import { EXCHANGE_HEADS_REPAIR_HINT, EntryWithRefs, ExchangeHeadsMessage, MAX_RAW_EXCHANGE_MESSAGE_SIZE, RawEntryWithRefs, RawExchangeHeadsMessage, RequestIPrune, RequestIPruneV2, ResponseIPrune, ResponseIPruneV2, SYNC_CAPABILITY_PERSISTED_ENTRY_RECEIPTS, SYNC_CAPABILITY_RAW_EXCHANGE_HEADS, SYNC_CAPABILITY_REPLICATION_INFO_V2_APPLY, SYNC_CAPABILITY_REPLICATION_INFO_V2_CONFIRM, SYNC_CAPABILITY_REPLICATION_INFO_V2_DECODE, SYNC_CAPABILITY_REPLICATION_INFO_V2_REARM, SYNC_CAPABILITY_REPLICATION_INFO_V2_SEND, StashBackedRawExchangeHeadsMessage, SyncCapabilitiesMessage, collectRawExchangeHeadSendPlan, createExchangeHeadsMessages, createRawExchangeHeadsMessages, getExchangeHeadHash, getPreparedRawExchangeGid, getPreparedRawExchangeHashNumber, getPreparedRawExchangeHeadAppendFacts, getPreparedRawExchangeHeadGid, getPreparedRawExchangeHeadRequestedReplicas, getPreparedRawExchangeHeadShallowEntry, getPreparedRawExchangeHeadSignatureVerified, getPreparedRawExchangeNext, getPreparedRawExchangeRequestedReplicas, getPreparedRawExchangeTimestamp, getRawExchangeHeadByteLength, getRawExchangeHeadStashIndexes, initExchangeHeadEntry, isPreparedRawEntryWithRefs, isStashBackedRawExchangeHeadsMessage, materializeVerifiedRawExchangeHeadsMessage, } from "./exchange-heads.js";
|
|
59
59
|
import { FanoutEnvelope } from "./fanout-envelope.js";
|
|
60
60
|
import { InstanceLifecycle } from "./instance-lifecycle.js";
|
|
61
61
|
import { MAX_U32, MAX_U64, createNumbers, } from "./integers.js";
|
|
@@ -2024,7 +2024,10 @@ let SharedLog = (() => {
|
|
|
2024
2024
|
const peerHash = properties.target.hashcode();
|
|
2025
2025
|
const receiverTransportSession = this.ownTransportSession();
|
|
2026
2026
|
await this.rpc.send(new SyncCapabilitiesMessage({
|
|
2027
|
-
capabilities: this.replicationInfoV2ReceiveCapabilities()
|
|
2027
|
+
capabilities: this.replicationInfoV2ReceiveCapabilities() |
|
|
2028
|
+
(properties.requestRemoteFullRearm
|
|
2029
|
+
? SYNC_CAPABILITY_REPLICATION_INFO_V2_REARM
|
|
2030
|
+
: 0),
|
|
2028
2031
|
}), {
|
|
2029
2032
|
mode: new AcknowledgeDelivery({
|
|
2030
2033
|
redundancy: 1,
|
|
@@ -2078,6 +2081,7 @@ let SharedLog = (() => {
|
|
|
2078
2081
|
peerSession: properties.peerSession,
|
|
2079
2082
|
receiveEpoch: properties.receiveEpoch,
|
|
2080
2083
|
signal: properties.signal,
|
|
2084
|
+
requestRemoteFullRearm: properties.requestRemoteFullRearm,
|
|
2081
2085
|
}),
|
|
2082
2086
|
onRequestError: (error) => {
|
|
2083
2087
|
if (isNotStartedError(error) ||
|
|
@@ -3447,7 +3451,7 @@ let SharedLog = (() => {
|
|
|
3447
3451
|
})) {
|
|
3448
3452
|
return undefined;
|
|
3449
3453
|
}
|
|
3450
|
-
return { capabilitySession, peerSession };
|
|
3454
|
+
return { capabilitySession, peerSession, receiveEpoch };
|
|
3451
3455
|
}
|
|
3452
3456
|
async waitPersistedReceiptRetry(signal, ms) {
|
|
3453
3457
|
try {
|
|
@@ -15966,6 +15970,13 @@ let SharedLog = (() => {
|
|
|
15966
15970
|
if (!context.from.equals(this.node.identity.publicKey)) {
|
|
15967
15971
|
const capabilityTransportSession = context.message?.header?.session;
|
|
15968
15972
|
const capabilityTimestamp = context.message?.header?.timestamp;
|
|
15973
|
+
const previousCapabilitySession = this._peerSyncCapabilitySessions.get(receiveFromHash);
|
|
15974
|
+
const previousCapabilityTimestamp = this._peerSyncCapabilityTimestamps.get(receiveFromHash);
|
|
15975
|
+
const requestsRemoteFullRearm = (msg.capabilities & SYNC_CAPABILITY_REPLICATION_INFO_V2_REARM) !==
|
|
15976
|
+
0;
|
|
15977
|
+
// The rearm bit is a one-shot authenticated command, not a sticky
|
|
15978
|
+
// negotiated capability. Store and promote only the steady bits.
|
|
15979
|
+
const steadyCapabilities = msg.capabilities & ~SYNC_CAPABILITY_REPLICATION_INFO_V2_REARM;
|
|
15969
15980
|
// No await separates this from the capture above, so the captured
|
|
15970
15981
|
// window state is exact: the legacy re-read of the opening map here
|
|
15971
15982
|
// could never observe a different value.
|
|
@@ -15976,7 +15987,7 @@ let SharedLog = (() => {
|
|
|
15976
15987
|
// cleanup cannot erase it before the opening transition commits.
|
|
15977
15988
|
this.observePeerSyncCapabilities({
|
|
15978
15989
|
peerHash: receiveFromHash,
|
|
15979
|
-
capabilities:
|
|
15990
|
+
capabilities: steadyCapabilities,
|
|
15980
15991
|
transportSession: capabilityTransportSession,
|
|
15981
15992
|
timestamp: capabilityTimestamp,
|
|
15982
15993
|
openingSession: receiveSession,
|
|
@@ -15985,12 +15996,34 @@ let SharedLog = (() => {
|
|
|
15985
15996
|
else {
|
|
15986
15997
|
const observed = this.observePeerSyncCapabilities({
|
|
15987
15998
|
peerHash: receiveFromHash,
|
|
15988
|
-
capabilities:
|
|
15999
|
+
capabilities: steadyCapabilities,
|
|
15989
16000
|
transportSession: capabilityTransportSession,
|
|
15990
16001
|
timestamp: capabilityTimestamp,
|
|
15991
16002
|
});
|
|
15992
16003
|
if (observed && receiveSession?.phase === "open") {
|
|
15993
16004
|
this.promoteReplicationInfoV2ReceiveCapability(context.from, receiveSession);
|
|
16005
|
+
const freshExactRearm = requestsRemoteFullRearm &&
|
|
16006
|
+
capabilityTransportSession !== undefined &&
|
|
16007
|
+
capabilityTimestamp !== undefined &&
|
|
16008
|
+
previousCapabilitySession === capabilityTransportSession &&
|
|
16009
|
+
previousCapabilityTimestamp !== undefined &&
|
|
16010
|
+
capabilityTimestamp > previousCapabilityTimestamp;
|
|
16011
|
+
if (freshExactRearm &&
|
|
16012
|
+
this._v2Receive.isCurrentActive({
|
|
16013
|
+
peerHash: receiveFromHash,
|
|
16014
|
+
peerSession: receiveSession,
|
|
16015
|
+
receiveEpoch: this._peerSessions.receiveEpoch(receiveFromHash),
|
|
16016
|
+
senderTransportSession: capabilityTransportSession,
|
|
16017
|
+
})) {
|
|
16018
|
+
// Rotate the receiver grant/challenge before requesting Full. A
|
|
16019
|
+
// sender rebuilt from no state starts at sequence one, which an
|
|
16020
|
+
// active receiver's old sequence fence must otherwise reject.
|
|
16021
|
+
this._v2Receive.advanceRecovery({
|
|
16022
|
+
peerHash: receiveFromHash,
|
|
16023
|
+
peerSession: receiveSession,
|
|
16024
|
+
receiveEpoch: this._peerSessions.receiveEpoch(receiveFromHash),
|
|
16025
|
+
});
|
|
16026
|
+
}
|
|
15994
16027
|
}
|
|
15995
16028
|
else if (observed && receiveSession === null) {
|
|
15996
16029
|
// A capability can arrive before the sender's topic Subscribe after
|
|
@@ -16855,8 +16888,8 @@ let SharedLog = (() => {
|
|
|
16855
16888
|
}
|
|
16856
16889
|
throwIfInactive();
|
|
16857
16890
|
}
|
|
16858
|
-
nudgePersistedReceiptPeerReadiness(publicKey) {
|
|
16859
|
-
if (this.closed)
|
|
16891
|
+
nudgePersistedReceiptPeerReadiness(publicKey, signal) {
|
|
16892
|
+
if (this.closed || signal.aborted)
|
|
16860
16893
|
return;
|
|
16861
16894
|
const peerHash = publicKey.hashcode();
|
|
16862
16895
|
const peerSession = this._peerSessions.current(peerHash);
|
|
@@ -16886,6 +16919,20 @@ let SharedLog = (() => {
|
|
|
16886
16919
|
peerSession,
|
|
16887
16920
|
receiveEpoch,
|
|
16888
16921
|
});
|
|
16922
|
+
const receiptTarget = this.persistedReceiptPeerSession(peerHash);
|
|
16923
|
+
if (receiptTarget &&
|
|
16924
|
+
!this._v2Send.hasCurrentStateForPeer({
|
|
16925
|
+
peerHash,
|
|
16926
|
+
peerSession: receiptTarget.peerSession,
|
|
16927
|
+
receiverTransportSession: receiptTarget.capabilitySession,
|
|
16928
|
+
})) {
|
|
16929
|
+
this._v2Receive.reAdvertiseLocalCapabilityForRemoteFull({
|
|
16930
|
+
peerHash,
|
|
16931
|
+
peerSession: receiptTarget.peerSession,
|
|
16932
|
+
receiveEpoch: receiptTarget.receiveEpoch,
|
|
16933
|
+
signal,
|
|
16934
|
+
});
|
|
16935
|
+
}
|
|
16889
16936
|
this.scheduleReplicationInfoV2Recovery(publicKey);
|
|
16890
16937
|
}
|
|
16891
16938
|
/**
|
|
@@ -17079,17 +17126,25 @@ let SharedLog = (() => {
|
|
|
17079
17126
|
throw new AbortError("Persisted-receipt readiness wait settled");
|
|
17080
17127
|
}
|
|
17081
17128
|
};
|
|
17129
|
+
const recoveryDelayMs = Math.max(50, Math.min(1_000, this.waitForReplicatorRequestIntervalMs));
|
|
17082
17130
|
const armRecoveryTick = () => {
|
|
17083
17131
|
if (settled || recoveryTimer)
|
|
17084
17132
|
return;
|
|
17085
|
-
const delayMs = Math.max(50, Math.min(1_000, this.waitForReplicatorRequestIntervalMs));
|
|
17086
17133
|
recoveryTimer = setTimeout(() => {
|
|
17087
17134
|
recoveryTimer = undefined;
|
|
17088
17135
|
if (!continueWait())
|
|
17089
17136
|
return;
|
|
17090
|
-
this.nudgePersistedReceiptPeerReadiness(key);
|
|
17137
|
+
this.nudgePersistedReceiptPeerReadiness(key, operationSignal);
|
|
17138
|
+
if (checkInFlight) {
|
|
17139
|
+
// Confirmation can legitimately span several recovery intervals.
|
|
17140
|
+
// Keep repairing the exact current generation without aborting its
|
|
17141
|
+
// one application-confirmation waiter on every tick.
|
|
17142
|
+
rerun = true;
|
|
17143
|
+
armRecoveryTick();
|
|
17144
|
+
return;
|
|
17145
|
+
}
|
|
17091
17146
|
scheduleCheck();
|
|
17092
|
-
},
|
|
17147
|
+
}, recoveryDelayMs);
|
|
17093
17148
|
recoveryTimer.unref?.();
|
|
17094
17149
|
};
|
|
17095
17150
|
const runCheck = async () => {
|
|
@@ -17119,6 +17174,11 @@ let SharedLog = (() => {
|
|
|
17119
17174
|
snapshot.reason === "replication-confirmation-pending") {
|
|
17120
17175
|
const target = this.persistedReceiptPeerSession(peerHash);
|
|
17121
17176
|
if (target) {
|
|
17177
|
+
// A confirmation waiter cannot create an outbound V2 stream when
|
|
17178
|
+
// that exact session state is missing. Nudge first, then keep the
|
|
17179
|
+
// recovery tick alive while the single confirmation wait remains.
|
|
17180
|
+
this.nudgePersistedReceiptPeerReadiness(key, operationSignal);
|
|
17181
|
+
armRecoveryTick();
|
|
17122
17182
|
const currentConfirmationController = new AbortController();
|
|
17123
17183
|
confirmationController = currentConfirmationController;
|
|
17124
17184
|
try {
|
|
@@ -17163,7 +17223,7 @@ let SharedLog = (() => {
|
|
|
17163
17223
|
}
|
|
17164
17224
|
if (!continueWait())
|
|
17165
17225
|
return;
|
|
17166
|
-
this.nudgePersistedReceiptPeerReadiness(key);
|
|
17226
|
+
this.nudgePersistedReceiptPeerReadiness(key, operationSignal);
|
|
17167
17227
|
}
|
|
17168
17228
|
catch (error) {
|
|
17169
17229
|
if (!settled)
|