@peerbit/shared-log 16.0.27 → 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 +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +78 -24
- package/dist/src/index.js.map +1 -1
- package/package.json +8 -8
- package/src/index.ts +81 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/shared-log",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.28",
|
|
4
4
|
"description": "Shared log",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -62,22 +62,22 @@
|
|
|
62
62
|
"pidusage": "^4.0.1",
|
|
63
63
|
"pino": "^9.4.0",
|
|
64
64
|
"uint8arrays": "^5.1.0",
|
|
65
|
+
"@peerbit/cache": "3.1.1",
|
|
65
66
|
"@peerbit/blocks": "4.3.0",
|
|
66
67
|
"@peerbit/blocks-interface": "2.2.0",
|
|
67
|
-
"@peerbit/cache": "3.1.1",
|
|
68
68
|
"@peerbit/crypto": "3.1.6",
|
|
69
|
-
"@peerbit/any-store": "2.2.17",
|
|
70
69
|
"@peerbit/diagnostics": "0.0.1",
|
|
71
70
|
"@peerbit/indexer-interface": "3.0.13",
|
|
71
|
+
"@peerbit/any-store": "2.2.17",
|
|
72
72
|
"@peerbit/indexer-sqlite3": "3.0.20",
|
|
73
73
|
"@peerbit/log": "6.2.32",
|
|
74
74
|
"@peerbit/logger": "2.0.2",
|
|
75
75
|
"@peerbit/program": "6.0.59",
|
|
76
76
|
"@peerbit/pubsub": "5.4.5",
|
|
77
|
-
"@peerbit/riblt": "1.2.0",
|
|
78
77
|
"@peerbit/pubsub-interface": "5.2.2",
|
|
79
|
-
"@peerbit/
|
|
78
|
+
"@peerbit/riblt": "1.2.0",
|
|
80
79
|
"@peerbit/time": "3.0.1",
|
|
80
|
+
"@peerbit/rpc": "6.1.27",
|
|
81
81
|
"@peerbit/stream-interface": "6.0.16"
|
|
82
82
|
},
|
|
83
83
|
"optionalDependencies": {
|
|
@@ -88,11 +88,11 @@
|
|
|
88
88
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
89
89
|
"@types/pidusage": "^2.0.5",
|
|
90
90
|
"uuid": "^11.1.1",
|
|
91
|
+
"@peerbit/indexer-simple": "1.2.17",
|
|
91
92
|
"@peerbit/any-store-rust": "0.1.7",
|
|
93
|
+
"peerbit": "5.4.0",
|
|
92
94
|
"@peerbit/indexer-rust": "1.0.14",
|
|
93
|
-
"@peerbit/
|
|
94
|
-
"@peerbit/test-utils": "3.1.39",
|
|
95
|
-
"peerbit": "5.4.0"
|
|
95
|
+
"@peerbit/test-utils": "3.1.39"
|
|
96
96
|
},
|
|
97
97
|
"repository": {
|
|
98
98
|
"type": "git",
|
package/src/index.ts
CHANGED
|
@@ -2723,6 +2723,10 @@ export class SharedLog<
|
|
|
2723
2723
|
// The epoch tokens are PeerSession objects (src/peer-session.ts); the map
|
|
2724
2724
|
// itself lives on the registry. Stage-2 of the fence refactor.
|
|
2725
2725
|
private _peerSessions!: PeerSessionRegistry;
|
|
2726
|
+
// An exact successor session gets at most one unchanged-Full repair. Weak
|
|
2727
|
+
// ownership keeps retired transport generations collectible without an
|
|
2728
|
+
// identity-keyed cleanup path.
|
|
2729
|
+
private _successorFullRepairSessions!: WeakSet<PeerSession>;
|
|
2726
2730
|
// A superseded removal may be the queue item that actually observed an active
|
|
2727
2731
|
// replicator. Carry that leave obligation to the transition that ultimately
|
|
2728
2732
|
// wins, while a winning reconnect clears it without emitting a stale leave.
|
|
@@ -4307,6 +4311,7 @@ export class SharedLog<
|
|
|
4307
4311
|
// replication-info blocked set (fence B5) alongside the session maps —
|
|
4308
4312
|
// the legacy inline `new Set()` that sat above moved there.
|
|
4309
4313
|
this._peerSessions = this.createPeerSessionRegistry();
|
|
4314
|
+
this._successorFullRepairSessions = new WeakSet();
|
|
4310
4315
|
this._pendingReplicatorLeaveByPeer = new Set();
|
|
4311
4316
|
this._activeReceiveHandlersByPeer = new Map();
|
|
4312
4317
|
this._receiveHandlerDrainByPeer = new Map();
|
|
@@ -17959,6 +17964,7 @@ export class SharedLog<
|
|
|
17959
17964
|
})) > 0;
|
|
17960
17965
|
|
|
17961
17966
|
this._gidPeersHistory = new Map();
|
|
17967
|
+
this._successorFullRepairSessions = new WeakSet();
|
|
17962
17968
|
this.resetGidPeerHistoryCleanupState();
|
|
17963
17969
|
const replicationChangeOwnershipLifecycleController =
|
|
17964
17970
|
this.captureReplicationOwnershipLifecycle();
|
|
@@ -20758,6 +20764,7 @@ export class SharedLog<
|
|
|
20758
20764
|
this._receiveHandlerDrainByPeer?.clear();
|
|
20759
20765
|
this._openingSyncCapabilitiesByPeer?.clear();
|
|
20760
20766
|
this._gidPeersHistory?.clear();
|
|
20767
|
+
this._successorFullRepairSessions = new WeakSet();
|
|
20761
20768
|
this._peerSyncCapabilities?.clear();
|
|
20762
20769
|
this._peerSyncCapabilitySessions?.clear();
|
|
20763
20770
|
this._peerSyncCapabilityTimestamps?.clear();
|
|
@@ -24026,6 +24033,10 @@ export class SharedLog<
|
|
|
24026
24033
|
) {
|
|
24027
24034
|
return;
|
|
24028
24035
|
}
|
|
24036
|
+
const isFirstSuccessorFull =
|
|
24037
|
+
msg instanceof FullReplicationInfoV2Message &&
|
|
24038
|
+
receiveSession.hasPredecessor &&
|
|
24039
|
+
!this._successorFullRepairSessions.has(receiveSession);
|
|
24029
24040
|
const admission = this._v2Receive.reserve(msg, {
|
|
24030
24041
|
from,
|
|
24031
24042
|
peerSession: receiveSession,
|
|
@@ -24059,6 +24070,8 @@ export class SharedLog<
|
|
|
24059
24070
|
const exactGate = () =>
|
|
24060
24071
|
hostGate() && this._v2Receive.isAdmissionCurrent(admission);
|
|
24061
24072
|
let durableCommitted = false;
|
|
24073
|
+
let committedSuccessorFull = false;
|
|
24074
|
+
let repairUnchangedSuccessorFull = false;
|
|
24062
24075
|
|
|
24063
24076
|
try {
|
|
24064
24077
|
if (
|
|
@@ -24102,6 +24115,12 @@ export class SharedLog<
|
|
|
24102
24115
|
) {
|
|
24103
24116
|
return;
|
|
24104
24117
|
}
|
|
24118
|
+
committedSuccessorFull =
|
|
24119
|
+
isFirstSuccessorFull &&
|
|
24120
|
+
msg instanceof FullReplicationInfoV2Message &&
|
|
24121
|
+
msg.segments.length > 0;
|
|
24122
|
+
repairUnchangedSuccessorFull =
|
|
24123
|
+
committedSuccessorFull && result.length === 0;
|
|
24105
24124
|
} else {
|
|
24106
24125
|
if (!exactGate()) {
|
|
24107
24126
|
return;
|
|
@@ -24175,6 +24194,30 @@ export class SharedLog<
|
|
|
24175
24194
|
if (!hostGate()) {
|
|
24176
24195
|
return;
|
|
24177
24196
|
}
|
|
24197
|
+
if (committedSuccessorFull) {
|
|
24198
|
+
if (!exactGate()) {
|
|
24199
|
+
return;
|
|
24200
|
+
}
|
|
24201
|
+
this._successorFullRepairSessions.add(receiveSession);
|
|
24202
|
+
if (repairUnchangedSuccessorFull) {
|
|
24203
|
+
// The unchanged range rows belong to the public-key principal, but
|
|
24204
|
+
// delivery evidence may belong to the superseded process. Reuse the
|
|
24205
|
+
// receipt-driven authoritative repair path and bypass only those stale
|
|
24206
|
+
// hints; do not synthesize public membership or range-change events.
|
|
24207
|
+
this._repairFrontierBypassKnownPeersByMode
|
|
24208
|
+
.get("join-authoritative")
|
|
24209
|
+
?.add(fromHash);
|
|
24210
|
+
const peers = new Set([fromHash]);
|
|
24211
|
+
this.scheduleRepairSweep(
|
|
24212
|
+
{ mode: "join-authoritative", peers },
|
|
24213
|
+
lane.ownershipLifecycleController,
|
|
24214
|
+
);
|
|
24215
|
+
this.scheduleJoinAuthoritativeRepair(
|
|
24216
|
+
peers,
|
|
24217
|
+
lane.ownershipLifecycleController,
|
|
24218
|
+
);
|
|
24219
|
+
}
|
|
24220
|
+
}
|
|
24178
24221
|
this._liveness.markReplicatorActivity(fromHash);
|
|
24179
24222
|
// A committed V2 announcement is applied progress: the peer answers,
|
|
24180
24223
|
// so recovery re-solicitation may restart from the base interval.
|
|
@@ -25141,6 +25184,11 @@ export class SharedLog<
|
|
|
25141
25184
|
timeout?: number;
|
|
25142
25185
|
},
|
|
25143
25186
|
) {
|
|
25187
|
+
if (this.closed) {
|
|
25188
|
+
throw new ClosedError();
|
|
25189
|
+
}
|
|
25190
|
+
const closeSignal = this._closeController.signal;
|
|
25191
|
+
if (closeSignal.aborted) throw new ClosedError();
|
|
25144
25192
|
if (options?.signal?.aborted) {
|
|
25145
25193
|
throw new AbortError();
|
|
25146
25194
|
}
|
|
@@ -25149,6 +25197,9 @@ export class SharedLog<
|
|
|
25149
25197
|
const resolvedRoleAge = options?.eager
|
|
25150
25198
|
? undefined
|
|
25151
25199
|
: (options?.roleAge ?? (await this.getDefaultMinRoleAge()));
|
|
25200
|
+
if (this.closed || closeSignal.aborted) {
|
|
25201
|
+
throw new ClosedError();
|
|
25202
|
+
}
|
|
25152
25203
|
if (options?.signal?.aborted) {
|
|
25153
25204
|
throw new AbortError();
|
|
25154
25205
|
}
|
|
@@ -25164,6 +25215,7 @@ export class SharedLog<
|
|
|
25164
25215
|
this.events.removeEventListener("replicator:mature", runCheck);
|
|
25165
25216
|
this.events.removeEventListener("replication:change", runCheck);
|
|
25166
25217
|
options?.signal?.removeEventListener("abort", onAbort);
|
|
25218
|
+
closeSignal.removeEventListener("abort", onClose);
|
|
25167
25219
|
if (timer != null) {
|
|
25168
25220
|
clearTimeout(timer);
|
|
25169
25221
|
timer = undefined;
|
|
@@ -25203,9 +25255,11 @@ export class SharedLog<
|
|
|
25203
25255
|
};
|
|
25204
25256
|
|
|
25205
25257
|
const onAbort = () => reject(new AbortError());
|
|
25258
|
+
const onClose = () => reject(new ClosedError());
|
|
25206
25259
|
if (options?.signal) {
|
|
25207
|
-
options.signal.addEventListener("abort", onAbort);
|
|
25260
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
25208
25261
|
}
|
|
25262
|
+
closeSignal.addEventListener("abort", onClose, { once: true });
|
|
25209
25263
|
|
|
25210
25264
|
timer = setTimeout(() => {
|
|
25211
25265
|
reject(
|
|
@@ -25248,31 +25302,32 @@ export class SharedLog<
|
|
|
25248
25302
|
return;
|
|
25249
25303
|
}
|
|
25250
25304
|
|
|
25251
|
-
if (requestAttempts
|
|
25252
|
-
|
|
25253
|
-
}
|
|
25254
|
-
|
|
25255
|
-
requestAttempts++;
|
|
25305
|
+
if (requestAttempts < maxRequestAttempts) {
|
|
25306
|
+
requestAttempts++;
|
|
25256
25307
|
|
|
25257
|
-
|
|
25258
|
-
|
|
25259
|
-
|
|
25260
|
-
|
|
25261
|
-
|
|
25262
|
-
|
|
25263
|
-
|
|
25264
|
-
|
|
25265
|
-
|
|
25266
|
-
|
|
25267
|
-
|
|
25268
|
-
|
|
25269
|
-
|
|
25270
|
-
|
|
25308
|
+
const peerHash = key.hashcode();
|
|
25309
|
+
const peerSession = this._peerSessions.current(peerHash);
|
|
25310
|
+
if (peerSession?.phase === "open") {
|
|
25311
|
+
this._v2Receive.ensureRequestProgress({
|
|
25312
|
+
peerHash,
|
|
25313
|
+
peerSession,
|
|
25314
|
+
receiveEpoch: this._peerSessions.receiveEpoch(peerHash),
|
|
25315
|
+
});
|
|
25316
|
+
} else if (peerSession === null || peerSession.phase === "departing") {
|
|
25317
|
+
// A peer can be known to routing before its SharedLog topic
|
|
25318
|
+
// subscription has been observed. Legacy requests used to bootstrap
|
|
25319
|
+
// that case directly; V2 needs an authoritative Subscribe snapshot
|
|
25320
|
+
// before it can create a fenced PeerSession and request a Full.
|
|
25321
|
+
requestSubscriberSnapshot();
|
|
25322
|
+
}
|
|
25271
25323
|
}
|
|
25272
25324
|
|
|
25273
|
-
|
|
25274
|
-
|
|
25275
|
-
|
|
25325
|
+
// Replication change events are wake hints, not replayable state. Keep
|
|
25326
|
+
// checking the authoritative index after the bounded network recovery
|
|
25327
|
+
// attempts are exhausted so a transiently empty transition read cannot
|
|
25328
|
+
// strand an otherwise-ready waiter until its outer timeout.
|
|
25329
|
+
runCheck();
|
|
25330
|
+
requestTimer = setTimeout(requestReplicationInfo, requestIntervalMs);
|
|
25276
25331
|
};
|
|
25277
25332
|
|
|
25278
25333
|
const check = async () => {
|
|
@@ -25324,8 +25379,9 @@ export class SharedLog<
|
|
|
25324
25379
|
// replay a maturity/change event that fires while that read is in flight.
|
|
25325
25380
|
this.events.addEventListener("replicator:mature", runCheck);
|
|
25326
25381
|
this.events.addEventListener("replication:change", runCheck);
|
|
25327
|
-
|
|
25328
|
-
|
|
25382
|
+
if (closeSignal.aborted) onClose();
|
|
25383
|
+
else if (options?.signal?.aborted) onAbort();
|
|
25384
|
+
else requestReplicationInfo();
|
|
25329
25385
|
|
|
25330
25386
|
return deferred.promise.finally(clear);
|
|
25331
25387
|
}
|