@peerbit/shared-log 13.1.12 → 13.1.14
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/index.d.ts +11 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +76 -22
- package/dist/src/index.js.map +1 -1
- package/package.json +12 -12
- package/src/index.ts +134 -48
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/shared-log",
|
|
3
|
-
"version": "13.1.
|
|
3
|
+
"version": "13.1.14",
|
|
4
4
|
"description": "Shared log",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"type": "module",
|
|
@@ -62,27 +62,27 @@
|
|
|
62
62
|
"pino": "^9.4.0",
|
|
63
63
|
"uint8arrays": "^5.1.0",
|
|
64
64
|
"@peerbit/any-store": "2.2.9",
|
|
65
|
-
"@peerbit/blocks": "4.1.
|
|
65
|
+
"@peerbit/blocks": "4.1.6",
|
|
66
66
|
"@peerbit/blocks-interface": "2.0.11",
|
|
67
|
-
"@peerbit/cache": "3.0.0",
|
|
68
67
|
"@peerbit/crypto": "3.1.1",
|
|
69
|
-
"@peerbit/
|
|
68
|
+
"@peerbit/cache": "3.0.0",
|
|
70
69
|
"@peerbit/indexer-interface": "3.0.3",
|
|
70
|
+
"@peerbit/indexer-sqlite3": "3.0.6",
|
|
71
71
|
"@peerbit/logger": "2.0.1",
|
|
72
|
-
"@peerbit/program": "6.0.
|
|
73
|
-
"@peerbit/
|
|
74
|
-
"@peerbit/
|
|
75
|
-
"@peerbit/riblt": "1.2.0",
|
|
72
|
+
"@peerbit/program": "6.0.27",
|
|
73
|
+
"@peerbit/pubsub": "5.2.8",
|
|
74
|
+
"@peerbit/log": "6.0.33",
|
|
76
75
|
"@peerbit/pubsub-interface": "5.1.3",
|
|
77
|
-
"@peerbit/
|
|
78
|
-
"@peerbit/
|
|
79
|
-
"@peerbit/
|
|
76
|
+
"@peerbit/riblt": "1.2.0",
|
|
77
|
+
"@peerbit/stream-interface": "6.0.9",
|
|
78
|
+
"@peerbit/rpc": "6.0.31",
|
|
79
|
+
"@peerbit/time": "3.0.0"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
83
83
|
"@types/pidusage": "^2.0.5",
|
|
84
84
|
"uuid": "^10.0.0",
|
|
85
|
-
"@peerbit/test-utils": "3.0.
|
|
85
|
+
"@peerbit/test-utils": "3.0.31"
|
|
86
86
|
},
|
|
87
87
|
"repository": {
|
|
88
88
|
"type": "git",
|
package/src/index.ts
CHANGED
|
@@ -241,6 +241,12 @@ export { MAX_U32, MAX_U64, type NumberFromType };
|
|
|
241
241
|
export const logger = loggerFn("peerbit:shared-log");
|
|
242
242
|
const warn = logger.newScope("warn");
|
|
243
243
|
|
|
244
|
+
type CheckedPruneLeaderMap = Map<string, { intersecting: boolean }>;
|
|
245
|
+
type CheckedPruneEntry<T, R extends "u32" | "u64"> =
|
|
246
|
+
| Entry<T>
|
|
247
|
+
| ShallowEntry
|
|
248
|
+
| EntryReplicated<R>;
|
|
249
|
+
|
|
244
250
|
const getLatestEntry = (
|
|
245
251
|
entries: (ShallowOrFullEntry<any> | EntryWithRefs<any>)[],
|
|
246
252
|
) => {
|
|
@@ -859,8 +865,8 @@ export class SharedLog<
|
|
|
859
865
|
|
|
860
866
|
// A fn for debouncing the calls for pruning
|
|
861
867
|
pruneDebouncedFn!: DebouncedAccumulatorMap<{
|
|
862
|
-
entry:
|
|
863
|
-
leaders:
|
|
868
|
+
entry: CheckedPruneEntry<T, R>;
|
|
869
|
+
leaders: CheckedPruneLeaderMap;
|
|
864
870
|
}>;
|
|
865
871
|
private responseToPruneDebouncedFn!: ReturnType<
|
|
866
872
|
typeof debounceAccumulator<
|
|
@@ -3554,8 +3560,8 @@ export class SharedLog<
|
|
|
3554
3560
|
private async pruneDebouncedFnAddIfNotKeeping(args: {
|
|
3555
3561
|
key: string;
|
|
3556
3562
|
value: {
|
|
3557
|
-
entry:
|
|
3558
|
-
leaders:
|
|
3563
|
+
entry: CheckedPruneEntry<T, R>;
|
|
3564
|
+
leaders: CheckedPruneLeaderMap;
|
|
3559
3565
|
};
|
|
3560
3566
|
}): Promise<boolean> {
|
|
3561
3567
|
if (this.keep && (await this.keep(args.value.entry))) {
|
|
@@ -3565,6 +3571,75 @@ export class SharedLog<
|
|
|
3565
3571
|
return true;
|
|
3566
3572
|
}
|
|
3567
3573
|
|
|
3574
|
+
private async cancelCheckedPruneForLocalLeader(hash: string) {
|
|
3575
|
+
this.pruneDebouncedFn.delete(hash);
|
|
3576
|
+
this.clearCheckedPruneRetry(hash);
|
|
3577
|
+
this.removePruneRequestSent(hash);
|
|
3578
|
+
this._requestIPruneResponseReplicatorSet.delete(hash);
|
|
3579
|
+
await this._pendingDeletes
|
|
3580
|
+
.get(hash)
|
|
3581
|
+
?.reject(new Error("Failed to delete, is leader again"));
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
private hasActiveCheckedPruneWork(hash: string) {
|
|
3585
|
+
return (
|
|
3586
|
+
this._pendingDeletes.has(hash) ||
|
|
3587
|
+
this._requestIPruneSent.has(hash) ||
|
|
3588
|
+
this._requestIPruneResponseReplicatorSet.has(hash) ||
|
|
3589
|
+
this._checkedPruneRetries.has(hash)
|
|
3590
|
+
);
|
|
3591
|
+
}
|
|
3592
|
+
|
|
3593
|
+
private async resolveCheckedPruneLeaders(args: {
|
|
3594
|
+
hash: string;
|
|
3595
|
+
entry: CheckedPruneEntry<T, R>;
|
|
3596
|
+
leaders: CheckedPruneLeaderMap;
|
|
3597
|
+
selfReplicating?: boolean;
|
|
3598
|
+
}): Promise<{
|
|
3599
|
+
leaders: CheckedPruneLeaderMap;
|
|
3600
|
+
localLeader: boolean;
|
|
3601
|
+
}> {
|
|
3602
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3603
|
+
if (args.leaders.has(selfHash)) {
|
|
3604
|
+
if (args.selfReplicating === false) {
|
|
3605
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3606
|
+
}
|
|
3607
|
+
if (args.selfReplicating == null && !(await this.isReplicating())) {
|
|
3608
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3609
|
+
}
|
|
3610
|
+
return { leaders: args.leaders, localLeader: true };
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
if (!this.hasActiveCheckedPruneWork(args.hash)) {
|
|
3614
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3617
|
+
if (args.selfReplicating === false) {
|
|
3618
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3619
|
+
}
|
|
3620
|
+
if (args.selfReplicating == null && !(await this.isReplicating())) {
|
|
3621
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3622
|
+
}
|
|
3623
|
+
|
|
3624
|
+
try {
|
|
3625
|
+
const currentLeaders = await this.findLeadersFromEntry(
|
|
3626
|
+
args.entry,
|
|
3627
|
+
decodeReplicas(args.entry).getValue(this),
|
|
3628
|
+
);
|
|
3629
|
+
if (currentLeaders.size > 0) {
|
|
3630
|
+
return {
|
|
3631
|
+
leaders: currentLeaders,
|
|
3632
|
+
localLeader: currentLeaders.has(selfHash),
|
|
3633
|
+
};
|
|
3634
|
+
}
|
|
3635
|
+
} catch {
|
|
3636
|
+
// Best-effort only. If the fresh check fails, keep the original prune
|
|
3637
|
+
// decision instead of hiding a legitimately prunable entry.
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
return { leaders: args.leaders, localLeader: false };
|
|
3641
|
+
}
|
|
3642
|
+
|
|
3568
3643
|
private async pruneJoinedEntriesNoLongerLed(entries: Entry<T>[]) {
|
|
3569
3644
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3570
3645
|
for (const entry of entries) {
|
|
@@ -3579,10 +3654,7 @@ export class SharedLog<
|
|
|
3579
3654
|
);
|
|
3580
3655
|
|
|
3581
3656
|
if (leaders.has(selfHash)) {
|
|
3582
|
-
this.
|
|
3583
|
-
await this._pendingDeletes
|
|
3584
|
-
.get(entry.hash)
|
|
3585
|
-
?.reject(new Error("Failed to delete, is leader again"));
|
|
3657
|
+
await this.cancelCheckedPruneForLocalLeader(entry.hash);
|
|
3586
3658
|
continue;
|
|
3587
3659
|
}
|
|
3588
3660
|
|
|
@@ -3622,11 +3694,7 @@ export class SharedLog<
|
|
|
3622
3694
|
);
|
|
3623
3695
|
|
|
3624
3696
|
if (leaders.has(selfHash)) {
|
|
3625
|
-
this.
|
|
3626
|
-
await this._pendingDeletes
|
|
3627
|
-
.get(entryReplicated.hash)
|
|
3628
|
-
?.reject(new Error("Failed to delete, is leader again"));
|
|
3629
|
-
this.removePruneRequestSent(entryReplicated.hash);
|
|
3697
|
+
await this.cancelCheckedPruneForLocalLeader(entryReplicated.hash);
|
|
3630
3698
|
continue;
|
|
3631
3699
|
}
|
|
3632
3700
|
|
|
@@ -3663,8 +3731,8 @@ export class SharedLog<
|
|
|
3663
3731
|
}
|
|
3664
3732
|
|
|
3665
3733
|
private scheduleCheckedPruneRetry(args: {
|
|
3666
|
-
entry:
|
|
3667
|
-
leaders:
|
|
3734
|
+
entry: CheckedPruneEntry<T, R>;
|
|
3735
|
+
leaders: CheckedPruneLeaderMap | Set<string>;
|
|
3668
3736
|
}) {
|
|
3669
3737
|
if (this.closed) return;
|
|
3670
3738
|
if (this._pendingDeletes.has(args.entry.hash)) return;
|
|
@@ -3694,7 +3762,7 @@ export class SharedLog<
|
|
|
3694
3762
|
if (this.closed) return;
|
|
3695
3763
|
if (this._pendingDeletes.has(hash)) return;
|
|
3696
3764
|
|
|
3697
|
-
let leadersMap:
|
|
3765
|
+
let leadersMap: CheckedPruneLeaderMap | undefined;
|
|
3698
3766
|
try {
|
|
3699
3767
|
const replicas = decodeReplicas(args.entry).getValue(this);
|
|
3700
3768
|
leadersMap = await this.findLeadersFromEntry(args.entry, replicas, {
|
|
@@ -3704,27 +3772,27 @@ export class SharedLog<
|
|
|
3704
3772
|
// Best-effort only.
|
|
3705
3773
|
}
|
|
3706
3774
|
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
}
|
|
3775
|
+
if (!leadersMap || leadersMap.size === 0) {
|
|
3776
|
+
if (args.leaders instanceof Map) {
|
|
3777
|
+
leadersMap = args.leaders;
|
|
3778
|
+
} else {
|
|
3779
|
+
leadersMap = new Map<string, { intersecting: boolean }>();
|
|
3780
|
+
for (const k of args.leaders) {
|
|
3781
|
+
leadersMap.set(k, { intersecting: true });
|
|
3715
3782
|
}
|
|
3716
3783
|
}
|
|
3784
|
+
}
|
|
3717
3785
|
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3786
|
+
try {
|
|
3787
|
+
const leadersForRetry =
|
|
3788
|
+
leadersMap ?? new Map<string, { intersecting: boolean }>();
|
|
3789
|
+
await this.pruneDebouncedFnAddIfNotKeeping({
|
|
3790
|
+
key: hash,
|
|
3791
|
+
value: { entry: args.entry, leaders: leadersForRetry },
|
|
3792
|
+
});
|
|
3793
|
+
} catch {
|
|
3794
|
+
// Best-effort only; pruning will be re-attempted on future changes.
|
|
3795
|
+
}
|
|
3728
3796
|
}, delayMs);
|
|
3729
3797
|
state.timer.unref?.();
|
|
3730
3798
|
this._checkedPruneRetries.set(hash, state);
|
|
@@ -4084,8 +4152,34 @@ export class SharedLog<
|
|
|
4084
4152
|
);
|
|
4085
4153
|
|
|
4086
4154
|
this.pruneDebouncedFn = debouncedAccumulatorMap(
|
|
4087
|
-
(map) => {
|
|
4088
|
-
|
|
4155
|
+
async (map) => {
|
|
4156
|
+
const current = new Map<
|
|
4157
|
+
string,
|
|
4158
|
+
{
|
|
4159
|
+
entry: CheckedPruneEntry<T, R>;
|
|
4160
|
+
leaders: CheckedPruneLeaderMap;
|
|
4161
|
+
}
|
|
4162
|
+
>();
|
|
4163
|
+
const selfReplicating = await this.isReplicating();
|
|
4164
|
+
for (const [hash, value] of map) {
|
|
4165
|
+
const checkedPruneLeaders = await this.resolveCheckedPruneLeaders({
|
|
4166
|
+
hash,
|
|
4167
|
+
entry: value.entry,
|
|
4168
|
+
leaders: value.leaders,
|
|
4169
|
+
selfReplicating,
|
|
4170
|
+
});
|
|
4171
|
+
if (checkedPruneLeaders.localLeader) {
|
|
4172
|
+
await this.cancelCheckedPruneForLocalLeader(hash);
|
|
4173
|
+
continue;
|
|
4174
|
+
}
|
|
4175
|
+
current.set(hash, {
|
|
4176
|
+
...value,
|
|
4177
|
+
leaders: checkedPruneLeaders.leaders,
|
|
4178
|
+
});
|
|
4179
|
+
}
|
|
4180
|
+
if (current.size > 0) {
|
|
4181
|
+
this.prune(current);
|
|
4182
|
+
}
|
|
4089
4183
|
},
|
|
4090
4184
|
PRUNE_DEBOUNCE_INTERVAL, // TODO make this dynamic on the number of replicators
|
|
4091
4185
|
(into, from) => {
|
|
@@ -6943,8 +7037,8 @@ export class SharedLog<
|
|
|
6943
7037
|
entries: Map<
|
|
6944
7038
|
string,
|
|
6945
7039
|
{
|
|
6946
|
-
entry:
|
|
6947
|
-
leaders:
|
|
7040
|
+
entry: CheckedPruneEntry<T, R>;
|
|
7041
|
+
leaders: CheckedPruneLeaderMap | Set<string>;
|
|
6948
7042
|
}
|
|
6949
7043
|
>,
|
|
6950
7044
|
options?: { timeout?: number; unchecked?: boolean },
|
|
@@ -7553,11 +7647,7 @@ export class SharedLog<
|
|
|
7553
7647
|
|
|
7554
7648
|
this.responseToPruneDebouncedFn.delete(entryReplicated.hash);
|
|
7555
7649
|
} else {
|
|
7556
|
-
this.
|
|
7557
|
-
await this._pendingDeletes
|
|
7558
|
-
.get(entryReplicated.hash)
|
|
7559
|
-
?.reject(new Error("Failed to delete, is leader again"));
|
|
7560
|
-
this.removePruneRequestSent(entryReplicated.hash);
|
|
7650
|
+
await this.cancelCheckedPruneForLocalLeader(entryReplicated.hash);
|
|
7561
7651
|
}
|
|
7562
7652
|
continue;
|
|
7563
7653
|
}
|
|
@@ -7627,11 +7717,7 @@ export class SharedLog<
|
|
|
7627
7717
|
|
|
7628
7718
|
this.responseToPruneDebouncedFn.delete(entryReplicated.hash); // don't allow others to prune because of expecting me to replicating this entry
|
|
7629
7719
|
} else {
|
|
7630
|
-
this.
|
|
7631
|
-
await this._pendingDeletes
|
|
7632
|
-
.get(entryReplicated.hash)
|
|
7633
|
-
?.reject(new Error("Failed to delete, is leader again"));
|
|
7634
|
-
this.removePruneRequestSent(entryReplicated.hash);
|
|
7720
|
+
await this.cancelCheckedPruneForLocalLeader(entryReplicated.hash);
|
|
7635
7721
|
}
|
|
7636
7722
|
}
|
|
7637
7723
|
}
|