@peerbit/shared-log 13.1.18 → 13.2.0
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/benchmark/index.js +91 -29
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/native-graph.js +120 -10
- package/dist/benchmark/native-graph.js.map +1 -1
- package/dist/benchmark/network-preset-e2e.d.ts +2 -0
- package/dist/benchmark/network-preset-e2e.d.ts.map +1 -0
- package/dist/benchmark/network-preset-e2e.js +497 -0
- package/dist/benchmark/network-preset-e2e.js.map +1 -0
- package/dist/benchmark/receive-prune.d.ts +2 -0
- package/dist/benchmark/receive-prune.d.ts.map +1 -0
- package/dist/benchmark/receive-prune.js +816 -0
- package/dist/benchmark/receive-prune.js.map +1 -0
- package/dist/benchmark/sync-catchup.d.ts +1 -2
- package/dist/benchmark/sync-catchup.d.ts.map +1 -1
- package/dist/benchmark/sync-catchup.js +175 -7
- package/dist/benchmark/sync-catchup.js.map +1 -1
- package/dist/src/checked-prune.d.ts +3 -0
- package/dist/src/checked-prune.d.ts.map +1 -1
- package/dist/src/checked-prune.js +24 -0
- package/dist/src/checked-prune.js.map +1 -1
- package/dist/src/exchange-heads.d.ts +238 -1
- package/dist/src/exchange-heads.d.ts.map +1 -1
- package/dist/src/exchange-heads.js +1512 -36
- package/dist/src/exchange-heads.js.map +1 -1
- package/dist/src/index.d.ts +276 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7358 -666
- package/dist/src/index.js.map +1 -1
- package/dist/src/pid.d.ts.map +1 -1
- package/dist/src/pid.js +25 -9
- package/dist/src/pid.js.map +1 -1
- package/dist/src/ranges.d.ts +11 -2
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +74 -30
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/sync/index.d.ts +77 -2
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.d.ts +11 -5
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +123 -60
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/dist/src/sync/simple.d.ts +56 -4
- package/dist/src/sync/simple.d.ts.map +1 -1
- package/dist/src/sync/simple.js +495 -63
- package/dist/src/sync/simple.js.map +1 -1
- package/dist/src/utils.d.ts +2 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +49 -2
- package/dist/src/utils.js.map +1 -1
- package/package.json +27 -17
- package/src/checked-prune.ts +27 -0
- package/src/exchange-heads.ts +2018 -41
- package/src/index.ts +13114 -3167
- package/src/pid.ts +24 -13
- package/src/ranges.ts +90 -40
- package/src/sync/index.ts +115 -2
- package/src/sync/rateless-iblt.ts +154 -75
- package/src/sync/simple.ts +590 -95
- package/src/utils.ts +73 -3
package/src/pid.ts
CHANGED
|
@@ -56,22 +56,32 @@ export class PIDReplicationController {
|
|
|
56
56
|
// prunes from repeatedly settling just above the hard budget.
|
|
57
57
|
const effectiveMemoryLimit =
|
|
58
58
|
this.maxMemoryLimit > 0 ? this.maxMemoryLimit * 0.95 : 0;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
if (effectiveMemoryLimit <= 0) {
|
|
60
|
+
// A zero storage budget can never hold data; drive the factor to zero
|
|
61
|
+
// instead of leaving the memory term neutral.
|
|
62
|
+
errorMemory = -currentFactor;
|
|
63
|
+
} else if (currentFactor > 0 && memoryUsage > 0) {
|
|
64
|
+
errorMemory =
|
|
65
|
+
Math.max(Math.min(1, effectiveMemoryLimit / estimatedTotalSize), 0) -
|
|
66
|
+
currentFactor;
|
|
67
|
+
} else {
|
|
68
|
+
errorMemory = 0;
|
|
69
|
+
}
|
|
66
70
|
// Math.max(Math.min((this.maxMemoryLimit - memoryUsage) / 100e5, 1), -1)// Math.min(Math.max((this.maxMemoryLimit - memoryUsage, 0) / 10e5, 0), 1);
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
const errorCoverageUnmodified = Math.min(1 - totalFactor, 1);
|
|
70
74
|
let errorCoverage =
|
|
71
|
-
(this.maxMemoryLimit
|
|
75
|
+
(this.maxMemoryLimit != null
|
|
76
|
+
? this.maxMemoryLimit > 0
|
|
77
|
+
? 1 - Math.sqrt(Math.abs(errorMemory))
|
|
78
|
+
: 0
|
|
79
|
+
: 1) *
|
|
72
80
|
errorCoverageUnmodified;
|
|
73
81
|
|
|
74
82
|
const errorFromEven = 1 / peerCount - currentFactor;
|
|
83
|
+
const hasMemoryHeadroom =
|
|
84
|
+
this.maxMemoryLimit != null && this.maxMemoryLimit > 0 && errorMemory > 0;
|
|
75
85
|
// When the network is under-covered (`totalFactor < 1`) balancing "down" (negative
|
|
76
86
|
// error) can further reduce coverage and force constrained peers (memory/CPU limited)
|
|
77
87
|
// to take boundary assignments that exceed their budgets.
|
|
@@ -81,11 +91,12 @@ export class PIDReplicationController {
|
|
|
81
91
|
const coverageDeficit = Math.max(0, errorCoverageUnmodified); // ~= max(0, 1 - totalFactor)
|
|
82
92
|
const negativeBalanceScale =
|
|
83
93
|
coverageDeficit <= 0 ? 1 : 1 - Math.min(1, coverageDeficit / 0.1); // full clamp at 10% deficit
|
|
84
|
-
|
|
94
|
+
let errorFromEvenForBalance =
|
|
85
95
|
errorFromEven >= 0 ? errorFromEven : errorFromEven * negativeBalanceScale;
|
|
96
|
+
if (hasMemoryHeadroom && coverageDeficit > 0 && errorFromEvenForBalance < 0) {
|
|
97
|
+
errorFromEvenForBalance = 0;
|
|
98
|
+
}
|
|
86
99
|
|
|
87
|
-
const hasMemoryHeadroom =
|
|
88
|
-
this.maxMemoryLimit != null && this.maxMemoryLimit > 0 && errorMemory > 0;
|
|
89
100
|
if (hasMemoryHeadroom && errorFromEvenForBalance > 0) {
|
|
90
101
|
// Coverage surplus often means another peer has not pruned yet. Do not let
|
|
91
102
|
// that transient surplus cancel a constrained peer that is still below an
|
|
@@ -93,7 +104,7 @@ export class PIDReplicationController {
|
|
|
93
104
|
errorCoverage = Math.max(errorCoverage, 0);
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
const balanceErrorScaler = this.maxMemoryLimit
|
|
107
|
+
const balanceErrorScaler = this.maxMemoryLimit != null
|
|
97
108
|
? hasMemoryHeadroom
|
|
98
109
|
? Math.max(
|
|
99
110
|
Math.abs(errorMemory),
|
|
@@ -105,7 +116,7 @@ export class PIDReplicationController {
|
|
|
105
116
|
// Balance should be symmetric (allow negative error) so a peer can *reduce*
|
|
106
117
|
// participation when peerCount increases. Otherwise early joiners can get
|
|
107
118
|
// "stuck" over-replicating even after new peers join (no memory/CPU limits).
|
|
108
|
-
const errorBalance = this.maxMemoryLimit
|
|
119
|
+
const errorBalance = this.maxMemoryLimit != null
|
|
109
120
|
? // Only balance when we have spare memory headroom. When memory is
|
|
110
121
|
// constrained (`errorMemory < 0`) the memory term will dominate anyway.
|
|
111
122
|
errorMemory > 0
|
package/src/ranges.ts
CHANGED
|
@@ -96,6 +96,7 @@ export interface EntryReplicated<R extends "u32" | "u64"> {
|
|
|
96
96
|
wallTime: bigint;
|
|
97
97
|
assignedToRangeBoundary: boolean;
|
|
98
98
|
get meta(): ShallowMeta;
|
|
99
|
+
getMetaBytes(): Uint8Array;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
export const isEntryReplicated = (x: any): x is EntryReplicated<any> => {
|
|
@@ -130,22 +131,33 @@ export class EntryReplicatedU32 implements EntryReplicated<"u32"> {
|
|
|
130
131
|
constructor(properties: {
|
|
131
132
|
coordinates: number[];
|
|
132
133
|
hash: string;
|
|
133
|
-
meta
|
|
134
|
+
meta?: Meta | ShallowMeta;
|
|
135
|
+
metaBytes?: Uint8Array;
|
|
136
|
+
gid?: string;
|
|
137
|
+
wallTime?: bigint;
|
|
134
138
|
assignedToRangeBoundary: boolean;
|
|
135
139
|
hashNumber: number;
|
|
136
140
|
}) {
|
|
141
|
+
if (!properties.meta && !properties.metaBytes) {
|
|
142
|
+
throw new Error("Expected meta or metaBytes");
|
|
143
|
+
}
|
|
144
|
+
if (!properties.meta && (properties.gid == null || properties.wallTime == null)) {
|
|
145
|
+
throw new Error("Expected gid and wallTime with metaBytes");
|
|
146
|
+
}
|
|
137
147
|
this.coordinates = properties.coordinates;
|
|
138
148
|
this.hash = properties.hash;
|
|
139
|
-
this.gid = properties.meta.gid
|
|
140
|
-
this.wallTime =
|
|
149
|
+
this.gid = properties.meta?.gid ?? properties.gid!;
|
|
150
|
+
this.wallTime =
|
|
151
|
+
properties.meta?.clock.timestamp.wallTime ?? properties.wallTime!;
|
|
141
152
|
this.hashNumber = properties.hashNumber;
|
|
142
|
-
|
|
143
|
-
properties.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
153
|
+
this._meta =
|
|
154
|
+
properties.metaBytes ??
|
|
155
|
+
serialize(
|
|
156
|
+
properties.meta instanceof Meta
|
|
157
|
+
? new ShallowMeta(properties.meta)
|
|
158
|
+
: properties.meta!,
|
|
159
|
+
);
|
|
160
|
+
this._metaResolved = properties.meta as ShallowMeta;
|
|
149
161
|
this.assignedToRangeBoundary = properties.assignedToRangeBoundary;
|
|
150
162
|
}
|
|
151
163
|
|
|
@@ -155,6 +167,10 @@ export class EntryReplicatedU32 implements EntryReplicated<"u32"> {
|
|
|
155
167
|
}
|
|
156
168
|
return this._metaResolved;
|
|
157
169
|
}
|
|
170
|
+
|
|
171
|
+
getMetaBytes(): Uint8Array {
|
|
172
|
+
return this._meta;
|
|
173
|
+
}
|
|
158
174
|
}
|
|
159
175
|
|
|
160
176
|
@variant("entry-u64")
|
|
@@ -185,22 +201,33 @@ export class EntryReplicatedU64 implements EntryReplicated<"u64"> {
|
|
|
185
201
|
constructor(properties: {
|
|
186
202
|
coordinates: bigint[];
|
|
187
203
|
hash: string;
|
|
188
|
-
meta
|
|
204
|
+
meta?: Meta | ShallowMeta;
|
|
205
|
+
metaBytes?: Uint8Array;
|
|
206
|
+
gid?: string;
|
|
207
|
+
wallTime?: bigint;
|
|
189
208
|
assignedToRangeBoundary: boolean;
|
|
190
209
|
hashNumber: bigint;
|
|
191
210
|
}) {
|
|
211
|
+
if (!properties.meta && !properties.metaBytes) {
|
|
212
|
+
throw new Error("Expected meta or metaBytes");
|
|
213
|
+
}
|
|
214
|
+
if (!properties.meta && (properties.gid == null || properties.wallTime == null)) {
|
|
215
|
+
throw new Error("Expected gid and wallTime with metaBytes");
|
|
216
|
+
}
|
|
192
217
|
this.coordinates = properties.coordinates;
|
|
193
218
|
this.hash = properties.hash;
|
|
194
219
|
this.hashNumber = properties.hashNumber;
|
|
195
|
-
this.gid = properties.meta.gid
|
|
196
|
-
this.wallTime =
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
220
|
+
this.gid = properties.meta?.gid ?? properties.gid!;
|
|
221
|
+
this.wallTime =
|
|
222
|
+
properties.meta?.clock.timestamp.wallTime ?? properties.wallTime!;
|
|
223
|
+
this._meta =
|
|
224
|
+
properties.metaBytes ??
|
|
225
|
+
serialize(
|
|
226
|
+
properties.meta instanceof Meta
|
|
227
|
+
? new ShallowMeta(properties.meta)
|
|
228
|
+
: properties.meta!,
|
|
229
|
+
);
|
|
230
|
+
this._metaResolved = properties.meta as ShallowMeta;
|
|
204
231
|
this.assignedToRangeBoundary = properties.assignedToRangeBoundary;
|
|
205
232
|
}
|
|
206
233
|
|
|
@@ -210,6 +237,10 @@ export class EntryReplicatedU64 implements EntryReplicated<"u64"> {
|
|
|
210
237
|
}
|
|
211
238
|
return this._metaResolved;
|
|
212
239
|
}
|
|
240
|
+
|
|
241
|
+
getMetaBytes(): Uint8Array {
|
|
242
|
+
return this._meta;
|
|
243
|
+
}
|
|
213
244
|
}
|
|
214
245
|
|
|
215
246
|
export const isReplicationRangeMessage = (
|
|
@@ -1310,6 +1341,11 @@ const allRangesContainingPoint = async <
|
|
|
1310
1341
|
},
|
|
1311
1342
|
options,
|
|
1312
1343
|
);
|
|
1344
|
+
try {
|
|
1345
|
+
(await firstIterator.all()).forEach((x) => allResults.push(x));
|
|
1346
|
+
} finally {
|
|
1347
|
+
await firstIterator.close();
|
|
1348
|
+
}
|
|
1313
1349
|
|
|
1314
1350
|
const secondIterator = rects.iterate(
|
|
1315
1351
|
{
|
|
@@ -1318,10 +1354,11 @@ const allRangesContainingPoint = async <
|
|
|
1318
1354
|
},
|
|
1319
1355
|
options,
|
|
1320
1356
|
);
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1357
|
+
try {
|
|
1358
|
+
(await secondIterator.all()).forEach((x) => allResults.push(x));
|
|
1359
|
+
} finally {
|
|
1360
|
+
await secondIterator.close();
|
|
1361
|
+
}
|
|
1325
1362
|
}
|
|
1326
1363
|
return allResults;
|
|
1327
1364
|
/* return [...await iterateRangesContainingPoint(rects, points, options).all()]; */
|
|
@@ -2040,15 +2077,19 @@ const collectClosestAround = async <R extends "u32" | "u64">(
|
|
|
2040
2077
|
);
|
|
2041
2078
|
|
|
2042
2079
|
let visited = new Set<string>();
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2080
|
+
try {
|
|
2081
|
+
while (aroundIterator.done() !== true && done() !== true) {
|
|
2082
|
+
const res = await aroundIterator.next(100);
|
|
2083
|
+
for (const rect of res) {
|
|
2084
|
+
visited.add(rect.value.idString);
|
|
2085
|
+
collector(rect.value, isMatured(rect.value, now, roleAge));
|
|
2086
|
+
if (done()) {
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2050
2089
|
}
|
|
2051
2090
|
}
|
|
2091
|
+
} finally {
|
|
2092
|
+
await aroundIterator.close();
|
|
2052
2093
|
}
|
|
2053
2094
|
};
|
|
2054
2095
|
|
|
@@ -2709,6 +2750,8 @@ export const mergeReplicationChanges = <R extends NumericType>(
|
|
|
2709
2750
|
return all;
|
|
2710
2751
|
};
|
|
2711
2752
|
|
|
2753
|
+
const REBALANCE_ITERATOR_BATCH_SIZE = 1048;
|
|
2754
|
+
|
|
2712
2755
|
export const toRebalance = <R extends "u32" | "u64">(
|
|
2713
2756
|
changeOrChanges:
|
|
2714
2757
|
| ReplicationChanges<ReplicationRangeIndexable<R>>
|
|
@@ -2718,22 +2761,29 @@ export const toRebalance = <R extends "u32" | "u64">(
|
|
|
2718
2761
|
options?: { forceFresh?: boolean },
|
|
2719
2762
|
): AsyncIterable<EntryReplicated<R>> => {
|
|
2720
2763
|
const change = options?.forceFresh
|
|
2721
|
-
?
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2764
|
+
? Array.isArray(changeOrChanges[0])
|
|
2765
|
+
? (
|
|
2766
|
+
changeOrChanges as ReplicationChanges<ReplicationRangeIndexable<R>>[]
|
|
2767
|
+
).flat()
|
|
2768
|
+
: (changeOrChanges as ReplicationChanges<ReplicationRangeIndexable<R>>)
|
|
2725
2769
|
: mergeReplicationChanges(changeOrChanges, rebalanceHistory);
|
|
2726
2770
|
return {
|
|
2727
2771
|
[Symbol.asyncIterator]: async function* () {
|
|
2728
2772
|
const iterator = index.iterate({
|
|
2729
2773
|
query: createAssignedRangesQuery(change),
|
|
2730
2774
|
});
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2775
|
+
try {
|
|
2776
|
+
while (iterator.done() !== true) {
|
|
2777
|
+
const entries = await iterator.next(REBALANCE_ITERATOR_BATCH_SIZE);
|
|
2778
|
+
if (entries.length === 0) {
|
|
2779
|
+
break;
|
|
2780
|
+
}
|
|
2781
|
+
for (const entry of entries) {
|
|
2782
|
+
yield entry.value;
|
|
2783
|
+
}
|
|
2736
2784
|
}
|
|
2785
|
+
} finally {
|
|
2786
|
+
await iterator.close();
|
|
2737
2787
|
}
|
|
2738
2788
|
},
|
|
2739
2789
|
};
|
package/src/sync/index.ts
CHANGED
|
@@ -15,6 +15,11 @@ export type SyncPriorityFn<R extends "u32" | "u64"> = (
|
|
|
15
15
|
entry: EntryReplicated<R>,
|
|
16
16
|
) => number;
|
|
17
17
|
|
|
18
|
+
export type SyncEntryCoordinates<R extends "u32" | "u64"> = Pick<
|
|
19
|
+
EntryReplicated<R>,
|
|
20
|
+
"assignedToRangeBoundary" | "hash" | "hashNumber"
|
|
21
|
+
>;
|
|
22
|
+
|
|
18
23
|
export type SyncOptions<R extends "u32" | "u64"> = {
|
|
19
24
|
/**
|
|
20
25
|
* Orders entries inside a sync batch; higher numbers are selected first.
|
|
@@ -39,6 +44,22 @@ export type SyncOptions<R extends "u32" | "u64"> = {
|
|
|
39
44
|
*/
|
|
40
45
|
maxSimpleCoordinatesPerMessage?: number;
|
|
41
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Experimental sync path for peers known to support raw exchange-head
|
|
49
|
+
* responses. When enabled, simple sync requests advertise raw-head support
|
|
50
|
+
* and capable responders can avoid full Entry materialization before sending.
|
|
51
|
+
*/
|
|
52
|
+
rawExchangeHeads?: boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Experimental receive-side raw-head parsing mode for native backbone. When
|
|
56
|
+
* enabled, signature verification happens while raw entries are decoded
|
|
57
|
+
* instead of during the later native commit step. When unset, shared-log may
|
|
58
|
+
* enable this automatically for retained native receive paths where planning
|
|
59
|
+
* already indicates that the local peer is replicating.
|
|
60
|
+
*/
|
|
61
|
+
rawExchangeHeadsVerifySignaturesDuringPrepare?: boolean;
|
|
62
|
+
|
|
42
63
|
/**
|
|
43
64
|
* Maximum number of hashes tracked per convergent repair session target.
|
|
44
65
|
* Large sessions still dispatch all entries, but only this many are tracked
|
|
@@ -53,6 +74,15 @@ export type SyncOptions<R extends "u32" | "u64"> = {
|
|
|
53
74
|
*/
|
|
54
75
|
repairSweepTargetBufferSize?: number;
|
|
55
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Native wire receive fusion (requires nativeBackbone). Shared-log
|
|
79
|
+
* registers its RPC topic with this session so raw exchange-head payloads
|
|
80
|
+
* recognized by the native wire decoder stay in wasm memory: the TS borsh
|
|
81
|
+
* decode of the entries and the JS-to-wasm copy of their block bytes are
|
|
82
|
+
* skipped. Messages without a stash entry fall back to the regular path.
|
|
83
|
+
*/
|
|
84
|
+
nativeWireSync?: SharedLogNativeWireSync;
|
|
85
|
+
|
|
56
86
|
/**
|
|
57
87
|
* Optional profiling callback. It is only invoked when provided, and should
|
|
58
88
|
* avoid blocking because it runs inside sync hot paths.
|
|
@@ -60,6 +90,72 @@ export type SyncOptions<R extends "u32" | "u64"> = {
|
|
|
60
90
|
profile?: SyncProfileFn;
|
|
61
91
|
};
|
|
62
92
|
|
|
93
|
+
/**
|
|
94
|
+
* The per-node native wire-sync session surface shared-log consumes
|
|
95
|
+
* (implemented by `NativeBackboneWireSyncSession` in `@peerbit/native-backbone`;
|
|
96
|
+
* the same object also implements the `nativeWire` option of
|
|
97
|
+
* `@peerbit/stream`'s DirectStream).
|
|
98
|
+
*/
|
|
99
|
+
export type SharedLogNativeWireSync = {
|
|
100
|
+
/** Raw wasm session handle consumed by `prepareStashedRawReceive*`. */
|
|
101
|
+
handle: unknown;
|
|
102
|
+
registerTopic(topic: string): void;
|
|
103
|
+
unregisterTopic(topic: string): boolean;
|
|
104
|
+
stashedMeta(id: Uint8Array):
|
|
105
|
+
| {
|
|
106
|
+
hashes: string[];
|
|
107
|
+
gidRefrences: string[][];
|
|
108
|
+
byteLengths: Uint32Array;
|
|
109
|
+
reserved: Uint8Array;
|
|
110
|
+
payloadLength: number;
|
|
111
|
+
}
|
|
112
|
+
| undefined;
|
|
113
|
+
stashedBlocks(
|
|
114
|
+
id: Uint8Array,
|
|
115
|
+
indexes?: Uint32Array,
|
|
116
|
+
): Uint8Array[] | undefined;
|
|
117
|
+
release(id: Uint8Array): boolean;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Fused raw exchange-heads sender provided by the shared log when the native
|
|
122
|
+
* backbone can serialize the sync payload in wasm (block bytes never
|
|
123
|
+
* materialize in JS). Resolves to the number of messages sent, or `undefined`
|
|
124
|
+
* when the fused path is unavailable for these hashes — the caller then falls
|
|
125
|
+
* back to the TS message path.
|
|
126
|
+
*/
|
|
127
|
+
export type RawExchangeHeadsSender = (
|
|
128
|
+
hashes: string[],
|
|
129
|
+
to: string[],
|
|
130
|
+
options?: { priority?: number },
|
|
131
|
+
) => Promise<number | undefined>;
|
|
132
|
+
|
|
133
|
+
export type HashSymbolInput = readonly bigint[] | BigUint64Array;
|
|
134
|
+
|
|
135
|
+
export type HashSymbolResolver = (
|
|
136
|
+
symbols: HashSymbolInput,
|
|
137
|
+
) =>
|
|
138
|
+
| ReadonlyMap<bigint, Iterable<string>>
|
|
139
|
+
| undefined
|
|
140
|
+
| Promise<ReadonlyMap<bigint, Iterable<string>> | undefined>;
|
|
141
|
+
|
|
142
|
+
export type HashSymbolHashListResolver = (
|
|
143
|
+
symbols: HashSymbolInput,
|
|
144
|
+
) =>
|
|
145
|
+
| Iterable<string>
|
|
146
|
+
| undefined
|
|
147
|
+
| Promise<Iterable<string> | undefined>;
|
|
148
|
+
|
|
149
|
+
export type HashSymbolRangeResolver = (range: {
|
|
150
|
+
start1: bigint | number;
|
|
151
|
+
end1: bigint | number;
|
|
152
|
+
start2: bigint | number;
|
|
153
|
+
end2: bigint | number;
|
|
154
|
+
}) =>
|
|
155
|
+
| Iterable<bigint | number>
|
|
156
|
+
| undefined
|
|
157
|
+
| Promise<Iterable<bigint | number> | undefined>;
|
|
158
|
+
|
|
63
159
|
export type SynchronizerComponents<R extends "u32" | "u64"> = {
|
|
64
160
|
rpc: RPC<TransportMessage, TransportMessage>;
|
|
65
161
|
rangeIndex: Index<ReplicationRangeIndexable<R>, any>;
|
|
@@ -67,7 +163,16 @@ export type SynchronizerComponents<R extends "u32" | "u64"> = {
|
|
|
67
163
|
log: Log<any>;
|
|
68
164
|
coordinateToHash: Cache<string>;
|
|
69
165
|
numbers: Numbers<R>;
|
|
166
|
+
resolveHashesForSymbols?: HashSymbolResolver;
|
|
167
|
+
resolveHashListForSymbols?: HashSymbolHashListResolver;
|
|
168
|
+
resolveHashNumbersInRange?: HashSymbolRangeResolver;
|
|
70
169
|
sync?: SyncOptions<R>;
|
|
170
|
+
isEntryRecentlyKnownByPeer?: (
|
|
171
|
+
hash: string,
|
|
172
|
+
peer: string,
|
|
173
|
+
maxAgeMs: number,
|
|
174
|
+
) => boolean;
|
|
175
|
+
sendRawExchangeHeads?: RawExchangeHeadsSender;
|
|
71
176
|
};
|
|
72
177
|
export type SynchronizerConstructor<R extends "u32" | "u64"> = new (
|
|
73
178
|
properties: SynchronizerComponents<R>,
|
|
@@ -97,7 +202,7 @@ export type RepairSession = {
|
|
|
97
202
|
|
|
98
203
|
export interface Syncronizer<R extends "u32" | "u64"> {
|
|
99
204
|
startRepairSession(properties: {
|
|
100
|
-
entries: Map<string,
|
|
205
|
+
entries: Map<string, SyncEntryCoordinates<R>>;
|
|
101
206
|
targets: string[];
|
|
102
207
|
mode?: RepairSessionMode;
|
|
103
208
|
timeoutMs?: number;
|
|
@@ -105,7 +210,7 @@ export interface Syncronizer<R extends "u32" | "u64"> {
|
|
|
105
210
|
}): RepairSession;
|
|
106
211
|
|
|
107
212
|
onMaybeMissingEntries(properties: {
|
|
108
|
-
entries: Map<string,
|
|
213
|
+
entries: Map<string, SyncEntryCoordinates<R>>;
|
|
109
214
|
targets: string[];
|
|
110
215
|
}): Promise<void> | void;
|
|
111
216
|
|
|
@@ -119,7 +224,15 @@ export interface Syncronizer<R extends "u32" | "u64"> {
|
|
|
119
224
|
from: PublicSignKey;
|
|
120
225
|
}): Promise<void> | void;
|
|
121
226
|
|
|
227
|
+
onReceivedEntryHashes?(properties: {
|
|
228
|
+
hashes: string[];
|
|
229
|
+
from: PublicSignKey;
|
|
230
|
+
}): Promise<void> | void;
|
|
231
|
+
|
|
232
|
+
onEntryAddedHashes?(hashes: string[]): void;
|
|
233
|
+
onEntryAddedHash?(hash: string): void;
|
|
122
234
|
onEntryAdded(entry: Entry<any>): void;
|
|
235
|
+
onEntryRemovedHashes?(hashes: string[]): void;
|
|
123
236
|
onEntryRemoved(hash: string): void;
|
|
124
237
|
onPeerDisconnected(key: PublicSignKey | string): void;
|
|
125
238
|
|