@peerbit/shared-log 9.1.2 → 9.2.0-0b8baa8
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/get-samples.js +2 -3
- package/dist/benchmark/get-samples.js.map +1 -1
- package/dist/benchmark/index.js +4 -6
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/memory/child.d.ts +2 -0
- package/dist/benchmark/memory/child.d.ts.map +1 -0
- package/dist/benchmark/memory/child.js +149 -0
- package/dist/benchmark/memory/child.js.map +1 -0
- package/dist/benchmark/memory/index.d.ts +2 -0
- package/dist/benchmark/memory/index.d.ts.map +1 -0
- package/dist/benchmark/memory/index.js +81 -0
- package/dist/benchmark/memory/index.js.map +1 -0
- package/dist/benchmark/memory/utils.d.ts +13 -0
- package/dist/benchmark/memory/utils.d.ts.map +1 -0
- package/dist/benchmark/memory/utils.js +2 -0
- package/dist/benchmark/memory/utils.js.map +1 -0
- package/dist/benchmark/replication-prune.js +27 -25
- package/dist/benchmark/replication-prune.js.map +1 -1
- package/dist/benchmark/replication.js +15 -16
- package/dist/benchmark/replication.js.map +1 -1
- package/dist/src/debounce.d.ts +25 -0
- package/dist/src/debounce.d.ts.map +1 -0
- package/dist/src/debounce.js +130 -0
- package/dist/src/debounce.js.map +1 -0
- package/dist/src/index.d.ts +55 -21
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +867 -390
- package/dist/src/index.js.map +1 -1
- package/dist/src/pid.d.ts.map +1 -1
- package/dist/src/pid.js +23 -21
- package/dist/src/pid.js.map +1 -1
- package/dist/src/ranges.d.ts +104 -8
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +497 -82
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/replication-domain-hash.d.ts.map +1 -1
- package/dist/src/replication-domain-hash.js.map +1 -1
- package/dist/src/replication-domain-time.d.ts.map +1 -1
- package/dist/src/replication-domain-time.js.map +1 -1
- package/dist/src/replication-domain.d.ts +22 -2
- package/dist/src/replication-domain.d.ts.map +1 -1
- package/dist/src/replication-domain.js +33 -0
- package/dist/src/replication-domain.js.map +1 -1
- package/dist/src/replication.d.ts +1 -55
- package/dist/src/replication.d.ts.map +1 -1
- package/dist/src/replication.js +5 -215
- package/dist/src/replication.js.map +1 -1
- package/dist/src/role.d.ts +1 -0
- package/dist/src/role.d.ts.map +1 -1
- package/dist/src/role.js +1 -0
- package/dist/src/role.js.map +1 -1
- package/dist/src/utils.d.ts +6 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +39 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +70 -70
- package/src/debounce.ts +172 -0
- package/src/index.ts +1282 -562
- package/src/pid.ts +27 -25
- package/src/ranges.ts +772 -187
- package/src/replication-domain-hash.ts +3 -1
- package/src/replication-domain-time.ts +2 -1
- package/src/replication-domain.ts +68 -5
- package/src/replication.ts +9 -235
- package/src/role.ts +1 -0
- package/src/utils.ts +49 -0
package/dist/src/ranges.js
CHANGED
|
@@ -1,7 +1,313 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { deserialize, field, serialize, variant } from "@dao-xyz/borsh";
|
|
11
|
+
import { PublicSignKey, equals, randomBytes, toBase64 } from "@peerbit/crypto";
|
|
12
|
+
import { And, BoolQuery, ByteMatchQuery, Compare, IntegerCompare, Not, Or, Sort, SortDirection, StringMatch, iteratorInSeries, } from "@peerbit/indexer-interface";
|
|
13
|
+
import { id } from "@peerbit/indexer-interface";
|
|
14
|
+
import { Meta, ShallowMeta } from "@peerbit/log";
|
|
15
|
+
import {} from "./replication-domain.js";
|
|
4
16
|
import { MAX_U32, scaleToU32 } from "./role.js";
|
|
17
|
+
import { groupByGidSync } from "./utils.js";
|
|
18
|
+
export var ReplicationIntent;
|
|
19
|
+
(function (ReplicationIntent) {
|
|
20
|
+
ReplicationIntent[ReplicationIntent["NonStrict"] = 0] = "NonStrict";
|
|
21
|
+
ReplicationIntent[ReplicationIntent["Strict"] = 1] = "Strict";
|
|
22
|
+
})(ReplicationIntent || (ReplicationIntent = {}));
|
|
23
|
+
export const getSegmentsFromOffsetAndRange = (offset, factor) => {
|
|
24
|
+
let start1 = offset;
|
|
25
|
+
let end1Unscaled = offset + factor; // only add factor if it is not 1 to prevent numerical issues (like (0.9 + 1) % 1 => 0.8999999)
|
|
26
|
+
let end1 = Math.min(end1Unscaled, MAX_U32);
|
|
27
|
+
return [
|
|
28
|
+
[start1, end1],
|
|
29
|
+
end1Unscaled > MAX_U32
|
|
30
|
+
? [0, (factor !== MAX_U32 ? offset + factor : offset) % MAX_U32]
|
|
31
|
+
: [start1, end1],
|
|
32
|
+
];
|
|
33
|
+
};
|
|
34
|
+
export const shouldAssigneToRangeBoundary = (leaders) => {
|
|
35
|
+
let assignedToRangeBoundary = leaders === false || leaders.size === 0;
|
|
36
|
+
if (!assignedToRangeBoundary && leaders) {
|
|
37
|
+
for (const [_, { intersecting }] of leaders) {
|
|
38
|
+
if (!intersecting) {
|
|
39
|
+
assignedToRangeBoundary = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return assignedToRangeBoundary;
|
|
45
|
+
};
|
|
46
|
+
export class EntryReplicated {
|
|
47
|
+
id; // hash + coordinate
|
|
48
|
+
hash;
|
|
49
|
+
gid;
|
|
50
|
+
coordinate;
|
|
51
|
+
wallTime;
|
|
52
|
+
assignedToRangeBoundary;
|
|
53
|
+
_meta;
|
|
54
|
+
_metaResolved;
|
|
55
|
+
constructor(properties) {
|
|
56
|
+
this.coordinate = properties.coordinate;
|
|
57
|
+
this.hash = properties.hash;
|
|
58
|
+
this.gid = properties.meta.gid;
|
|
59
|
+
this.id = this.hash + "-" + this.coordinate;
|
|
60
|
+
this.wallTime = properties.meta.clock.timestamp.wallTime;
|
|
61
|
+
const shallow = properties.meta instanceof Meta
|
|
62
|
+
? new ShallowMeta(properties.meta)
|
|
63
|
+
: properties.meta;
|
|
64
|
+
this._meta = serialize(shallow);
|
|
65
|
+
this._metaResolved = deserialize(this._meta, ShallowMeta);
|
|
66
|
+
this._metaResolved = properties.meta;
|
|
67
|
+
this.assignedToRangeBoundary = properties.assignedToRangeBoundary;
|
|
68
|
+
}
|
|
69
|
+
get meta() {
|
|
70
|
+
if (!this._metaResolved) {
|
|
71
|
+
this._metaResolved = deserialize(this._meta, ShallowMeta);
|
|
72
|
+
}
|
|
73
|
+
return this._metaResolved;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
__decorate([
|
|
77
|
+
id({ type: "string" }),
|
|
78
|
+
__metadata("design:type", String)
|
|
79
|
+
], EntryReplicated.prototype, "id", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
field({ type: "string" }),
|
|
82
|
+
__metadata("design:type", String)
|
|
83
|
+
], EntryReplicated.prototype, "hash", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
field({ type: "string" }),
|
|
86
|
+
__metadata("design:type", String)
|
|
87
|
+
], EntryReplicated.prototype, "gid", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
field({ type: "u32" }),
|
|
90
|
+
__metadata("design:type", Number)
|
|
91
|
+
], EntryReplicated.prototype, "coordinate", void 0);
|
|
92
|
+
__decorate([
|
|
93
|
+
field({ type: "u64" }),
|
|
94
|
+
__metadata("design:type", BigInt)
|
|
95
|
+
], EntryReplicated.prototype, "wallTime", void 0);
|
|
96
|
+
__decorate([
|
|
97
|
+
field({ type: "bool" }),
|
|
98
|
+
__metadata("design:type", Boolean)
|
|
99
|
+
], EntryReplicated.prototype, "assignedToRangeBoundary", void 0);
|
|
100
|
+
__decorate([
|
|
101
|
+
field({ type: Uint8Array }),
|
|
102
|
+
__metadata("design:type", Uint8Array)
|
|
103
|
+
], EntryReplicated.prototype, "_meta", void 0);
|
|
104
|
+
let ReplicationRange = class ReplicationRange {
|
|
105
|
+
id;
|
|
106
|
+
timestamp;
|
|
107
|
+
_offset;
|
|
108
|
+
_factor;
|
|
109
|
+
mode;
|
|
110
|
+
constructor(properties) {
|
|
111
|
+
const { id, offset, factor, timestamp, mode } = properties;
|
|
112
|
+
this.id = id;
|
|
113
|
+
this._offset = offset;
|
|
114
|
+
this._factor = factor;
|
|
115
|
+
this.timestamp = timestamp;
|
|
116
|
+
this.mode = mode;
|
|
117
|
+
}
|
|
118
|
+
get factor() {
|
|
119
|
+
return this._factor;
|
|
120
|
+
}
|
|
121
|
+
get offset() {
|
|
122
|
+
return this._offset;
|
|
123
|
+
}
|
|
124
|
+
toReplicationRangeIndexable(key) {
|
|
125
|
+
return new ReplicationRangeIndexable({
|
|
126
|
+
id: this.id,
|
|
127
|
+
publicKeyHash: key.hashcode(),
|
|
128
|
+
offset: this.offset,
|
|
129
|
+
length: this.factor,
|
|
130
|
+
timestamp: this.timestamp,
|
|
131
|
+
mode: this.mode,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
__decorate([
|
|
136
|
+
field({ type: Uint8Array }),
|
|
137
|
+
__metadata("design:type", Uint8Array)
|
|
138
|
+
], ReplicationRange.prototype, "id", void 0);
|
|
139
|
+
__decorate([
|
|
140
|
+
field({ type: "u64" }),
|
|
141
|
+
__metadata("design:type", BigInt)
|
|
142
|
+
], ReplicationRange.prototype, "timestamp", void 0);
|
|
143
|
+
__decorate([
|
|
144
|
+
field({ type: "u32" }),
|
|
145
|
+
__metadata("design:type", Number)
|
|
146
|
+
], ReplicationRange.prototype, "_offset", void 0);
|
|
147
|
+
__decorate([
|
|
148
|
+
field({ type: "u32" }),
|
|
149
|
+
__metadata("design:type", Number)
|
|
150
|
+
], ReplicationRange.prototype, "_factor", void 0);
|
|
151
|
+
__decorate([
|
|
152
|
+
field({ type: "u8" }),
|
|
153
|
+
__metadata("design:type", Number)
|
|
154
|
+
], ReplicationRange.prototype, "mode", void 0);
|
|
155
|
+
ReplicationRange = __decorate([
|
|
156
|
+
variant(0),
|
|
157
|
+
__metadata("design:paramtypes", [Object])
|
|
158
|
+
], ReplicationRange);
|
|
159
|
+
export { ReplicationRange };
|
|
160
|
+
export class ReplicationRangeIndexable {
|
|
161
|
+
id;
|
|
162
|
+
hash;
|
|
163
|
+
timestamp;
|
|
164
|
+
start1;
|
|
165
|
+
end1;
|
|
166
|
+
start2;
|
|
167
|
+
end2;
|
|
168
|
+
width;
|
|
169
|
+
mode;
|
|
170
|
+
constructor(properties) {
|
|
171
|
+
this.id = properties.id ?? randomBytes(32);
|
|
172
|
+
this.hash =
|
|
173
|
+
properties.publicKeyHash ||
|
|
174
|
+
properties.publicKey.hashcode();
|
|
175
|
+
if (!properties.normalized) {
|
|
176
|
+
this.transform({ length: properties.length, offset: properties.offset });
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
this.transform({
|
|
180
|
+
length: scaleToU32(properties.length),
|
|
181
|
+
offset: scaleToU32(properties.offset),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
this.mode = properties.mode ?? ReplicationIntent.NonStrict;
|
|
185
|
+
this.timestamp = properties.timestamp || BigInt(0);
|
|
186
|
+
}
|
|
187
|
+
transform(properties) {
|
|
188
|
+
const ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.length);
|
|
189
|
+
this.start1 = Math.round(ranges[0][0]);
|
|
190
|
+
this.end1 = Math.round(ranges[0][1]);
|
|
191
|
+
this.start2 = Math.round(ranges[1][0]);
|
|
192
|
+
this.end2 = Math.round(ranges[1][1]);
|
|
193
|
+
this.width =
|
|
194
|
+
this.end1 -
|
|
195
|
+
this.start1 +
|
|
196
|
+
(this.end2 < this.end1 ? this.end2 - this.start2 : 0);
|
|
197
|
+
if (this.start1 > 0xffffffff ||
|
|
198
|
+
this.end1 > 0xffffffff ||
|
|
199
|
+
this.start2 > 0xffffffff ||
|
|
200
|
+
this.end2 > 0xffffffff ||
|
|
201
|
+
this.width > 0xffffffff ||
|
|
202
|
+
this.width < 0) {
|
|
203
|
+
throw new Error("Segment coordinate out of bounds");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
get idString() {
|
|
207
|
+
return toBase64(this.id);
|
|
208
|
+
}
|
|
209
|
+
contains(point) {
|
|
210
|
+
return ((point >= this.start1 && point < this.end1) ||
|
|
211
|
+
(point >= this.start2 && point < this.end2));
|
|
212
|
+
}
|
|
213
|
+
overlaps(other, checkOther = true) {
|
|
214
|
+
if (this.contains(other.start1) ||
|
|
215
|
+
this.contains(other.start2) ||
|
|
216
|
+
this.contains(other.end1 - 1) ||
|
|
217
|
+
this.contains(other.end2 - 1)) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
if (checkOther) {
|
|
221
|
+
return other.overlaps(this, false);
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
toReplicationRange() {
|
|
226
|
+
return new ReplicationRange({
|
|
227
|
+
id: this.id,
|
|
228
|
+
offset: this.start1,
|
|
229
|
+
factor: this.width,
|
|
230
|
+
timestamp: this.timestamp,
|
|
231
|
+
mode: this.mode,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
distanceTo(point) {
|
|
235
|
+
let wrappedPoint = MAX_U32 - point;
|
|
236
|
+
return Math.min(Math.abs(this.start1 - point), Math.abs(this.end2 - point), Math.abs(this.start1 - wrappedPoint), Math.abs(this.end2 - wrappedPoint));
|
|
237
|
+
}
|
|
238
|
+
get wrapped() {
|
|
239
|
+
return this.end2 < this.end1;
|
|
240
|
+
}
|
|
241
|
+
get widthNormalized() {
|
|
242
|
+
return this.width / MAX_U32;
|
|
243
|
+
}
|
|
244
|
+
equals(other) {
|
|
245
|
+
if (equals(this.id, other.id) &&
|
|
246
|
+
this.hash === other.hash &&
|
|
247
|
+
this.timestamp === other.timestamp &&
|
|
248
|
+
this.mode === other.mode &&
|
|
249
|
+
this.start1 === other.start1 &&
|
|
250
|
+
this.end1 === other.end1 &&
|
|
251
|
+
this.start2 === other.start2 &&
|
|
252
|
+
this.end2 === other.end2 &&
|
|
253
|
+
this.width === other.width) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
equalRange(other) {
|
|
259
|
+
return (this.start1 === other.start1 &&
|
|
260
|
+
this.end1 === other.end1 &&
|
|
261
|
+
this.start2 === other.start2 &&
|
|
262
|
+
this.end2 === other.end2);
|
|
263
|
+
}
|
|
264
|
+
toString() {
|
|
265
|
+
let roundToTwoDecimals = (num) => Math.round(num * 100) / 100;
|
|
266
|
+
if (Math.abs(this.start1 - this.start2) < 0.0001) {
|
|
267
|
+
return `([${roundToTwoDecimals(this.start1 / MAX_U32)}, ${roundToTwoDecimals(this.end1 / MAX_U32)}])`;
|
|
268
|
+
}
|
|
269
|
+
return `([${roundToTwoDecimals(this.start1 / MAX_U32)}, ${roundToTwoDecimals(this.end1 / MAX_U32)}] [${roundToTwoDecimals(this.start2 / MAX_U32)}, ${roundToTwoDecimals(this.end2 / MAX_U32)}])`;
|
|
270
|
+
}
|
|
271
|
+
toStringDetailed() {
|
|
272
|
+
return `(hash ${this.hash} range: ${this.toString()})`;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
__decorate([
|
|
276
|
+
id({ type: Uint8Array }),
|
|
277
|
+
__metadata("design:type", Uint8Array)
|
|
278
|
+
], ReplicationRangeIndexable.prototype, "id", void 0);
|
|
279
|
+
__decorate([
|
|
280
|
+
field({ type: "string" }),
|
|
281
|
+
__metadata("design:type", String)
|
|
282
|
+
], ReplicationRangeIndexable.prototype, "hash", void 0);
|
|
283
|
+
__decorate([
|
|
284
|
+
field({ type: "u64" }),
|
|
285
|
+
__metadata("design:type", BigInt)
|
|
286
|
+
], ReplicationRangeIndexable.prototype, "timestamp", void 0);
|
|
287
|
+
__decorate([
|
|
288
|
+
field({ type: "u32" }),
|
|
289
|
+
__metadata("design:type", Number)
|
|
290
|
+
], ReplicationRangeIndexable.prototype, "start1", void 0);
|
|
291
|
+
__decorate([
|
|
292
|
+
field({ type: "u32" }),
|
|
293
|
+
__metadata("design:type", Number)
|
|
294
|
+
], ReplicationRangeIndexable.prototype, "end1", void 0);
|
|
295
|
+
__decorate([
|
|
296
|
+
field({ type: "u32" }),
|
|
297
|
+
__metadata("design:type", Number)
|
|
298
|
+
], ReplicationRangeIndexable.prototype, "start2", void 0);
|
|
299
|
+
__decorate([
|
|
300
|
+
field({ type: "u32" }),
|
|
301
|
+
__metadata("design:type", Number)
|
|
302
|
+
], ReplicationRangeIndexable.prototype, "end2", void 0);
|
|
303
|
+
__decorate([
|
|
304
|
+
field({ type: "u32" }),
|
|
305
|
+
__metadata("design:type", Number)
|
|
306
|
+
], ReplicationRangeIndexable.prototype, "width", void 0);
|
|
307
|
+
__decorate([
|
|
308
|
+
field({ type: "u8" }),
|
|
309
|
+
__metadata("design:type", Number)
|
|
310
|
+
], ReplicationRangeIndexable.prototype, "mode", void 0);
|
|
5
311
|
const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
|
|
6
312
|
// 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
|
|
7
313
|
let queries = [
|
|
@@ -37,19 +343,12 @@ const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
|
|
|
37
343
|
value: BigInt(now - roleAgeLimit),
|
|
38
344
|
}),
|
|
39
345
|
];
|
|
40
|
-
return iterate(
|
|
346
|
+
return rects.iterate({
|
|
41
347
|
query: queries,
|
|
42
348
|
sort: options?.sort,
|
|
43
|
-
|
|
44
|
-
}));
|
|
45
|
-
/* const results = await rects.query(new SearchRequest({
|
|
46
|
-
query: queries,
|
|
47
|
-
sort: options?.sort,
|
|
48
|
-
fetch: 0xffffffff
|
|
49
|
-
}))
|
|
50
|
-
return results.results.map(x => x.value) */
|
|
349
|
+
}, options);
|
|
51
350
|
};
|
|
52
|
-
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict) => {
|
|
351
|
+
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict, options) => {
|
|
53
352
|
const createQueries = (p, equality) => {
|
|
54
353
|
let queries;
|
|
55
354
|
if (direction === "below") {
|
|
@@ -90,22 +389,32 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
|
|
|
90
389
|
}
|
|
91
390
|
return queries;
|
|
92
391
|
};
|
|
93
|
-
const
|
|
392
|
+
const sortByOldest = new Sort({ key: "timestamp", direction: "asc" });
|
|
393
|
+
const sortByHash = new Sort({ key: "hash", direction: "asc" }); // when breaking even
|
|
394
|
+
const iterator = rects.iterate({
|
|
94
395
|
query: createQueries(point, false),
|
|
95
|
-
sort:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
396
|
+
sort: [
|
|
397
|
+
direction === "below"
|
|
398
|
+
? new Sort({ key: ["end2"], direction: "desc" })
|
|
399
|
+
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
400
|
+
sortByOldest,
|
|
401
|
+
sortByHash,
|
|
402
|
+
],
|
|
403
|
+
}, options);
|
|
404
|
+
const iteratorWrapped = rects.iterate({
|
|
100
405
|
query: createQueries(direction === "below" ? MAX_U32 : 0, true),
|
|
101
|
-
sort:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
406
|
+
sort: [
|
|
407
|
+
direction === "below"
|
|
408
|
+
? new Sort({ key: ["end2"], direction: "desc" })
|
|
409
|
+
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
410
|
+
sortByOldest,
|
|
411
|
+
sortByHash,
|
|
412
|
+
],
|
|
413
|
+
}, options);
|
|
105
414
|
return joinIterator([iterator, iteratorWrapped], point, direction);
|
|
106
415
|
};
|
|
107
416
|
export const hasCoveringRange = async (rects, range) => {
|
|
108
|
-
return ((await rects.count(
|
|
417
|
+
return ((await rects.count({
|
|
109
418
|
query: [
|
|
110
419
|
new Or([
|
|
111
420
|
new And([
|
|
@@ -169,7 +478,7 @@ export const hasCoveringRange = async (rects, range) => {
|
|
|
169
478
|
value: range.id,
|
|
170
479
|
})),
|
|
171
480
|
],
|
|
172
|
-
}))
|
|
481
|
+
})) > 0);
|
|
173
482
|
};
|
|
174
483
|
export const getDistance = (from, to, direction, end = MAX_U32) => {
|
|
175
484
|
// if direction is 'above' only measure distance from 'from to 'to' from above.
|
|
@@ -202,21 +511,17 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
202
511
|
let queues = [];
|
|
203
512
|
return {
|
|
204
513
|
next: async (count) => {
|
|
205
|
-
let results =
|
|
206
|
-
kept: 0, // TODO
|
|
207
|
-
results: [],
|
|
208
|
-
};
|
|
514
|
+
let results = [];
|
|
209
515
|
for (let i = 0; i < iterators.length; i++) {
|
|
210
516
|
let queue = queues[i];
|
|
211
517
|
if (!queue) {
|
|
212
|
-
queue = { elements: []
|
|
518
|
+
queue = { elements: [] };
|
|
213
519
|
queues[i] = queue;
|
|
214
520
|
}
|
|
215
521
|
let iterator = iterators[i];
|
|
216
|
-
if (queue.elements.length < count && iterator.done()
|
|
522
|
+
if (queue.elements.length < count && iterator.done() !== true) {
|
|
217
523
|
let res = await iterator.next(count);
|
|
218
|
-
|
|
219
|
-
for (const el of res.results) {
|
|
524
|
+
for (const el of res) {
|
|
220
525
|
const closest = el.value;
|
|
221
526
|
let dist;
|
|
222
527
|
if (direction === "closest") {
|
|
@@ -254,15 +559,16 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
254
559
|
}
|
|
255
560
|
let closest = queues[closestQueue]?.elements.shift();
|
|
256
561
|
if (closest) {
|
|
257
|
-
results.
|
|
562
|
+
results.push(closest.result);
|
|
258
563
|
}
|
|
259
564
|
}
|
|
260
|
-
for (let i = 0; i < queues.length; i++) {
|
|
261
|
-
results.kept += queues[i].elements.length + queues[i].kept;
|
|
262
|
-
}
|
|
263
565
|
return results;
|
|
264
566
|
},
|
|
265
|
-
|
|
567
|
+
pending: async () => {
|
|
568
|
+
let allPending = await Promise.all(iterators.map((x) => x.pending()));
|
|
569
|
+
return allPending.reduce((acc, x) => acc + x, 0);
|
|
570
|
+
},
|
|
571
|
+
done: () => iterators.every((x) => x.done() === true),
|
|
266
572
|
close: async () => {
|
|
267
573
|
for (const iterator of iterators) {
|
|
268
574
|
await iterator.close();
|
|
@@ -278,71 +584,80 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
278
584
|
},
|
|
279
585
|
};
|
|
280
586
|
};
|
|
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);
|
|
587
|
+
const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
|
|
588
|
+
const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow, options);
|
|
589
|
+
const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove, options);
|
|
590
|
+
const containing = containingPoint(peers, point, roleAge, true, now, options);
|
|
285
591
|
return iteratorInSeries(containing, joinIterator([closestBelow, closestAbove], point, "closest"));
|
|
286
592
|
};
|
|
287
593
|
const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, done = () => true) => {
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
594
|
+
/* let shape = { timestamp: true, hash: true } as const */
|
|
595
|
+
const containing = containingPoint(peers, point, 0, true, now /* , { shape } */);
|
|
596
|
+
const allContaining = await containing.all();
|
|
597
|
+
for (const rect of allContaining) {
|
|
598
|
+
collector(rect.value, isMatured(rect.value, now, roleAge), true);
|
|
292
599
|
}
|
|
293
600
|
if (done()) {
|
|
294
601
|
return;
|
|
295
602
|
}
|
|
296
|
-
const closestBelow = getClosest("below", peers, point, 0, true, now, false);
|
|
297
|
-
const closestAbove = getClosest("above", peers, point, 0, true, now, false);
|
|
603
|
+
const closestBelow = getClosest("below", peers, point, 0, true, now, false /* , { shape } */);
|
|
604
|
+
const closestAbove = getClosest("above", peers, point, 0, true, now, false /* , { shape } */);
|
|
298
605
|
const aroundIterator = joinIterator([closestBelow, closestAbove], point, "closest");
|
|
299
|
-
while (aroundIterator.done()
|
|
606
|
+
while (aroundIterator.done() !== true && done() !== true) {
|
|
300
607
|
const res = await aroundIterator.next(1);
|
|
301
|
-
for (const rect of res
|
|
302
|
-
collector(rect.value, isMatured(rect.value, now, roleAge));
|
|
608
|
+
for (const rect of res) {
|
|
609
|
+
collector(rect.value, isMatured(rect.value, now, roleAge), false);
|
|
303
610
|
if (done()) {
|
|
304
611
|
return;
|
|
305
612
|
}
|
|
306
613
|
}
|
|
307
614
|
}
|
|
308
615
|
};
|
|
616
|
+
export const getEvenlySpacedU32 = (from, count) => {
|
|
617
|
+
let ret = new Array(count);
|
|
618
|
+
for (let i = 0; i < count; i++) {
|
|
619
|
+
ret[i] = Math.round(from + (i * MAX_U32) / count) % MAX_U32;
|
|
620
|
+
}
|
|
621
|
+
return ret;
|
|
622
|
+
};
|
|
309
623
|
export const isMatured = (segment, now, minAge) => {
|
|
310
624
|
return now - Number(segment.timestamp) >= minAge;
|
|
311
625
|
};
|
|
312
|
-
|
|
313
|
-
|
|
626
|
+
// get peer sample that are responsible for the cursor point
|
|
627
|
+
// will return a list of peers that want to replicate the data,
|
|
628
|
+
// but also if necessary a list of peers that are responsible for the data
|
|
629
|
+
// but have not explicitly replicating a range that cover the cursor point
|
|
630
|
+
export const getSamples = async (cursor, peers, roleAge) => {
|
|
631
|
+
const leaders = new Map();
|
|
314
632
|
if (!peers) {
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
const size = await peers.getSize();
|
|
318
|
-
amount = Math.min(amount, size);
|
|
319
|
-
if (amount === 0) {
|
|
320
|
-
return [];
|
|
633
|
+
return new Map();
|
|
321
634
|
}
|
|
322
635
|
const now = +new Date();
|
|
323
636
|
const maturedLeaders = new Set();
|
|
324
|
-
for (let i = 0; i <
|
|
637
|
+
for (let i = 0; i < cursor.length; i++) {
|
|
325
638
|
// evenly distributed
|
|
326
|
-
const point = Math.round(cursor + (i * MAX_U32) / amount) % MAX_U32;
|
|
327
639
|
// aquire at least one unique node for each point
|
|
328
|
-
await collectNodesAroundPoint(roleAge, peers, (rect, m) => {
|
|
640
|
+
await collectNodesAroundPoint(roleAge, peers, (rect, m, intersecting) => {
|
|
329
641
|
if (m) {
|
|
330
642
|
maturedLeaders.add(rect.hash);
|
|
331
643
|
}
|
|
332
|
-
leaders.
|
|
333
|
-
|
|
644
|
+
const prev = leaders.get(rect.hash);
|
|
645
|
+
if (!prev || (intersecting && !prev.intersecting)) {
|
|
646
|
+
leaders.set(rect.hash, { intersecting });
|
|
647
|
+
}
|
|
648
|
+
}, cursor[i], now, () => {
|
|
334
649
|
if (maturedLeaders.size > i) {
|
|
335
650
|
return true;
|
|
336
651
|
}
|
|
337
652
|
return false;
|
|
338
653
|
});
|
|
339
654
|
}
|
|
340
|
-
return
|
|
655
|
+
return leaders;
|
|
341
656
|
};
|
|
342
657
|
const fetchOne = async (iterator) => {
|
|
343
658
|
const value = await iterator.next(1);
|
|
344
659
|
await iterator.close();
|
|
345
|
-
return value
|
|
660
|
+
return value[0]?.value;
|
|
346
661
|
};
|
|
347
662
|
export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */) => {
|
|
348
663
|
/* minReplicas = Math.min(minReplicas, replicatorCount); */ // TODO do we need this?
|
|
@@ -365,10 +680,9 @@ export const getCoverSet = async (properties) => {
|
|
|
365
680
|
if (properties.eager) {
|
|
366
681
|
const eagerFetch = properties.eager === true
|
|
367
682
|
? 1000
|
|
368
|
-
: properties.eager.unmaturedFetchCoverSize;
|
|
683
|
+
: (properties.eager.unmaturedFetchCoverSize ?? 1000);
|
|
369
684
|
// pull all umatured
|
|
370
|
-
const
|
|
371
|
-
fetch: eagerFetch,
|
|
685
|
+
const iterator = peers.iterate({
|
|
372
686
|
query: [
|
|
373
687
|
new IntegerCompare({
|
|
374
688
|
key: "timestamp",
|
|
@@ -376,8 +690,10 @@ export const getCoverSet = async (properties) => {
|
|
|
376
690
|
value: BigInt(now - roleAge),
|
|
377
691
|
}),
|
|
378
692
|
],
|
|
379
|
-
})
|
|
380
|
-
|
|
693
|
+
});
|
|
694
|
+
const rects = await iterator.next(eagerFetch);
|
|
695
|
+
await iterator.close();
|
|
696
|
+
for (const rect of rects) {
|
|
381
697
|
ret.add(rect.value.hash);
|
|
382
698
|
}
|
|
383
699
|
}
|
|
@@ -467,15 +783,114 @@ export const getCoverSet = async (properties) => {
|
|
|
467
783
|
start instanceof PublicSignKey && ret.add(start.hashcode());
|
|
468
784
|
return ret;
|
|
469
785
|
};
|
|
470
|
-
export const
|
|
471
|
-
|
|
786
|
+
/* export const getReplicationDiff = (changes: ReplicationChange) => {
|
|
787
|
+
// reduce the change set to only regions that are changed for each peer
|
|
788
|
+
// i.e. subtract removed regions from added regions, and vice versa
|
|
789
|
+
const result = new Map<string, { range: ReplicationRangeIndexable, added: boolean }[]>();
|
|
790
|
+
|
|
791
|
+
for (const addedChange of changes.added ?? []) {
|
|
792
|
+
let prev = result.get(addedChange.hash) ?? [];
|
|
793
|
+
for (const [_hash, ranges] of result.entries()) {
|
|
794
|
+
for (const r of ranges) {
|
|
795
|
+
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
*/
|
|
801
|
+
const matchRangeQuery = (range) => {
|
|
802
|
+
let ors = [];
|
|
803
|
+
ors.push(new And([
|
|
804
|
+
new IntegerCompare({
|
|
805
|
+
key: "coordinate",
|
|
806
|
+
compare: "gte",
|
|
807
|
+
value: range.start1,
|
|
808
|
+
}),
|
|
809
|
+
new IntegerCompare({
|
|
810
|
+
key: "coordinate",
|
|
811
|
+
compare: "lt",
|
|
812
|
+
value: range.end1,
|
|
813
|
+
}),
|
|
814
|
+
]));
|
|
815
|
+
ors.push(new And([
|
|
816
|
+
new IntegerCompare({
|
|
817
|
+
key: "coordinate",
|
|
818
|
+
compare: "gte",
|
|
819
|
+
value: range.start2,
|
|
820
|
+
}),
|
|
821
|
+
new IntegerCompare({
|
|
822
|
+
key: "coordinate",
|
|
823
|
+
compare: "lt",
|
|
824
|
+
value: range.end2,
|
|
825
|
+
}),
|
|
826
|
+
]));
|
|
827
|
+
return new Or(ors);
|
|
828
|
+
};
|
|
829
|
+
export const toRebalance = (changes, index) => {
|
|
830
|
+
const assignedRangesQuery = (changes) => {
|
|
831
|
+
let ors = [];
|
|
832
|
+
for (const change of changes) {
|
|
833
|
+
const matchRange = matchRangeQuery(change.range);
|
|
834
|
+
if (change.type === "updated") {
|
|
835
|
+
// assuming a range is to be removed, is this entry still enoughly replicated
|
|
836
|
+
const prevMatchRange = matchRangeQuery(change.prev);
|
|
837
|
+
ors.push(prevMatchRange);
|
|
838
|
+
ors.push(matchRange);
|
|
839
|
+
/* ors.push(
|
|
840
|
+
new And([
|
|
841
|
+
// not sufficiently replicated
|
|
842
|
+
new IntegerCompare({
|
|
843
|
+
key: "replicatorsMissingShifted",
|
|
844
|
+
compare: Compare.Greater,
|
|
845
|
+
value: HALF_MAX_U32 - 1, // + 1 since we are going to remove a replicator for this entry
|
|
846
|
+
}),
|
|
847
|
+
|
|
848
|
+
// is not the current range
|
|
849
|
+
new Not(matchRange),
|
|
850
|
+
|
|
851
|
+
// but was in the the previous range
|
|
852
|
+
prevMatchRange,
|
|
853
|
+
]),
|
|
854
|
+
); */
|
|
855
|
+
}
|
|
856
|
+
else {
|
|
857
|
+
ors.push(matchRange);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
// entry is assigned to a range boundary, meaning it is due to be inspected
|
|
861
|
+
ors.push(new BoolQuery({
|
|
862
|
+
key: "assignedToRangeBoundary",
|
|
863
|
+
value: true,
|
|
864
|
+
}));
|
|
865
|
+
// entry is not sufficiently replicated, and we are to still keep it
|
|
866
|
+
return new Or(ors);
|
|
867
|
+
};
|
|
868
|
+
return {
|
|
869
|
+
[Symbol.asyncIterator]: async function* () {
|
|
870
|
+
const iterator = index.iterate({
|
|
871
|
+
query: assignedRangesQuery(changes),
|
|
872
|
+
});
|
|
873
|
+
while (iterator.done() !== true) {
|
|
874
|
+
const entries = await iterator.next(1000); // TODO choose right batch sizes here for optimal memory usage / speed
|
|
875
|
+
// TODO do we need this
|
|
876
|
+
const grouped = await groupByGidSync(entries.map((x) => x.value));
|
|
877
|
+
for (const [gid, entries] of grouped.entries()) {
|
|
878
|
+
yield { gid, entries };
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
},
|
|
882
|
+
};
|
|
883
|
+
};
|
|
884
|
+
export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, options) => {
|
|
885
|
+
let iterator = index.iterate({
|
|
472
886
|
query: [new StringMatch({ key: "hash", value: publicKey.hashcode() })],
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
887
|
+
}, options);
|
|
888
|
+
let result = await iterator.next(1);
|
|
889
|
+
await iterator.close();
|
|
890
|
+
let node = result[0]?.value;
|
|
476
891
|
if (node) {
|
|
477
892
|
if (!isMatured(node, now, roleAge)) {
|
|
478
|
-
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false));
|
|
893
|
+
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, options));
|
|
479
894
|
if (matured) {
|
|
480
895
|
node = matured;
|
|
481
896
|
}
|
|
@@ -483,17 +898,17 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now) => {
|
|
|
483
898
|
}
|
|
484
899
|
return node;
|
|
485
900
|
};
|
|
486
|
-
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth) => {
|
|
901
|
+
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth, options) => {
|
|
487
902
|
// find a good starting point
|
|
488
903
|
let startNode = undefined;
|
|
489
904
|
let startLocation = undefined;
|
|
490
905
|
const nodeFromPoint = async (point = scaleToU32(Math.random())) => {
|
|
491
906
|
startLocation = point;
|
|
492
|
-
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true);
|
|
907
|
+
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, options);
|
|
493
908
|
};
|
|
494
909
|
if (start instanceof PublicSignKey) {
|
|
495
910
|
// start at our node (local first)
|
|
496
|
-
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now);
|
|
911
|
+
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, options);
|
|
497
912
|
if (!startNode) {
|
|
498
913
|
// fetch randomly
|
|
499
914
|
await nodeFromPoint();
|
|
@@ -533,7 +948,7 @@ export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge,
|
|
|
533
948
|
endLocation: Math.round(endLocation),
|
|
534
949
|
};
|
|
535
950
|
};
|
|
536
|
-
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove) => {
|
|
537
|
-
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove));
|
|
951
|
+
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
|
|
952
|
+
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options));
|
|
538
953
|
};
|
|
539
954
|
//# sourceMappingURL=ranges.js.map
|