@peerbit/shared-log 12.1.3 → 12.2.0-874976b
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 +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/like.d.ts +71 -0
- package/dist/src/like.d.ts.map +1 -0
- package/dist/src/like.js +2 -0
- package/dist/src/like.js.map +1 -0
- package/dist/src/sync/index.d.ts +14 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.d.ts +6 -22
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -1
- package/dist/src/sync/rateless-iblt.js +33 -5
- package/dist/src/sync/rateless-iblt.js.map +1 -1
- package/dist/src/sync/simple.d.ts +3 -1
- package/dist/src/sync/simple.d.ts.map +1 -1
- package/dist/src/sync/simple.js +24 -2
- package/dist/src/sync/simple.js.map +1 -1
- package/package.json +20 -20
- package/src/index.ts +15 -1
- package/src/like.ts +84 -0
- package/src/sync/index.ts +19 -0
- package/src/sync/rateless-iblt.ts +58 -15
- package/src/sync/simple.ts +26 -3
package/src/sync/index.ts
CHANGED
|
@@ -8,6 +8,24 @@ import type { Numbers } from "../integers.js";
|
|
|
8
8
|
import type { TransportMessage } from "../message.js";
|
|
9
9
|
import type { EntryReplicated, ReplicationRangeIndexable } from "../ranges.js";
|
|
10
10
|
|
|
11
|
+
export type SyncPriorityFn<R extends "u32" | "u64"> = (
|
|
12
|
+
entry: EntryReplicated<R>,
|
|
13
|
+
) => number;
|
|
14
|
+
|
|
15
|
+
export type SyncOptions<R extends "u32" | "u64"> = {
|
|
16
|
+
/**
|
|
17
|
+
* Higher numbers are synced first.
|
|
18
|
+
* The callback should be fast and side-effect free.
|
|
19
|
+
*/
|
|
20
|
+
priority?: SyncPriorityFn<R>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* When using rateless IBLT sync, optionally pre-sync up to this many
|
|
24
|
+
* high-priority entries using the simple synchronizer.
|
|
25
|
+
*/
|
|
26
|
+
maxSimpleEntries?: number;
|
|
27
|
+
};
|
|
28
|
+
|
|
11
29
|
export type SynchronizerComponents<R extends "u32" | "u64"> = {
|
|
12
30
|
rpc: RPC<TransportMessage, TransportMessage>;
|
|
13
31
|
rangeIndex: Index<ReplicationRangeIndexable<R>, any>;
|
|
@@ -15,6 +33,7 @@ export type SynchronizerComponents<R extends "u32" | "u64"> = {
|
|
|
15
33
|
log: Log<any>;
|
|
16
34
|
coordinateToHash: Cache<string>;
|
|
17
35
|
numbers: Numbers<R>;
|
|
36
|
+
sync?: SyncOptions<R>;
|
|
18
37
|
};
|
|
19
38
|
export type SynchronizerConstructor<R extends "u32" | "u64"> = new (
|
|
20
39
|
properties: SynchronizerComponents<R>,
|
|
@@ -4,18 +4,24 @@ 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
6
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DecoderWrapper,
|
|
9
|
+
EncoderWrapper,
|
|
10
|
+
ready as ribltReady,
|
|
11
|
+
} from "@peerbit/riblt";
|
|
8
12
|
import type { RPC, RequestContext } from "@peerbit/rpc";
|
|
9
13
|
import { SilentDelivery } from "@peerbit/stream-interface";
|
|
10
14
|
import { type EntryWithRefs } from "../exchange-heads.js";
|
|
11
|
-
import { type Numbers } from "../integers.js";
|
|
12
15
|
import { TransportMessage } from "../message.js";
|
|
13
16
|
import {
|
|
14
17
|
type EntryReplicated,
|
|
15
|
-
type ReplicationRangeIndexable,
|
|
16
18
|
matchEntriesInRangeQuery,
|
|
17
19
|
} from "../ranges.js";
|
|
18
|
-
import type {
|
|
20
|
+
import type {
|
|
21
|
+
SyncableKey,
|
|
22
|
+
SynchronizerComponents,
|
|
23
|
+
Syncronizer,
|
|
24
|
+
} from "./index.js";
|
|
19
25
|
import { SimpleSyncronizer } from "./simple.js";
|
|
20
26
|
|
|
21
27
|
export const logger = loggerFn("peerbit:shared-log:rateless");
|
|
@@ -142,6 +148,7 @@ const buildEncoderOrDecoderFromRange = async <
|
|
|
142
148
|
entryIndex: Index<EntryReplicated<D>>,
|
|
143
149
|
type: T,
|
|
144
150
|
): Promise<E | false> => {
|
|
151
|
+
await ribltReady;
|
|
145
152
|
const encoder =
|
|
146
153
|
type === "encoder" ? new EncoderWrapper() : new DecoderWrapper();
|
|
147
154
|
|
|
@@ -207,14 +214,7 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
207
214
|
>;
|
|
208
215
|
|
|
209
216
|
constructor(
|
|
210
|
-
readonly properties:
|
|
211
|
-
rpc: RPC<TransportMessage, TransportMessage>;
|
|
212
|
-
rangeIndex: Index<ReplicationRangeIndexable<D>, any>;
|
|
213
|
-
entryIndex: Index<EntryReplicated<D>, any>;
|
|
214
|
-
log: Log<any>;
|
|
215
|
-
coordinateToHash: Cache<string>;
|
|
216
|
-
numbers: Numbers<D>;
|
|
217
|
-
},
|
|
217
|
+
readonly properties: SynchronizerComponents<D>,
|
|
218
218
|
) {
|
|
219
219
|
this.simple = new SimpleSyncronizer(properties);
|
|
220
220
|
this.outgoingSyncProcesses = new Map();
|
|
@@ -233,7 +233,6 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
233
233
|
// such as those assigned to range boundaries.
|
|
234
234
|
|
|
235
235
|
let entriesToSyncNaively: Map<string, EntryReplicated<D>> = new Map();
|
|
236
|
-
let allCoordinatesToSyncWithIblt: bigint[] = [];
|
|
237
236
|
let minSyncIbltSize = 333; // TODO: make configurable
|
|
238
237
|
let maxSyncWithSimpleMethod = 1e3;
|
|
239
238
|
|
|
@@ -246,15 +245,57 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
246
245
|
return;
|
|
247
246
|
}
|
|
248
247
|
|
|
249
|
-
|
|
248
|
+
const nonBoundaryEntries: EntryReplicated<D>[] = [];
|
|
250
249
|
for (const entry of properties.entries.values()) {
|
|
251
250
|
if (entry.assignedToRangeBoundary) {
|
|
252
251
|
entriesToSyncNaively.set(entry.hash, entry);
|
|
253
252
|
} else {
|
|
254
|
-
|
|
253
|
+
nonBoundaryEntries.push(entry);
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
256
|
|
|
257
|
+
const priorityFn = this.properties.sync?.priority;
|
|
258
|
+
const maxSimpleEntries = this.properties.sync?.maxSimpleEntries;
|
|
259
|
+
const maxAdditionalNaive =
|
|
260
|
+
priorityFn &&
|
|
261
|
+
typeof maxSimpleEntries === "number" &&
|
|
262
|
+
Number.isFinite(maxSimpleEntries) &&
|
|
263
|
+
maxSimpleEntries > 0
|
|
264
|
+
? Math.max(
|
|
265
|
+
0,
|
|
266
|
+
Math.min(
|
|
267
|
+
Math.floor(maxSimpleEntries),
|
|
268
|
+
maxSyncWithSimpleMethod - entriesToSyncNaively.size,
|
|
269
|
+
),
|
|
270
|
+
)
|
|
271
|
+
: 0;
|
|
272
|
+
|
|
273
|
+
if (priorityFn && maxAdditionalNaive > 0 && nonBoundaryEntries.length > 0) {
|
|
274
|
+
let index = 0;
|
|
275
|
+
const scored: {
|
|
276
|
+
entry: EntryReplicated<D>;
|
|
277
|
+
index: number;
|
|
278
|
+
priority: number;
|
|
279
|
+
}[] = [];
|
|
280
|
+
for (const entry of nonBoundaryEntries) {
|
|
281
|
+
const priorityValue = priorityFn(entry);
|
|
282
|
+
scored.push({
|
|
283
|
+
entry,
|
|
284
|
+
index,
|
|
285
|
+
priority: Number.isFinite(priorityValue) ? priorityValue : 0,
|
|
286
|
+
});
|
|
287
|
+
index += 1;
|
|
288
|
+
}
|
|
289
|
+
scored.sort((a, b) => b.priority - a.priority || a.index - b.index);
|
|
290
|
+
for (const { entry } of scored.slice(0, maxAdditionalNaive)) {
|
|
291
|
+
entriesToSyncNaively.set(entry.hash, entry);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
let allCoordinatesToSyncWithIblt = nonBoundaryEntries
|
|
296
|
+
.filter((entry) => !entriesToSyncNaively.has(entry.hash))
|
|
297
|
+
.map((entry) => coerceBigInt(entry.hashNumber));
|
|
298
|
+
|
|
258
299
|
if (entriesToSyncNaively.size > 0) {
|
|
259
300
|
// If there are special-case entries, sync them simply in parallel
|
|
260
301
|
await this.simple.onMaybeMissingEntries({
|
|
@@ -277,6 +318,8 @@ export class RatelessIBLTSynchronizer<D extends "u32" | "u64">
|
|
|
277
318
|
return;
|
|
278
319
|
}
|
|
279
320
|
|
|
321
|
+
await ribltReady;
|
|
322
|
+
|
|
280
323
|
const sortedEntries = allCoordinatesToSyncWithIblt.sort((a, b) => {
|
|
281
324
|
if (a > b) {
|
|
282
325
|
return 1;
|
package/src/sync/simple.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "../exchange-heads.js";
|
|
17
17
|
import { TransportMessage } from "../message.js";
|
|
18
18
|
import type { EntryReplicated } from "../ranges.js";
|
|
19
|
-
import type { SyncableKey, Syncronizer } from "./index.js";
|
|
19
|
+
import type { SyncableKey, SyncOptions, Syncronizer } from "./index.js";
|
|
20
20
|
|
|
21
21
|
@variant([0, 1])
|
|
22
22
|
export class RequestMaybeSync extends TransportMessage {
|
|
@@ -57,7 +57,7 @@ const getHashesFromSymbols = async (
|
|
|
57
57
|
coordinateToHash: Cache<string>,
|
|
58
58
|
) => {
|
|
59
59
|
let queries: IntegerCompare[] = [];
|
|
60
|
-
let batchSize =
|
|
60
|
+
let batchSize = 128; // TODO arg
|
|
61
61
|
let results = new Set<string>();
|
|
62
62
|
const handleBatch = async (end = false) => {
|
|
63
63
|
if (queries.length >= batchSize || (end && queries.length > 0)) {
|
|
@@ -109,6 +109,7 @@ export class SimpleSyncronizer<R extends "u32" | "u64">
|
|
|
109
109
|
log: Log<any>;
|
|
110
110
|
entryIndex: Index<EntryReplicated<R>, any>;
|
|
111
111
|
coordinateToHash: Cache<string>;
|
|
112
|
+
private syncOptions?: SyncOptions<R>;
|
|
112
113
|
|
|
113
114
|
// Syncing and dedeplucation work
|
|
114
115
|
syncMoreInterval?: ReturnType<typeof setTimeout>;
|
|
@@ -120,6 +121,7 @@ export class SimpleSyncronizer<R extends "u32" | "u64">
|
|
|
120
121
|
entryIndex: Index<EntryReplicated<R>, any>;
|
|
121
122
|
log: Log<any>;
|
|
122
123
|
coordinateToHash: Cache<string>;
|
|
124
|
+
sync?: SyncOptions<R>;
|
|
123
125
|
}) {
|
|
124
126
|
this.syncInFlightQueue = new Map();
|
|
125
127
|
this.syncInFlightQueueInverted = new Map();
|
|
@@ -128,14 +130,35 @@ export class SimpleSyncronizer<R extends "u32" | "u64">
|
|
|
128
130
|
this.log = properties.log;
|
|
129
131
|
this.entryIndex = properties.entryIndex;
|
|
130
132
|
this.coordinateToHash = properties.coordinateToHash;
|
|
133
|
+
this.syncOptions = properties.sync;
|
|
131
134
|
}
|
|
132
135
|
|
|
133
136
|
onMaybeMissingEntries(properties: {
|
|
134
137
|
entries: Map<string, EntryReplicated<R>>;
|
|
135
138
|
targets: string[];
|
|
136
139
|
}): Promise<void> {
|
|
140
|
+
let hashes: string[];
|
|
141
|
+
const priorityFn = this.syncOptions?.priority;
|
|
142
|
+
if (priorityFn) {
|
|
143
|
+
let index = 0;
|
|
144
|
+
const scored: { hash: string; index: number; priority: number }[] = [];
|
|
145
|
+
for (const [hash, entry] of properties.entries) {
|
|
146
|
+
const priorityValue = priorityFn(entry);
|
|
147
|
+
scored.push({
|
|
148
|
+
hash,
|
|
149
|
+
index,
|
|
150
|
+
priority: Number.isFinite(priorityValue) ? priorityValue : 0,
|
|
151
|
+
});
|
|
152
|
+
index += 1;
|
|
153
|
+
}
|
|
154
|
+
scored.sort((a, b) => b.priority - a.priority || a.index - b.index);
|
|
155
|
+
hashes = scored.map((x) => x.hash);
|
|
156
|
+
} else {
|
|
157
|
+
hashes = [...properties.entries.keys()];
|
|
158
|
+
}
|
|
159
|
+
|
|
137
160
|
return this.rpc.send(
|
|
138
|
-
new RequestMaybeSync({ hashes
|
|
161
|
+
new RequestMaybeSync({ hashes }),
|
|
139
162
|
{
|
|
140
163
|
priority: 1,
|
|
141
164
|
mode: new SilentDelivery({ to: properties.targets, redundancy: 1 }),
|