@peerbit/shared-log 9.0.5 → 9.0.6-b57d808
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 +4 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +60 -35
- package/dist/src/index.js.map +1 -1
- package/dist/src/replication.d.ts +8 -0
- package/dist/src/replication.d.ts.map +1 -1
- package/dist/src/replication.js +36 -24
- package/dist/src/replication.js.map +1 -1
- package/dist/src/role.d.ts +37 -0
- package/dist/src/role.d.ts.map +1 -1
- package/dist/src/role.js +99 -92
- package/dist/src/role.js.map +1 -1
- package/package.json +70 -70
- package/src/index.ts +79 -38
- package/src/replication.ts +37 -22
- package/src/role.ts +68 -63
package/src/index.ts
CHANGED
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
ReplicationRangeIndexable,
|
|
74
74
|
RequestReplicationInfoMessage,
|
|
75
75
|
ResponseReplicationInfoMessage,
|
|
76
|
+
ResponseRoleMessage,
|
|
76
77
|
StartedReplicating,
|
|
77
78
|
StoppedReplicating,
|
|
78
79
|
decodeReplicas,
|
|
@@ -80,7 +81,7 @@ import {
|
|
|
80
81
|
hashToUniformNumber,
|
|
81
82
|
maxReplicas,
|
|
82
83
|
} from "./replication.js";
|
|
83
|
-
import { SEGMENT_COORDINATE_SCALE } from "./role.js";
|
|
84
|
+
import { Observer, Replicator, SEGMENT_COORDINATE_SCALE } from "./role.js";
|
|
84
85
|
|
|
85
86
|
export * from "./replication.js";
|
|
86
87
|
|
|
@@ -96,10 +97,10 @@ const groupByGid = async <
|
|
|
96
97
|
const groupByGid: Map<string, T[]> = new Map();
|
|
97
98
|
for (const head of entries) {
|
|
98
99
|
const gid = await (head instanceof Entry
|
|
99
|
-
? head.
|
|
100
|
+
? (await head.getMeta()).gid
|
|
100
101
|
: head instanceof ShallowEntry
|
|
101
102
|
? head.meta.gid
|
|
102
|
-
: head.entry.
|
|
103
|
+
: (await head.entry.getMeta()).gid);
|
|
103
104
|
let value = groupByGid.get(gid);
|
|
104
105
|
if (!value) {
|
|
105
106
|
value = [];
|
|
@@ -156,6 +157,7 @@ export type SharedLogOptions<T> = {
|
|
|
156
157
|
timeUntilRoleMaturity?: number;
|
|
157
158
|
waitForReplicatorTimeout?: number;
|
|
158
159
|
distributionDebounceTime?: number;
|
|
160
|
+
compatiblity?: number;
|
|
159
161
|
};
|
|
160
162
|
|
|
161
163
|
export const DEFAULT_MIN_REPLICAS = 2;
|
|
@@ -205,7 +207,9 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
205
207
|
publicKey: PublicSignKey,
|
|
206
208
|
) => Promise<boolean> | boolean;
|
|
207
209
|
|
|
208
|
-
private _logProperties?: LogProperties<T> &
|
|
210
|
+
private _logProperties?: LogProperties<T> &
|
|
211
|
+
LogEvents<T> &
|
|
212
|
+
SharedLogOptions<T>;
|
|
209
213
|
private _closeController!: AbortController;
|
|
210
214
|
private _gidParentCache!: Cache<Entry<any>[]>;
|
|
211
215
|
private _respondToIHaveTimeout!: any;
|
|
@@ -278,6 +282,28 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
278
282
|
return this._replicationSettings;
|
|
279
283
|
}
|
|
280
284
|
|
|
285
|
+
private get v8Behaviour() {
|
|
286
|
+
return (this._logProperties?.compatiblity ?? Number.MAX_SAFE_INTEGER) < 9;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// @deprecated
|
|
290
|
+
private getRole() {
|
|
291
|
+
let isFixedReplicationSettings =
|
|
292
|
+
(this._replicationSettings as FixedReplicationOptions).factor !==
|
|
293
|
+
undefined;
|
|
294
|
+
if (isFixedReplicationSettings) {
|
|
295
|
+
const fixedSettings = this
|
|
296
|
+
._replicationSettings as FixedReplicationOptions;
|
|
297
|
+
return new Replicator({
|
|
298
|
+
factor: fixedSettings.factor,
|
|
299
|
+
offset: fixedSettings.offset ?? 0,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// TODO this is not accurate but might be good enough
|
|
304
|
+
return new Observer();
|
|
305
|
+
}
|
|
306
|
+
|
|
281
307
|
async isReplicating() {
|
|
282
308
|
if (!this._replicationSettings) {
|
|
283
309
|
return false;
|
|
@@ -596,41 +622,15 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
596
622
|
logger.warn("Not allowed to replicate by canReplicate");
|
|
597
623
|
}
|
|
598
624
|
|
|
599
|
-
added
|
|
600
|
-
|
|
625
|
+
if (added) {
|
|
626
|
+
await this.rpc.send(
|
|
601
627
|
new StartedReplicating({ segments: [range.toReplicationRange()] }),
|
|
602
628
|
{
|
|
603
629
|
priority: 1,
|
|
604
630
|
},
|
|
605
|
-
)
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
/* async updateRole(role: InitialReplicationOptions, onRoleChange = true) {
|
|
609
|
-
await this.setupReplicationSettings(role)
|
|
610
|
-
return this._updateRole(, onRoleChange);
|
|
611
|
-
} */
|
|
612
|
-
|
|
613
|
-
/* private async _updateRole(
|
|
614
|
-
role: Observer | Replicator = this._role,
|
|
615
|
-
onRoleChange = true
|
|
616
|
-
) {
|
|
617
|
-
this._role = role;
|
|
618
|
-
const { changed } = await this._modifyReplicators(
|
|
619
|
-
this.role,
|
|
620
|
-
this.node.identity.publicKey
|
|
621
|
-
);
|
|
622
|
-
|
|
623
|
-
await this.rpc.subscribe();
|
|
624
|
-
await this.rpc.send(new ResponseReplicationInfoMessage({ segments: await }), {
|
|
625
|
-
priority: 1
|
|
626
|
-
});
|
|
627
|
-
|
|
628
|
-
if (onRoleChange && changed !== "none") {
|
|
629
|
-
await this.onRoleChange(this._role, this.node.identity.publicKey);
|
|
631
|
+
);
|
|
630
632
|
}
|
|
631
|
-
|
|
632
|
-
return changed;
|
|
633
|
-
} */
|
|
633
|
+
}
|
|
634
634
|
|
|
635
635
|
async append(
|
|
636
636
|
data: T,
|
|
@@ -1019,12 +1019,16 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1019
1019
|
async _onMessage(
|
|
1020
1020
|
msg: TransportMessage,
|
|
1021
1021
|
context: RequestContext,
|
|
1022
|
-
): Promise<
|
|
1022
|
+
): Promise<void> {
|
|
1023
1023
|
try {
|
|
1024
1024
|
if (!context.from) {
|
|
1025
1025
|
throw new Error("Missing from in update role message");
|
|
1026
1026
|
}
|
|
1027
1027
|
|
|
1028
|
+
if (msg instanceof ResponseRoleMessage) {
|
|
1029
|
+
msg = msg.toReplicationInfoMessage(); // migration
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1028
1032
|
if (msg instanceof ExchangeHeadsMessage) {
|
|
1029
1033
|
/**
|
|
1030
1034
|
* I have received heads from someone else.
|
|
@@ -1132,7 +1136,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1132
1136
|
|
|
1133
1137
|
logger.debug(
|
|
1134
1138
|
`${this.node.identity.publicKey.hashcode()}: Dropping heads with gid: ${
|
|
1135
|
-
entry.entry.gid
|
|
1139
|
+
entry.entry.meta.gid
|
|
1136
1140
|
}. Because not leader`,
|
|
1137
1141
|
);
|
|
1138
1142
|
}
|
|
@@ -1300,6 +1304,8 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1300
1304
|
} else if (msg instanceof BlocksMessage) {
|
|
1301
1305
|
await this.remoteBlocks.onMessage(msg.message);
|
|
1302
1306
|
} else if (msg instanceof RequestReplicationInfoMessage) {
|
|
1307
|
+
// TODO this message type is never used, should we remove it?
|
|
1308
|
+
|
|
1303
1309
|
if (context.from.equals(this.node.identity.publicKey)) {
|
|
1304
1310
|
return;
|
|
1305
1311
|
}
|
|
@@ -1313,6 +1319,28 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1313
1319
|
mode: new SilentDelivery({ to: [context.from], redundancy: 1 }),
|
|
1314
1320
|
},
|
|
1315
1321
|
);
|
|
1322
|
+
|
|
1323
|
+
// for backwards compatibility (v8) remove this when we are sure that all nodes are v9+
|
|
1324
|
+
if (this.v8Behaviour) {
|
|
1325
|
+
const role = this.getRole();
|
|
1326
|
+
if (role instanceof Replicator) {
|
|
1327
|
+
const fixedSettings = this
|
|
1328
|
+
._replicationSettings as FixedReplicationOptions;
|
|
1329
|
+
if (fixedSettings.factor === 1) {
|
|
1330
|
+
await this.rpc.send(
|
|
1331
|
+
new ResponseRoleMessage({
|
|
1332
|
+
role,
|
|
1333
|
+
}),
|
|
1334
|
+
{
|
|
1335
|
+
mode: new SilentDelivery({
|
|
1336
|
+
to: [context.from],
|
|
1337
|
+
redundancy: 1,
|
|
1338
|
+
}),
|
|
1339
|
+
},
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1316
1344
|
} else if (
|
|
1317
1345
|
msg instanceof ResponseReplicationInfoMessage ||
|
|
1318
1346
|
msg instanceof StartedReplicating
|
|
@@ -1321,6 +1349,10 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1321
1349
|
return;
|
|
1322
1350
|
}
|
|
1323
1351
|
|
|
1352
|
+
let replicationInfoMessage = msg as
|
|
1353
|
+
| ResponseReplicationInfoMessage
|
|
1354
|
+
| StartedReplicating;
|
|
1355
|
+
|
|
1324
1356
|
// we have this statement because peers might have changed/announced their role,
|
|
1325
1357
|
// but we don't know them as "subscribers" yet. i.e. they are not online
|
|
1326
1358
|
|
|
@@ -1343,7 +1375,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1343
1375
|
await this.removeReplicator(context.from!);
|
|
1344
1376
|
}
|
|
1345
1377
|
let addedOnce = false;
|
|
1346
|
-
for (const segment of
|
|
1378
|
+
for (const segment of replicationInfoMessage.segments) {
|
|
1347
1379
|
const added = await this.addReplicationRange(
|
|
1348
1380
|
segment.toReplicationRangeIndexable(context.from!),
|
|
1349
1381
|
context.from!,
|
|
@@ -1646,7 +1678,7 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1646
1678
|
},
|
|
1647
1679
|
) {
|
|
1648
1680
|
return this.isLeader(
|
|
1649
|
-
entry.gid,
|
|
1681
|
+
entry.meta.gid,
|
|
1650
1682
|
decodeReplicas(entry).getValue(this),
|
|
1651
1683
|
options,
|
|
1652
1684
|
);
|
|
@@ -1698,6 +1730,15 @@ export class SharedLog<T = Uint8Array> extends Program<
|
|
|
1698
1730
|
},
|
|
1699
1731
|
)
|
|
1700
1732
|
.catch((e) => logger.error(e.toString()));
|
|
1733
|
+
|
|
1734
|
+
if (this.v8Behaviour) {
|
|
1735
|
+
// for backwards compatibility
|
|
1736
|
+
this.rpc
|
|
1737
|
+
.send(new ResponseRoleMessage({ role: this.getRole() }), {
|
|
1738
|
+
mode: new SilentDelivery({ redundancy: 1, to: [publicKey] }),
|
|
1739
|
+
})
|
|
1740
|
+
.catch((e) => logger.error(e.toString()));
|
|
1741
|
+
}
|
|
1701
1742
|
}
|
|
1702
1743
|
} else {
|
|
1703
1744
|
await this.removeReplicator(publicKey);
|
package/src/replication.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
BinaryReader,
|
|
3
3
|
deserialize,
|
|
4
4
|
field,
|
|
5
|
+
option,
|
|
5
6
|
serialize,
|
|
6
7
|
variant,
|
|
7
8
|
vec,
|
|
@@ -9,28 +10,14 @@ import {
|
|
|
9
10
|
import { PublicSignKey, equals, randomBytes } from "@peerbit/crypto";
|
|
10
11
|
import { type Index, id } from "@peerbit/indexer-interface";
|
|
11
12
|
import { TransportMessage } from "./message.js";
|
|
12
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
Observer,
|
|
15
|
+
Replicator,
|
|
16
|
+
Role,
|
|
17
|
+
SEGMENT_COORDINATE_SCALE,
|
|
18
|
+
} from "./role.js";
|
|
13
19
|
|
|
14
20
|
export type ReplicationLimits = { min: MinReplicas; max?: MinReplicas };
|
|
15
|
-
/*
|
|
16
|
-
export class ReplicatorRect {
|
|
17
|
-
|
|
18
|
-
@id({ type: Uint8Array })
|
|
19
|
-
id: Uint8Array;
|
|
20
|
-
|
|
21
|
-
@field({ type: 'string' })
|
|
22
|
-
hash: string;
|
|
23
|
-
|
|
24
|
-
@field({ type: vec(ReplicationSegment) })
|
|
25
|
-
segments: ReplicationSegment[];
|
|
26
|
-
|
|
27
|
-
constructor(properties: { hash: string; segments: ReplicationSegment[] }) {
|
|
28
|
-
this.id = randomBytes(32);
|
|
29
|
-
this.hash = properties.hash;
|
|
30
|
-
this.segments = properties.segments;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
*/
|
|
34
21
|
|
|
35
22
|
export enum ReplicationIntent {
|
|
36
23
|
Explicit = 0,
|
|
@@ -280,7 +267,35 @@ export class RequestReplicationInfoMessage extends TransportMessage {
|
|
|
280
267
|
}
|
|
281
268
|
}
|
|
282
269
|
|
|
270
|
+
// @deprecated remove when possible
|
|
283
271
|
@variant([1, 1])
|
|
272
|
+
export class ResponseRoleMessage extends TransportMessage {
|
|
273
|
+
@field({ type: option(Role) })
|
|
274
|
+
role: Observer | Replicator;
|
|
275
|
+
|
|
276
|
+
constructor(properties: { role: Observer | Replicator }) {
|
|
277
|
+
super();
|
|
278
|
+
this.role = properties.role;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
toReplicationInfoMessage(): ResponseReplicationInfoMessage {
|
|
282
|
+
return new ResponseReplicationInfoMessage({
|
|
283
|
+
segments:
|
|
284
|
+
this.role instanceof Replicator
|
|
285
|
+
? this.role.segments.map((x) => {
|
|
286
|
+
return new ReplicationRange({
|
|
287
|
+
id: randomBytes(32),
|
|
288
|
+
offset: x.offset,
|
|
289
|
+
factor: x.factor,
|
|
290
|
+
timestamp: x.timestamp,
|
|
291
|
+
});
|
|
292
|
+
})
|
|
293
|
+
: [],
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
@variant([1, 2])
|
|
284
299
|
export class ResponseReplicationInfoMessage extends TransportMessage {
|
|
285
300
|
@field({ type: vec(ReplicationRange) })
|
|
286
301
|
segments: ReplicationRange[];
|
|
@@ -291,7 +306,7 @@ export class ResponseReplicationInfoMessage extends TransportMessage {
|
|
|
291
306
|
}
|
|
292
307
|
}
|
|
293
308
|
|
|
294
|
-
@variant([1,
|
|
309
|
+
@variant([1, 3])
|
|
295
310
|
export class StartedReplicating extends TransportMessage {
|
|
296
311
|
@field({ type: vec(ReplicationRange) })
|
|
297
312
|
segments: ReplicationRange[];
|
|
@@ -302,7 +317,7 @@ export class StartedReplicating extends TransportMessage {
|
|
|
302
317
|
}
|
|
303
318
|
}
|
|
304
319
|
|
|
305
|
-
@variant([1,
|
|
320
|
+
@variant([1, 4])
|
|
306
321
|
export class StoppedReplicating extends TransportMessage {
|
|
307
322
|
@field({ type: vec(Uint8Array) })
|
|
308
323
|
segmentIds: Uint8Array[];
|
package/src/role.ts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated
|
|
3
|
+
* Code below is deprecated and will be removed in the future.
|
|
4
|
+
* Roles have been replaces with just replication segments.
|
|
5
|
+
*/
|
|
6
|
+
import { field, variant, vec } from "@dao-xyz/borsh";
|
|
7
|
+
|
|
8
|
+
export const SEGMENT_COORDINATE_SCALE = 4294967295;
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
export const overlaps = (x1: number, x2: number, y1: number, y2: number) => {
|
|
4
11
|
if (x1 <= y2 && y1 <= x2) {
|
|
5
12
|
return true;
|
|
6
13
|
}
|
|
7
14
|
return false;
|
|
8
|
-
};
|
|
15
|
+
};
|
|
9
16
|
|
|
10
|
-
|
|
11
|
-
abstract equals(other: Role): boolean;
|
|
17
|
+
export abstract class Role {
|
|
18
|
+
abstract equals(other: Role): boolean;
|
|
12
19
|
}
|
|
13
|
-
|
|
20
|
+
|
|
14
21
|
export const NO_TYPE_VARIANT = new Uint8Array([0]);
|
|
15
22
|
|
|
16
23
|
@variant(0)
|
|
@@ -29,83 +36,81 @@ export class Observer extends Role {
|
|
|
29
36
|
}
|
|
30
37
|
}
|
|
31
38
|
|
|
32
|
-
export const REPLICATOR_TYPE_VARIANT = new Uint8Array([2])
|
|
33
|
-
|
|
34
|
-
export const SEGMENT_COORDINATE_SCALE = 4294967295;
|
|
35
|
-
/* export class ReplicationSegment {
|
|
39
|
+
export const REPLICATOR_TYPE_VARIANT = new Uint8Array([2]);
|
|
36
40
|
|
|
41
|
+
export class RoleReplicationSegment {
|
|
37
42
|
@field({ type: "u64" })
|
|
38
43
|
timestamp: bigint;
|
|
39
44
|
|
|
40
45
|
@field({ type: "u32" })
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
@field({ type: 'u32' })
|
|
44
|
-
end: number;
|
|
45
|
-
|
|
46
|
+
private factorNominator: number;
|
|
46
47
|
|
|
48
|
+
@field({ type: "u32" })
|
|
49
|
+
private offsetNominator: number;
|
|
47
50
|
|
|
48
51
|
constructor(properties: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
timestamp
|
|
52
|
+
factor: number;
|
|
53
|
+
offset: number;
|
|
54
|
+
timestamp?: bigint;
|
|
52
55
|
}) {
|
|
53
|
-
const {
|
|
56
|
+
const { factor, timestamp, offset } = properties;
|
|
57
|
+
if (factor > 1 || factor < 0) {
|
|
58
|
+
throw new Error("Expecting factor to be between 0 and 1, got: " + factor);
|
|
59
|
+
}
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
this.timestamp = timestamp ?? BigInt(+new Date());
|
|
62
|
+
this.factorNominator = Math.round(SEGMENT_COORDINATE_SCALE * factor);
|
|
63
|
+
|
|
64
|
+
if (offset > 1 || offset < 0) {
|
|
65
|
+
throw new Error("Expecting offset to be between 0 and 1, got: " + offset);
|
|
57
66
|
}
|
|
58
|
-
this.
|
|
59
|
-
this.end = Math.round(end * SEGMENT_COORDINATE_SCALE);
|
|
60
|
-
this.timestamp = timestamp
|
|
67
|
+
this.offsetNominator = Math.round(SEGMENT_COORDINATE_SCALE * offset);
|
|
61
68
|
}
|
|
62
69
|
|
|
70
|
+
get factor(): number {
|
|
71
|
+
return this.factorNominator / SEGMENT_COORDINATE_SCALE;
|
|
72
|
+
}
|
|
63
73
|
|
|
74
|
+
get offset(): number {
|
|
75
|
+
return this.offsetNominator / SEGMENT_COORDINATE_SCALE;
|
|
76
|
+
}
|
|
64
77
|
|
|
65
78
|
}
|
|
66
|
-
*/
|
|
67
|
-
|
|
68
|
-
/* abstract class Capacity { }
|
|
69
79
|
|
|
70
80
|
@variant(2)
|
|
71
81
|
export class Replicator extends Role {
|
|
82
|
+
@field({ type: vec(RoleReplicationSegment) })
|
|
83
|
+
segments: RoleReplicationSegment[];
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
constructor(properties: {
|
|
86
|
+
factor: number;
|
|
87
|
+
timestamp?: bigint;
|
|
88
|
+
offset: number;
|
|
89
|
+
}) {
|
|
77
90
|
super();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
factor: number;
|
|
84
|
-
offset: number;
|
|
85
|
-
}) {
|
|
86
|
-
super();
|
|
87
|
-
let timestamp = properties.timestamp || BigInt(+new Date);
|
|
88
|
-
let ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.factor);
|
|
89
|
-
this.segments = ranges.map(x => new ReplicationSegment({ start: x[0], end: x[1], timestamp }));
|
|
90
|
-
}
|
|
91
|
-
*/
|
|
92
|
-
/* get factor(): number {
|
|
93
|
-
return this.segments[0]!.factor;
|
|
94
|
-
}
|
|
91
|
+
const segment: RoleReplicationSegment = new RoleReplicationSegment(
|
|
92
|
+
properties,
|
|
93
|
+
);
|
|
94
|
+
this.segments = [segment];
|
|
95
|
+
}
|
|
95
96
|
|
|
96
|
-
get
|
|
97
|
-
|
|
98
|
-
}
|
|
97
|
+
get factor(): number {
|
|
98
|
+
return this.segments[0]!.factor;
|
|
99
|
+
}
|
|
99
100
|
|
|
100
|
-
get
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
get offset(): number {
|
|
102
|
+
return this.segments[0]!.offset;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get timestamp(): bigint {
|
|
106
|
+
return this.segments[0]!.timestamp;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
equals(other: Role) {
|
|
110
|
+
return (
|
|
111
|
+
other instanceof Replicator &&
|
|
112
|
+
other.factor === this.factor &&
|
|
113
|
+
other.offset === this.offset
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|