@peerbit/shared-log 9.0.10 → 9.1.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/dist/benchmark/index.js +2 -2
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/replication.js +3 -3
- package/dist/benchmark/replication.js.map +1 -1
- package/dist/src/index.d.ts +46 -31
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +426 -229
- package/dist/src/index.js.map +1 -1
- package/dist/src/pid.d.ts.map +1 -1
- package/dist/src/pid.js +20 -19
- package/dist/src/pid.js.map +1 -1
- package/dist/src/ranges.d.ts +13 -3
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +207 -335
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/replication-domain-hash.d.ts +5 -0
- package/dist/src/replication-domain-hash.d.ts.map +1 -0
- package/dist/src/replication-domain-hash.js +30 -0
- package/dist/src/replication-domain-hash.js.map +1 -0
- package/dist/src/replication-domain-time.d.ts +14 -0
- package/dist/src/replication-domain-time.d.ts.map +1 -0
- package/dist/src/replication-domain-time.js +59 -0
- package/dist/src/replication-domain-time.js.map +1 -0
- package/dist/src/replication-domain.d.ts +33 -0
- package/dist/src/replication-domain.d.ts.map +1 -0
- package/dist/src/replication-domain.js +6 -0
- package/dist/src/replication-domain.js.map +1 -0
- package/dist/src/replication.d.ts +10 -8
- package/dist/src/replication.d.ts.map +1 -1
- package/dist/src/replication.js +64 -46
- package/dist/src/replication.js.map +1 -1
- package/dist/src/role.d.ts +2 -1
- package/dist/src/role.d.ts.map +1 -1
- package/dist/src/role.js +6 -5
- package/dist/src/role.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +604 -310
- package/src/pid.ts +20 -19
- package/src/ranges.ts +291 -371
- package/src/replication-domain-hash.ts +43 -0
- package/src/replication-domain-time.ts +85 -0
- package/src/replication-domain.ts +50 -0
- package/src/replication.ts +50 -46
- package/src/role.ts +6 -5
package/dist/src/ranges.js
CHANGED
|
@@ -1,116 +1,33 @@
|
|
|
1
|
-
import { equals } from "@peerbit/crypto";
|
|
2
|
-
import { And, Compare, IntegerCompare, Or, SearchRequest, Sort, SortDirection, StringMatch, iterate, iteratorInSeries, } from "@peerbit/indexer-interface";
|
|
3
|
-
import {} from "./replication.js";
|
|
4
|
-
import {
|
|
5
|
-
/*
|
|
6
|
-
export const containsPoint = (
|
|
7
|
-
rect: { offset: number; length: number },
|
|
8
|
-
point: number,
|
|
9
|
-
eps = 0.00001 // we do this to handle numerical errors
|
|
10
|
-
) => {
|
|
11
|
-
if (rect.factor === 0) {
|
|
12
|
-
return false;
|
|
13
|
-
}
|
|
14
|
-
const start = rect.offset;
|
|
15
|
-
const width = rect.factor + eps; // we do this to handle numerical errors. It is better to be more inclusive
|
|
16
|
-
const endUnwrapped = rect.offset + width;
|
|
17
|
-
let end = endUnwrapped;
|
|
18
|
-
let wrapped = false;
|
|
19
|
-
if (endUnwrapped > 1) {
|
|
20
|
-
end = endUnwrapped % 1;
|
|
21
|
-
wrapped = true;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const inFirstInterval = point >= start && point < Math.min(endUnwrapped, 1);
|
|
25
|
-
const inSecondInterval =
|
|
26
|
-
!inFirstInterval && wrapped && point >= 0 && point < end;
|
|
27
|
-
|
|
28
|
-
return inFirstInterval || inSecondInterval;
|
|
29
|
-
}; */
|
|
30
|
-
/* const resolveRectsThatContainPoint = async (
|
|
31
|
-
rects: Index<ReplicationRangeIndexable>,
|
|
32
|
-
point: number,
|
|
33
|
-
roleAgeLimit: number,
|
|
34
|
-
matured: boolean
|
|
35
|
-
): Promise<ReplicationRangeIndexable[]> => {
|
|
36
|
-
// point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
|
|
37
|
-
// so we need to query for all ranges that contain the point
|
|
38
|
-
const scaledPoint = Math.round(point * SEGMENT_COORDINATE_SCALE)
|
|
39
|
-
let queries = [
|
|
40
|
-
new IntegerCompare({ key: 'start', compare: Compare.LessOrEqual, value: scaledPoint }),
|
|
41
|
-
new IntegerCompare({ key: 'end', compare: Compare.Greater, value: scaledPoint }),
|
|
42
|
-
new IntegerCompare({ key: 'timestamp', compare: matured ? Compare.LessOrEqual : Compare.Greater, value: Date.now() - roleAgeLimit })
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
const results = await rects.query(new SearchRequest({
|
|
46
|
-
query: [
|
|
47
|
-
new Nested({
|
|
48
|
-
path: 'segments',
|
|
49
|
-
query: queries
|
|
50
|
-
})
|
|
51
|
-
]
|
|
52
|
-
}))
|
|
53
|
-
return results.results.map(x => x.value)
|
|
54
|
-
} */
|
|
55
|
-
/* const resolveRectsInRange = async (rects: Index<ReplicationRangeIndexable>,
|
|
56
|
-
start: number,
|
|
57
|
-
end: number,
|
|
58
|
-
roleAgeLimit: number,
|
|
59
|
-
matured: boolean
|
|
60
|
-
): Promise<ReplicationRangeIndexable[]> => {
|
|
61
|
-
// point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
|
|
62
|
-
// so we need to query for all ranges that contain the point
|
|
63
|
-
let endScaled = Math.round(end * SEGMENT_COORDINATE_SCALE);
|
|
64
|
-
let startScaled = Math.round(start * SEGMENT_COORDINATE_SCALE);
|
|
65
|
-
let queries = [
|
|
66
|
-
new Or([
|
|
67
|
-
new And([
|
|
68
|
-
new IntegerCompare({ key: 'start1', compare: Compare.Less, value: endScaled }),
|
|
69
|
-
new IntegerCompare({ key: 'end1', compare: Compare.GreaterOrEqual, value: startScaled }),
|
|
70
|
-
]),
|
|
71
|
-
new And([
|
|
72
|
-
new IntegerCompare({ key: 'start2', compare: Compare.Less, value: endScaled }),
|
|
73
|
-
new IntegerCompare({ key: 'end2', compare: Compare.GreaterOrEqual, value: startScaled }),
|
|
74
|
-
])
|
|
75
|
-
]),
|
|
76
|
-
new IntegerCompare({ key: 'timestamp', compare: matured ? Compare.LessOrEqual : Compare.Greater, value: BigInt(+new Date - roleAgeLimit) })
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
const results = await rects.query(new SearchRequest({
|
|
80
|
-
query: queries,
|
|
81
|
-
sort: [new Sort({ key: "start1" }), new Sort({ key: "start2" })],
|
|
82
|
-
fetch: 0xffffffff
|
|
83
|
-
}))
|
|
84
|
-
return results.results.map(x => x.value)
|
|
85
|
-
} */
|
|
1
|
+
import { PublicSignKey, equals } from "@peerbit/crypto";
|
|
2
|
+
import { And, ByteMatchQuery, Compare, IntegerCompare, Not, Or, SearchRequest, Sort, SortDirection, StringMatch, iterate, iteratorInSeries, } from "@peerbit/indexer-interface";
|
|
3
|
+
import { ReplicationIntent, } from "./replication.js";
|
|
4
|
+
import { MAX_U32, scaleToU32 } from "./role.js";
|
|
86
5
|
const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
|
|
87
6
|
// point is between 0 and 1, and the range can start at any offset between 0 and 1 and have length between 0 and 1
|
|
88
|
-
// so we need to query for all ranges that contain the point
|
|
89
|
-
let pointScaled = Math.round(point * (options?.scaled ? 1 : SEGMENT_COORDINATE_SCALE));
|
|
90
7
|
let queries = [
|
|
91
8
|
new Or([
|
|
92
9
|
new And([
|
|
93
10
|
new IntegerCompare({
|
|
94
11
|
key: "start1",
|
|
95
12
|
compare: Compare.LessOrEqual,
|
|
96
|
-
value:
|
|
13
|
+
value: point,
|
|
97
14
|
}),
|
|
98
15
|
new IntegerCompare({
|
|
99
16
|
key: "end1",
|
|
100
17
|
compare: Compare.Greater,
|
|
101
|
-
value:
|
|
18
|
+
value: point,
|
|
102
19
|
}),
|
|
103
20
|
]),
|
|
104
21
|
new And([
|
|
105
22
|
new IntegerCompare({
|
|
106
23
|
key: "start2",
|
|
107
24
|
compare: Compare.LessOrEqual,
|
|
108
|
-
value:
|
|
25
|
+
value: point,
|
|
109
26
|
}),
|
|
110
27
|
new IntegerCompare({
|
|
111
28
|
key: "end2",
|
|
112
29
|
compare: Compare.Greater,
|
|
113
|
-
value:
|
|
30
|
+
value: point,
|
|
114
31
|
}),
|
|
115
32
|
]),
|
|
116
33
|
]),
|
|
@@ -132,8 +49,7 @@ const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
|
|
|
132
49
|
}))
|
|
133
50
|
return results.results.map(x => x.value) */
|
|
134
51
|
};
|
|
135
|
-
const getClosest = (direction, rects, point, roleAgeLimit, matured, now,
|
|
136
|
-
const scaledPoint = Math.round(point * (scaled ? 1 : SEGMENT_COORDINATE_SCALE));
|
|
52
|
+
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict) => {
|
|
137
53
|
const createQueries = (p, equality) => {
|
|
138
54
|
let queries;
|
|
139
55
|
if (direction === "below") {
|
|
@@ -165,23 +81,97 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, scaled
|
|
|
165
81
|
];
|
|
166
82
|
}
|
|
167
83
|
queries.push(new IntegerCompare({ key: "width", compare: Compare.Greater, value: 0 }));
|
|
84
|
+
if (!includeStrict) {
|
|
85
|
+
queries.push(new IntegerCompare({
|
|
86
|
+
key: "mode",
|
|
87
|
+
compare: Compare.Equal,
|
|
88
|
+
value: ReplicationIntent.NonStrict,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
168
91
|
return queries;
|
|
169
92
|
};
|
|
170
93
|
const iterator = iterate(rects, new SearchRequest({
|
|
171
|
-
query: createQueries(
|
|
94
|
+
query: createQueries(point, false),
|
|
172
95
|
sort: direction === "below"
|
|
173
96
|
? new Sort({ key: ["end2"], direction: "desc" })
|
|
174
97
|
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
175
98
|
}));
|
|
176
99
|
const iteratorWrapped = iterate(rects, new SearchRequest({
|
|
177
|
-
query: createQueries(direction === "below" ?
|
|
100
|
+
query: createQueries(direction === "below" ? MAX_U32 : 0, true),
|
|
178
101
|
sort: direction === "below"
|
|
179
102
|
? new Sort({ key: ["end2"], direction: "desc" })
|
|
180
103
|
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
181
104
|
}));
|
|
182
|
-
return joinIterator([iterator, iteratorWrapped],
|
|
105
|
+
return joinIterator([iterator, iteratorWrapped], point, direction);
|
|
106
|
+
};
|
|
107
|
+
export const hasCoveringRange = async (rects, range) => {
|
|
108
|
+
return ((await rects.count(new SearchRequest({
|
|
109
|
+
query: [
|
|
110
|
+
new Or([
|
|
111
|
+
new And([
|
|
112
|
+
new IntegerCompare({
|
|
113
|
+
key: "start1",
|
|
114
|
+
compare: Compare.LessOrEqual,
|
|
115
|
+
value: range.start1,
|
|
116
|
+
}),
|
|
117
|
+
new IntegerCompare({
|
|
118
|
+
key: "end1",
|
|
119
|
+
compare: Compare.GreaterOrEqual,
|
|
120
|
+
value: range.end1,
|
|
121
|
+
}),
|
|
122
|
+
]),
|
|
123
|
+
new And([
|
|
124
|
+
new IntegerCompare({
|
|
125
|
+
key: "start2",
|
|
126
|
+
compare: Compare.LessOrEqual,
|
|
127
|
+
value: range.start1,
|
|
128
|
+
}),
|
|
129
|
+
new IntegerCompare({
|
|
130
|
+
key: "end2",
|
|
131
|
+
compare: Compare.GreaterOrEqual,
|
|
132
|
+
value: range.end1,
|
|
133
|
+
}),
|
|
134
|
+
]),
|
|
135
|
+
]),
|
|
136
|
+
new Or([
|
|
137
|
+
new And([
|
|
138
|
+
new IntegerCompare({
|
|
139
|
+
key: "start1",
|
|
140
|
+
compare: Compare.LessOrEqual,
|
|
141
|
+
value: range.start2,
|
|
142
|
+
}),
|
|
143
|
+
new IntegerCompare({
|
|
144
|
+
key: "end1",
|
|
145
|
+
compare: Compare.GreaterOrEqual,
|
|
146
|
+
value: range.end2,
|
|
147
|
+
}),
|
|
148
|
+
]),
|
|
149
|
+
new And([
|
|
150
|
+
new IntegerCompare({
|
|
151
|
+
key: "start2",
|
|
152
|
+
compare: Compare.LessOrEqual,
|
|
153
|
+
value: range.start2,
|
|
154
|
+
}),
|
|
155
|
+
new IntegerCompare({
|
|
156
|
+
key: "end2",
|
|
157
|
+
compare: Compare.GreaterOrEqual,
|
|
158
|
+
value: range.end2,
|
|
159
|
+
}),
|
|
160
|
+
]),
|
|
161
|
+
]),
|
|
162
|
+
new StringMatch({
|
|
163
|
+
key: "hash",
|
|
164
|
+
value: range.hash,
|
|
165
|
+
}),
|
|
166
|
+
// assume that we are looking for other ranges, not want to update an existing one
|
|
167
|
+
new Not(new ByteMatchQuery({
|
|
168
|
+
key: "id",
|
|
169
|
+
value: range.id,
|
|
170
|
+
})),
|
|
171
|
+
],
|
|
172
|
+
}))) > 0);
|
|
183
173
|
};
|
|
184
|
-
export const getDistance = (from, to, direction, end =
|
|
174
|
+
export const getDistance = (from, to, direction, end = MAX_U32) => {
|
|
185
175
|
// if direction is 'above' only measure distance from 'from to 'to' from above.
|
|
186
176
|
// i.e if from < to, then from needs to wrap around 0 to 1 and then to to
|
|
187
177
|
// if direction is 'below' and from > to, then from needs to wrap around 1 to 0 and then to to
|
|
@@ -208,8 +198,7 @@ export const getDistance = (from, to, direction, end = SEGMENT_COORDINATE_SCALE)
|
|
|
208
198
|
}
|
|
209
199
|
throw new Error("Invalid direction");
|
|
210
200
|
};
|
|
211
|
-
const joinIterator = (iterators, point,
|
|
212
|
-
const scaledPoint = Math.round(point * (scaled ? 1 : SEGMENT_COORDINATE_SCALE));
|
|
201
|
+
const joinIterator = (iterators, point, direction) => {
|
|
213
202
|
let queues = [];
|
|
214
203
|
return {
|
|
215
204
|
next: async (count) => {
|
|
@@ -231,13 +220,13 @@ const joinIterator = (iterators, point, scaled, direction) => {
|
|
|
231
220
|
const closest = el.value;
|
|
232
221
|
let dist;
|
|
233
222
|
if (direction === "closest") {
|
|
234
|
-
dist = Math.min(getDistance(closest.start1,
|
|
223
|
+
dist = Math.min(getDistance(closest.start1, point, direction), getDistance(closest.end2, point, direction));
|
|
235
224
|
}
|
|
236
225
|
else if (direction === "above") {
|
|
237
|
-
dist = getDistance(closest.start1,
|
|
226
|
+
dist = getDistance(closest.start1, point, direction);
|
|
238
227
|
}
|
|
239
228
|
else if (direction === "below") {
|
|
240
|
-
dist = getDistance(closest.end2,
|
|
229
|
+
dist = getDistance(closest.end2, point, direction);
|
|
241
230
|
}
|
|
242
231
|
else {
|
|
243
232
|
throw new Error("Invalid direction");
|
|
@@ -289,18 +278,14 @@ const joinIterator = (iterators, point, scaled, direction) => {
|
|
|
289
278
|
},
|
|
290
279
|
};
|
|
291
280
|
};
|
|
292
|
-
const getClosestAround = (peers, point, roleAge, now,
|
|
293
|
-
const closestBelow = getClosest("below", peers, point, roleAge, true, now,
|
|
294
|
-
const closestAbove = getClosest("above", peers, point, roleAge, true, now,
|
|
295
|
-
const containing = containingPoint(peers, point, roleAge, true, now
|
|
296
|
-
|
|
297
|
-
});
|
|
298
|
-
return iteratorInSeries(containing, joinIterator([closestBelow, closestAbove], point, scaled, "closest"));
|
|
281
|
+
const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove) => {
|
|
282
|
+
const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow);
|
|
283
|
+
const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove);
|
|
284
|
+
const containing = containingPoint(peers, point, roleAge, true, now);
|
|
285
|
+
return iteratorInSeries(containing, joinIterator([closestBelow, closestAbove], point, "closest"));
|
|
299
286
|
};
|
|
300
287
|
const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, done = () => true) => {
|
|
301
|
-
const containing = containingPoint(peers, point, 0, true, now
|
|
302
|
-
scaled: false,
|
|
303
|
-
});
|
|
288
|
+
const containing = containingPoint(peers, point, 0, true, now);
|
|
304
289
|
const allContaining = await containing.next(0xffffffff);
|
|
305
290
|
for (const rect of allContaining.results) {
|
|
306
291
|
collector(rect.value, isMatured(rect.value, now, roleAge));
|
|
@@ -310,7 +295,7 @@ const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, do
|
|
|
310
295
|
}
|
|
311
296
|
const closestBelow = getClosest("below", peers, point, 0, true, now, false);
|
|
312
297
|
const closestAbove = getClosest("above", peers, point, 0, true, now, false);
|
|
313
|
-
const aroundIterator = joinIterator([closestBelow, closestAbove], point,
|
|
298
|
+
const aroundIterator = joinIterator([closestBelow, closestAbove], point, "closest");
|
|
314
299
|
while (aroundIterator.done() === false && done() === false) {
|
|
315
300
|
const res = await aroundIterator.next(1);
|
|
316
301
|
for (const rect of res.results) {
|
|
@@ -326,7 +311,6 @@ export const isMatured = (segment, now, minAge) => {
|
|
|
326
311
|
};
|
|
327
312
|
export const getSamples = async (cursor, peers, amount, roleAge) => {
|
|
328
313
|
const leaders = new Set();
|
|
329
|
-
const width = 1;
|
|
330
314
|
if (!peers) {
|
|
331
315
|
return [];
|
|
332
316
|
}
|
|
@@ -339,10 +323,9 @@ export const getSamples = async (cursor, peers, amount, roleAge) => {
|
|
|
339
323
|
const maturedLeaders = new Set();
|
|
340
324
|
for (let i = 0; i < amount; i++) {
|
|
341
325
|
// evenly distributed
|
|
342
|
-
const point = (
|
|
326
|
+
const point = Math.round(cursor + (i * MAX_U32) / amount) % MAX_U32;
|
|
343
327
|
// aquire at least one unique node for each point
|
|
344
328
|
await collectNodesAroundPoint(roleAge, peers, (rect, m) => {
|
|
345
|
-
// console.log(m, rect.start1 / SEGMENT_COORDINATE_SCALE, rect.width / SEGMENT_COORDINATE_SCALE)
|
|
346
329
|
if (m) {
|
|
347
330
|
maturedLeaders.add(rect.hash);
|
|
348
331
|
}
|
|
@@ -361,61 +344,28 @@ const fetchOne = async (iterator) => {
|
|
|
361
344
|
await iterator.close();
|
|
362
345
|
return value.results[0]?.value;
|
|
363
346
|
};
|
|
364
|
-
export const
|
|
365
|
-
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}));
|
|
376
|
-
startNode = result.results[0]?.value;
|
|
377
|
-
if (startNode) {
|
|
378
|
-
if (!isMatured(startNode, now, roleAge)) {
|
|
379
|
-
const matured = await fetchOne(getClosestAround(peers, startNode.start1, roleAge, now, true));
|
|
380
|
-
if (matured) {
|
|
381
|
-
startNode = matured;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
let startLocation;
|
|
387
|
-
if (!startNode) {
|
|
388
|
-
startLocation = Math.random() * SEGMENT_COORDINATE_SCALE;
|
|
389
|
-
startNode = await fetchOne(getClosestAround(peers, startLocation, roleAge, now, true));
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
// TODO choose start location as the point with the longest range?
|
|
393
|
-
startLocation =
|
|
394
|
-
startNode.start1 ?? Math.random() * SEGMENT_COORDINATE_SCALE;
|
|
395
|
-
}
|
|
396
|
-
if (!startNode) {
|
|
397
|
-
return new Set();
|
|
398
|
-
}
|
|
347
|
+
export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */) => {
|
|
348
|
+
/* minReplicas = Math.min(minReplicas, replicatorCount); */ // TODO do we need this?
|
|
349
|
+
// If min replicas = 2
|
|
350
|
+
// then we need to make sure we cover 0.5 of the total 'width' of the replication space
|
|
351
|
+
// to make sure we reach sufficient amount of nodes such that at least one one has
|
|
352
|
+
// the entry we are looking for
|
|
353
|
+
let widthToCoverScaled = Math.round(MAX_U32 / minReplicas);
|
|
354
|
+
return widthToCoverScaled;
|
|
355
|
+
};
|
|
356
|
+
export const getCoverSet = async (peers, roleAge, start, widthToCoverScaled, intervalWidth = MAX_U32) => {
|
|
357
|
+
const { startNode, startLocation, endLocation } = await getStartAndEnd(peers, start, widthToCoverScaled, roleAge, Date.now(), intervalWidth);
|
|
399
358
|
let results = [];
|
|
400
|
-
let
|
|
401
|
-
const endLocation = (startLocation + widthToCoverScaled) % SEGMENT_COORDINATE_SCALE;
|
|
359
|
+
let now = +new Date();
|
|
402
360
|
const endIsWrapped = endLocation <= startLocation;
|
|
403
|
-
|
|
404
|
-
if (!endRect) {
|
|
361
|
+
if (!startNode) {
|
|
405
362
|
return new Set();
|
|
406
363
|
}
|
|
407
|
-
let current =
|
|
408
|
-
/* (await getClosestAround(peers, startLocation, roleAge, 1, true))[0] */ startNode ||
|
|
409
|
-
(await fetchOne(getClosestAround(peers, startLocation, 0, now, true))); //(await getClosest('above', peers, startLocation, roleAge, true, 1, true))[0]
|
|
410
|
-
let coveredLength = current.width;
|
|
411
|
-
let nextLocation = current.end2;
|
|
364
|
+
let current = startNode;
|
|
412
365
|
// push edges
|
|
413
|
-
results.push(endRect);
|
|
414
366
|
results.push(current);
|
|
415
|
-
/* const endIsSameAsStart = equals(endRect.id, current.id); */
|
|
416
367
|
const resolveNextContaining = async (nextLocation, roleAge) => {
|
|
417
368
|
let next = await fetchOne(containingPoint(peers, nextLocation, roleAge, true, now, {
|
|
418
|
-
scaled: true,
|
|
419
369
|
sort: [new Sort({ key: "end2", direction: SortDirection.DESC })],
|
|
420
370
|
})); // get entersecting sort by largest end2
|
|
421
371
|
return next;
|
|
@@ -434,11 +384,23 @@ export const getCoverSet = async (coveringWidth, peers, roleAge, startNodeIdenti
|
|
|
434
384
|
};
|
|
435
385
|
// fill the middle
|
|
436
386
|
let wrappedOnce = current.end2 < current.end1;
|
|
387
|
+
let coveredLength = 0;
|
|
388
|
+
const addLength = (from) => {
|
|
389
|
+
if (current.end2 < from || current.wrapped) {
|
|
390
|
+
wrappedOnce = true;
|
|
391
|
+
coveredLength += MAX_U32 - from;
|
|
392
|
+
coveredLength += current.end2;
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
coveredLength += current.end1 - from;
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
addLength(startLocation);
|
|
437
399
|
let maturedCoveredLength = coveredLength;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
400
|
+
let nextLocation = current.end2;
|
|
401
|
+
while (maturedCoveredLength < widthToCoverScaled && // eslint-disable-line no-unmodified-loop-condition
|
|
402
|
+
coveredLength <= MAX_U32 // eslint-disable-line no-unmodified-loop-condition
|
|
403
|
+
) {
|
|
442
404
|
let nextCandidate = await resolveNext(nextLocation, roleAge);
|
|
443
405
|
/* let fromAbove = false; */
|
|
444
406
|
let matured = true;
|
|
@@ -450,44 +412,28 @@ export const getCoverSet = async (coveringWidth, peers, roleAge, startNodeIdenti
|
|
|
450
412
|
if (!nextCandidate[0]) {
|
|
451
413
|
break;
|
|
452
414
|
}
|
|
415
|
+
let nextIsCurrent = equals(nextCandidate[0].id, current.id);
|
|
416
|
+
if (nextIsCurrent) {
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
let last = current;
|
|
453
420
|
current = nextCandidate[0];
|
|
454
421
|
let distanceBefore = coveredLength;
|
|
455
|
-
|
|
456
|
-
wrappedOnce = true;
|
|
457
|
-
coveredLength += SEGMENT_COORDINATE_SCALE - nextLocation;
|
|
458
|
-
coveredLength += current.end2;
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
coveredLength += current.end1 - nextLocation;
|
|
462
|
-
}
|
|
422
|
+
addLength(nextLocation);
|
|
463
423
|
let isLast = distanceBefore < widthToCoverScaled &&
|
|
464
424
|
coveredLength >= widthToCoverScaled;
|
|
465
|
-
if (
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
/* if (lastMatured && lastMatured.distanceTo(endLocation) < current.distanceTo(endLocation)) {
|
|
471
|
-
breaks;
|
|
472
|
-
} */
|
|
473
|
-
break;
|
|
425
|
+
if (!isLast ||
|
|
426
|
+
nextCandidate[1] ||
|
|
427
|
+
Math.min(getDistance(last.start1, endLocation, "closest"), getDistance(last.end2, endLocation, "closest")) >
|
|
428
|
+
Math.min(getDistance(current.start1, endLocation, "closest"), getDistance(current.end2, endLocation, "closest"))) {
|
|
429
|
+
results.push(current);
|
|
474
430
|
}
|
|
475
|
-
|
|
431
|
+
if (isLast && !nextCandidate[1] /* || equals(endRect.id, current.id) */) {
|
|
476
432
|
break;
|
|
477
|
-
}
|
|
478
|
-
// this is a skip condition to not include too many rects
|
|
433
|
+
}
|
|
479
434
|
if (matured) {
|
|
480
435
|
maturedCoveredLength = coveredLength;
|
|
481
|
-
/* lastMatured = current; */
|
|
482
436
|
}
|
|
483
|
-
results.push(current);
|
|
484
|
-
/*
|
|
485
|
-
|
|
486
|
-
if (current.start1 > endLocation && (wrappedOnce || !endIsWrapped)) {
|
|
487
|
-
break;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
*/
|
|
491
437
|
nextLocation = endIsWrapped
|
|
492
438
|
? wrappedOnce
|
|
493
439
|
? Math.min(current.end2, endLocation)
|
|
@@ -495,150 +441,76 @@ export const getCoverSet = async (coveringWidth, peers, roleAge, startNodeIdenti
|
|
|
495
441
|
: Math.min(current.end2, endLocation);
|
|
496
442
|
}
|
|
497
443
|
const res = new Set(results.map((x) => x.hash));
|
|
498
|
-
|
|
444
|
+
start instanceof PublicSignKey && res.add(start.hashcode());
|
|
499
445
|
return res;
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
let
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
if (nextPoint > 1 || nextPoint < startPoint) {
|
|
513
|
-
wrappedOnce = true;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
nextPoint = nextPoint % 1;
|
|
517
|
-
let distanceStart: number;
|
|
518
|
-
|
|
519
|
-
if (wrappedOnce) {
|
|
520
|
-
distanceStart = (1 - startPoint + currentNode.segment.offset) % 1;
|
|
521
|
-
} else {
|
|
522
|
-
distanceStart = (currentNode.segment.offset - startPoint) % 1;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
const distanceEnd = distanceStart + currentNode.segment.factor;
|
|
526
|
-
|
|
527
|
-
return [nextPoint, distanceStart, distanceEnd, wrappedOnce];
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
const getNextMatured = async (from: ReplicatorRect) => {
|
|
531
|
-
let next = (await peers.query(new SearchRequest({ query: [new IntegerCompare({ key: ['segment', 'offset'], compare: Compare.Greater, value: from.segment.offset })], fetch: 1 })))?.results[0]?.value // (from.next || peers.head)!;
|
|
532
|
-
while (
|
|
533
|
-
next.hash !== from.hash &&
|
|
534
|
-
next.hash !== startNode.hash
|
|
535
|
-
) {
|
|
536
|
-
if (isMatured(next.segment, t, roleAge)) {
|
|
537
|
-
return next;
|
|
446
|
+
};
|
|
447
|
+
export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now) => {
|
|
448
|
+
let result = await index.query(new SearchRequest({
|
|
449
|
+
query: [new StringMatch({ key: "hash", value: publicKey.hashcode() })],
|
|
450
|
+
fetch: 1,
|
|
451
|
+
}));
|
|
452
|
+
let node = result.results[0]?.value;
|
|
453
|
+
if (node) {
|
|
454
|
+
if (!isMatured(node, now, roleAge)) {
|
|
455
|
+
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false));
|
|
456
|
+
if (matured) {
|
|
457
|
+
node = matured;
|
|
538
458
|
}
|
|
539
|
-
next = (next.next || peers.head)!;
|
|
540
|
-
}
|
|
541
|
-
return undefined;
|
|
542
|
-
}; */
|
|
543
|
-
/**
|
|
544
|
-
* The purpose of this loop is to cover at least coveringWidth
|
|
545
|
-
* so that if we query all nodes in this range, we know we will
|
|
546
|
-
* "query" all data in that range
|
|
547
|
-
*/
|
|
548
|
-
/* let isPastThePoint = false;
|
|
549
|
-
outer: while (currentNode) {
|
|
550
|
-
if (set.has(currentNode.hash)) break;
|
|
551
|
-
|
|
552
|
-
const [nextPoint, distanceStart, distanceEnd, wrapped] = getNextPoint();
|
|
553
|
-
|
|
554
|
-
if (distanceStart <= coveringWidth) {
|
|
555
|
-
set.add(currentNode.hash);
|
|
556
459
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
(nextHasWrapped &&
|
|
575
|
-
(wrapped ? nextOffset > nextPoint : prevOffset < nextPoint)) ||
|
|
576
|
-
(!nextHasWrapped && prevOffset < nextPoint && nextPoint <= nextOffset)
|
|
577
|
-
) {
|
|
578
|
-
isPastThePoint = true;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (isPastThePoint) {
|
|
582
|
-
break; // include this next in the set;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
const overlapsRange = containsPoint(next.value.role, nextPoint);
|
|
586
|
-
|
|
587
|
-
if (overlapsRange) {
|
|
588
|
-
// Find out if there is a better choice ahead of us
|
|
589
|
-
const nextNext = await getNextMatured(next);
|
|
590
|
-
if (
|
|
591
|
-
nextNext &&
|
|
592
|
-
nextNext.hash === currentNode.hash &&
|
|
593
|
-
nextNext.segment.offset < nextPoint &&
|
|
594
|
-
nextNext.segment.offset + nextNext.segment.factor > nextPoint
|
|
595
|
-
) {
|
|
596
|
-
// nextNext is better (continue to iterate)
|
|
597
|
-
} else {
|
|
598
|
-
// done
|
|
599
|
-
break;
|
|
600
|
-
}
|
|
601
|
-
} else {
|
|
602
|
-
// (continue to iterate)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
next = next.next || peers.head;
|
|
460
|
+
}
|
|
461
|
+
return node;
|
|
462
|
+
};
|
|
463
|
+
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth) => {
|
|
464
|
+
// find a good starting point
|
|
465
|
+
let startNode = undefined;
|
|
466
|
+
let startLocation = undefined;
|
|
467
|
+
const nodeFromPoint = async (point = scaleToU32(Math.random())) => {
|
|
468
|
+
startLocation = point;
|
|
469
|
+
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true);
|
|
470
|
+
};
|
|
471
|
+
if (start instanceof PublicSignKey) {
|
|
472
|
+
// start at our node (local first)
|
|
473
|
+
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now);
|
|
474
|
+
if (!startNode) {
|
|
475
|
+
// fetch randomly
|
|
476
|
+
await nodeFromPoint();
|
|
606
477
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
// collect 1 point around the boundary of the start and one at the end,
|
|
610
|
-
// preferrd matured and that we already have it
|
|
611
|
-
/* for (const point of [
|
|
612
|
-
startNode.segment.offset,
|
|
613
|
-
(startNode.segment.offset + coveringWidth) % 1
|
|
614
|
-
]) {
|
|
615
|
-
let done = false;
|
|
616
|
-
const unmatured: string[] = [];
|
|
617
|
-
collectNodesAroundPoint(
|
|
618
|
-
t,
|
|
619
|
-
roleAge,
|
|
620
|
-
peers,
|
|
621
|
-
isMatured(startNode.segment, t, roleAge) ? startNode : peers.head, // start at startNode is matured, else start at head (we only seek to find one matured node at the point)
|
|
622
|
-
(rect, matured) => {
|
|
623
|
-
if (matured) {
|
|
624
|
-
if (set.has(rect.hash)) {
|
|
625
|
-
// great!
|
|
626
|
-
} else {
|
|
627
|
-
set.add(rect.hash);
|
|
628
|
-
}
|
|
629
|
-
done = true;
|
|
630
|
-
} else {
|
|
631
|
-
unmatured.push(rect.hash);
|
|
632
|
-
}
|
|
633
|
-
},
|
|
634
|
-
point,
|
|
635
|
-
() => done
|
|
636
|
-
);
|
|
637
|
-
if (!done && unmatured.length > 0) {
|
|
638
|
-
set.add(unmatured[0]);
|
|
639
|
-
// TODO add more elements?
|
|
478
|
+
else {
|
|
479
|
+
startLocation = startNode.start1;
|
|
640
480
|
}
|
|
641
481
|
}
|
|
642
|
-
|
|
482
|
+
else if (typeof start === "number") {
|
|
483
|
+
await nodeFromPoint(start);
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
await nodeFromPoint();
|
|
487
|
+
}
|
|
488
|
+
if (!startNode || startLocation == null) {
|
|
489
|
+
return { startNode: undefined, startLocation: 0, endLocation: 0 };
|
|
490
|
+
}
|
|
491
|
+
let endLocation = startLocation + widthToCoverScaled;
|
|
492
|
+
if (intervalWidth != null) {
|
|
493
|
+
endLocation = endLocation % intervalWidth;
|
|
494
|
+
}
|
|
495
|
+
// if start location is after endLocation and startNode is strict then return undefined because this is not a node we want to choose
|
|
496
|
+
let coveredDistanceToStart = 0;
|
|
497
|
+
if (startNode.start1 < startLocation) {
|
|
498
|
+
coveredDistanceToStart += intervalWidth - startLocation + startNode.start1;
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
coveredDistanceToStart += startNode.start1 - startLocation;
|
|
502
|
+
}
|
|
503
|
+
if (startNode.mode === ReplicationIntent.Strict &&
|
|
504
|
+
coveredDistanceToStart > widthToCoverScaled) {
|
|
505
|
+
return { startNode: undefined, startLocation: 0, endLocation: 0 };
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
startNode,
|
|
509
|
+
startLocation: Math.round(startLocation),
|
|
510
|
+
endLocation: Math.round(endLocation),
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove) => {
|
|
514
|
+
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove));
|
|
643
515
|
};
|
|
644
516
|
//# sourceMappingURL=ranges.js.map
|