@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.
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 +497 -82
  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 +70 -70
  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 +772 -187
  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,19 +343,12 @@ 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
- }));
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 iterator = iterate(rects, new SearchRequest({
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: direction === "below"
96
- ? new Sort({ key: ["end2"], direction: "desc" })
97
- : new Sort({ key: ["start1"], direction: "asc" }),
98
- }));
99
- const iteratorWrapped = iterate(rects, new SearchRequest({
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: direction === "below"
102
- ? new Sort({ key: ["end2"], direction: "desc" })
103
- : new Sort({ key: ["start1"], direction: "asc" }),
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(new SearchRequest({
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
- }))) > 0);
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: [], kept: 0 };
518
+ queue = { elements: [] };
213
519
  queues[i] = queue;
214
520
  }
215
521
  let iterator = iterators[i];
216
- if (queue.elements.length < count && iterator.done() === false) {
522
+ if (queue.elements.length < count && iterator.done() !== true) {
217
523
  let res = await iterator.next(count);
218
- queue.kept = res.kept;
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.results.push(closest.result);
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
- done: () => iterators.every((x) => x.done()),
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
- 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));
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() === false && done() === false) {
606
+ while (aroundIterator.done() !== true && done() !== true) {
300
607
  const res = await aroundIterator.next(1);
301
- for (const rect of res.results) {
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
- export const getSamples = async (cursor, peers, amount, roleAge) => {
313
- const leaders = new Set();
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 < amount; 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.add(rect.hash);
333
- }, point, now, () => {
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 [...leaders];
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.results[0]?.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 rects = await peers.query(new SearchRequest({
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
- for (const rect of rects.results) {
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 fetchOneFromPublicKey = async (publicKey, index, roleAge, now) => {
471
- let result = await index.query(new SearchRequest({
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
- fetch: 1,
474
- }));
475
- let node = result.results[0]?.value;
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