@peerbit/shared-log 12.2.0-874976b → 12.2.0-90d77b6
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/pid-convergence.d.ts +2 -0
- package/dist/benchmark/pid-convergence.d.ts.map +1 -0
- package/dist/benchmark/pid-convergence.js +138 -0
- package/dist/benchmark/pid-convergence.js.map +1 -0
- package/dist/benchmark/rateless-iblt-sender-startsync.d.ts +2 -0
- package/dist/benchmark/rateless-iblt-sender-startsync.d.ts.map +1 -0
- package/dist/benchmark/rateless-iblt-sender-startsync.js +104 -0
- package/dist/benchmark/rateless-iblt-sender-startsync.js.map +1 -0
- package/dist/benchmark/rateless-iblt-startsync-cache.d.ts +2 -0
- package/dist/benchmark/rateless-iblt-startsync-cache.d.ts.map +1 -0
- package/dist/benchmark/rateless-iblt-startsync-cache.js +112 -0
- package/dist/benchmark/rateless-iblt-startsync-cache.js.map +1 -0
- package/dist/benchmark/sync-catchup.d.ts +3 -0
- package/dist/benchmark/sync-catchup.d.ts.map +1 -0
- package/dist/benchmark/sync-catchup.js +109 -0
- package/dist/benchmark/sync-catchup.js.map +1 -0
- package/dist/src/index.d.ts +14 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +256 -82
- package/dist/src/index.js.map +1 -1
- package/dist/src/ranges.d.ts +1 -0
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +48 -18
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/sync/rateless-iblt.d.ts +8 -0
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +109 -20
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/package.json +18 -18
- package/src/index.ts +324 -125
- package/src/ranges.ts +97 -65
- package/src/sync/rateless-iblt.ts +138 -28
package/src/ranges.ts
CHANGED
|
@@ -2064,6 +2064,7 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
2064
2064
|
options?: {
|
|
2065
2065
|
onlyIntersecting?: boolean;
|
|
2066
2066
|
uniqueReplicators?: Set<string>;
|
|
2067
|
+
peerFilter?: Set<string>;
|
|
2067
2068
|
},
|
|
2068
2069
|
): Promise<Map<string, { intersecting: boolean }>> => {
|
|
2069
2070
|
const leaders: Map<string, { intersecting: boolean }> = new Map();
|
|
@@ -2075,6 +2076,7 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
2075
2076
|
let matured = 0;
|
|
2076
2077
|
|
|
2077
2078
|
let uniqueVisited = new Set<string>();
|
|
2079
|
+
const peerFilter = options?.peerFilter;
|
|
2078
2080
|
for (let i = 0; i < cursor.length; i++) {
|
|
2079
2081
|
let point = cursor[i];
|
|
2080
2082
|
|
|
@@ -2084,6 +2086,9 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
2084
2086
|
);
|
|
2085
2087
|
|
|
2086
2088
|
for (const rect of allContaining) {
|
|
2089
|
+
if (peerFilter && !peerFilter.has(rect.value.hash)) {
|
|
2090
|
+
continue;
|
|
2091
|
+
}
|
|
2087
2092
|
uniqueVisited.add(rect.value.hash);
|
|
2088
2093
|
let prev = leaders.get(rect.value.hash);
|
|
2089
2094
|
if (!prev) {
|
|
@@ -2096,7 +2101,7 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
2096
2101
|
}
|
|
2097
2102
|
}
|
|
2098
2103
|
|
|
2099
|
-
if (options?.uniqueReplicators) {
|
|
2104
|
+
if (options?.uniqueReplicators && options.uniqueReplicators.size > 0) {
|
|
2100
2105
|
if (
|
|
2101
2106
|
options.uniqueReplicators.size === leaders.size ||
|
|
2102
2107
|
options.uniqueReplicators.size === uniqueVisited.size
|
|
@@ -2114,6 +2119,9 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
2114
2119
|
roleAge,
|
|
2115
2120
|
peers,
|
|
2116
2121
|
(rect, m) => {
|
|
2122
|
+
if (peerFilter && !peerFilter.has(rect.hash)) {
|
|
2123
|
+
return;
|
|
2124
|
+
}
|
|
2117
2125
|
uniqueVisited.add(rect.hash);
|
|
2118
2126
|
const prev = leaders.get(rect.hash);
|
|
2119
2127
|
if (m) {
|
|
@@ -2234,7 +2242,7 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2234
2242
|
nextLocation: NumberFromType<R>,
|
|
2235
2243
|
roleAge: number,
|
|
2236
2244
|
) => {
|
|
2237
|
-
|
|
2245
|
+
const next = await fetchOne(
|
|
2238
2246
|
iterateRangesContainingPoint<undefined, R>(peers, nextLocation, {
|
|
2239
2247
|
sort: [new Sort({ key: "end2", direction: SortDirection.DESC })],
|
|
2240
2248
|
time: {
|
|
@@ -2243,31 +2251,31 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2243
2251
|
now,
|
|
2244
2252
|
},
|
|
2245
2253
|
}),
|
|
2246
|
-
); // get
|
|
2254
|
+
); // get intersecting sort by largest end2
|
|
2247
2255
|
return next;
|
|
2248
2256
|
};
|
|
2249
2257
|
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2258
|
+
const resolveNextAbove = async (
|
|
2259
|
+
nextLocation: NumberFromType<R>,
|
|
2260
|
+
roleAge: number,
|
|
2261
|
+
) => {
|
|
2262
|
+
// if not get closest from above
|
|
2263
|
+
const next = await fetchOne<undefined, R>(
|
|
2264
|
+
getClosest("above", peers, nextLocation, true, properties.numbers, {
|
|
2265
|
+
time: {
|
|
2266
|
+
matured: true,
|
|
2267
|
+
roleAgeLimit: roleAge,
|
|
2268
|
+
now,
|
|
2269
|
+
},
|
|
2270
|
+
}),
|
|
2271
|
+
);
|
|
2272
|
+
return next;
|
|
2273
|
+
};
|
|
2266
2274
|
|
|
2267
2275
|
const resolveNext = async (
|
|
2268
2276
|
nextLocation: NumberFromType<R>,
|
|
2269
2277
|
roleAge: number,
|
|
2270
|
-
): Promise<[ReplicationRangeIndexable<R
|
|
2278
|
+
): Promise<[ReplicationRangeIndexable<R> | undefined, boolean]> => {
|
|
2271
2279
|
const containing = await resolveNextContaining(nextLocation, roleAge);
|
|
2272
2280
|
if (containing) {
|
|
2273
2281
|
return [containing, true];
|
|
@@ -2288,12 +2296,25 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2288
2296
|
from: NumberFromType<R>,
|
|
2289
2297
|
) => {
|
|
2290
2298
|
const toEnd2 = properties.numbers.increment(to.end2); // TODO investigate why this is needed
|
|
2291
|
-
if (toEnd2 < from
|
|
2299
|
+
if (toEnd2 < from) {
|
|
2292
2300
|
wrappedOnce = true;
|
|
2293
2301
|
// @ts-ignore
|
|
2294
2302
|
coveredLength += properties.numbers.maxValue - from;
|
|
2295
2303
|
// @ts-ignore
|
|
2296
2304
|
coveredLength += toEnd2;
|
|
2305
|
+
} else if (to.wrapped) {
|
|
2306
|
+
// When the range is wrapped and `from` is in the second segment (near zero),
|
|
2307
|
+
// the distance to `end2` does not wrap. Otherwise we must wrap to reach `end2`.
|
|
2308
|
+
if (from < to.end2) {
|
|
2309
|
+
// @ts-ignore
|
|
2310
|
+
coveredLength += toEnd2 - from;
|
|
2311
|
+
} else {
|
|
2312
|
+
wrappedOnce = true;
|
|
2313
|
+
// @ts-ignore
|
|
2314
|
+
coveredLength += properties.numbers.maxValue - from;
|
|
2315
|
+
// @ts-ignore
|
|
2316
|
+
coveredLength += toEnd2;
|
|
2317
|
+
}
|
|
2297
2318
|
} else {
|
|
2298
2319
|
// @ts-ignore
|
|
2299
2320
|
coveredLength += to.end1 - from;
|
|
@@ -2314,6 +2335,7 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2314
2335
|
(coveredLength <= properties.numbers.maxValue || !wrappedOnce) // eslint-disable-line no-unmodified-loop-condition
|
|
2315
2336
|
) {
|
|
2316
2337
|
let distanceBefore = coveredLength;
|
|
2338
|
+
const nextLocationBefore = nextLocation;
|
|
2317
2339
|
|
|
2318
2340
|
let nextCandidate = await resolveNext(nextLocation, roleAge);
|
|
2319
2341
|
let matured = true;
|
|
@@ -2343,55 +2365,53 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2343
2365
|
let last = current;
|
|
2344
2366
|
current = nextCandidate[0];
|
|
2345
2367
|
|
|
2346
|
-
|
|
2347
|
-
distanceBefore < widthToCoverScaled &&
|
|
2348
|
-
|
|
2368
|
+
const isLast =
|
|
2369
|
+
distanceBefore < widthToCoverScaled && coveredLength >= widthToCoverScaled;
|
|
2370
|
+
|
|
2371
|
+
const lastDistanceToEndLocation = properties.numbers.min(
|
|
2372
|
+
getDistance(
|
|
2373
|
+
last.start1,
|
|
2374
|
+
endLocation,
|
|
2375
|
+
"closest",
|
|
2376
|
+
properties.numbers.maxValue,
|
|
2377
|
+
),
|
|
2378
|
+
getDistance(
|
|
2379
|
+
last.end2,
|
|
2380
|
+
endLocation,
|
|
2381
|
+
"closest",
|
|
2382
|
+
properties.numbers.maxValue,
|
|
2383
|
+
),
|
|
2384
|
+
);
|
|
2385
|
+
|
|
2386
|
+
const currentDistanceToEndLocation = properties.numbers.min(
|
|
2387
|
+
getDistance(
|
|
2388
|
+
current.start1,
|
|
2389
|
+
endLocation,
|
|
2390
|
+
"closest",
|
|
2391
|
+
properties.numbers.maxValue,
|
|
2392
|
+
),
|
|
2393
|
+
getDistance(
|
|
2394
|
+
current.end2,
|
|
2395
|
+
endLocation,
|
|
2396
|
+
"closest",
|
|
2397
|
+
properties.numbers.maxValue,
|
|
2398
|
+
),
|
|
2399
|
+
);
|
|
2349
2400
|
|
|
2350
2401
|
if (
|
|
2351
2402
|
!isLast ||
|
|
2352
2403
|
nextCandidate[1] ||
|
|
2353
|
-
|
|
2354
|
-
getDistance(
|
|
2355
|
-
last.start1,
|
|
2356
|
-
endLocation,
|
|
2357
|
-
"closest",
|
|
2358
|
-
properties.numbers.maxValue,
|
|
2359
|
-
),
|
|
2360
|
-
getDistance(
|
|
2361
|
-
last.end2,
|
|
2362
|
-
endLocation,
|
|
2363
|
-
"closest",
|
|
2364
|
-
properties.numbers.maxValue,
|
|
2365
|
-
),
|
|
2366
|
-
) >
|
|
2367
|
-
properties.numbers.min(
|
|
2368
|
-
getDistance(
|
|
2369
|
-
current.start1,
|
|
2370
|
-
endLocation,
|
|
2371
|
-
"closest",
|
|
2372
|
-
properties.numbers.maxValue,
|
|
2373
|
-
),
|
|
2374
|
-
getDistance(
|
|
2375
|
-
current.end2,
|
|
2376
|
-
endLocation,
|
|
2377
|
-
"closest",
|
|
2378
|
-
properties.numbers.maxValue,
|
|
2379
|
-
),
|
|
2380
|
-
)
|
|
2404
|
+
lastDistanceToEndLocation >= currentDistanceToEndLocation
|
|
2381
2405
|
) {
|
|
2382
2406
|
ret.add(current.hash);
|
|
2383
2407
|
}
|
|
2384
2408
|
|
|
2385
|
-
if (isLast && !nextCandidate[1] /* || equals(endRect.id, current.id) */) {
|
|
2386
|
-
break;
|
|
2387
|
-
}
|
|
2388
|
-
|
|
2389
2409
|
if (matured) {
|
|
2390
2410
|
maturedCoveredLength = coveredLength;
|
|
2391
2411
|
}
|
|
2392
2412
|
|
|
2393
2413
|
let startForNext = extraDistanceForNext
|
|
2394
|
-
? properties.numbers.increment(
|
|
2414
|
+
? properties.numbers.increment(nextLocation)
|
|
2395
2415
|
: current.end2;
|
|
2396
2416
|
nextLocation = endIsWrapped
|
|
2397
2417
|
? wrappedOnce
|
|
@@ -2399,6 +2419,15 @@ export const getCoverSet = async <R extends "u32" | "u64">(properties: {
|
|
|
2399
2419
|
: startForNext
|
|
2400
2420
|
: properties.numbers.min(startForNext, endLocation);
|
|
2401
2421
|
|
|
2422
|
+
// Safety: ensure we always make progress to avoid infinite loops (can happen when
|
|
2423
|
+
// the chosen range is the same and `nextLocation` doesn't advance).
|
|
2424
|
+
if (
|
|
2425
|
+
nextLocation === nextLocationBefore &&
|
|
2426
|
+
coveredLength === distanceBefore
|
|
2427
|
+
) {
|
|
2428
|
+
break;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2402
2431
|
if (
|
|
2403
2432
|
(typeof nextLocation === "bigint" &&
|
|
2404
2433
|
nextLocation === (endLocation as bigint)) ||
|
|
@@ -2603,19 +2632,19 @@ export const mergeReplicationChanges = <R extends NumericType>(
|
|
|
2603
2632
|
let results: ReplicationChange<ReplicationRangeIndexable<R>>[] = [];
|
|
2604
2633
|
let consumed: Set<number> = new Set();
|
|
2605
2634
|
for (let i = 0; i < v.length; i++) {
|
|
2606
|
-
//
|
|
2607
|
-
//
|
|
2608
|
-
// equivalent is that this would represent (1 - 1 + 1) = 1
|
|
2635
|
+
// If segment is removed and we have previously processed it then go over each
|
|
2636
|
+
// overlapping added segment and remove the overlap. Equivalent to: (1 - 1 + 1) = 1.
|
|
2609
2637
|
if (v[i].type === "removed" || v[i].type === "replaced") {
|
|
2610
2638
|
if (rebalanceHistory.has(v[i].range.rangeHash)) {
|
|
2611
|
-
let
|
|
2639
|
+
let adjusted = false;
|
|
2640
|
+
const vStart = v.length;
|
|
2612
2641
|
for (let j = i + 1; j < vStart; j++) {
|
|
2613
2642
|
const newer = v[j];
|
|
2614
2643
|
if (newer.type === "added" && !newer.matured) {
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2644
|
+
adjusted = true;
|
|
2645
|
+
const { rangesFromA: updatedRemoved, rangesFromB: updatedNewer } =
|
|
2646
|
+
symmetricDifferenceRanges(v[i].range, newer.range);
|
|
2647
|
+
|
|
2619
2648
|
for (const diff of updatedRemoved) {
|
|
2620
2649
|
results.push({
|
|
2621
2650
|
range: diff,
|
|
@@ -2634,6 +2663,9 @@ export const mergeReplicationChanges = <R extends NumericType>(
|
|
|
2634
2663
|
}
|
|
2635
2664
|
}
|
|
2636
2665
|
rebalanceHistory.del(v[i].range.rangeHash);
|
|
2666
|
+
if (!adjusted) {
|
|
2667
|
+
results.push(v[i]);
|
|
2668
|
+
}
|
|
2637
2669
|
} else {
|
|
2638
2670
|
results.push(v[i]);
|
|
2639
2671
|
}
|
|
@@ -187,6 +187,13 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
187
187
|
simple: SimpleSyncronizer<D>;
|
|
188
188
|
|
|
189
189
|
startedOrCompletedSynchronizations: Cache<string>;
|
|
190
|
+
private localRangeEncoderCacheVersion = 0;
|
|
191
|
+
private localRangeEncoderCache: Map<
|
|
192
|
+
string,
|
|
193
|
+
{ encoder: EncoderWrapper; version: number; lastUsed: number }
|
|
194
|
+
> = new Map();
|
|
195
|
+
private localRangeEncoderCacheMax = 2;
|
|
196
|
+
|
|
190
197
|
ingoingSyncProcesses: Map<
|
|
191
198
|
string,
|
|
192
199
|
{
|
|
@@ -222,6 +229,91 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
222
229
|
this.startedOrCompletedSynchronizations = new Cache({ max: 1e4 });
|
|
223
230
|
}
|
|
224
231
|
|
|
232
|
+
private clearLocalRangeEncoderCache() {
|
|
233
|
+
for (const [, cached] of this.localRangeEncoderCache) {
|
|
234
|
+
cached.encoder.free();
|
|
235
|
+
}
|
|
236
|
+
this.localRangeEncoderCache.clear();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private invalidateLocalRangeEncoderCache() {
|
|
240
|
+
this.localRangeEncoderCacheVersion += 1;
|
|
241
|
+
this.clearLocalRangeEncoderCache();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private localRangeEncoderCacheKey(ranges: {
|
|
245
|
+
start1: NumberOrBigint;
|
|
246
|
+
end1: NumberOrBigint;
|
|
247
|
+
start2: NumberOrBigint;
|
|
248
|
+
end2: NumberOrBigint;
|
|
249
|
+
}) {
|
|
250
|
+
return `${String(ranges.start1)}:${String(ranges.end1)}:${String(
|
|
251
|
+
ranges.start2,
|
|
252
|
+
)}:${String(ranges.end2)}`;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private decoderFromCachedEncoder(encoder: EncoderWrapper): DecoderWrapper {
|
|
256
|
+
const clone = encoder.clone();
|
|
257
|
+
const decoder = clone.to_decoder();
|
|
258
|
+
clone.free();
|
|
259
|
+
return decoder;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private async getLocalDecoderForRange(ranges: {
|
|
263
|
+
start1: NumberOrBigint;
|
|
264
|
+
end1: NumberOrBigint;
|
|
265
|
+
start2: NumberOrBigint;
|
|
266
|
+
end2: NumberOrBigint;
|
|
267
|
+
}): Promise<DecoderWrapper | false> {
|
|
268
|
+
const key = this.localRangeEncoderCacheKey(ranges);
|
|
269
|
+
const cached = this.localRangeEncoderCache.get(key);
|
|
270
|
+
if (cached && cached.version === this.localRangeEncoderCacheVersion) {
|
|
271
|
+
cached.lastUsed = Date.now();
|
|
272
|
+
return this.decoderFromCachedEncoder(cached.encoder);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const encoder = (await buildEncoderOrDecoderFromRange(
|
|
276
|
+
ranges,
|
|
277
|
+
this.properties.entryIndex,
|
|
278
|
+
"encoder",
|
|
279
|
+
)) as EncoderWrapper | false;
|
|
280
|
+
if (!encoder) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const now = Date.now();
|
|
285
|
+
const existing = this.localRangeEncoderCache.get(key);
|
|
286
|
+
if (existing) {
|
|
287
|
+
existing.encoder.free();
|
|
288
|
+
}
|
|
289
|
+
this.localRangeEncoderCache.set(key, {
|
|
290
|
+
encoder,
|
|
291
|
+
version: this.localRangeEncoderCacheVersion,
|
|
292
|
+
lastUsed: now,
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
while (this.localRangeEncoderCache.size > this.localRangeEncoderCacheMax) {
|
|
296
|
+
let oldestKey: string | undefined;
|
|
297
|
+
let oldestUsed = Number.POSITIVE_INFINITY;
|
|
298
|
+
for (const [candidateKey, value] of this.localRangeEncoderCache) {
|
|
299
|
+
if (value.lastUsed < oldestUsed) {
|
|
300
|
+
oldestUsed = value.lastUsed;
|
|
301
|
+
oldestKey = candidateKey;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (!oldestKey) {
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
const victim = this.localRangeEncoderCache.get(oldestKey);
|
|
308
|
+
if (victim) {
|
|
309
|
+
victim.encoder.free();
|
|
310
|
+
}
|
|
311
|
+
this.localRangeEncoderCache.delete(oldestKey);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return this.decoderFromCachedEncoder(encoder);
|
|
315
|
+
}
|
|
316
|
+
|
|
225
317
|
async onMaybeMissingEntries(properties: {
|
|
226
318
|
entries: Map<string, EntryReplicated<D>>;
|
|
227
319
|
targets: string[];
|
|
@@ -292,9 +384,13 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
292
384
|
}
|
|
293
385
|
}
|
|
294
386
|
|
|
295
|
-
let allCoordinatesToSyncWithIblt =
|
|
296
|
-
|
|
297
|
-
.
|
|
387
|
+
let allCoordinatesToSyncWithIblt: bigint[] = [];
|
|
388
|
+
for (const entry of nonBoundaryEntries) {
|
|
389
|
+
if (entriesToSyncNaively.has(entry.hash)) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
allCoordinatesToSyncWithIblt.push(coerceBigInt(entry.hashNumber));
|
|
393
|
+
}
|
|
298
394
|
|
|
299
395
|
if (entriesToSyncNaively.size > 0) {
|
|
300
396
|
// If there are special-case entries, sync them simply in parallel
|
|
@@ -309,9 +405,10 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
309
405
|
entriesToSyncNaively.size > maxSyncWithSimpleMethod
|
|
310
406
|
) {
|
|
311
407
|
// Fallback: if nothing left for IBLT (or simple set is too large), include all in IBLT
|
|
312
|
-
allCoordinatesToSyncWithIblt =
|
|
313
|
-
|
|
314
|
-
|
|
408
|
+
allCoordinatesToSyncWithIblt = [];
|
|
409
|
+
for (const entry of properties.entries.values()) {
|
|
410
|
+
allCoordinatesToSyncWithIblt.push(coerceBigInt(entry.hashNumber));
|
|
411
|
+
}
|
|
315
412
|
}
|
|
316
413
|
|
|
317
414
|
if (allCoordinatesToSyncWithIblt.length === 0) {
|
|
@@ -320,22 +417,32 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
320
417
|
|
|
321
418
|
await ribltReady;
|
|
322
419
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
} else {
|
|
329
|
-
return 0;
|
|
420
|
+
let sortedEntries: bigint[] | BigUint64Array;
|
|
421
|
+
if (typeof BigUint64Array !== "undefined") {
|
|
422
|
+
const typed = new BigUint64Array(allCoordinatesToSyncWithIblt.length);
|
|
423
|
+
for (let i = 0; i < allCoordinatesToSyncWithIblt.length; i++) {
|
|
424
|
+
typed[i] = allCoordinatesToSyncWithIblt[i];
|
|
330
425
|
}
|
|
331
|
-
|
|
426
|
+
typed.sort();
|
|
427
|
+
sortedEntries = typed;
|
|
428
|
+
} else {
|
|
429
|
+
sortedEntries = allCoordinatesToSyncWithIblt.sort((a, b) => {
|
|
430
|
+
if (a > b) {
|
|
431
|
+
return 1;
|
|
432
|
+
} else if (a < b) {
|
|
433
|
+
return -1;
|
|
434
|
+
} else {
|
|
435
|
+
return 0;
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
}
|
|
332
439
|
|
|
333
440
|
// assume sorted, and find the largest gap
|
|
334
441
|
let largestGap = 0n;
|
|
335
442
|
let largestGapIndex = 0;
|
|
336
|
-
for (let i = 0; i < sortedEntries.length
|
|
443
|
+
for (let i = 0; i < sortedEntries.length; i++) {
|
|
337
444
|
const current = sortedEntries[i];
|
|
338
|
-
const next = sortedEntries[i + 1];
|
|
445
|
+
const next = sortedEntries[(i + 1) % sortedEntries.length];
|
|
339
446
|
const gap =
|
|
340
447
|
next >= current
|
|
341
448
|
? next - current
|
|
@@ -365,8 +472,12 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
365
472
|
|
|
366
473
|
const startSync = new StartSync({ from: start, to: end, symbols: [] });
|
|
367
474
|
const encoder = new EncoderWrapper();
|
|
368
|
-
|
|
369
|
-
encoder.
|
|
475
|
+
if (typeof BigUint64Array !== "undefined" && sortedEntries instanceof BigUint64Array) {
|
|
476
|
+
encoder.add_symbols(sortedEntries);
|
|
477
|
+
} else {
|
|
478
|
+
for (const entry of sortedEntries) {
|
|
479
|
+
encoder.add_symbol(coerceBigInt(entry));
|
|
480
|
+
}
|
|
370
481
|
}
|
|
371
482
|
|
|
372
483
|
let initialSymbols = Math.round(
|
|
@@ -442,16 +553,12 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
442
553
|
this.startedOrCompletedSynchronizations.add(syncId);
|
|
443
554
|
|
|
444
555
|
const wrapped = message.end < message.start;
|
|
445
|
-
const decoder = await
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
},
|
|
452
|
-
this.properties.entryIndex,
|
|
453
|
-
"decoder",
|
|
454
|
-
);
|
|
556
|
+
const decoder = await this.getLocalDecoderForRange({
|
|
557
|
+
start1: message.start,
|
|
558
|
+
end1: wrapped ? this.properties.numbers.maxValue : message.end,
|
|
559
|
+
start2: 0n,
|
|
560
|
+
end2: wrapped ? message.end : 0n,
|
|
561
|
+
});
|
|
455
562
|
|
|
456
563
|
if (!decoder) {
|
|
457
564
|
await this.simple.rpc.send(
|
|
@@ -656,10 +763,12 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
656
763
|
}
|
|
657
764
|
|
|
658
765
|
onEntryAdded(entry: Entry<any>): void {
|
|
766
|
+
this.invalidateLocalRangeEncoderCache();
|
|
659
767
|
return this.simple.onEntryAdded(entry);
|
|
660
768
|
}
|
|
661
769
|
|
|
662
770
|
onEntryRemoved(hash: string) {
|
|
771
|
+
this.invalidateLocalRangeEncoderCache();
|
|
663
772
|
return this.simple.onEntryRemoved(hash);
|
|
664
773
|
}
|
|
665
774
|
|
|
@@ -678,6 +787,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
678
787
|
for (const [, obj] of this.outgoingSyncProcesses) {
|
|
679
788
|
obj.free();
|
|
680
789
|
}
|
|
790
|
+
this.clearLocalRangeEncoderCache();
|
|
681
791
|
return this.simple.close();
|
|
682
792
|
}
|
|
683
793
|
|