@peerbit/shared-log 10.3.2-6b5241d → 10.3.2

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/src/index.ts CHANGED
@@ -694,32 +694,27 @@ export class SharedLog<
694
694
 
695
695
  // also merge segments that are already in the index
696
696
  if (this.domain.canMerge) {
697
- const mergeRangesThatAlreadyExist = await getAllMergeCandiates(
697
+ const mergable = await getAllMergeCandiates(
698
698
  this.replicationIndex,
699
699
  range,
700
700
  this.indexableDomain.numbers,
701
701
  );
702
- const mergeableFiltered: ReplicationRangeIndexable<R>[] = [];
702
+ const mergeableFiltered: ReplicationRangeIndexable<R>[] = [range];
703
703
 
704
- for (const [_key, mergeCandidate] of mergeRangesThatAlreadyExist) {
704
+ for (const mergeCandidate of mergable) {
705
705
  if (this.domain.canMerge(mergeCandidate, range)) {
706
706
  mergeableFiltered.push(mergeCandidate);
707
+ if (mergeCandidate.idString !== range.idString) {
708
+ rangesToUnreplicate.push(mergeCandidate);
709
+ }
707
710
  }
708
711
  }
709
-
710
- mergeableFiltered.push(range); // * we push this last, because mergeRanges will reuse ids of the first elements
711
712
  if (mergeableFiltered.length > 1) {
712
- // ** this is important here as we want to reuse ids of what we already persist, not the new ranges, so we dont get a delet add op, but just a update op
713
713
  range = mergeRanges(
714
714
  mergeableFiltered,
715
715
  this.indexableDomain.numbers,
716
716
  );
717
717
  }
718
- for (const [_key, mergeCandidate] of mergeRangesThatAlreadyExist) {
719
- if (mergeCandidate.idString !== range.idString) {
720
- rangesToUnreplicate.push(mergeCandidate);
721
- }
722
- }
723
718
  }
724
719
  rangesToReplicate = [range];
725
720
  }
@@ -1010,9 +1005,6 @@ export class SharedLog<
1010
1005
  this.pendingMaturity.delete(from.hashcode());
1011
1006
  }
1012
1007
  }
1013
- if (ranges.length === 0) {
1014
- throw new Error("???");
1015
- }
1016
1008
 
