@peerbit/shared-log 16.0.31 → 16.0.33
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 +26 -0
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +4 -2
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/sync/dispatch-lifecycle.d.ts +5 -0
- package/dist/src/sync/dispatch-lifecycle.d.ts.map +1 -1
- package/dist/src/sync/dispatch-lifecycle.js +15 -0
- package/dist/src/sync/dispatch-lifecycle.js.map +1 -1
- package/dist/src/sync/index.d.ts +3 -1
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.d.ts +7 -1
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +132 -10
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/dist/src/sync/simple.d.ts +5 -2
- package/dist/src/sync/simple.d.ts.map +1 -1
- package/dist/src/sync/simple.js +165 -119
- package/dist/src/sync/simple.js.map +1 -1
- package/package.json +16 -16
- package/src/errors.ts +4 -2
- package/src/index.ts +27 -7
- package/src/sync/dispatch-lifecycle.ts +20 -0
- package/src/sync/index.ts +3 -0
- package/src/sync/rateless-iblt.ts +169 -8
- package/src/sync/simple.ts +235 -151
package/src/index.ts
CHANGED
|
@@ -297,6 +297,7 @@ import {
|
|
|
297
297
|
maxReplicas,
|
|
298
298
|
} from "./replication.js";
|
|
299
299
|
import { ReplicatorLivenessMonitor } from "./replicator-liveness.js";
|
|
300
|
+
import { SyncReceiveAbortError } from "./sync/dispatch-lifecycle.js";
|
|
300
301
|
import { createSyncronizer } from "./sync/factory.js";
|
|
301
302
|
import type {
|
|
302
303
|
SharedLogNativeWireSync,
|
|
@@ -417,6 +418,7 @@ type PendingIHave<T> = {
|
|
|
417
418
|
|
|
418
419
|
type PeerReceiveLeaseBucket = {
|
|
419
420
|
active: number;
|
|
421
|
+
controller: AbortController;
|
|
420
422
|
drain?: DeferredPromise<void>;
|
|
421
423
|
};
|
|
422
424
|
|
|
@@ -433,13 +435,15 @@ type PeerReceiveLeaseState = {
|
|
|
433
435
|
*/
|
|
434
436
|
type PeerReceiveLease = {
|
|
435
437
|
release: () => void;
|
|
438
|
+
signal: AbortSignal;
|
|
436
439
|
};
|
|
437
440
|
|
|
438
441
|
const createOneShotPeerReceiveLease = (
|
|
439
|
-
releaseFn: () => void,
|
|
442
|
+
releaseFn: (() => void) & { signal: AbortSignal },
|
|
440
443
|
): PeerReceiveLease => {
|
|
441
444
|
let released = false;
|
|
442
445
|
return {
|
|
446
|
+
signal: releaseFn.signal,
|
|
443
447
|
release: () => {
|
|
444
448
|
if (released) {
|
|
445
449
|
return;
|
|
@@ -6527,7 +6531,7 @@ export class SharedLog<
|
|
|
6527
6531
|
(leaders.size === 1 && leaders.has(selfHash)),
|
|
6528
6532
|
)
|
|
6529
6533
|
) {
|
|
6530
|
-
throw new NoPeersError(this.rpc.topic);
|
|
6534
|
+
throw new NoPeersError(this.rpc.topic, "persisted");
|
|
6531
6535
|
}
|
|
6532
6536
|
}
|
|
6533
6537
|
for (let index = 0; index < entryArray.length; index++) {
|
|
@@ -7837,7 +7841,7 @@ export class SharedLog<
|
|
|
7837
7841
|
allowReplicationInfoBlocked?: boolean;
|
|
7838
7842
|
allowCleanupGate?: boolean;
|
|
7839
7843
|
},
|
|
7840
|
-
): (() => void) | undefined {
|
|
7844
|
+
): ((() => void) & { signal: AbortSignal }) | undefined {
|
|
7841
7845
|
if (
|
|
7842
7846
|
!this._peerSessions.isReceiveAdmissionOpen(
|
|
7843
7847
|
peerHash,
|
|
@@ -7851,7 +7855,10 @@ export class SharedLog<
|
|
|
7851
7855
|
|
|
7852
7856
|
let state = this._activeReceiveHandlersByPeer.get(peerHash);
|
|
7853
7857
|
if (!state) {
|
|
7854
|
-
const current: PeerReceiveLeaseBucket = {
|
|
7858
|
+
const current: PeerReceiveLeaseBucket = {
|
|
7859
|
+
active: 0,
|
|
7860
|
+
controller: new AbortController(),
|
|
7861
|
+
};
|
|
7855
7862
|
state = { current, activeBuckets: new Set() };
|
|
7856
7863
|
this._activeReceiveHandlersByPeer.set(peerHash, state);
|
|
7857
7864
|
}
|
|
@@ -7859,7 +7866,7 @@ export class SharedLog<
|
|
|
7859
7866
|
bucket.active += 1;
|
|
7860
7867
|
state.activeBuckets.add(bucket);
|
|
7861
7868
|
let released = false;
|
|
7862
|
-
|
|
7869
|
+
const release = () => {
|
|
7863
7870
|
if (released) {
|
|
7864
7871
|
return;
|
|
7865
7872
|
}
|
|
@@ -7878,6 +7885,7 @@ export class SharedLog<
|
|
|
7878
7885
|
this._activeReceiveHandlersByPeer.delete(peerHash);
|
|
7879
7886
|
}
|
|
7880
7887
|
};
|
|
7888
|
+
return Object.assign(release, { signal: bucket.controller.signal });
|
|
7881
7889
|
}
|
|
7882
7890
|
|
|
7883
7891
|
private async drainPeerReceiveHandlers(peerHash: string): Promise<void> {
|
|
@@ -7890,7 +7898,7 @@ export class SharedLog<
|
|
|
7890
7898
|
// sync traffic without joining the drain for the previous subscription. Cleanup
|
|
7891
7899
|
// callers gate admission first; terminal callers also repeat until empty.
|
|
7892
7900
|
const buckets = [...state.activeBuckets];
|
|
7893
|
-
state.current = { active: 0 };
|
|
7901
|
+
state.current = { active: 0, controller: new AbortController() };
|
|
7894
7902
|
const drain = Promise.all(
|
|
7895
7903
|
buckets.map((bucket) => {
|
|
7896
7904
|
bucket.drain ??= pDefer<void>();
|
|
@@ -7903,6 +7911,14 @@ export class SharedLog<
|
|
|
7903
7911
|
this._receiveHandlerDrainByPeer.set(peerHash, drains);
|
|
7904
7912
|
}
|
|
7905
7913
|
drains.add(drain);
|
|
7914
|
+
// Cancel only work admitted into this snapshot, never a replacement's
|
|
7915
|
+
// current bucket. Aborting requests cooperation; the physical receive
|
|
7916
|
+
// leases below still own all cleanup until their actual finally settles.
|
|
7917
|
+
for (const bucket of buckets) {
|
|
7918
|
+
bucket.controller.abort(
|
|
7919
|
+
new SyncReceiveAbortError("peer receive generation draining"),
|
|
7920
|
+
);
|
|
7921
|
+
}
|
|
7906
7922
|
try {
|
|
7907
7923
|
await drain;
|
|
7908
7924
|
} finally {
|
|
@@ -23652,7 +23668,11 @@ export class SharedLog<
|
|
|
23652
23668
|
this._liveness.markReplicatorActivity(receiveFromHash);
|
|
23653
23669
|
}
|
|
23654
23670
|
return;
|
|
23655
|
-
} else if (
|
|
23671
|
+
} else if (
|
|
23672
|
+
await this.syncronizer.onMessage(msg, context, {
|
|
23673
|
+
signal: peerReceiveLease.signal,
|
|
23674
|
+
})
|
|
23675
|
+
) {
|
|
23656
23676
|
return; // the syncronizer has handled the message
|
|
23657
23677
|
} else if (msg instanceof BlocksMessage) {
|
|
23658
23678
|
await this.remoteBlocks.onMessage(msg.message, {
|
|
@@ -16,6 +16,26 @@
|
|
|
16
16
|
// caller-specific fields such as epochs, batches and retained-work
|
|
17
17
|
// counters); the registry owns the per-target active sets, the listener
|
|
18
18
|
// add/remove pairing and the dispose gating.
|
|
19
|
+
import { AbortError } from "@peerbit/time";
|
|
20
|
+
|
|
21
|
+
/** Local receive drain cancellation; never a transport or persistence failure. */
|
|
22
|
+
export class SyncReceiveAbortError extends AbortError {}
|
|
23
|
+
|
|
24
|
+
export const isSyncDispatchCancellation = (
|
|
25
|
+
error: unknown,
|
|
26
|
+
signal: AbortSignal | undefined,
|
|
27
|
+
inactive = signal?.aborted === true,
|
|
28
|
+
): boolean => {
|
|
29
|
+
if (!inactive) return false;
|
|
30
|
+
// Keep the existing owner/disconnect error policy. Only the new receive
|
|
31
|
+
// cancellation must distinguish unrelated failures that race its abort.
|
|
32
|
+
if (!(signal?.reason instanceof SyncReceiveAbortError)) return true;
|
|
33
|
+
return (
|
|
34
|
+
error === signal.reason ||
|
|
35
|
+
error instanceof AbortError ||
|
|
36
|
+
(error instanceof Error && error.name === "AbortError")
|
|
37
|
+
);
|
|
38
|
+
};
|
|
19
39
|
|
|
20
40
|
export interface DispatchTargetLifecycleBase<LC> {
|
|
21
41
|
lifecycle: LC;
|
package/src/sync/index.ts
CHANGED
|
@@ -231,6 +231,9 @@ export interface Syncronizer<R extends "u32" | "u64"> {
|
|
|
231
231
|
onMessage(
|
|
232
232
|
message: TransportMessage,
|
|
233
233
|
context: RequestContext,
|
|
234
|
+
// Exact admitted receive lifetime, not a peer-hash-wide disconnect.
|
|
235
|
+
// Implementations must still settle physical work before returning.
|
|
236
|
+
options?: { signal?: AbortSignal },
|
|
234
237
|
): Promise<boolean> | boolean;
|
|
235
238
|
|
|
236
239
|
onReceivedEntries(properties: {
|
|
@@ -27,7 +27,9 @@ import { TransportMessage } from "../message.js";
|
|
|
27
27
|
import { type EntryReplicated } from "../ranges.js";
|
|
28
28
|
import {
|
|
29
29
|
DispatchLifecycleRegistry,
|
|
30
|
+
SyncReceiveAbortError,
|
|
30
31
|
isOwnershipGenerationActive,
|
|
32
|
+
isSyncDispatchCancellation,
|
|
31
33
|
isTrackedSessionActive,
|
|
32
34
|
} from "./dispatch-lifecycle.js";
|
|
33
35
|
import type {
|
|
@@ -827,6 +829,7 @@ type OutgoingRatelessSyncProcess = {
|
|
|
827
829
|
lastSeqNo: bigint;
|
|
828
830
|
}) => { symbols: CodedSymbolBatch; exhaustedAfterSend: boolean } | undefined;
|
|
829
831
|
startSimpleFallback: () => Promise<void>;
|
|
832
|
+
cancelSimpleFallback: (reason: unknown) => void;
|
|
830
833
|
simpleFallbackStarted: boolean;
|
|
831
834
|
free: (reason?: unknown) => void;
|
|
832
835
|
processController: AbortController;
|
|
@@ -863,6 +866,7 @@ type IncomingRatelessSyncProcess = {
|
|
|
863
866
|
symbols: CodedSymbolInput;
|
|
864
867
|
}) => Promise<IncomingRatelessProcessResult>;
|
|
865
868
|
requestAll: () => Promise<void>;
|
|
869
|
+
drain: () => Promise<void>;
|
|
866
870
|
fallbackToSimple: (reason?: unknown) => Promise<void>;
|
|
867
871
|
free: (reason?: unknown) => void;
|
|
868
872
|
complete: () => void;
|
|
@@ -1571,6 +1575,35 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
1571
1575
|
);
|
|
1572
1576
|
}
|
|
1573
1577
|
|
|
1578
|
+
private async settleIncomingReceive(
|
|
1579
|
+
process: IncomingRatelessSyncProcess,
|
|
1580
|
+
signal: AbortSignal,
|
|
1581
|
+
): Promise<void> {
|
|
1582
|
+
const errors: unknown[] = [];
|
|
1583
|
+
try {
|
|
1584
|
+
await process.drain();
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
errors.push(error);
|
|
1587
|
+
}
|
|
1588
|
+
if (signal.aborted) {
|
|
1589
|
+
try {
|
|
1590
|
+
process.free(signal.reason);
|
|
1591
|
+
} catch (error) {
|
|
1592
|
+
errors.push(error);
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
if (errors.length === 1) throw errors[0];
|
|
1596
|
+
if (errors.length > 1) {
|
|
1597
|
+
throw new AggregateError(
|
|
1598
|
+
errors,
|
|
1599
|
+
"incoming receive drain and cleanup failed",
|
|
1600
|
+
{
|
|
1601
|
+
cause: errors[0],
|
|
1602
|
+
},
|
|
1603
|
+
);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1574
1607
|
async onMaybeMissingEntries(properties: {
|
|
1575
1608
|
entries: Map<string, SyncEntryCoordinates<D>>;
|
|
1576
1609
|
targets: string[];
|
|
@@ -2008,6 +2041,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2008
2041
|
let symbolsProduced = startSyncSymbols.length;
|
|
2009
2042
|
let symbolBudgetExhausted = false;
|
|
2010
2043
|
let simpleFallbackPromise: Promise<void> | undefined;
|
|
2044
|
+
const simpleFallbackController = new AbortController();
|
|
2011
2045
|
const symbolBudget = getOutgoingRatelessSymbolBudget(
|
|
2012
2046
|
properties.coordinates.length,
|
|
2013
2047
|
startSyncSymbols.length,
|
|
@@ -2055,7 +2089,14 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2055
2089
|
this.simple.onMaybeMissingHashes({
|
|
2056
2090
|
hashes: properties.outgoingHashes,
|
|
2057
2091
|
targets: [target],
|
|
2058
|
-
|
|
2092
|
+
// Encoder retirement must not cancel an admitted fallback.
|
|
2093
|
+
// A receive awaiting that exact memoized operation can do so.
|
|
2094
|
+
signal: lifecycle.callerSignal
|
|
2095
|
+
? AbortSignal.any([
|
|
2096
|
+
lifecycle.callerSignal,
|
|
2097
|
+
simpleFallbackController.signal,
|
|
2098
|
+
])
|
|
2099
|
+
: simpleFallbackController.signal,
|
|
2059
2100
|
}),
|
|
2060
2101
|
);
|
|
2061
2102
|
}
|
|
@@ -2150,6 +2191,8 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2150
2191
|
return { symbols, exhaustedAfterSend };
|
|
2151
2192
|
},
|
|
2152
2193
|
startSimpleFallback,
|
|
2194
|
+
cancelSimpleFallback: (reason) =>
|
|
2195
|
+
simpleFallbackController.abort(reason),
|
|
2153
2196
|
simpleFallbackStarted: false,
|
|
2154
2197
|
free: clear,
|
|
2155
2198
|
outgoingHashes: properties.outgoingHashes,
|
|
@@ -2386,7 +2429,74 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2386
2429
|
async onMessage(
|
|
2387
2430
|
message: TransportMessage,
|
|
2388
2431
|
context: RequestContext,
|
|
2432
|
+
options?: { signal?: AbortSignal },
|
|
2389
2433
|
): Promise<boolean> {
|
|
2434
|
+
const signal = options?.signal;
|
|
2435
|
+
if (!signal) {
|
|
2436
|
+
return this.onMessageForReceive(message, context);
|
|
2437
|
+
}
|
|
2438
|
+
let cancel: (() => void) | undefined;
|
|
2439
|
+
let settle: (() => Promise<void>) | undefined;
|
|
2440
|
+
const onAbort = () => cancel?.();
|
|
2441
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2442
|
+
const errors: unknown[] = [];
|
|
2443
|
+
let handled = false;
|
|
2444
|
+
try {
|
|
2445
|
+
handled = await this.onMessageForReceive(message, context, {
|
|
2446
|
+
signal,
|
|
2447
|
+
bind: (cancelWork, settleWork) => {
|
|
2448
|
+
cancel = cancelWork;
|
|
2449
|
+
settle = settleWork;
|
|
2450
|
+
if (signal.aborted) {
|
|
2451
|
+
onAbort();
|
|
2452
|
+
}
|
|
2453
|
+
},
|
|
2454
|
+
});
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
errors.push(error);
|
|
2457
|
+
} finally {
|
|
2458
|
+
// Keep cancellation connected while a bounded fallback's logical
|
|
2459
|
+
// completion still leaves its lower send physically draining.
|
|
2460
|
+
try {
|
|
2461
|
+
await settle?.();
|
|
2462
|
+
} catch (error) {
|
|
2463
|
+
if (!errors.includes(error)) {
|
|
2464
|
+
errors.push(error);
|
|
2465
|
+
}
|
|
2466
|
+
} finally {
|
|
2467
|
+
signal.removeEventListener("abort", onAbort);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
if (errors.length === 1) throw errors[0];
|
|
2471
|
+
if (errors.length > 1) {
|
|
2472
|
+
throw new AggregateError(
|
|
2473
|
+
errors,
|
|
2474
|
+
"sync receive and physical cleanup failed",
|
|
2475
|
+
{
|
|
2476
|
+
cause: errors[0],
|
|
2477
|
+
},
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
return handled;
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
private async onMessageForReceive(
|
|
2484
|
+
message: TransportMessage,
|
|
2485
|
+
context: RequestContext,
|
|
2486
|
+
options?: {
|
|
2487
|
+
signal: AbortSignal;
|
|
2488
|
+
bind: (cancel: () => void, settle?: () => Promise<void>) => void;
|
|
2489
|
+
},
|
|
2490
|
+
): Promise<boolean> {
|
|
2491
|
+
if (options?.signal.aborted) {
|
|
2492
|
+
return (
|
|
2493
|
+
message instanceof StartSync ||
|
|
2494
|
+
message instanceof MoreSymbols ||
|
|
2495
|
+
message instanceof RequestMoreSymbols ||
|
|
2496
|
+
message instanceof RequestAll ||
|
|
2497
|
+
(await this.simple.onMessage(message, context, options))
|
|
2498
|
+
);
|
|
2499
|
+
}
|
|
2390
2500
|
const profile = this.properties.sync?.profile;
|
|
2391
2501
|
if (message instanceof StartSync) {
|
|
2392
2502
|
const from = context.from;
|
|
@@ -2511,6 +2621,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2511
2621
|
symbolBudget: getIncomingRatelessSymbolBudget(message.symbols.length),
|
|
2512
2622
|
process: async () => undefined,
|
|
2513
2623
|
requestAll: async () => {},
|
|
2624
|
+
drain: async () => {},
|
|
2514
2625
|
fallbackToSimple: async () => {},
|
|
2515
2626
|
free,
|
|
2516
2627
|
complete,
|
|
@@ -2522,6 +2633,10 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2522
2633
|
onOwnershipAbort,
|
|
2523
2634
|
{ once: true },
|
|
2524
2635
|
);
|
|
2636
|
+
options?.bind(
|
|
2637
|
+
() => controller.abort(options.signal.reason),
|
|
2638
|
+
() => this.settleIncomingReceive(obj, options.signal),
|
|
2639
|
+
);
|
|
2525
2640
|
obj.deadlineTimeout = setTimeout(() => {
|
|
2526
2641
|
void obj.fallbackToSimple(
|
|
2527
2642
|
new Error("incoming rateless process deadline exceeded"),
|
|
@@ -2534,6 +2649,9 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2534
2649
|
}
|
|
2535
2650
|
|
|
2536
2651
|
let requestAllPromise: Promise<void> | undefined;
|
|
2652
|
+
obj.drain = async () => {
|
|
2653
|
+
await requestAllPromise;
|
|
2654
|
+
};
|
|
2537
2655
|
obj.requestAll = () => {
|
|
2538
2656
|
if (requestAllPromise) {
|
|
2539
2657
|
return requestAllPromise;
|
|
@@ -2566,6 +2684,12 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2566
2684
|
syncId,
|
|
2567
2685
|
});
|
|
2568
2686
|
}
|
|
2687
|
+
} catch (error) {
|
|
2688
|
+
// Classify before complete() aborts the process as normal cleanup;
|
|
2689
|
+
// that cleanup must not disguise a genuine lower-send failure.
|
|
2690
|
+
if (!isSyncDispatchCancellation(error, controller.signal)) {
|
|
2691
|
+
throw error;
|
|
2692
|
+
}
|
|
2569
2693
|
} finally {
|
|
2570
2694
|
fallbackSendPending = false;
|
|
2571
2695
|
if (this.isIncomingSyncProcessActive(obj)) {
|
|
@@ -2643,7 +2767,8 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2643
2767
|
const processAborted = controller.signal.aborted;
|
|
2644
2768
|
free(error);
|
|
2645
2769
|
if (
|
|
2646
|
-
processAborted
|
|
2770
|
+
(processAborted &&
|
|
2771
|
+
isSyncDispatchCancellation(error, controller.signal)) ||
|
|
2647
2772
|
!this.isIncomingSyncGenerationActive(ownershipLifecycleController)
|
|
2648
2773
|
) {
|
|
2649
2774
|
return true;
|
|
@@ -2924,7 +3049,13 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2924
3049
|
},
|
|
2925
3050
|
);
|
|
2926
3051
|
} catch (error) {
|
|
2927
|
-
if (
|
|
3052
|
+
if (
|
|
3053
|
+
isSyncDispatchCancellation(
|
|
3054
|
+
error,
|
|
3055
|
+
controller.signal,
|
|
3056
|
+
!this.isIncomingSyncProcessActive(obj),
|
|
3057
|
+
)
|
|
3058
|
+
) {
|
|
2928
3059
|
return true;
|
|
2929
3060
|
}
|
|
2930
3061
|
free(error);
|
|
@@ -2959,6 +3090,10 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
2959
3090
|
) {
|
|
2960
3091
|
return true;
|
|
2961
3092
|
}
|
|
3093
|
+
options?.bind(
|
|
3094
|
+
() => obj.controller.abort(options.signal.reason),
|
|
3095
|
+
() => this.settleIncomingReceive(obj, options.signal),
|
|
3096
|
+
);
|
|
2962
3097
|
let outProcess: IncomingRatelessProcessResult;
|
|
2963
3098
|
try {
|
|
2964
3099
|
outProcess = await obj.process(message);
|
|
@@ -3005,7 +3140,13 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3005
3140
|
signal: obj.controller.signal,
|
|
3006
3141
|
},
|
|
3007
3142
|
);
|
|
3008
|
-
} catch {
|
|
3143
|
+
} catch (error) {
|
|
3144
|
+
if (
|
|
3145
|
+
obj.controller.signal.reason instanceof SyncReceiveAbortError &&
|
|
3146
|
+
!isSyncDispatchCancellation(error, obj.controller.signal)
|
|
3147
|
+
) {
|
|
3148
|
+
throw error;
|
|
3149
|
+
}
|
|
3009
3150
|
if (profile) {
|
|
3010
3151
|
emitSyncProfileDuration(profile, sendStartedAt, {
|
|
3011
3152
|
name: "rateless.sendRequestMoreSymbols",
|
|
@@ -3039,6 +3180,14 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3039
3180
|
if (context.from?.hashcode() !== obj.target) {
|
|
3040
3181
|
return true;
|
|
3041
3182
|
}
|
|
3183
|
+
options?.bind(
|
|
3184
|
+
() => obj.processController.abort(options.signal.reason),
|
|
3185
|
+
async () => {
|
|
3186
|
+
if (options.signal.aborted) {
|
|
3187
|
+
obj.free(options.signal.reason);
|
|
3188
|
+
}
|
|
3189
|
+
},
|
|
3190
|
+
);
|
|
3042
3191
|
const signal = obj.signal;
|
|
3043
3192
|
if (signal.aborted) {
|
|
3044
3193
|
return true;
|
|
@@ -3066,7 +3215,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3066
3215
|
},
|
|
3067
3216
|
);
|
|
3068
3217
|
} catch (error) {
|
|
3069
|
-
if (signal
|
|
3218
|
+
if (isSyncDispatchCancellation(error, signal)) {
|
|
3070
3219
|
return true;
|
|
3071
3220
|
}
|
|
3072
3221
|
throw error;
|
|
@@ -3101,7 +3250,14 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3101
3250
|
}
|
|
3102
3251
|
// RequestAll ends only this target's rateless attempt. Other target
|
|
3103
3252
|
// encoders and response authorizations remain independently owned.
|
|
3104
|
-
|
|
3253
|
+
let fallback: Promise<void> | undefined;
|
|
3254
|
+
options?.bind(
|
|
3255
|
+
() => p.cancelSimpleFallback(options.signal.reason),
|
|
3256
|
+
async () => {
|
|
3257
|
+
await fallback;
|
|
3258
|
+
},
|
|
3259
|
+
);
|
|
3260
|
+
fallback = p.startSimpleFallback();
|
|
3105
3261
|
p.free();
|
|
3106
3262
|
await fallback;
|
|
3107
3263
|
return true;
|
|
@@ -3174,13 +3330,17 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3174
3330
|
entries: 0,
|
|
3175
3331
|
};
|
|
3176
3332
|
try {
|
|
3333
|
+
const signal = options?.signal
|
|
3334
|
+
? AbortSignal.any([response.signal, options.signal])
|
|
3335
|
+
: response.signal;
|
|
3177
3336
|
responseShipment =
|
|
3178
3337
|
await this.simple.shipAuthorizedMaybeSyncResponse({
|
|
3179
3338
|
hashes: response.authorized,
|
|
3180
3339
|
from,
|
|
3181
3340
|
response: message,
|
|
3182
|
-
signal
|
|
3341
|
+
signal,
|
|
3183
3342
|
});
|
|
3343
|
+
rollbackRatelessAuthorization = signal.aborted;
|
|
3184
3344
|
} catch (error) {
|
|
3185
3345
|
firstError = error;
|
|
3186
3346
|
rollbackRatelessAuthorization = true;
|
|
@@ -3209,6 +3369,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3209
3369
|
leases: simpleLeases,
|
|
3210
3370
|
from,
|
|
3211
3371
|
response: simpleMessage,
|
|
3372
|
+
signal: options?.signal,
|
|
3212
3373
|
});
|
|
3213
3374
|
} catch (error) {
|
|
3214
3375
|
firstError ??= error;
|
|
@@ -3229,7 +3390,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
3229
3390
|
}
|
|
3230
3391
|
}
|
|
3231
3392
|
}
|
|
3232
|
-
return this.simple.onMessage(message, context);
|
|
3393
|
+
return this.simple.onMessage(message, context, options);
|
|
3233
3394
|
}
|
|
3234
3395
|
|
|
3235
3396
|
onReceivedEntries(properties: {
|