@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.
Files changed (66) hide show
  1. package/dist/benchmark/get-samples.js +2 -3
  2. package/dist/benchmark/get-samples.js.map +1 -1
  3. package/dist/benchmark/index.js +4 -6
  4. package/dist/benchmark/index.js.map +1 -1
  5. package/dist/benchmark/memory/child.d.ts +2 -0
  6. package/dist/benchmark/memory/child.d.ts.map +1 -0
  7. package/dist/benchmark/memory/child.js +149 -0
  8. package/dist/benchmark/memory/child.js.map +1 -0
  9. package/dist/benchmark/memory/index.d.ts +2 -0
  10. package/dist/benchmark/memory/index.d.ts.map +1 -0
  11. package/dist/benchmark/memory/index.js +81 -0
  12. package/dist/benchmark/memory/index.js.map +1 -0
  13. package/dist/benchmark/memory/utils.d.ts +13 -0
  14. package/dist/benchmark/memory/utils.d.ts.map +1 -0
  15. package/dist/benchmark/memory/utils.js +2 -0
  16. package/dist/benchmark/memory/utils.js.map +1 -0
  17. package/dist/benchmark/replication-prune.js +27 -25
  18. package/dist/benchmark/replication-prune.js.map +1 -1
  19. package/dist/benchmark/replication.js +15 -16
  20. package/dist/benchmark/replication.js.map +1 -1
  21. package/dist/src/debounce.d.ts +25 -0
  22. package/dist/src/debounce.d.ts.map +1 -0
  23. package/dist/src/debounce.js +130 -0
  24. package/dist/src/debounce.js.map +1 -0
  25. package/dist/src/index.d.ts +55 -21
  26. package/dist/src/index.d.ts.map +1 -1
  27. package/dist/src/index.js +867 -390
  28. package/dist/src/index.js.map +1 -1
  29. package/dist/src/pid.d.ts.map +1 -1
  30. package/dist/src/pid.js +23 -21
  31. package/dist/src/pid.js.map +1 -1
  32. package/dist/src/ranges.d.ts +104 -8
  33. package/dist/src/ranges.d.ts.map +1 -1
  34. package/dist/src/ranges.js +518 -76
  35. package/dist/src/ranges.js.map +1 -1
  36. package/dist/src/replication-domain-hash.d.ts.map +1 -1
  37. package/dist/src/replication-domain-hash.js.map +1 -1
  38. package/dist/src/replication-domain-time.d.ts.map +1 -1
  39. package/dist/src/replication-domain-time.js.map +1 -1
  40. package/dist/src/replication-domain.d.ts +22 -2
  41. package/dist/src/replication-domain.d.ts.map +1 -1
  42. package/dist/src/replication-domain.js +33 -0
  43. package/dist/src/replication-domain.js.map +1 -1
  44. package/dist/src/replication.d.ts +1 -55
  45. package/dist/src/replication.d.ts.map +1 -1
  46. package/dist/src/replication.js +5 -215
  47. package/dist/src/replication.js.map +1 -1
  48. package/dist/src/role.d.ts +1 -0
  49. package/dist/src/role.d.ts.map +1 -1
  50. package/dist/src/role.js +1 -0
  51. package/dist/src/role.js.map +1 -1
  52. package/dist/src/utils.d.ts +6 -0
  53. package/dist/src/utils.d.ts.map +1 -0
  54. package/dist/src/utils.js +39 -0
  55. package/dist/src/utils.js.map +1 -0
  56. package/package.json +5 -5
  57. package/src/debounce.ts +172 -0
  58. package/src/index.ts +1282 -562
  59. package/src/pid.ts +27 -25
  60. package/src/ranges.ts +794 -181
  61. package/src/replication-domain-hash.ts +3 -1
  62. package/src/replication-domain-time.ts +2 -1
  63. package/src/replication-domain.ts +68 -5
  64. package/src/replication.ts +9 -235
  65. package/src/role.ts +1 -0
  66. package/src/utils.ts +49 -0
@@ -1,7 +1,313 @@
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";
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(rects, new SearchRequest({
346
+ return rects.iterate({
41
347
  query: queries,
42
348
  sort: options?.sort,
43
- fetch: 0xffffffff,
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 iterator = iterate(rects, new SearchRequest({
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: direction === "below"
96
- ? new Sort({ key: ["end2"], direction: "desc" })
97
- : new Sort({ key: ["start1"], direction: "asc" }),
98
- }));
99
- const iteratorWrapped = iterate(rects, new SearchRequest({
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: direction === "below"
102
- ? new Sort({ key: ["end2"], direction: "desc" })
103
- : new Sort({ key: ["start1"], direction: "asc" }),
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(new SearchRequest({
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
- }))) > 0);
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: [], kept: 0 };
524
+ queue = { elements: [] };
213
525
  queues[i] = queue;
214
526
  }
215
527
  let iterator = iterators[i];
216
- if (queue.elements.length < count && iterator.done() === false) {
528
+ if (queue.elements.length < count && iterator.done() !== true) {
217
529
  let res = await iterator.next(count);
218
- queue.kept = res.kept;
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.results.push(closest.result);
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
- done: () => iterators.every((x) => x.done()),
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
- const containing = containingPoint(peers, point, 0, true, now);
289
- const allContaining = await containing.next(0xffffffff);
290
- for (const rect of allContaining.results) {
291
- collector(rect.value, isMatured(rect.value, now, roleAge));
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() === false && done() === false) {
612
+ while (aroundIterator.done() !== true && done() !== true) {
300
613
  const res = await aroundIterator.next(1);
301
- for (const rect of res.results) {
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
- export const getSamples = async (cursor, peers, amount, roleAge) => {
313
- const leaders = new Set();
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 < amount; 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.add(rect.hash);
333
- }, point, now, () => {
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 [...leaders];
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.results[0]?.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 rects = await peers.query(new SearchRequest({
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
- for (const rect of rects.results) {
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 fetchOneFromPublicKey = async (publicKey, index, roleAge, now) => {
471
- let result = await index.query(new SearchRequest({
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
- fetch: 1,
474
- }));
475
- let node = result.results[0]?.value;
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