1017
1009
  await this.replicationIndex.del({
1018
1010
  query: new Or(
@@ -1311,29 +1303,24 @@ export class SharedLog<
1311
1303
  logger.warn("Not allowed to replicate by canReplicate");
1312
1304
  }
1313
1305
 
1306
+ let message: AllReplicatingSegmentsMessage | AddedReplicationSegmentMessage;
1307
+
1314
1308
  if (change) {
1315
- let addedOrReplaced = change.filter((x) => x.type !== "removed");
1316
- if (addedOrReplaced.length > 0) {
1317
- let message:
1318
- | AllReplicatingSegmentsMessage
1319
- | AddedReplicationSegmentMessage
1320
- | undefined = undefined;
1321
- if (options.reset) {
1322
- message = new AllReplicatingSegmentsMessage({
1323
- segments: addedOrReplaced.map((x) => x.range.toReplicationRange()),
1324
- });
1325
- } else {
1326
- message = new AddedReplicationSegmentMessage({
1327
- segments: addedOrReplaced.map((x) => x.range.toReplicationRange()),
1328
- });
1329
- }
1330
- if (options.announce) {
1331
- return options.announce(message);
1332
- } else {
1333
- await this.rpc.send(message, {
1334
- priority: 1,
1335
- });
1336
- }
1309
+ if (options.reset) {
1310
+ message = new AllReplicatingSegmentsMessage({
1311
+ segments: range.map((x) => x.toReplicationRange()),
1312
+ });
1313
+ } else {
1314
+ message = new AddedReplicationSegmentMessage({
1315
+ segments: range.map((x) => x.toReplicationRange()),
1316
+ });
1317
+ }
1318
+ if (options.announce) {
1319
+ return options.announce(message);
1320
+ } else {
1321
+ await this.rpc.send(message, {
1322
+ priority: 1,
1323
+ });
1337
1324
  }
1338
1325
  }
1339
1326
  }
@@ -2297,7 +2284,10 @@ export class SharedLog<
2297
2284
  }
2298
2285
 
2299
2286
  if (isLeader) {
2287
+ //console.log("IS LEADER", this.node.identity.publicKey.hashcode(), hash);
2288
+
2300
2289
  hasAndIsLeader.push(hash);
2290
+
2301
2291
  hasAndIsLeader.length > 0 &&
2302
2292
  this.responseToPruneDebouncedFn.add({
2303
2293
  hashes: hasAndIsLeader,
@@ -2494,7 +2484,6 @@ export class SharedLog<
2494
2484
  msg.segmentIds,
2495
2485
  context.from,
2496
2486
  );
2497
-
2498
2487
  await this.removeReplicationRanges(rangesToRemove, context.from);
2499
2488
  const timestamp = BigInt(+new Date());
2500
2489
  for (const range of rangesToRemove) {
@@ -3646,6 +3635,7 @@ export class SharedLog<
3646
3635
  });
3647
3636
  }
3648
3637
 
3638
+ // console.log("DELETE RESPONSE AS LEADER", this.node.identity.publicKey.hashcode(), entryReplicated.hash)
3649
3639
  this.responseToPruneDebouncedFn.delete(entryReplicated.hash); // don't allow others to prune because of expecting me to replicating this entry
3650
3640
  } else {
3651
3641
  this.pruneDebouncedFn.delete(entryReplicated.hash);
package/src/ranges.ts CHANGED
@@ -1019,112 +1019,68 @@ export const mergeRanges = <R extends "u32" | "u64">(
1019
1019
  throw new Error("Segments have different publicKeyHash");
1020
1020
  }
1021
1021
 
1022
- // 1) Sort by start offset (avoid subtracting bigints).
1023
- // We do slice() to avoid mutating the original 'segments'.
1024
- const sorted = segments.slice().sort((a, b) => {
1025
- if (a.start1 < b.start1) return -1;
1026
- if (a.start1 > b.start1) return 1;
1027
- return 0;
1028
- });
1029
-
1030
- // 2) Merge overlapping arcs in a purely functional way
1031
- // so we don’t mutate any intermediate objects.
1032
- const merged = sorted.reduce<ReplicationRangeIndexable<R>[]>(
1033
- (acc, current) => {
1034
- if (acc.length === 0) {
1035
- return [current];
1022
+ const sorted = segments.sort((a, b) => Number(a.start1 - b.start1));
1023
+
1024
+ let calculateLargeGap = (): [
1025
+ NumberFromType<R>,
1026
+ number,
1027
+ ReplicationIntent,
1028
+ ] => {
1029
+ let last = sorted[sorted.length - 1];
1030
+ let largestArc = numbers.zero;
1031
+ let largestArcIndex = -1;
1032
+ let mode = ReplicationIntent.NonStrict;
1033
+ for (let i = 0; i < sorted.length; i++) {
1034
+ const current = sorted[i];
1035
+
1036
+ if (current.mode === ReplicationIntent.Strict) {
1037
+ mode = ReplicationIntent.Strict;
1036
1038
  }
1037
1039
 
1038
- const last = acc[acc.length - 1];
1039
-
1040
- // Check overlap: next arc starts before (or exactly at) last arc's end => overlap
1041
- if (current.start1 <= last.end2) {
1042
- // Merge them:
1043
- // - end2 is the max of last.end2 and current.end2
1044
- // - width is adjusted so total covers both
1045
- // - mode is strict if either arc is strict
1046
- const newEnd2 = last.end2 > current.end2 ? last.end2 : current.end2;
1047
- const extendedWidth = Number(newEnd2 - last.start1); // safe if smaller arcs
1048
-
1049
- // If you need to handle big widths carefully, you might do BigInt logic here.
1050
- const newMode =
1051
- last.mode === ReplicationIntent.Strict ||
1052
- current.mode === ReplicationIntent.Strict
1053
- ? ReplicationIntent.Strict
1054
- : ReplicationIntent.NonStrict;
1055
-
1056
- // Create a new merged arc object (no mutation of last)
1057
- const proto = segments[0].constructor as any;
1058
- const mergedArc = new proto({
1059
- width: extendedWidth,
1060
- offset: last.start1,
1061
- publicKeyHash: last.hash,
1062
- mode: newMode,
1063
- id: last.id, // re-use id
1064
- });
1065
-
1066
- // Return a new array with the last item replaced by mergedArc
1067
- return [...acc.slice(0, -1), mergedArc];
1068
- } else {
1069
- // No overlap => just append current
1070
- return [...acc, current];
1071
- }
1072
- },
1073
- [],
1074
- );
1040
+ if (current.start1 !== last.start1) {
1041
+ let arc = numbers.zero;
1042
+ if (current.start1 < last.end2) {
1043
+ arc += ((numbers.maxValue as any) - last.end2) as any;
1075
1044
 
1076
- // After the merge pass:
1077
- if (merged.length === 1) {
1078
- // Everything merged into one arc already
1079
- return merged[0];
1080
- }
1081
-
1082
- // 3) OPTIONAL: If your existing logic always wants to produce a single ring arc
1083
- // that covers "everything except the largest gap," do it here:
1084
-
1085
- // Determine if any arc ended up Strict
1086
- const finalMode = merged.some((m) => m.mode === ReplicationIntent.Strict)
1087
- ? ReplicationIntent.Strict
1088
- : ReplicationIntent.NonStrict;
1089
-
1090
- // Find the largest gap on a ring among these disjoint arcs
1091
- const { largestGap, largestGapIndex } = merged.reduce<{
1092
- largestGap: NumberFromType<R>;
1093
- largestGapIndex: number;
1094
- }>(
1095
- (acc, arc, i, arr) => {
1096
- // next arc in a ring
1097
- const nextArc = arr[(i + 1) % arr.length];
1098
-
1099
- // measure gap from arc.end2 -> nextArc.start1
1100
- let gap: NumberFromType<R>;
1101
- if (nextArc.start1 < arc.end2) {
1102
- // wrap-around scenario
1103
- gap = (numbers.maxValue -
1104
- arc.end2 +
1105
- (nextArc.start1 - numbers.zero)) as NumberFromType<R>;
1106
- } else {
1107
- gap = (nextArc.start1 - arc.end2) as NumberFromType<R>;
1108
- }
1045
+ arc += (current.start1 - numbers.zero) as any;
1046
+ } else {
1047
+ arc += (current.start1 - last.end2) as any;
1048
+ }
1109
1049
 
1110
- if (gap > acc.largestGap) {
1111
- return { largestGap: gap, largestGapIndex: (i + 1) % arr.length };
1050
+ if (arc > largestArc) {
1051
+ largestArc = arc;
1052
+ largestArcIndex = i;
1053
+ }
1112
1054
  }
1113
- return acc;
1114
- },
1115
- { largestGap: numbers.zero, largestGapIndex: -1 },
1116
- );
1055
+ last = current;
1056
+ }
1057
+
1058
+ return [largestArc, largestArcIndex, mode];
1059
+ };
1060
+ const [largestArc, largestArcIndex, mode] = calculateLargeGap();
1061
+
1062
+ let totalLengthFinal: number = numbers.maxValue - largestArc;
1117
1063
 
1118
- // Single arc coverage = "the ring minus largestGap"
1119
- const totalCoverage = (numbers.maxValue - largestGap) as number;
1120
- const offset = merged[largestGapIndex].start1;
1064
+ const proto = segments[0].constructor;
1121
1065
 
1122
- const proto = segments[0].constructor as any;
1123
- return new proto({
1124
- width: totalCoverage,
1125
- offset,
1066
+ if (largestArcIndex === -1) {
1067
+ if (mode !== segments[0].mode) {
1068
+ return new (proto as any)({
1069
+ width: segments[0].width,
1070
+ offset: segments[0].start1,
1071
+ publicKeyHash: segments[0].hash,
1072
+ mode,
1073
+ });
1074
+ }
1075
+ return segments[0]; // all ranges are the same
1076
+ }
1077
+ // use segments[0] constructor to create a new object
1078
+
1079
+ return new (proto as any)({
1080
+ width: totalLengthFinal,
1081
+ offset: segments[largestArcIndex].start1,
1126
1082
  publicKeyHash: segments[0].hash,
1127
- mode: finalMode,
1083
+ mode,
1128
1084
  });
1129
1085
  };
1130
1086
 
@@ -1846,7 +1802,7 @@ export const getAllMergeCandiates = async <R extends "u32" | "u64">(
1846
1802
  id: Uint8Array;
1847
1803
  },
1848
1804
  numbers: Numbers<R>,
1849
- ): Promise<Map<string, ReplicationRangeIndexable<R>>> => {
1805
+ ): Promise<MapIterator<ReplicationRangeIndexable<R>>> => {
1850
1806
  const adjacent = await getAdjecentSameOwner(peers, range, numbers);
1851
1807
  const covering = await getCoveringRangesSameOwner(peers, range).all();
1852
1808
 
@@ -1860,7 +1816,7 @@ export const getAllMergeCandiates = async <R extends "u32" | "u64">(
1860
1816
  for (const range of covering) {
1861
1817
  ret.set(range.value.idString, range.value);
1862
1818
  }
1863
- return ret;
1819
+ return ret.values();
1864
1820
  };
1865
1821
 
1866
1822
  export const isMatured = (