@peerbit/shared-log 10.3.0 → 10.3.1-c0de42e
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/blocks.d.ts.map +1 -1
- package/dist/src/blocks.js.map +1 -1
- package/dist/src/index.d.ts +6 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +38 -52
- package/dist/src/index.js.map +1 -1
- package/dist/src/ranges.d.ts +0 -4
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +3 -10
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/sync/rateless-iblt.d.ts +1 -0
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +14 -1
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/package.json +70 -70
- package/src/blocks.ts +0 -1
- package/src/index.ts +56 -63
- package/src/ranges.ts +4 -12
- package/src/sync/rateless-iblt.ts +13 -1
package/src/index.ts
CHANGED
|
@@ -85,7 +85,6 @@ import {
|
|
|
85
85
|
ReplicationRangeIndexableU32,
|
|
86
86
|
ReplicationRangeIndexableU64,
|
|
87
87
|
ReplicationRangeMessage,
|
|
88
|
-
SyncStatus,
|
|
89
88
|
appromixateCoverage,
|
|
90
89
|
countCoveringRangesSameOwner,
|
|
91
90
|
debounceAggregationChanges,
|
|
@@ -572,15 +571,17 @@ export class SharedLog<
|
|
|
572
571
|
checkDuplicates,
|
|
573
572
|
announce,
|
|
574
573
|
mergeSegments,
|
|
574
|
+
rebalance,
|
|
575
575
|
}: {
|
|
576
576
|
reset?: boolean;
|
|
577
577
|
checkDuplicates?: boolean;
|
|
578
578
|
mergeSegments?: boolean;
|
|
579
|
+
rebalance?: boolean;
|
|
579
580
|
announce?: (
|
|
580
581
|
msg: AddedReplicationSegmentMessage | AllReplicatingSegmentsMessage,
|
|
581
582
|
) => void;
|
|
582
583
|
} = {},
|
|
583
|
-
) {
|
|
584
|
+
): Promise<ReplicationRangeIndexable<R>[]> {
|
|
584
585
|
let offsetWasProvided = false;
|
|
585
586
|
if (isUnreplicationOptions(options)) {
|
|
586
587
|
await this.unreplicate();
|
|
@@ -607,7 +608,7 @@ export class SharedLog<
|
|
|
607
608
|
const maybeRange = await this.getDynamicRange();
|
|
608
609
|
if (!maybeRange) {
|
|
609
610
|
// not allowed
|
|
610
|
-
return;
|
|
611
|
+
return [];
|
|
611
612
|
}
|
|
612
613
|
rangesToReplicate = [maybeRange];
|
|
613
614
|
|
|
@@ -634,7 +635,7 @@ export class SharedLog<
|
|
|
634
635
|
|
|
635
636
|
if (rangeArgs.length === 0) {
|
|
636
637
|
// nothing to do
|
|
637
|
-
return;
|
|
638
|
+
return [];
|
|
638
639
|
}
|
|
639
640
|
|
|
640
641
|
for (const rangeArg of rangeArgs) {
|
|
@@ -744,6 +745,7 @@ export class SharedLog<
|
|
|
744
745
|
reset: resetRanges ?? false,
|
|
745
746
|
checkDuplicates,
|
|
746
747
|
announce,
|
|
748
|
+
rebalance,
|
|
747
749
|
});
|
|
748
750
|
|
|
749
751
|
if (rangesToUnreplicate.length > 0) {
|
|
@@ -759,6 +761,8 @@ export class SharedLog<
|
|
|
759
761
|
|
|
760
762
|
return rangesToReplicate;
|
|
761
763
|
}
|
|
764
|
+
|
|
765
|
+
return [];
|
|
762
766
|
}
|
|
763
767
|
|
|
764
768
|
setupDebouncedRebalancing(options?: DynamicReplicationOptions<R>) {
|
|
@@ -796,6 +800,7 @@ export class SharedLog<
|
|
|
796
800
|
options?: {
|
|
797
801
|
reset?: boolean;
|
|
798
802
|
checkDuplicates?: boolean;
|
|
803
|
+
rebalance?: boolean;
|
|
799
804
|
mergeSegments?: boolean;
|
|
800
805
|
announce?: (
|
|
801
806
|
msg: AllReplicatingSegmentsMessage | AddedReplicationSegmentMessage,
|
|
@@ -1036,13 +1041,20 @@ export class SharedLog<
|
|
|
1036
1041
|
reset,
|
|
1037
1042
|
checkDuplicates,
|
|
1038
1043
|
timestamp: ts,
|
|
1039
|
-
|
|
1044
|
+
rebalance,
|
|
1045
|
+
}: {
|
|
1046
|
+
reset?: boolean;
|
|
1047
|
+
rebalance?: boolean;
|
|
1048
|
+
checkDuplicates?: boolean;
|
|
1049
|
+
timestamp?: number;
|
|
1050
|
+
} = {},
|
|
1040
1051
|
) {
|
|
1041
1052
|
if (this._isTrustedReplicator && !(await this._isTrustedReplicator(from))) {
|
|
1042
1053
|
return undefined;
|
|
1043
1054
|
}
|
|
1044
1055
|
let isNewReplicator = false;
|
|
1045
1056
|
let timestamp = BigInt(ts ?? +new Date());
|
|
1057
|
+
rebalance = rebalance == null ? true : rebalance;
|
|
1046
1058
|
|
|
1047
1059
|
let diffs: ReplicationChanges<ReplicationRangeIndexable<R>>;
|
|
1048
1060
|
let deleted: ReplicationRangeIndexable<R>[] | undefined = undefined;
|
|
@@ -1070,16 +1082,25 @@ export class SharedLog<
|
|
|
1070
1082
|
|
|
1071
1083
|
isNewReplicator = prevCount === 0 && ranges.length > 0;
|
|
1072
1084
|
} else {
|
|
1073
|
-
let
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1085
|
+
let batchSize = 100;
|
|
1086
|
+
let existing: ReplicationRangeIndexable<R>[] = [];
|
|
1087
|
+
for (let i = 0; i < ranges.length; i += batchSize) {
|
|
1088
|
+
const results = await this.replicationIndex
|
|
1089
|
+
.iterate(
|
|
1090
|
+
{
|
|
1091
|
+
query: (ranges.length <= batchSize
|
|
1092
|
+
? ranges
|
|
1093
|
+
: ranges.slice(i, i + batchSize)
|
|
1094
|
+
).map((x) => new ByteMatchQuery({ key: "id", value: x.id })),
|
|
1095
|
+
},
|
|
1096
|
+
{ reference: true },
|
|
1097
|
+
)
|
|
1098
|
+
.all();
|
|
1099
|
+
for (const result of results) {
|
|
1100
|
+
existing.push(result.value);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1083
1104
|
if (existing.length === 0) {
|
|
1084
1105
|
let prevCount = await this.replicationIndex.count({
|
|
1085
1106
|
query: new StringMatch({ key: "hash", value: from.hashcode() }),
|
|
@@ -1104,7 +1125,7 @@ export class SharedLog<
|
|
|
1104
1125
|
}
|
|
1105
1126
|
let existingMap = new Map<string, ReplicationRangeIndexable<any>>();
|
|
1106
1127
|
for (const result of existing) {
|
|
1107
|
-
existingMap.set(result.
|
|
1128
|
+
existingMap.set(result.idString, result);
|
|
1108
1129
|
}
|
|
1109
1130
|
|
|
1110
1131
|
let changes: ReplicationChanges<ReplicationRangeIndexable<R>> = ranges
|
|
@@ -1181,7 +1202,13 @@ export class SharedLog<
|
|
|
1181
1202
|
}),
|
|
1182
1203
|
);
|
|
1183
1204
|
|
|
1184
|
-
|
|
1205
|
+
if (rebalance && diff.range.mode !== ReplicationIntent.Strict) {
|
|
1206
|
+
// TODO this statement (might) cause issues with triggering pruning if the segment is strict and maturity timings will affect the outcome of rebalancing
|
|
1207
|
+
this.replicationChangeDebounceFn.add({
|
|
1208
|
+
...diff,
|
|
1209
|
+
matured: true,
|
|
1210
|
+
}); // we need to call this here because the outcom of findLeaders will be different when some ranges become mature, i.e. some of data we own might be prunable!
|
|
1211
|
+
}
|
|
1185
1212
|
pendingRanges.delete(diff.range.idString);
|
|
1186
1213
|
if (pendingRanges.size === 0) {
|
|
1187
1214
|
this.pendingMaturity.delete(diff.range.hash);
|
|
@@ -1242,7 +1269,7 @@ export class SharedLog<
|
|
|
1242
1269
|
}
|
|
1243
1270
|
}
|
|
1244
1271
|
|
|
1245
|
-
if (diffs.length > 0) {
|
|
1272
|
+
if (rebalance && diffs.length > 0) {
|
|
1246
1273
|
for (const diff of diffs) {
|
|
1247
1274
|
this.replicationChangeDebounceFn.add(diff);
|
|
1248
1275
|
}
|
|
@@ -1258,9 +1285,9 @@ export class SharedLog<
|
|
|
1258
1285
|
async startAnnounceReplicating(
|
|
1259
1286
|
range: ReplicationRangeIndexable<R>[],
|
|
1260
1287
|
options: {
|
|
1261
|
-
syncStatus?: SyncStatus;
|
|
1262
1288
|
reset?: boolean;
|
|
1263
1289
|
checkDuplicates?: boolean;
|
|
1290
|
+
rebalance?: boolean;
|
|
1264
1291
|
announce?: (
|
|
1265
1292
|
msg: AllReplicatingSegmentsMessage | AddedReplicationSegmentMessage,
|
|
1266
1293
|
) => void;
|
|
@@ -1315,7 +1342,7 @@ export class SharedLog<
|
|
|
1315
1342
|
}
|
|
1316
1343
|
}
|
|
1317
1344
|
|
|
1318
|
-
|
|
1345
|
+
addPeersToGidPeerHistory(
|
|
1319
1346
|
gid: string,
|
|
1320
1347
|
publicKeys: Iterable<string>,
|
|
1321
1348
|
reset?: boolean,
|
|
@@ -1922,7 +1949,6 @@ export class SharedLog<
|
|
|
1922
1949
|
this.coordinateToHash.clear();
|
|
1923
1950
|
this.recentlyRebalanced.clear();
|
|
1924
1951
|
this.uniqueReplicators.clear();
|
|
1925
|
-
|
|
1926
1952
|
this._closeController.abort();
|
|
1927
1953
|
|
|
1928
1954
|
clearInterval(this.interval);
|
|
@@ -2667,6 +2693,10 @@ export class SharedLog<
|
|
|
2667
2693
|
}
|
|
2668
2694
|
: undefined;
|
|
2669
2695
|
|
|
2696
|
+
let assumeSynced =
|
|
2697
|
+
options?.replicate &&
|
|
2698
|
+
typeof options.replicate !== "boolean" &&
|
|
2699
|
+
options.replicate.assumeSynced;
|
|
2670
2700
|
const persistCoordinate = async (entry: Entry<T>) => {
|
|
2671
2701
|
const minReplicas = decodeReplicas(entry).getValue(this);
|
|
2672
2702
|
const leaders = await this.findLeaders(
|
|
@@ -2675,11 +2705,7 @@ export class SharedLog<
|
|
|
2675
2705
|
{ persist: {} },
|
|
2676
2706
|
);
|
|
2677
2707
|
|
|
2678
|
-
if (
|
|
2679
|
-
options?.replicate &&
|
|
2680
|
-
typeof options.replicate !== "boolean" &&
|
|
2681
|
-
options.replicate.assumeSynced
|
|
2682
|
-
) {
|
|
2708
|
+
if (assumeSynced) {
|
|
2683
2709
|
// make sure we dont start to initate syncing process outwards for this entry
|
|
2684
2710
|
this.addPeersToGidPeerHistory(entry.meta.gid, leaders.keys());
|
|
2685
2711
|
}
|
|
@@ -2711,7 +2737,9 @@ export class SharedLog<
|
|
|
2711
2737
|
|
|
2712
2738
|
if (options?.replicate) {
|
|
2713
2739
|
let messageToSend: AddedReplicationSegmentMessage | undefined = undefined;
|
|
2740
|
+
|
|
2714
2741
|
await this.replicate(entriesToReplicate, {
|
|
2742
|
+
rebalance: assumeSynced ? false : true,
|
|
2715
2743
|
checkDuplicates: true,
|
|
2716
2744
|
mergeSegments:
|
|
2717
2745
|
typeof options.replicate !== "boolean" && options.replicate
|
|
@@ -2736,6 +2764,7 @@ export class SharedLog<
|
|
|
2736
2764
|
},
|
|
2737
2765
|
});
|
|
2738
2766
|
|
|
2767
|
+
// it is importat that we call persistCoordinate after this.replicate(entries) as else there might be a prune job deleting the entry before replication duties has been assigned to self
|
|
2739
2768
|
for (const entry of entriesToPersist) {
|
|
2740
2769
|
await persistCoordinate(entry);
|
|
2741
2770
|
}
|
|
@@ -2747,39 +2776,6 @@ export class SharedLog<
|
|
|
2747
2776
|
}
|
|
2748
2777
|
}
|
|
2749
2778
|
}
|
|
2750
|
-
/*
|
|
2751
|
-
private async updateLeaders(
|
|
2752
|
-
cursor: NumberFromType<R>,
|
|
2753
|
-
prev: EntryReplicated<R>,
|
|
2754
|
-
options?: {
|
|
2755
|
-
roleAge?: number;
|
|
2756
|
-
},
|
|
2757
|
-
): Promise<{
|
|
2758
|
-
isLeader: boolean;
|
|
2759
|
-
leaders: Map<string, { intersecting: boolean }>;
|
|
2760
|
-
}> {
|
|
2761
|
-
// we consume a list of coordinates in this method since if we are leader of one coordinate we want to persist all of them
|
|
2762
|
-
const leaders = await this._findLeaders(cursor, options);
|
|
2763
|
-
const isLeader = leaders.has(this.node.identity.publicKey.hashcode());
|
|
2764
|
-
const isAtRangeBoundary = shouldAssignToRangeBoundary(leaders, 1);
|
|
2765
|
-
|
|
2766
|
-
// dont do anthing if nothing has changed
|
|
2767
|
-
if (prev.assignedToRangeBoundary !== isAtRangeBoundary) {
|
|
2768
|
-
return { isLeader, leaders };
|
|
2769
|
-
}
|
|
2770
|
-
|
|
2771
|
-
await this.entryCoordinatesIndex.put(
|
|
2772
|
-
new this.indexableDomain.constructorEntry({
|
|
2773
|
-
assignedToRangeBoundary: isAtRangeBoundary,
|
|
2774
|
-
coordinate: cursor,
|
|
2775
|
-
meta: prev.meta,
|
|
2776
|
-
hash: prev.hash,
|
|
2777
|
-
}),
|
|
2778
|
-
);
|
|
2779
|
-
|
|
2780
|
-
return { isLeader, leaders };
|
|
2781
|
-
}
|
|
2782
|
-
*/
|
|
2783
2779
|
|
|
2784
2780
|
private async _waitForReplicators(
|
|
2785
2781
|
cursors: NumberFromType<R>[],
|
|
@@ -3411,7 +3407,6 @@ export class SharedLog<
|
|
|
3411
3407
|
const minReplicasValue = minReplicasObj.getValue(this);
|
|
3412
3408
|
|
|
3413
3409
|
// TODO is this check necessary
|
|
3414
|
-
|
|
3415
3410
|
if (
|
|
3416
3411
|
!(await this._waitForReplicators(
|
|
3417
3412
|
cursor ??
|
|
@@ -3542,7 +3537,7 @@ export class SharedLog<
|
|
|
3542
3537
|
}
|
|
3543
3538
|
|
|
3544
3539
|
const timestamp = BigInt(+new Date());
|
|
3545
|
-
this.onReplicationChange(
|
|
3540
|
+
return this.onReplicationChange(
|
|
3546
3541
|
(await this.getAllReplicationSegments()).map((x) => {
|
|
3547
3542
|
return { range: x, type: "added", timestamp };
|
|
3548
3543
|
}),
|
|
@@ -3577,7 +3572,6 @@ export class SharedLog<
|
|
|
3577
3572
|
Map<string, EntryReplicated<any>>
|
|
3578
3573
|
> = new Map();
|
|
3579
3574
|
|
|
3580
|
-
let c = 0;
|
|
3581
3575
|
for await (const entryReplicated of toRebalance<R>(
|
|
3582
3576
|
changeOrChanges,
|
|
3583
3577
|
this.entryCoordinatesIndex,
|
|
@@ -3586,7 +3580,6 @@ export class SharedLog<
|
|
|
3586
3580
|
if (this.closed) {
|
|
3587
3581
|
break;
|
|
3588
3582
|
}
|
|
3589
|
-
c++;
|
|
3590
3583
|
|
|
3591
3584
|
let oldPeersSet = this._gidPeersHistory.get(entryReplicated.gid);
|
|
3592
3585
|
let isLeader = false;
|
package/src/ranges.ts
CHANGED
|
@@ -43,11 +43,6 @@ export enum ReplicationIntent {
|
|
|
43
43
|
Strict = 1, // only replicate data in the segment to the specified replicator, not any other data
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
export enum SyncStatus {
|
|
47
|
-
Unsynced = 0,
|
|
48
|
-
Synced = 1,
|
|
49
|
-
}
|
|
50
|
-
|
|
51
46
|
const min = (a: number | bigint, b: number | bigint) => (a < b ? a : b);
|
|
52
47
|
|
|
53
48
|
const getSegmentsFromOffsetAndRange = <T extends number | bigint>(
|
|
@@ -1897,7 +1892,6 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
1897
1892
|
const now = +new Date();
|
|
1898
1893
|
let matured = 0;
|
|
1899
1894
|
|
|
1900
|
-
/* let missingForCursors: NumberFromType<R>[] = [] */
|
|
1901
1895
|
let uniqueVisited = new Set<string>();
|
|
1902
1896
|
for (let i = 0; i < cursor.length; i++) {
|
|
1903
1897
|
let point = cursor[i];
|
|
@@ -1962,6 +1956,7 @@ export const getSamples = async <R extends "u32" | "u64">(
|
|
|
1962
1956
|
/* if (leaders.size < cursor.length) {
|
|
1963
1957
|
throw new Error("Missing leaders got: " + leaders.size + " -- expected -- " + cursor.length + " role age " + roleAge + " missing " + missingForCursors.length + " replication index size: " + (await peers.count()));
|
|
1964
1958
|
} */
|
|
1959
|
+
|
|
1965
1960
|
return leaders;
|
|
1966
1961
|
};
|
|
1967
1962
|
|
|
@@ -2277,6 +2272,9 @@ export const debounceAggregationChanges = <
|
|
|
2277
2272
|
) => {
|
|
2278
2273
|
return debounceAccumulator(
|
|
2279
2274
|
(result) => {
|
|
2275
|
+
if (result.size === 0) {
|
|
2276
|
+
return;
|
|
2277
|
+
}
|
|
2280
2278
|
return fn([...result.values()]);
|
|
2281
2279
|
},
|
|
2282
2280
|
() => {
|
|
@@ -2450,12 +2448,6 @@ export const toRebalance = <R extends "u32" | "u64">(
|
|
|
2450
2448
|
|
|
2451
2449
|
while (iterator.done() !== true) {
|
|
2452
2450
|
const entries = await iterator.all(); // TODO choose right batch sizes here for optimal memory usage / speed
|
|
2453
|
-
|
|
2454
|
-
/* const grouped = await groupByGidSync(entries.map((x) => x.value));
|
|
2455
|
-
for (const [gid, entries] of grouped.entries()) {
|
|
2456
|
-
yield { gid, entries };
|
|
2457
|
-
} */
|
|
2458
|
-
|
|
2459
2451
|
for (const entry of entries) {
|
|
2460
2452
|
yield entry.value;
|
|
2461
2453
|
}
|
|
@@ -3,6 +3,7 @@ import { Cache } from "@peerbit/cache";
|
|
|
3
3
|
import { type PublicSignKey, randomBytes, toBase64 } from "@peerbit/crypto";
|
|
4
4
|
import { type Index } from "@peerbit/indexer-interface";
|
|
5
5
|
import type { Entry, Log } from "@peerbit/log";
|
|
6
|
+
import { logger as loggerFn } from "@peerbit/logger";
|
|
6
7
|
import { DecoderWrapper, EncoderWrapper } from "@peerbit/riblt";
|
|
7
8
|
import type { RPC, RequestContext } from "@peerbit/rpc";
|
|
8
9
|
import { SilentDelivery } from "@peerbit/stream-interface";
|
|
@@ -17,6 +18,8 @@ import {
|
|
|
17
18
|
} from "../ranges.js";
|
|
18
19
|
import { SimpleSyncronizer } from "./simple.js";
|
|
19
20
|
|
|
21
|
+
export const logger = loggerFn({ module: "shared-log" });
|
|
22
|
+
|
|
20
23
|
type NumberOrBigint = number | bigint;
|
|
21
24
|
|
|
22
25
|
const coerceBigInt = (value: NumberOrBigint): bigint =>
|
|
@@ -470,7 +473,16 @@ export class RatelessIBLTSynchronizer<
|
|
|
470
473
|
for (const symbol of message.symbols) {
|
|
471
474
|
decoder.add_coded_symbol(symbol);
|
|
472
475
|
}
|
|
473
|
-
|
|
476
|
+
try {
|
|
477
|
+
decoder.try_decode();
|
|
478
|
+
} catch (error: any) {
|
|
479
|
+
if (error?.message === "Invalid degree") {
|
|
480
|
+
logger.error(error?.message);
|
|
481
|
+
return false;
|
|
482
|
+
} else {
|
|
483
|
+
throw error;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
474
486
|
count += message.symbols.length;
|
|
475
487
|
|
|
476
488
|
if (decoder.decoded()) {
|