@peerbit/shared-log 7.0.10 → 8.0.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/lib/esm/exchange-heads.js +1 -1
- package/lib/esm/exchange-heads.js.map +1 -1
- package/lib/esm/index.d.ts +17 -5
- package/lib/esm/index.js +131 -61
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/pid.d.ts +1 -1
- package/lib/esm/pid.js +1 -1
- package/lib/esm/pid.js.map +1 -1
- package/lib/esm/ranges.d.ts +8 -1
- package/lib/esm/ranges.js +145 -67
- package/lib/esm/ranges.js.map +1 -1
- package/lib/esm/role.d.ts +1 -4
- package/lib/esm/role.js +1 -17
- package/lib/esm/role.js.map +1 -1
- package/package.json +6 -6
- package/src/exchange-heads.ts +1 -1
- package/src/index.ts +165 -80
- package/src/pid.ts +2 -9
- package/src/ranges.ts +201 -89
- package/src/role.ts +2 -24
package/lib/esm/role.d.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
offset: number;
|
|
3
|
-
factor: number;
|
|
4
|
-
}, point: number) => boolean;
|
|
1
|
+
export declare const overlaps: (x1: number, x2: number, y1: number, y2: number) => boolean;
|
|
5
2
|
export declare abstract class Role {
|
|
6
3
|
abstract equals(other: Role): any;
|
|
7
4
|
}
|
package/lib/esm/role.js
CHANGED
|
@@ -9,23 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
var NoType_1, Observer_1, Replicator_1;
|
|
11
11
|
import { field, variant, vec } from "@dao-xyz/borsh";
|
|
12
|
-
export const
|
|
13
|
-
if (rect.factor === 0) {
|
|
14
|
-
return false;
|
|
15
|
-
}
|
|
16
|
-
const start = rect.offset;
|
|
17
|
-
const endUnwrapped = rect.offset + rect.factor;
|
|
18
|
-
let end = endUnwrapped;
|
|
19
|
-
let wrapped = false;
|
|
20
|
-
if (endUnwrapped > 1) {
|
|
21
|
-
end = endUnwrapped % 1;
|
|
22
|
-
wrapped = true;
|
|
23
|
-
}
|
|
24
|
-
const inFirstInterval = point >= start && point < Math.min(endUnwrapped, 1);
|
|
25
|
-
const inSecondInterval = !inFirstInterval && wrapped && point >= 0 && point < end;
|
|
26
|
-
return inFirstInterval || inSecondInterval;
|
|
27
|
-
};
|
|
28
|
-
const overlaps = (x1, x2, y1, y2) => {
|
|
12
|
+
export const overlaps = (x1, x2, y1, y2) => {
|
|
29
13
|
if (x1 <= y2 && y1 <= x2) {
|
|
30
14
|
return true;
|
|
31
15
|
}
|
package/lib/esm/role.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role.js","sourceRoot":"","sources":["../../src/role.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"role.js","sourceRoot":"","sources":["../../src/role.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/shared-log",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "Shared log",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@dao-xyz/borsh": "^5.2.1",
|
|
34
|
-
"@peerbit/log": "3.0.
|
|
34
|
+
"@peerbit/log": "3.0.27",
|
|
35
35
|
"@peerbit/logger": "1.0.2",
|
|
36
|
-
"@peerbit/program": "
|
|
37
|
-
"@peerbit/rpc": "
|
|
36
|
+
"@peerbit/program": "4.0.0",
|
|
37
|
+
"@peerbit/rpc": "4.0.0",
|
|
38
38
|
"@peerbit/time": "2.0.6",
|
|
39
39
|
"p-debounce": "^4.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@peerbit/test-utils": "^2.0.
|
|
42
|
+
"@peerbit/test-utils": "^2.0.26"
|
|
43
43
|
},
|
|
44
|
-
"gitHead": "
|
|
44
|
+
"gitHead": "9536898b1f74d42c4f97183b864945fa29422d3e"
|
|
45
45
|
}
|
package/src/exchange-heads.ts
CHANGED
|
@@ -86,7 +86,7 @@ export class ResponseIPrune extends TransportMessage {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
const MAX_EXCHANGE_MESSAGE_SIZE =
|
|
89
|
+
const MAX_EXCHANGE_MESSAGE_SIZE = 1e5; // 100kb. Too large size might not be faster (even if we can do 5mb)
|
|
90
90
|
|
|
91
91
|
export const createExchangeHeadsMessages = async (
|
|
92
92
|
log: Log<any>,
|
package/src/index.ts
CHANGED
|
@@ -51,7 +51,6 @@ import yallist from "yallist";
|
|
|
51
51
|
import {
|
|
52
52
|
AcknowledgeDelivery,
|
|
53
53
|
DeliveryMode,
|
|
54
|
-
SeekDelivery,
|
|
55
54
|
SilentDelivery,
|
|
56
55
|
NotStartedError
|
|
57
56
|
} from "@peerbit/stream-interface";
|
|
@@ -62,7 +61,7 @@ import { PIDReplicationController } from "./pid.js";
|
|
|
62
61
|
export * from "./replication.js";
|
|
63
62
|
import PQueue from "p-queue";
|
|
64
63
|
import { CPUUsage, CPUUsageIntervalLag } from "./cpu.js";
|
|
65
|
-
import {
|
|
64
|
+
import { getCoverSet, getSamples, isMatured } from "./ranges.js";
|
|
66
65
|
export { type CPUUsage, CPUUsageIntervalLag };
|
|
67
66
|
export { Observer, Replicator, Role };
|
|
68
67
|
|
|
@@ -92,20 +91,20 @@ export type ReplicationLimitsOptions =
|
|
|
92
91
|
|
|
93
92
|
type StringRoleOptions = "observer" | "replicator";
|
|
94
93
|
|
|
95
|
-
type AdaptiveReplicatorOptions = {
|
|
94
|
+
export type AdaptiveReplicatorOptions = {
|
|
96
95
|
type: "replicator";
|
|
97
96
|
limits?: {
|
|
98
|
-
|
|
97
|
+
storage?: number;
|
|
99
98
|
cpu?: number | { max: number; monitor?: CPUUsage };
|
|
100
99
|
};
|
|
101
100
|
};
|
|
102
101
|
|
|
103
|
-
type FixedReplicatorOptions = {
|
|
102
|
+
export type FixedReplicatorOptions = {
|
|
104
103
|
type: "replicator";
|
|
105
104
|
factor: number;
|
|
106
105
|
};
|
|
107
106
|
|
|
108
|
-
type ObserverType = {
|
|
107
|
+
export type ObserverType = {
|
|
109
108
|
type: "observer";
|
|
110
109
|
};
|
|
111
110
|
|
|
@@ -167,7 +166,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
167
166
|
|
|
168
167
|
// options
|
|
169
168
|
private _role: Observer | Replicator;
|
|
170
|
-
private
|
|
169
|
+
private _roleConfig: AdaptiveReplicatorOptions | Observer | Replicator;
|
|
171
170
|
private _sortedPeersCache: yallist<ReplicatorRect> | undefined;
|
|
172
171
|
private _totalParticipation: number;
|
|
173
172
|
private _gidPeersHistory: Map<string, Set<string>>;
|
|
@@ -204,6 +203,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
204
203
|
private remoteBlocks: RemoteBlocks;
|
|
205
204
|
|
|
206
205
|
private openTime: number;
|
|
206
|
+
private oldestOpenTime: number;
|
|
207
207
|
|
|
208
208
|
private sync?: (entry: Entry<T>) => boolean;
|
|
209
209
|
|
|
@@ -219,6 +219,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
219
219
|
private syncMoreInterval?: ReturnType<typeof setTimeout>;
|
|
220
220
|
private syncInFlightQueue: Map<string, PublicSignKey[]>;
|
|
221
221
|
private syncInFlightQueueInverted: Map<string, Set<string>>;
|
|
222
|
+
private syncInFlight: Map<string, Map<string, { timestamp: number }>>;
|
|
222
223
|
|
|
223
224
|
replicas: ReplicationLimits;
|
|
224
225
|
|
|
@@ -233,10 +234,20 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
233
234
|
this.rpc = new RPC();
|
|
234
235
|
}
|
|
235
236
|
|
|
237
|
+
/**
|
|
238
|
+
* Returns the current role
|
|
239
|
+
*/
|
|
236
240
|
get role(): Observer | Replicator {
|
|
237
241
|
return this._role;
|
|
238
242
|
}
|
|
239
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Return the
|
|
246
|
+
*/
|
|
247
|
+
get roleConfig(): Observer | Replicator | AdaptiveReplicatorOptions {
|
|
248
|
+
return this._roleConfig;
|
|
249
|
+
}
|
|
250
|
+
|
|
240
251
|
get totalParticipation(): number {
|
|
241
252
|
return this._totalParticipation;
|
|
242
253
|
}
|
|
@@ -261,9 +272,9 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
261
272
|
this.replicationController = new PIDReplicationController(
|
|
262
273
|
this.node.identity.publicKey.hashcode(),
|
|
263
274
|
{
|
|
264
|
-
|
|
265
|
-
options?.limits?.
|
|
266
|
-
? { max: options?.limits?.
|
|
275
|
+
storage:
|
|
276
|
+
options?.limits?.storage != null
|
|
277
|
+
? { max: options?.limits?.storage }
|
|
267
278
|
: undefined,
|
|
268
279
|
cpu:
|
|
269
280
|
options?.limits?.cpu != null
|
|
@@ -289,49 +300,49 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
289
300
|
if (options instanceof Observer || options instanceof Replicator) {
|
|
290
301
|
throw new Error("Unsupported role option type");
|
|
291
302
|
} else if (options === "observer") {
|
|
292
|
-
this.
|
|
303
|
+
this._roleConfig = new Observer();
|
|
293
304
|
} else if (options === "replicator") {
|
|
294
305
|
setupDebouncedRebalancing();
|
|
295
|
-
this.
|
|
306
|
+
this._roleConfig = { type: options };
|
|
296
307
|
} else if (options) {
|
|
297
308
|
if (options.type === "replicator") {
|
|
298
309
|
if (isAdaptiveReplicatorOption(options)) {
|
|
299
310
|
setupDebouncedRebalancing(options);
|
|
300
|
-
this.
|
|
311
|
+
this._roleConfig = options;
|
|
301
312
|
} else {
|
|
302
|
-
this.
|
|
313
|
+
this._roleConfig = new Replicator({
|
|
303
314
|
factor: options.factor,
|
|
304
|
-
offset:
|
|
315
|
+
offset: this.getReplicationOffset()
|
|
305
316
|
});
|
|
306
317
|
}
|
|
307
318
|
} else {
|
|
308
|
-
this.
|
|
319
|
+
this._roleConfig = new Observer();
|
|
309
320
|
}
|
|
310
321
|
} else {
|
|
311
322
|
// Default option
|
|
312
323
|
setupDebouncedRebalancing();
|
|
313
|
-
this.
|
|
324
|
+
this._roleConfig = { type: "replicator" };
|
|
314
325
|
}
|
|
315
326
|
|
|
316
327
|
// setup the initial role
|
|
317
328
|
|
|
318
329
|
if (
|
|
319
|
-
this.
|
|
320
|
-
this.
|
|
330
|
+
this._roleConfig instanceof Replicator ||
|
|
331
|
+
this._roleConfig instanceof Observer
|
|
321
332
|
) {
|
|
322
|
-
this._role = this.
|
|
333
|
+
this._role = this._roleConfig as Replicator | Observer;
|
|
323
334
|
} else {
|
|
324
335
|
// initial role in a dynamic setup
|
|
325
336
|
|
|
326
|
-
if (this.
|
|
337
|
+
if (this._roleConfig?.limits) {
|
|
327
338
|
this._role = new Replicator({
|
|
328
339
|
factor: this._role instanceof Replicator ? this._role.factor : 0,
|
|
329
|
-
offset:
|
|
340
|
+
offset: this.getReplicationOffset()
|
|
330
341
|
});
|
|
331
342
|
} else {
|
|
332
343
|
this._role = new Replicator({
|
|
333
344
|
factor: this._role instanceof Replicator ? this._role.factor : 1,
|
|
334
|
-
offset:
|
|
345
|
+
offset: this.getReplicationOffset()
|
|
335
346
|
});
|
|
336
347
|
}
|
|
337
348
|
}
|
|
@@ -354,12 +365,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
354
365
|
);
|
|
355
366
|
|
|
356
367
|
await this.rpc.subscribe();
|
|
357
|
-
|
|
358
|
-
await this.rpc.send(new ResponseRoleMessage({ role: this._role }), {
|
|
359
|
-
mode: new SeekDelivery({
|
|
360
|
-
redundancy: 1
|
|
361
|
-
})
|
|
362
|
-
});
|
|
368
|
+
await this.rpc.send(new ResponseRoleMessage({ role: this._role }));
|
|
363
369
|
|
|
364
370
|
if (onRoleChange && changed !== "none") {
|
|
365
371
|
this.onRoleChange(this._role, this.node.identity.publicKey);
|
|
@@ -418,6 +424,15 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
418
424
|
}
|
|
419
425
|
leaders = newAndOldLeaders;
|
|
420
426
|
}
|
|
427
|
+
let set = this._gidPeersHistory.get(result.entry.meta.gid);
|
|
428
|
+
if (!set) {
|
|
429
|
+
set = new Set(leaders);
|
|
430
|
+
this._gidPeersHistory.set(result.entry.meta.gid, set);
|
|
431
|
+
} else {
|
|
432
|
+
for (const receiver of leaders) {
|
|
433
|
+
set.add(receiver);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
421
436
|
mode = isLeader
|
|
422
437
|
? new SilentDelivery({ redundancy: 1, to: leaders })
|
|
423
438
|
: new AcknowledgeDelivery({ redundancy: 1, to: leaders });
|
|
@@ -453,7 +468,9 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
453
468
|
this.latestRoleMessages = new Map();
|
|
454
469
|
this.syncInFlightQueue = new Map();
|
|
455
470
|
this.syncInFlightQueueInverted = new Map();
|
|
471
|
+
this.syncInFlight = new Map();
|
|
456
472
|
this.openTime = +new Date();
|
|
473
|
+
this.oldestOpenTime = this.openTime;
|
|
457
474
|
this.timeUntilRoleMaturity =
|
|
458
475
|
options?.timeUntilRoleMaturity || WAIT_FOR_ROLE_MATURITY;
|
|
459
476
|
this.waitForReplicatorTimeout =
|
|
@@ -467,7 +484,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
467
484
|
this.setupRole(options?.role);
|
|
468
485
|
|
|
469
486
|
const id = sha256Base64Sync(this.log.id);
|
|
470
|
-
const storage = await this.node.
|
|
487
|
+
const storage = await this.node.storage.sublevel(id);
|
|
471
488
|
|
|
472
489
|
const localBlocks = await new AnyBlockStore(
|
|
473
490
|
await storage.sublevel("blocks")
|
|
@@ -590,21 +607,25 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
590
607
|
this.syncInFlightQueue.delete(key);
|
|
591
608
|
}
|
|
592
609
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
{
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
)
|
|
602
|
-
.finally(() => {
|
|
603
|
-
if (this.closed) {
|
|
604
|
-
return;
|
|
610
|
+
|
|
611
|
+
const nowMin10s = +new Date() - 1e4;
|
|
612
|
+
for (const [key, map] of this.syncInFlight) {
|
|
613
|
+
// cleanup "old" missing syncs
|
|
614
|
+
for (const [hash, { timestamp }] of map) {
|
|
615
|
+
if (timestamp < nowMin10s) {
|
|
616
|
+
map.delete(hash);
|
|
605
617
|
}
|
|
606
|
-
|
|
607
|
-
|
|
618
|
+
}
|
|
619
|
+
if (map.size === 0) {
|
|
620
|
+
this.syncInFlight.delete(key);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
this.requestSync(requestHashes, from).finally(() => {
|
|
624
|
+
if (this.closed) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
this.syncMoreInterval = setTimeout(requestSync, 1e4);
|
|
628
|
+
});
|
|
608
629
|
};
|
|
609
630
|
requestSync();
|
|
610
631
|
}
|
|
@@ -668,6 +689,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
668
689
|
this._pendingIHave.clear();
|
|
669
690
|
this.syncInFlightQueue.clear();
|
|
670
691
|
this.syncInFlightQueueInverted.clear();
|
|
692
|
+
this.syncInFlight.clear();
|
|
671
693
|
this.latestRoleMessages.clear();
|
|
672
694
|
this._gidPeersHistory.clear();
|
|
673
695
|
|
|
@@ -824,6 +846,17 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
824
846
|
this.rebalanceParticipationDebounced?.();
|
|
825
847
|
}
|
|
826
848
|
|
|
849
|
+
/// we clear sync in flight here because we want to join before that, so that entries are totally accounted for
|
|
850
|
+
for (const head of heads) {
|
|
851
|
+
const set = this.syncInFlight.get(context.from.hashcode());
|
|
852
|
+
if (set) {
|
|
853
|
+
set.delete(head.entry.hash);
|
|
854
|
+
if (set?.size === 0) {
|
|
855
|
+
this.syncInFlight.delete(context.from.hashcode());
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
827
860
|
if (maybeDelete) {
|
|
828
861
|
for (const entries of maybeDelete as EntryWithRefs<any>[][]) {
|
|
829
862
|
const headsWithGid = this.log.headsIndex.gids.get(
|
|
@@ -930,18 +963,11 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
930
963
|
inverted.add(hash);
|
|
931
964
|
} else if (!this.log.has(hash)) {
|
|
932
965
|
this.syncInFlightQueue.set(hash, []);
|
|
933
|
-
requestHashes.push(hash);
|
|
966
|
+
requestHashes.push(hash); // request immediately (first time we have seen this hash)
|
|
934
967
|
}
|
|
935
968
|
}
|
|
936
969
|
|
|
937
|
-
await this.
|
|
938
|
-
new ResponseMaybeSync({
|
|
939
|
-
hashes: requestHashes
|
|
940
|
-
}),
|
|
941
|
-
{
|
|
942
|
-
mode: new SilentDelivery({ to: [context.from], redundancy: 1 })
|
|
943
|
-
}
|
|
944
|
-
);
|
|
970
|
+
await this.requestSync(requestHashes, [context.from.hashcode()]);
|
|
945
971
|
} else if (msg instanceof ResponseMaybeSync) {
|
|
946
972
|
// TODO better choice of step size
|
|
947
973
|
const entries = (
|
|
@@ -1042,10 +1068,12 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1042
1068
|
async waitForReplicator(...keys: PublicSignKey[]) {
|
|
1043
1069
|
const check = () => {
|
|
1044
1070
|
for (const k of keys) {
|
|
1071
|
+
const rect = this.getReplicatorsSorted()
|
|
1072
|
+
?.toArray()
|
|
1073
|
+
?.find((x) => x.publicKey.equals(k));
|
|
1045
1074
|
if (
|
|
1046
|
-
!
|
|
1047
|
-
|
|
1048
|
-
?.find((x) => x.publicKey.equals(k))
|
|
1075
|
+
!rect ||
|
|
1076
|
+
!isMatured(rect.role, +new Date(), this.getDefaultMinRoleAge())
|
|
1049
1077
|
) {
|
|
1050
1078
|
return false;
|
|
1051
1079
|
}
|
|
@@ -1069,6 +1097,10 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1069
1097
|
return !!isLeader;
|
|
1070
1098
|
}
|
|
1071
1099
|
|
|
1100
|
+
private getReplicationOffset() {
|
|
1101
|
+
return hashToUniformNumber(this.node.identity.publicKey.bytes);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1072
1104
|
private async waitForIsLeader(
|
|
1073
1105
|
slot: { toString(): string },
|
|
1074
1106
|
numberOfLeaders: number,
|
|
@@ -1137,6 +1169,17 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1137
1169
|
return this.findLeadersFromUniformNumber(cursor, numberOfLeaders, options);
|
|
1138
1170
|
}
|
|
1139
1171
|
|
|
1172
|
+
getDefaultMinRoleAge(): number {
|
|
1173
|
+
const now = +new Date();
|
|
1174
|
+
const replLength = this.getReplicatorsSorted()!.length;
|
|
1175
|
+
const diffToOldest =
|
|
1176
|
+
replLength > 1 ? now - this.oldestOpenTime - 1 : Number.MAX_SAFE_INTEGER;
|
|
1177
|
+
return Math.min(
|
|
1178
|
+
this.timeUntilRoleMaturity,
|
|
1179
|
+
diffToOldest,
|
|
1180
|
+
(this.timeUntilRoleMaturity * Math.log(replLength)) / 3
|
|
1181
|
+
); // / 3 so that if 2 replicators and timeUntilRoleMaturity = 1e4 the result will be 1
|
|
1182
|
+
}
|
|
1140
1183
|
private findLeadersFromUniformNumber(
|
|
1141
1184
|
cursor: number,
|
|
1142
1185
|
numberOfLeaders: number,
|
|
@@ -1144,33 +1187,26 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1144
1187
|
roleAge?: number;
|
|
1145
1188
|
}
|
|
1146
1189
|
) {
|
|
1147
|
-
const
|
|
1148
|
-
const width = 1;
|
|
1149
|
-
const peers = this.getReplicatorsSorted();
|
|
1150
|
-
if (!peers || peers?.length === 0) {
|
|
1151
|
-
return [];
|
|
1152
|
-
}
|
|
1153
|
-
numberOfLeaders = Math.min(numberOfLeaders, peers.length);
|
|
1190
|
+
const roleAge = options?.roleAge ?? this.getDefaultMinRoleAge(); // TODO -500 as is added so that i f someone else is just as new as us, then we treat them as mature as us. without -500 we might be slower syncing if two nodes starts almost at the same time
|
|
1154
1191
|
|
|
1155
|
-
const
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
}
|
|
1192
|
+
const sampes = getSamples(
|
|
1193
|
+
cursor,
|
|
1194
|
+
this.getReplicatorsSorted()!,
|
|
1195
|
+
numberOfLeaders,
|
|
1196
|
+
roleAge,
|
|
1197
|
+
this.role instanceof Replicator && this.role.factor === 0
|
|
1198
|
+
? this.node.identity.publicKey.hashcode()
|
|
1199
|
+
: undefined
|
|
1200
|
+
);
|
|
1165
1201
|
|
|
1166
|
-
return
|
|
1202
|
+
return sampes;
|
|
1167
1203
|
}
|
|
1168
1204
|
|
|
1169
1205
|
/**
|
|
1170
1206
|
*
|
|
1171
1207
|
* @returns groups where at least one in any group will have the entry you are looking for
|
|
1172
1208
|
*/
|
|
1173
|
-
getReplicatorUnion(roleAge: number = this.
|
|
1209
|
+
getReplicatorUnion(roleAge: number = this.getDefaultMinRoleAge()) {
|
|
1174
1210
|
if (this.closed === true) {
|
|
1175
1211
|
throw new Error("Closed");
|
|
1176
1212
|
}
|
|
@@ -1192,12 +1228,18 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1192
1228
|
// the entry we are looking for
|
|
1193
1229
|
const coveringWidth = width / minReplicas;
|
|
1194
1230
|
|
|
1195
|
-
|
|
1231
|
+
const set = getCoverSet(
|
|
1196
1232
|
coveringWidth,
|
|
1197
1233
|
peers,
|
|
1198
1234
|
roleAge,
|
|
1199
1235
|
this.role instanceof Replicator ? this.node.identity.publicKey : undefined
|
|
1200
1236
|
);
|
|
1237
|
+
|
|
1238
|
+
// add all in flight
|
|
1239
|
+
for (const [key, _] of this.syncInFlight) {
|
|
1240
|
+
set.add(key);
|
|
1241
|
+
}
|
|
1242
|
+
return [...set];
|
|
1201
1243
|
}
|
|
1202
1244
|
|
|
1203
1245
|
async replicator(
|
|
@@ -1255,7 +1297,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1255
1297
|
await this.rebalanceParticipationDebounced?.(); /* await this.rebalanceParticipation(false); */
|
|
1256
1298
|
if (update.changed === "added") {
|
|
1257
1299
|
await this.rpc.send(new ResponseRoleMessage({ role: this._role }), {
|
|
1258
|
-
mode: new
|
|
1300
|
+
mode: new SilentDelivery({
|
|
1259
1301
|
to: [publicKey.hashcode()],
|
|
1260
1302
|
redundancy: 1
|
|
1261
1303
|
})
|
|
@@ -1303,6 +1345,10 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1303
1345
|
// TODO should we remove replicators if they are already added?
|
|
1304
1346
|
return { changed: "none" };
|
|
1305
1347
|
}
|
|
1348
|
+
this.oldestOpenTime = Math.min(
|
|
1349
|
+
this.oldestOpenTime,
|
|
1350
|
+
Number(role.timestamp)
|
|
1351
|
+
);
|
|
1306
1352
|
|
|
1307
1353
|
// insert or if already there do nothing
|
|
1308
1354
|
const rect: ReplicatorRect = {
|
|
@@ -1380,13 +1426,29 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1380
1426
|
for (const [_a, b] of this._gidPeersHistory) {
|
|
1381
1427
|
b.delete(publicKey.hashcode());
|
|
1382
1428
|
}
|
|
1429
|
+
this.syncInFlight.delete(publicKey.hashcode());
|
|
1430
|
+
const waitingHashes = this.syncInFlightQueueInverted.get(
|
|
1431
|
+
publicKey.hashcode()
|
|
1432
|
+
);
|
|
1433
|
+
if (waitingHashes) {
|
|
1434
|
+
for (const hash of waitingHashes) {
|
|
1435
|
+
let arr = this.syncInFlightQueue.get(hash);
|
|
1436
|
+
if (arr) {
|
|
1437
|
+
arr = arr.filter((x) => !x.equals(publicKey));
|
|
1438
|
+
}
|
|
1439
|
+
if (this.syncInFlightQueue.size === 0) {
|
|
1440
|
+
this.syncInFlightQueue.delete(hash);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
this.syncInFlightQueueInverted.delete(publicKey.hashcode());
|
|
1383
1445
|
}
|
|
1384
1446
|
|
|
1385
1447
|
if (subscribed) {
|
|
1386
1448
|
if (this.role instanceof Replicator) {
|
|
1387
1449
|
this.rpc
|
|
1388
1450
|
.send(new ResponseRoleMessage({ role: this._role }), {
|
|
1389
|
-
mode: new
|
|
1451
|
+
mode: new SilentDelivery({ redundancy: 1, to: [publicKey] })
|
|
1390
1452
|
})
|
|
1391
1453
|
.catch((e) => logger.error(e.toString()));
|
|
1392
1454
|
}
|
|
@@ -1637,6 +1699,29 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1637
1699
|
return changed;
|
|
1638
1700
|
}
|
|
1639
1701
|
|
|
1702
|
+
private async requestSync(hashes: string[], to: Set<string> | string[]) {
|
|
1703
|
+
const now = +new Date();
|
|
1704
|
+
for (const node of to) {
|
|
1705
|
+
let map = this.syncInFlight.get(node);
|
|
1706
|
+
if (!map) {
|
|
1707
|
+
map = new Map();
|
|
1708
|
+
this.syncInFlight.set(node, map);
|
|
1709
|
+
}
|
|
1710
|
+
for (const hash of hashes) {
|
|
1711
|
+
map.set(hash, { timestamp: now });
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
await this.rpc.send(
|
|
1716
|
+
new ResponseMaybeSync({
|
|
1717
|
+
hashes: hashes
|
|
1718
|
+
}),
|
|
1719
|
+
{
|
|
1720
|
+
mode: new SilentDelivery({ to, redundancy: 1 })
|
|
1721
|
+
}
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1640
1725
|
async _onUnsubscription(evt: CustomEvent<UnsubcriptionEvent>) {
|
|
1641
1726
|
logger.debug(
|
|
1642
1727
|
`Peer disconnected '${evt.detail.from.hashcode()}' from '${JSON.stringify(
|
|
@@ -1715,13 +1800,13 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1715
1800
|
}
|
|
1716
1801
|
|
|
1717
1802
|
// The role is fixed (no changes depending on memory usage or peer count etc)
|
|
1718
|
-
if (this.
|
|
1803
|
+
if (this._roleConfig instanceof Role) {
|
|
1719
1804
|
return false;
|
|
1720
1805
|
}
|
|
1721
1806
|
|
|
1722
1807
|
// TODO second condition: what if the current role is Observer?
|
|
1723
1808
|
if (
|
|
1724
|
-
this.
|
|
1809
|
+
this._roleConfig.type == "replicator" &&
|
|
1725
1810
|
this._role instanceof Replicator
|
|
1726
1811
|
) {
|
|
1727
1812
|
const peers = this.getReplicatorsSorted();
|
package/src/pid.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
type ReplicationErrorFunction = (objectives: {
|
|
2
|
-
coverage: number;
|
|
3
|
-
balance: number;
|
|
4
|
-
memory: number;
|
|
5
|
-
cpu: number;
|
|
6
|
-
}) => number;
|
|
7
|
-
|
|
8
1
|
export class PIDReplicationController {
|
|
9
2
|
integral: number;
|
|
10
3
|
prevError: number;
|
|
@@ -18,14 +11,14 @@ export class PIDReplicationController {
|
|
|
18
11
|
constructor(
|
|
19
12
|
readonly id: string,
|
|
20
13
|
options: {
|
|
21
|
-
|
|
14
|
+
storage?: { max: number };
|
|
22
15
|
cpu?: { max: number };
|
|
23
16
|
kp?: number;
|
|
24
17
|
ki?: number;
|
|
25
18
|
kd?: number;
|
|
26
19
|
} = {}
|
|
27
20
|
) {
|
|
28
|
-
const { memory, cpu, kp = 0.7, ki = 0.025, kd = 0.05 } = options;
|
|
21
|
+
const { storage: memory, cpu, kp = 0.7, ki = 0.025, kd = 0.05 } = options;
|
|
29
22
|
this.kp = kp;
|
|
30
23
|
this.ki = ki;
|
|
31
24
|
this.kd = kd;
|