@peerbit/shared-log 9.1.2 → 9.2.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/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 +518 -76
- 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 +5 -5
- package/src/debounce.ts +172 -0
- package/src/index.ts +1282 -562
- package/src/pid.ts +27 -25
- package/src/ranges.ts +794 -181
- 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,11 +343,10 @@ 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
|
-
}));
|
|
349
|
+
}, options);
|
|
45
350
|
/* const results = await rects.query(new SearchRequest({
|
|
46
351
|
query: queries,
|
|
47
352
|
sort: options?.sort,
|
|
@@ -49,7 +354,7 @@ const containingPoint = (rects, point, roleAgeLimit, matured, now, options) => {
|
|
|
49
354
|
}))
|
|
50
355
|
return results.results.map(x => x.value) */
|
|
51
356
|
};
|
|
52
|
-
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict) => {
|
|
357
|
+
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict, options) => {
|
|
53
358
|
const createQueries = (p, equality) => {
|
|
54
359
|
let queries;
|
|
55
360
|
if (direction === "below") {
|
|
@@ -90,22 +395,32 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
|
|
|
90
395
|
}
|
|
91
396
|
return queries;
|
|
92
397
|
};
|
|
93
|
-
const
|
|
398
|
+
const sortByOldest = new Sort({ key: "timestamp", direction: "asc" });
|
|
399
|
+
const sortByHash = new Sort({ key: "hash", direction: "asc" }); // when breaking even
|
|
400
|
+
const iterator = rects.iterate({
|
|
94
401
|
query: createQueries(point, false),
|
|
95
|
-
sort:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
402
|
+
sort: [
|
|
403
|
+
direction === "below"
|
|
404
|
+
? new Sort({ key: ["end2"], direction: "desc" })
|
|
405
|
+
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
406
|
+
sortByOldest,
|
|
407
|
+
sortByHash,
|
|
408
|
+
],
|
|
409
|
+
}, options);
|
|
410
|
+
const iteratorWrapped = rects.iterate({
|
|
100
411
|
query: createQueries(direction === "below" ? MAX_U32 : 0, true),
|
|
101
|
-
sort:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
412
|
+
sort: [
|
|
413
|
+
direction === "below"
|
|
414
|
+
? new Sort({ key: ["end2"], direction: "desc" })
|
|
415
|
+
: new Sort({ key: ["start1"], direction: "asc" }),
|
|
416
|
+
sortByOldest,
|
|
417
|
+
sortByHash,
|
|
418
|
+
],
|
|
419
|
+
}, options);
|
|
105
420
|
return joinIterator([iterator, iteratorWrapped], point, direction);
|
|
106
421
|
};
|
|
107
422
|
export const hasCoveringRange = async (rects, range) => {
|
|
108
|
-
return ((await rects.count(
|
|
423
|
+
return ((await rects.count({
|
|
109
424
|
query: [
|
|
110
425
|
new Or([
|
|
111
426
|
new And([
|
|
@@ -169,7 +484,7 @@ export const hasCoveringRange = async (rects, range) => {
|
|
|
169
484
|
value: range.id,
|
|
170
485
|
})),
|
|
171
486
|
],
|
|
172
|
-
}))
|
|
487
|
+
})) > 0);
|
|
173
488
|
};
|
|
174
489
|
export const getDistance = (from, to, direction, end = MAX_U32) => {
|
|
175
490
|
// if direction is 'above' only measure distance from 'from to 'to' from above.
|
|
@@ -202,21 +517,17 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
202
517
|
let queues = [];
|
|
203
518
|
return {
|
|
204
519
|
next: async (count) => {
|
|
205
|
-
let results =
|
|
206
|
-
kept: 0, // TODO
|
|
207
|
-
results: [],
|
|
208
|
-
};
|
|
520
|
+
let results = [];
|
|
209
521
|
for (let i = 0; i < iterators.length; i++) {
|
|
210
522
|
let queue = queues[i];
|
|
211
523
|
if (!queue) {
|
|
212
|
-
queue = { elements: []
|
|
524
|
+
queue = { elements: [] };
|
|
213
525
|
queues[i] = queue;
|
|
214
526
|
}
|
|
215
527
|
let iterator = iterators[i];
|
|
216
|
-
if (queue.elements.length < count && iterator.done()
|
|
528
|
+
if (queue.elements.length < count && iterator.done() !== true) {
|
|
217
529
|
let res = await iterator.next(count);
|
|
218
|
-
|
|
219
|
-
for (const el of res.results) {
|
|
530
|
+
for (const el of res) {
|
|
220
531
|
const closest = el.value;
|
|
221
532
|
let dist;
|
|
222
533
|
if (direction === "closest") {
|
|
@@ -254,15 +565,16 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
254
565
|
}
|
|
255
566
|
let closest = queues[closestQueue]?.elements.shift();
|
|
256
567
|
if (closest) {
|
|
257
|
-
results.
|
|
568
|
+
results.push(closest.result);
|
|
258
569
|
}
|
|
259
570
|
}
|
|
260
|
-
for (let i = 0; i < queues.length; i++) {
|
|
261
|
-
results.kept += queues[i].elements.length + queues[i].kept;
|
|
262
|
-
}
|
|
263
571
|
return results;
|
|
264
572
|
},
|
|
265
|
-
|
|
573
|
+
pending: async () => {
|
|
574
|
+
let allPending = await Promise.all(iterators.map((x) => x.pending()));
|
|
575
|
+
return allPending.reduce((acc, x) => acc + x, 0);
|
|
576
|
+
},
|
|
577
|
+
done: () => iterators.every((x) => x.done() === true),
|
|
266
578
|
close: async () => {
|
|
267
579
|
for (const iterator of iterators) {
|
|
268
580
|
await iterator.close();
|
|
@@ -278,71 +590,80 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
278
590
|
},
|
|
279
591
|
};
|
|
280
592
|
};
|
|
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);
|
|
593
|
+
const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
|
|
594
|
+
const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow, options);
|
|
595
|
+
const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove, options);
|
|
596
|
+
const containing = containingPoint(peers, point, roleAge, true, now, options);
|
|
285
597
|
return iteratorInSeries(containing, joinIterator([closestBelow, closestAbove], point, "closest"));
|
|
286
598
|
};
|
|
287
599
|
const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, done = () => true) => {
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
600
|
+
/* let shape = { timestamp: true, hash: true } as const */
|
|
601
|
+
const containing = containingPoint(peers, point, 0, true, now /* , { shape } */);
|
|
602
|
+
const allContaining = await containing.all();
|
|
603
|
+
for (const rect of allContaining) {
|
|
604
|
+
collector(rect.value, isMatured(rect.value, now, roleAge), true);
|
|
292
605
|
}
|
|
293
606
|
if (done()) {
|
|
294
607
|
return;
|
|
295
608
|
}
|
|
296
|
-
const closestBelow = getClosest("below", peers, point, 0, true, now, false);
|
|
297
|
-
const closestAbove = getClosest("above", peers, point, 0, true, now, false);
|
|
609
|
+
const closestBelow = getClosest("below", peers, point, 0, true, now, false /* , { shape } */);
|
|
610
|
+
const closestAbove = getClosest("above", peers, point, 0, true, now, false /* , { shape } */);
|
|
298
611
|
const aroundIterator = joinIterator([closestBelow, closestAbove], point, "closest");
|
|
299
|
-
while (aroundIterator.done()
|
|
612
|
+
while (aroundIterator.done() !== true && done() !== true) {
|
|
300
613
|
const res = await aroundIterator.next(1);
|
|
301
|
-
for (const rect of res
|
|
302
|
-
collector(rect.value, isMatured(rect.value, now, roleAge));
|
|
614
|
+
for (const rect of res) {
|
|
615
|
+
collector(rect.value, isMatured(rect.value, now, roleAge), false);
|
|
303
616
|
if (done()) {
|
|
304
617
|
return;
|
|
305
618
|
}
|
|
306
619
|
}
|
|
307
620
|
}
|
|
308
621
|
};
|
|
622
|
+
export const getEvenlySpacedU32 = (from, count) => {
|
|
623
|
+
let ret = new Array(count);
|
|
624
|
+
for (let i = 0; i < count; i++) {
|
|
625
|
+
ret[i] = Math.round(from + (i * MAX_U32) / count) % MAX_U32;
|
|
626
|
+
}
|
|
627
|
+
return ret;
|
|
628
|
+
};
|
|
309
629
|
export const isMatured = (segment, now, minAge) => {
|
|
310
630
|
return now - Number(segment.timestamp) >= minAge;
|
|
311
631
|
};
|
|
312
|
-
|
|
313
|
-
|
|
632
|
+
// get peer sample that are responsible for the cursor point
|
|
633
|
+
// will return a list of peers that want to replicate the data,
|
|
634
|
+
// but also if necessary a list of peers that are responsible for the data
|
|
635
|
+
// but have not explicitly replicating a range that cover the cursor point
|
|
636
|
+
export const getSamples = async (cursor, peers, roleAge) => {
|
|
637
|
+
const leaders = new Map();
|
|
314
638
|
if (!peers) {
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
const size = await peers.getSize();
|
|
318
|
-
amount = Math.min(amount, size);
|
|
319
|
-
if (amount === 0) {
|
|
320
|
-
return [];
|
|
639
|
+
return new Map();
|
|
321
640
|
}
|
|
322
641
|
const now = +new Date();
|
|
323
642
|
const maturedLeaders = new Set();
|
|
324
|
-
for (let i = 0; i <
|
|
643
|
+
for (let i = 0; i < cursor.length; i++) {
|
|
325
644
|
// evenly distributed
|
|
326
|
-
const point = Math.round(cursor + (i * MAX_U32) / amount) % MAX_U32;
|
|
327
645
|
// aquire at least one unique node for each point
|
|
328
|
-
await collectNodesAroundPoint(roleAge, peers, (rect, m) => {
|
|
646
|
+
await collectNodesAroundPoint(roleAge, peers, (rect, m, intersecting) => {
|
|
329
647
|
if (m) {
|
|
330
648
|
maturedLeaders.add(rect.hash);
|
|
331
649
|
}
|
|
332
|
-
leaders.
|
|
333
|
-
|
|
650
|
+
const prev = leaders.get(rect.hash);
|
|
651
|
+
if (!prev || (intersecting && !prev.intersecting)) {
|
|
652
|
+
leaders.set(rect.hash, { intersecting });
|
|
653
|
+
}
|
|
654
|
+
}, cursor[i], now, () => {
|
|
334
655
|
if (maturedLeaders.size > i) {
|
|
335
656
|
return true;
|
|
336
657
|
}
|
|
337
658
|
return false;
|
|
338
659
|
});
|
|
339
660
|
}
|
|
340
|
-
return
|
|
661
|
+
return leaders;
|
|
341
662
|
};
|
|
342
663
|
const fetchOne = async (iterator) => {
|
|
343
664
|
const value = await iterator.next(1);
|
|
344
665
|
await iterator.close();
|
|
345
|
-
return value
|
|
666
|
+
return value[0]?.value;
|
|
346
667
|
};
|
|
347
668
|
export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */) => {
|
|
348
669
|
/* minReplicas = Math.min(minReplicas, replicatorCount); */ // TODO do we need this?
|
|
@@ -365,10 +686,9 @@ export const getCoverSet = async (properties) => {
|
|
|
365
686
|
if (properties.eager) {
|
|
366
687
|
const eagerFetch = properties.eager === true
|
|
367
688
|
? 1000
|
|
368
|
-
: properties.eager.unmaturedFetchCoverSize;
|
|
689
|
+
: (properties.eager.unmaturedFetchCoverSize ?? 1000);
|
|
369
690
|
// pull all umatured
|
|
370
|
-
const
|
|
371
|
-
fetch: eagerFetch,
|
|
691
|
+
const iterator = peers.iterate({
|
|
372
692
|
query: [
|
|
373
693
|
new IntegerCompare({
|
|
374
694
|
key: "timestamp",
|
|
@@ -376,8 +696,10 @@ export const getCoverSet = async (properties) => {
|
|
|
376
696
|
value: BigInt(now - roleAge),
|
|
377
697
|
}),
|
|
378
698
|
],
|
|
379
|
-
})
|
|
380
|
-
|
|
699
|
+
});
|
|
700
|
+
const rects = await iterator.next(eagerFetch);
|
|
701
|
+
await iterator.close();
|
|
702
|
+
for (const rect of rects) {
|
|
381
703
|
ret.add(rect.value.hash);
|
|
382
704
|
}
|
|
383
705
|
}
|
|
@@ -467,15 +789,135 @@ export const getCoverSet = async (properties) => {
|
|
|
467
789
|
start instanceof PublicSignKey && ret.add(start.hashcode());
|
|
468
790
|
return ret;
|
|
469
791
|
};
|
|
470
|
-
export const
|
|
471
|
-
|
|
792
|
+
/* export const getReplicationDiff = (changes: ReplicationChange) => {
|
|
793
|
+
// reduce the change set to only regions that are changed for each peer
|
|
794
|
+
// i.e. subtract removed regions from added regions, and vice versa
|
|
795
|
+
const result = new Map<string, { range: ReplicationRangeIndexable, added: boolean }[]>();
|
|
796
|
+
|
|
797
|
+
for (const addedChange of changes.added ?? []) {
|
|
798
|
+
let prev = result.get(addedChange.hash) ?? [];
|
|
799
|
+
for (const [_hash, ranges] of result.entries()) {
|
|
800
|
+
for (const r of ranges) {
|
|
801
|
+
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
*/
|
|
807
|
+
const matchRangeQuery = (range) => {
|
|
808
|
+
let ors = [];
|
|
809
|
+
ors.push(new And([
|
|
810
|
+
new IntegerCompare({
|
|
811
|
+
key: "coordinate",
|
|
812
|
+
compare: "gte",
|
|
813
|
+
value: range.start1,
|
|
814
|
+
}),
|
|
815
|
+
new IntegerCompare({
|
|
816
|
+
key: "coordinate",
|
|
817
|
+
compare: "lt",
|
|
818
|
+
value: range.end1,
|
|
819
|
+
}),
|
|
820
|
+
]));
|
|
821
|
+
ors.push(new And([
|
|
822
|
+
new IntegerCompare({
|
|
823
|
+
key: "coordinate",
|
|
824
|
+
compare: "gte",
|
|
825
|
+
value: range.start2,
|
|
826
|
+
}),
|
|
827
|
+
new IntegerCompare({
|
|
828
|
+
key: "coordinate",
|
|
829
|
+
compare: "lt",
|
|
830
|
+
value: range.end2,
|
|
831
|
+
}),
|
|
832
|
+
]));
|
|
833
|
+
return new Or(ors);
|
|
834
|
+
};
|
|
835
|
+
export const toRebalance = (changes, index) => {
|
|
836
|
+
const assignedRangesQuery = (changes) => {
|
|
837
|
+
let ors = [];
|
|
838
|
+
for (const change of changes) {
|
|
839
|
+
const matchRange = matchRangeQuery(change.range);
|
|
840
|
+
if (change.type === "updated") {
|
|
841
|
+
// assuming a range is to be removed, is this entry still enoughly replicated
|
|
842
|
+
const prevMatchRange = matchRangeQuery(change.prev);
|
|
843
|
+
ors.push(prevMatchRange);
|
|
844
|
+
ors.push(matchRange);
|
|
845
|
+
/* ors.push(
|
|
846
|
+
new And([
|
|
847
|
+
// not sufficiently replicated
|
|
848
|
+
new IntegerCompare({
|
|
849
|
+
key: "replicatorsMissingShifted",
|
|
850
|
+
compare: Compare.Greater,
|
|
851
|
+
value: HALF_MAX_U32 - 1, // + 1 since we are going to remove a replicator for this entry
|
|
852
|
+
}),
|
|
853
|
+
|
|
854
|
+
// is not the current range
|
|
855
|
+
new Not(matchRange),
|
|
856
|
+
|
|
857
|
+
// but was in the the previous range
|
|
858
|
+
prevMatchRange,
|
|
859
|
+
]),
|
|
860
|
+
); */
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
ors.push(matchRange);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
// entry is assigned to a range boundary, meaning it is due to be inspected
|
|
867
|
+
ors.push(new BoolQuery({
|
|
868
|
+
key: "assignedToRangeBoundary",
|
|
869
|
+
value: true,
|
|
870
|
+
}));
|
|
871
|
+
// entry is not sufficiently replicated, and we are to still keep it
|
|
872
|
+
return new Or(ors);
|
|
873
|
+
};
|
|
874
|
+
return {
|
|
875
|
+
[Symbol.asyncIterator]: async function* () {
|
|
876
|
+
const iterator = index.iterate({
|
|
877
|
+
query: assignedRangesQuery(changes),
|
|
878
|
+
});
|
|
879
|
+
/* const iteratorFitlered = index.iterate({
|
|
880
|
+
query: assignedRangesQuery(changes),
|
|
881
|
+
}); */
|
|
882
|
+
while (iterator.done() !== true) {
|
|
883
|
+
const entries = await iterator.next(0xffffffff); // TODO batch sizes
|
|
884
|
+
/* const entriesFiltered = await iteratorFitlered.next(0xffffffff); // TODO batch sizes
|
|
885
|
+
|
|
886
|
+
console.log(
|
|
887
|
+
"SIZE",
|
|
888
|
+
await index.getSize(),
|
|
889
|
+
entries.results.length,
|
|
890
|
+
entriesFiltered.results.length,
|
|
891
|
+
Math.min(
|
|
892
|
+
...entries.results
|
|
893
|
+
.filter((x) => x.value.assignedToRangeBoundary === false)
|
|
894
|
+
.map((x) => x.value.coordinate / 0xffffffff),
|
|
895
|
+
),
|
|
896
|
+
Math.max(
|
|
897
|
+
...entries.results
|
|
898
|
+
.filter((x) => x.value.assignedToRangeBoundary === false)
|
|
899
|
+
.map((x) => x.value.coordinate / 0xffffffff),
|
|
900
|
+
),
|
|
901
|
+
); */
|
|
902
|
+
// TODO do we need this
|
|
903
|
+
const grouped = await groupByGidSync(entries.map((x) => x.value));
|
|
904
|
+
for (const [gid, entries] of grouped.entries()) {
|
|
905
|
+
yield { gid, entries };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
};
|
|
910
|
+
};
|
|
911
|
+
export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, options) => {
|
|
912
|
+
let iterator = index.iterate({
|
|
472
913
|
query: [new StringMatch({ key: "hash", value: publicKey.hashcode() })],
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
914
|
+
}, options);
|
|
915
|
+
let result = await iterator.next(1);
|
|
916
|
+
await iterator.close();
|
|
917
|
+
let node = result[0]?.value;
|
|
476
918
|
if (node) {
|
|
477
919
|
if (!isMatured(node, now, roleAge)) {
|
|
478
|
-
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false));
|
|
920
|
+
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, options));
|
|
479
921
|
if (matured) {
|
|
480
922
|
node = matured;
|
|
481
923
|
}
|
|
@@ -483,17 +925,17 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now) => {
|
|
|
483
925
|
}
|
|
484
926
|
return node;
|
|
485
927
|
};
|
|
486
|
-
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth) => {
|
|
928
|
+
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, intervalWidth, options) => {
|
|
487
929
|
// find a good starting point
|
|
488
930
|
let startNode = undefined;
|
|
489
931
|
let startLocation = undefined;
|
|
490
932
|
const nodeFromPoint = async (point = scaleToU32(Math.random())) => {
|
|
491
933
|
startLocation = point;
|
|
492
|
-
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true);
|
|
934
|
+
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, options);
|
|
493
935
|
};
|
|
494
936
|
if (start instanceof PublicSignKey) {
|
|
495
937
|
// start at our node (local first)
|
|
496
|
-
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now);
|
|
938
|
+
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, options);
|
|
497
939
|
if (!startNode) {
|
|
498
940
|
// fetch randomly
|
|
499
941
|
await nodeFromPoint();
|
|
@@ -533,7 +975,7 @@ export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge,
|
|
|
533
975
|
endLocation: Math.round(endLocation),
|
|
534
976
|
};
|
|
535
977
|
};
|
|
536
|
-
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove) => {
|
|
537
|
-
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove));
|
|
978
|
+
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
|
|
979
|
+
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options));
|
|
538
980
|
};
|
|
539
981
|
//# sourceMappingURL=ranges.js.map
|