@peerbit/shared-log 9.2.13 → 10.0.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 +190 -64
- package/dist/benchmark/get-samples.js.map +1 -1
- package/dist/benchmark/index.js +16 -38
- package/dist/benchmark/index.js.map +1 -1
- package/dist/benchmark/memory/child.js.map +1 -1
- package/dist/benchmark/partial-sync.d.ts +3 -0
- package/dist/benchmark/partial-sync.d.ts.map +1 -0
- package/dist/benchmark/partial-sync.js +121 -0
- package/dist/benchmark/partial-sync.js.map +1 -0
- package/dist/benchmark/replication-prune.js.map +1 -1
- package/dist/benchmark/replication.js.map +1 -1
- package/dist/benchmark/to-rebalance.d.ts +2 -0
- package/dist/benchmark/to-rebalance.d.ts.map +1 -0
- package/dist/benchmark/to-rebalance.js +117 -0
- package/dist/benchmark/to-rebalance.js.map +1 -0
- package/dist/benchmark/utils.d.ts +24 -0
- package/dist/benchmark/utils.d.ts.map +1 -0
- package/dist/benchmark/utils.js +47 -0
- package/dist/benchmark/utils.js.map +1 -0
- package/dist/src/debounce.d.ts +2 -2
- package/dist/src/debounce.d.ts.map +1 -1
- package/dist/src/debounce.js +17 -47
- package/dist/src/debounce.js.map +1 -1
- package/dist/src/exchange-heads.d.ts +1 -13
- package/dist/src/exchange-heads.d.ts.map +1 -1
- package/dist/src/exchange-heads.js +0 -32
- package/dist/src/exchange-heads.js.map +1 -1
- package/dist/src/index.d.ts +119 -60
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1116 -762
- package/dist/src/index.js.map +1 -1
- package/dist/src/integers.d.ts +22 -0
- package/dist/src/integers.d.ts.map +1 -0
- package/dist/src/integers.js +76 -0
- package/dist/src/integers.js.map +1 -0
- package/dist/src/pid.d.ts.map +1 -1
- package/dist/src/pid.js +22 -22
- package/dist/src/pid.js.map +1 -1
- package/dist/src/ranges.d.ts +168 -38
- package/dist/src/ranges.d.ts.map +1 -1
- package/dist/src/ranges.js +869 -272
- package/dist/src/ranges.js.map +1 -1
- package/dist/src/replication-domain-hash.d.ts +2 -3
- package/dist/src/replication-domain-hash.d.ts.map +1 -1
- package/dist/src/replication-domain-hash.js +40 -15
- package/dist/src/replication-domain-hash.js.map +1 -1
- package/dist/src/replication-domain-time.d.ts +5 -5
- package/dist/src/replication-domain-time.d.ts.map +1 -1
- package/dist/src/replication-domain-time.js +2 -0
- package/dist/src/replication-domain-time.js.map +1 -1
- package/dist/src/replication-domain.d.ts +17 -19
- package/dist/src/replication-domain.d.ts.map +1 -1
- package/dist/src/replication-domain.js +2 -6
- package/dist/src/replication-domain.js.map +1 -1
- package/dist/src/replication.d.ts +6 -6
- package/dist/src/replication.d.ts.map +1 -1
- package/dist/src/replication.js +4 -4
- package/dist/src/replication.js.map +1 -1
- package/dist/src/role.d.ts +3 -6
- package/dist/src/role.d.ts.map +1 -1
- package/dist/src/role.js +4 -5
- package/dist/src/role.js.map +1 -1
- package/dist/src/sync/index.d.ts +40 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +2 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/rateless-iblt.d.ts +124 -0
- package/dist/src/sync/rateless-iblt.d.ts.map +1 -0
- package/dist/src/sync/rateless-iblt.js +495 -0
- package/dist/src/sync/rateless-iblt.js.map +1 -0
- package/dist/src/sync/simple.d.ts +69 -0
- package/dist/src/sync/simple.d.ts.map +1 -0
- package/dist/src/sync/simple.js +338 -0
- package/dist/src/sync/simple.js.map +1 -0
- package/dist/src/sync/wasm-init.browser.d.ts +1 -0
- package/dist/src/sync/wasm-init.browser.d.ts.map +1 -0
- package/dist/src/sync/wasm-init.browser.js +3 -0
- package/dist/src/sync/wasm-init.browser.js.map +1 -0
- package/dist/src/sync/wasm-init.d.ts +2 -0
- package/dist/src/sync/wasm-init.d.ts.map +1 -0
- package/dist/src/sync/wasm-init.js +13 -0
- package/dist/src/sync/wasm-init.js.map +1 -0
- package/dist/src/utils.d.ts +3 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +2 -2
- package/dist/src/utils.js.map +1 -1
- package/package.json +10 -6
- package/src/debounce.ts +16 -51
- package/src/exchange-heads.ts +1 -23
- package/src/index.ts +1532 -1038
- package/src/integers.ts +102 -0
- package/src/pid.ts +23 -22
- package/src/ranges.ts +1204 -413
- package/src/replication-domain-hash.ts +43 -18
- package/src/replication-domain-time.ts +9 -9
- package/src/replication-domain.ts +21 -31
- package/src/replication.ts +10 -9
- package/src/role.ts +4 -6
- package/src/sync/index.ts +51 -0
- package/src/sync/rateless-iblt.ts +617 -0
- package/src/sync/simple.ts +403 -0
- package/src/sync/wasm-init.browser.ts +1 -0
- package/src/sync/wasm-init.ts +14 -0
- package/src/utils.ts +10 -4
package/dist/src/ranges.js
CHANGED
|
@@ -7,35 +7,47 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
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,
|
|
10
|
+
import { deserialize, field, serialize, variant, vec } from "@dao-xyz/borsh";
|
|
11
|
+
import { PublicSignKey, equals, randomBytes, sha256Base64Sync, toBase64, } from "@peerbit/crypto";
|
|
12
|
+
import { And, BoolQuery, ByteMatchQuery, Compare, IntegerCompare, Not, Or, Sort, SortDirection, StringMatch,
|
|
13
|
+
/* iteratorInSeries, */
|
|
14
|
+
} from "@peerbit/indexer-interface";
|
|
13
15
|
import { id } from "@peerbit/indexer-interface";
|
|
14
16
|
import { Meta, ShallowMeta } from "@peerbit/log";
|
|
17
|
+
import { MAX_U32, MAX_U64, } from "./integers.js";
|
|
15
18
|
import {} from "./replication-domain.js";
|
|
16
|
-
import { MAX_U32, scaleToU32 } from "./role.js";
|
|
17
|
-
import { groupByGidSync } from "./utils.js";
|
|
18
19
|
export var ReplicationIntent;
|
|
19
20
|
(function (ReplicationIntent) {
|
|
20
21
|
ReplicationIntent[ReplicationIntent["NonStrict"] = 0] = "NonStrict";
|
|
21
22
|
ReplicationIntent[ReplicationIntent["Strict"] = 1] = "Strict";
|
|
22
23
|
})(ReplicationIntent || (ReplicationIntent = {}));
|
|
23
|
-
export
|
|
24
|
+
export var SyncStatus;
|
|
25
|
+
(function (SyncStatus) {
|
|
26
|
+
SyncStatus[SyncStatus["Unsynced"] = 0] = "Unsynced";
|
|
27
|
+
SyncStatus[SyncStatus["Synced"] = 1] = "Synced";
|
|
28
|
+
})(SyncStatus || (SyncStatus = {}));
|
|
29
|
+
const min = (a, b) => (a < b ? a : b);
|
|
30
|
+
const getSegmentsFromOffsetAndRange = (offset, factor, zero, max) => {
|
|
24
31
|
let start1 = offset;
|
|
32
|
+
// @ts-ignore
|
|
25
33
|
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 =
|
|
34
|
+
let end1 = min(end1Unscaled, max);
|
|
27
35
|
return [
|
|
28
36
|
[start1, end1],
|
|
29
|
-
|
|
30
|
-
|
|
37
|
+
/* eslint-disable no-irregular-whitespace */
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
end1Unscaled > max
|
|
40
|
+
? /* eslint-disable no-irregular-whitespace */
|
|
41
|
+
// @ts-ignore
|
|
42
|
+
[zero, (factor !== max ? offset + factor : offset) % max]
|
|
31
43
|
: [start1, end1],
|
|
32
44
|
];
|
|
33
45
|
};
|
|
34
46
|
export const shouldAssigneToRangeBoundary = (leaders, minReplicas) => {
|
|
35
47
|
let assignedToRangeBoundary = leaders === false || leaders.size < minReplicas;
|
|
36
48
|
if (!assignedToRangeBoundary && leaders) {
|
|
37
|
-
for (const [_,
|
|
38
|
-
if (!intersecting) {
|
|
49
|
+
for (const [_, value] of leaders) {
|
|
50
|
+
if (!value.intersecting) {
|
|
39
51
|
assignedToRangeBoundary = true;
|
|
40
52
|
break;
|
|
41
53
|
}
|
|
@@ -43,20 +55,21 @@ export const shouldAssigneToRangeBoundary = (leaders, minReplicas) => {
|
|
|
43
55
|
}
|
|
44
56
|
return assignedToRangeBoundary;
|
|
45
57
|
};
|
|
46
|
-
export
|
|
47
|
-
|
|
58
|
+
export const isEntryReplicated = (x) => {
|
|
59
|
+
return x instanceof EntryReplicatedU32 || x instanceof EntryReplicatedU64;
|
|
60
|
+
};
|
|
61
|
+
export class EntryReplicatedU32 {
|
|
48
62
|
hash;
|
|
49
63
|
gid;
|
|
50
|
-
|
|
64
|
+
coordinates;
|
|
51
65
|
wallTime;
|
|
52
66
|
assignedToRangeBoundary;
|
|
53
67
|
_meta;
|
|
54
68
|
_metaResolved;
|
|
55
69
|
constructor(properties) {
|
|
56
|
-
this.
|
|
70
|
+
this.coordinates = properties.coordinates;
|
|
57
71
|
this.hash = properties.hash;
|
|
58
72
|
this.gid = properties.meta.gid;
|
|
59
|
-
this.id = this.hash + "-" + this.coordinate;
|
|
60
73
|
this.wallTime = properties.meta.clock.timestamp.wallTime;
|
|
61
74
|
const shallow = properties.meta instanceof Meta
|
|
62
75
|
? new ShallowMeta(properties.meta)
|
|
@@ -76,38 +89,92 @@ export class EntryReplicated {
|
|
|
76
89
|
__decorate([
|
|
77
90
|
id({ type: "string" }),
|
|
78
91
|
__metadata("design:type", String)
|
|
79
|
-
],
|
|
92
|
+
], EntryReplicatedU32.prototype, "hash", void 0);
|
|
80
93
|
__decorate([
|
|
81
94
|
field({ type: "string" }),
|
|
82
95
|
__metadata("design:type", String)
|
|
83
|
-
],
|
|
96
|
+
], EntryReplicatedU32.prototype, "gid", void 0);
|
|
97
|
+
__decorate([
|
|
98
|
+
field({ type: vec("u32") }),
|
|
99
|
+
__metadata("design:type", Array)
|
|
100
|
+
], EntryReplicatedU32.prototype, "coordinates", void 0);
|
|
101
|
+
__decorate([
|
|
102
|
+
field({ type: "u64" }),
|
|
103
|
+
__metadata("design:type", BigInt)
|
|
104
|
+
], EntryReplicatedU32.prototype, "wallTime", void 0);
|
|
105
|
+
__decorate([
|
|
106
|
+
field({ type: "bool" }),
|
|
107
|
+
__metadata("design:type", Boolean)
|
|
108
|
+
], EntryReplicatedU32.prototype, "assignedToRangeBoundary", void 0);
|
|
109
|
+
__decorate([
|
|
110
|
+
field({ type: Uint8Array }),
|
|
111
|
+
__metadata("design:type", Uint8Array)
|
|
112
|
+
], EntryReplicatedU32.prototype, "_meta", void 0);
|
|
113
|
+
export class EntryReplicatedU64 {
|
|
114
|
+
hash;
|
|
115
|
+
gid;
|
|
116
|
+
coordinates;
|
|
117
|
+
wallTime;
|
|
118
|
+
assignedToRangeBoundary;
|
|
119
|
+
_meta;
|
|
120
|
+
_metaResolved;
|
|
121
|
+
constructor(properties) {
|
|
122
|
+
this.coordinates = properties.coordinates;
|
|
123
|
+
this.hash = properties.hash;
|
|
124
|
+
this.gid = properties.meta.gid;
|
|
125
|
+
this.wallTime = properties.meta.clock.timestamp.wallTime;
|
|
126
|
+
const shallow = properties.meta instanceof Meta
|
|
127
|
+
? new ShallowMeta(properties.meta)
|
|
128
|
+
: properties.meta;
|
|
129
|
+
this._meta = serialize(shallow);
|
|
130
|
+
this._metaResolved = deserialize(this._meta, ShallowMeta);
|
|
131
|
+
this._metaResolved = properties.meta;
|
|
132
|
+
this.assignedToRangeBoundary = properties.assignedToRangeBoundary;
|
|
133
|
+
}
|
|
134
|
+
get meta() {
|
|
135
|
+
if (!this._metaResolved) {
|
|
136
|
+
this._metaResolved = deserialize(this._meta, ShallowMeta);
|
|
137
|
+
}
|
|
138
|
+
return this._metaResolved;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
__decorate([
|
|
142
|
+
id({ type: "string" }),
|
|
143
|
+
__metadata("design:type", String)
|
|
144
|
+
], EntryReplicatedU64.prototype, "hash", void 0);
|
|
84
145
|
__decorate([
|
|
85
146
|
field({ type: "string" }),
|
|
86
147
|
__metadata("design:type", String)
|
|
87
|
-
],
|
|
148
|
+
], EntryReplicatedU64.prototype, "gid", void 0);
|
|
88
149
|
__decorate([
|
|
89
|
-
field({ type: "
|
|
90
|
-
__metadata("design:type",
|
|
91
|
-
],
|
|
150
|
+
field({ type: vec("u64") }),
|
|
151
|
+
__metadata("design:type", Array)
|
|
152
|
+
], EntryReplicatedU64.prototype, "coordinates", void 0);
|
|
92
153
|
__decorate([
|
|
93
154
|
field({ type: "u64" }),
|
|
94
155
|
__metadata("design:type", BigInt)
|
|
95
|
-
],
|
|
156
|
+
], EntryReplicatedU64.prototype, "wallTime", void 0);
|
|
96
157
|
__decorate([
|
|
97
158
|
field({ type: "bool" }),
|
|
98
159
|
__metadata("design:type", Boolean)
|
|
99
|
-
],
|
|
160
|
+
], EntryReplicatedU64.prototype, "assignedToRangeBoundary", void 0);
|
|
100
161
|
__decorate([
|
|
101
162
|
field({ type: Uint8Array }),
|
|
102
163
|
__metadata("design:type", Uint8Array)
|
|
103
|
-
],
|
|
104
|
-
|
|
164
|
+
], EntryReplicatedU64.prototype, "_meta", void 0);
|
|
165
|
+
export const isReplicationRangeMessage = (x) => {
|
|
166
|
+
return x instanceof ReplicationRangeMessage;
|
|
167
|
+
};
|
|
168
|
+
export class ReplicationRangeMessage {
|
|
169
|
+
}
|
|
170
|
+
let ReplicationRangeMessageU32 = class ReplicationRangeMessageU32 extends ReplicationRangeMessage {
|
|
105
171
|
id;
|
|
106
172
|
timestamp;
|
|
107
173
|
_offset;
|
|
108
174
|
_factor;
|
|
109
175
|
mode;
|
|
110
176
|
constructor(properties) {
|
|
177
|
+
super();
|
|
111
178
|
const { id, offset, factor, timestamp, mode } = properties;
|
|
112
179
|
this.id = id;
|
|
113
180
|
this._offset = offset;
|
|
@@ -122,7 +189,7 @@ let ReplicationRange = class ReplicationRange {
|
|
|
122
189
|
return this._offset;
|
|
123
190
|
}
|
|
124
191
|
toReplicationRangeIndexable(key) {
|
|
125
|
-
return new
|
|
192
|
+
return new ReplicationRangeIndexableU32({
|
|
126
193
|
id: this.id,
|
|
127
194
|
publicKeyHash: key.hashcode(),
|
|
128
195
|
offset: this.offset,
|
|
@@ -135,29 +202,154 @@ let ReplicationRange = class ReplicationRange {
|
|
|
135
202
|
__decorate([
|
|
136
203
|
field({ type: Uint8Array }),
|
|
137
204
|
__metadata("design:type", Uint8Array)
|
|
138
|
-
],
|
|
205
|
+
], ReplicationRangeMessageU32.prototype, "id", void 0);
|
|
139
206
|
__decorate([
|
|
140
207
|
field({ type: "u64" }),
|
|
141
208
|
__metadata("design:type", BigInt)
|
|
142
|
-
],
|
|
209
|
+
], ReplicationRangeMessageU32.prototype, "timestamp", void 0);
|
|
143
210
|
__decorate([
|
|
144
211
|
field({ type: "u32" }),
|
|
145
212
|
__metadata("design:type", Number)
|
|
146
|
-
],
|
|
213
|
+
], ReplicationRangeMessageU32.prototype, "_offset", void 0);
|
|
147
214
|
__decorate([
|
|
148
215
|
field({ type: "u32" }),
|
|
149
216
|
__metadata("design:type", Number)
|
|
150
|
-
],
|
|
217
|
+
], ReplicationRangeMessageU32.prototype, "_factor", void 0);
|
|
151
218
|
__decorate([
|
|
152
219
|
field({ type: "u8" }),
|
|
153
220
|
__metadata("design:type", Number)
|
|
154
|
-
],
|
|
155
|
-
|
|
221
|
+
], ReplicationRangeMessageU32.prototype, "mode", void 0);
|
|
222
|
+
ReplicationRangeMessageU32 = __decorate([
|
|
156
223
|
variant(0),
|
|
157
224
|
__metadata("design:paramtypes", [Object])
|
|
158
|
-
],
|
|
159
|
-
export {
|
|
160
|
-
|
|
225
|
+
], ReplicationRangeMessageU32);
|
|
226
|
+
export { ReplicationRangeMessageU32 };
|
|
227
|
+
let ReplicationRangeMessageU64 = class ReplicationRangeMessageU64 extends ReplicationRangeMessage {
|
|
228
|
+
id;
|
|
229
|
+
timestamp;
|
|
230
|
+
_offset;
|
|
231
|
+
_factor;
|
|
232
|
+
mode;
|
|
233
|
+
constructor(properties) {
|
|
234
|
+
super();
|
|
235
|
+
const { id, offset, factor, timestamp, mode } = properties;
|
|
236
|
+
this.id = id;
|
|
237
|
+
this._offset = offset;
|
|
238
|
+
this._factor = factor;
|
|
239
|
+
this.timestamp = timestamp;
|
|
240
|
+
this.mode = mode;
|
|
241
|
+
}
|
|
242
|
+
get factor() {
|
|
243
|
+
return this._factor;
|
|
244
|
+
}
|
|
245
|
+
get offset() {
|
|
246
|
+
return this._offset;
|
|
247
|
+
}
|
|
248
|
+
toReplicationRangeIndexable(key) {
|
|
249
|
+
return new ReplicationRangeIndexableU64({
|
|
250
|
+
id: this.id,
|
|
251
|
+
publicKeyHash: key.hashcode(),
|
|
252
|
+
offset: this.offset,
|
|
253
|
+
length: this.factor,
|
|
254
|
+
timestamp: this.timestamp,
|
|
255
|
+
mode: this.mode,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
__decorate([
|
|
260
|
+
field({ type: Uint8Array }),
|
|
261
|
+
__metadata("design:type", Uint8Array)
|
|
262
|
+
], ReplicationRangeMessageU64.prototype, "id", void 0);
|
|
263
|
+
__decorate([
|
|
264
|
+
field({ type: "u64" }),
|
|
265
|
+
__metadata("design:type", BigInt)
|
|
266
|
+
], ReplicationRangeMessageU64.prototype, "timestamp", void 0);
|
|
267
|
+
__decorate([
|
|
268
|
+
field({ type: "u64" }),
|
|
269
|
+
__metadata("design:type", BigInt)
|
|
270
|
+
], ReplicationRangeMessageU64.prototype, "_offset", void 0);
|
|
271
|
+
__decorate([
|
|
272
|
+
field({ type: "u64" }),
|
|
273
|
+
__metadata("design:type", BigInt)
|
|
274
|
+
], ReplicationRangeMessageU64.prototype, "_factor", void 0);
|
|
275
|
+
__decorate([
|
|
276
|
+
field({ type: "u8" }),
|
|
277
|
+
__metadata("design:type", Number)
|
|
278
|
+
], ReplicationRangeMessageU64.prototype, "mode", void 0);
|
|
279
|
+
ReplicationRangeMessageU64 = __decorate([
|
|
280
|
+
variant(1),
|
|
281
|
+
__metadata("design:paramtypes", [Object])
|
|
282
|
+
], ReplicationRangeMessageU64);
|
|
283
|
+
export { ReplicationRangeMessageU64 };
|
|
284
|
+
class HashableSegmentU32 {
|
|
285
|
+
start1;
|
|
286
|
+
end1;
|
|
287
|
+
start2;
|
|
288
|
+
end2;
|
|
289
|
+
mode;
|
|
290
|
+
constructor(properties) {
|
|
291
|
+
this.start1 = properties.start1;
|
|
292
|
+
this.end1 = properties.end1;
|
|
293
|
+
this.start2 = properties.start2;
|
|
294
|
+
this.end2 = properties.end2;
|
|
295
|
+
this.mode = properties.mode;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
__decorate([
|
|
299
|
+
field({ type: "u32" }),
|
|
300
|
+
__metadata("design:type", Number)
|
|
301
|
+
], HashableSegmentU32.prototype, "start1", void 0);
|
|
302
|
+
__decorate([
|
|
303
|
+
field({ type: "u32" }),
|
|
304
|
+
__metadata("design:type", Number)
|
|
305
|
+
], HashableSegmentU32.prototype, "end1", void 0);
|
|
306
|
+
__decorate([
|
|
307
|
+
field({ type: "u32" }),
|
|
308
|
+
__metadata("design:type", Number)
|
|
309
|
+
], HashableSegmentU32.prototype, "start2", void 0);
|
|
310
|
+
__decorate([
|
|
311
|
+
field({ type: "u32" }),
|
|
312
|
+
__metadata("design:type", Number)
|
|
313
|
+
], HashableSegmentU32.prototype, "end2", void 0);
|
|
314
|
+
__decorate([
|
|
315
|
+
field({ type: "u8" }),
|
|
316
|
+
__metadata("design:type", Number)
|
|
317
|
+
], HashableSegmentU32.prototype, "mode", void 0);
|
|
318
|
+
class HashableSegmentU64 {
|
|
319
|
+
start1;
|
|
320
|
+
end1;
|
|
321
|
+
start2;
|
|
322
|
+
end2;
|
|
323
|
+
mode;
|
|
324
|
+
constructor(properties) {
|
|
325
|
+
this.start1 = properties.start1;
|
|
326
|
+
this.end1 = properties.end1;
|
|
327
|
+
this.start2 = properties.start2;
|
|
328
|
+
this.end2 = properties.end2;
|
|
329
|
+
this.mode = properties.mode;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
__decorate([
|
|
333
|
+
field({ type: "u64" }),
|
|
334
|
+
__metadata("design:type", BigInt)
|
|
335
|
+
], HashableSegmentU64.prototype, "start1", void 0);
|
|
336
|
+
__decorate([
|
|
337
|
+
field({ type: "u64" }),
|
|
338
|
+
__metadata("design:type", BigInt)
|
|
339
|
+
], HashableSegmentU64.prototype, "end1", void 0);
|
|
340
|
+
__decorate([
|
|
341
|
+
field({ type: "u64" }),
|
|
342
|
+
__metadata("design:type", BigInt)
|
|
343
|
+
], HashableSegmentU64.prototype, "start2", void 0);
|
|
344
|
+
__decorate([
|
|
345
|
+
field({ type: "u64" }),
|
|
346
|
+
__metadata("design:type", BigInt)
|
|
347
|
+
], HashableSegmentU64.prototype, "end2", void 0);
|
|
348
|
+
__decorate([
|
|
349
|
+
field({ type: "u8" }),
|
|
350
|
+
__metadata("design:type", Number)
|
|
351
|
+
], HashableSegmentU64.prototype, "mode", void 0);
|
|
352
|
+
export class ReplicationRangeIndexableU32 {
|
|
161
353
|
id;
|
|
162
354
|
hash;
|
|
163
355
|
timestamp;
|
|
@@ -172,20 +364,12 @@ export class ReplicationRangeIndexable {
|
|
|
172
364
|
this.hash =
|
|
173
365
|
properties.publicKeyHash ||
|
|
174
366
|
properties.publicKey.hashcode();
|
|
175
|
-
|
|
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
|
-
}
|
|
367
|
+
this.transform({ length: properties.length, offset: properties.offset });
|
|
184
368
|
this.mode = properties.mode ?? ReplicationIntent.NonStrict;
|
|
185
369
|
this.timestamp = properties.timestamp || BigInt(0);
|
|
186
370
|
}
|
|
187
371
|
transform(properties) {
|
|
188
|
-
const ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.length);
|
|
372
|
+
const ranges = getSegmentsFromOffsetAndRange(properties.offset, properties.length, 0, MAX_U32);
|
|
189
373
|
this.start1 = Math.round(ranges[0][0]);
|
|
190
374
|
this.end1 = Math.round(ranges[0][1]);
|
|
191
375
|
this.start2 = Math.round(ranges[1][0]);
|
|
@@ -194,11 +378,11 @@ export class ReplicationRangeIndexable {
|
|
|
194
378
|
this.end1 -
|
|
195
379
|
this.start1 +
|
|
196
380
|
(this.end2 < this.end1 ? this.end2 - this.start2 : 0);
|
|
197
|
-
if (this.start1 >
|
|
198
|
-
this.end1 >
|
|
199
|
-
this.start2 >
|
|
200
|
-
this.end2 >
|
|
201
|
-
this.width >
|
|
381
|
+
if (this.start1 > MAX_U32 ||
|
|
382
|
+
this.end1 > MAX_U32 ||
|
|
383
|
+
this.start2 > MAX_U32 ||
|
|
384
|
+
this.end2 > MAX_U32 ||
|
|
385
|
+
this.width > MAX_U32 ||
|
|
202
386
|
this.width < 0) {
|
|
203
387
|
throw new Error("Segment coordinate out of bounds");
|
|
204
388
|
}
|
|
@@ -223,7 +407,7 @@ export class ReplicationRangeIndexable {
|
|
|
223
407
|
return false;
|
|
224
408
|
}
|
|
225
409
|
toReplicationRange() {
|
|
226
|
-
return new
|
|
410
|
+
return new ReplicationRangeMessageU32({
|
|
227
411
|
id: this.id,
|
|
228
412
|
offset: this.start1,
|
|
229
413
|
factor: this.width,
|
|
@@ -231,10 +415,6 @@ export class ReplicationRangeIndexable {
|
|
|
231
415
|
mode: this.mode,
|
|
232
416
|
});
|
|
233
417
|
}
|
|
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
418
|
get wrapped() {
|
|
239
419
|
return this.end2 < this.end1;
|
|
240
420
|
}
|
|
@@ -271,84 +451,371 @@ export class ReplicationRangeIndexable {
|
|
|
271
451
|
toStringDetailed() {
|
|
272
452
|
return `(hash ${this.hash} range: ${this.toString()})`;
|
|
273
453
|
}
|
|
454
|
+
toUniqueSegmentId() {
|
|
455
|
+
// return a unique id as a function of the segments location and the replication intent
|
|
456
|
+
const hashable = new HashableSegmentU32(this);
|
|
457
|
+
return sha256Base64Sync(serialize(hashable));
|
|
458
|
+
}
|
|
274
459
|
}
|
|
275
460
|
__decorate([
|
|
276
461
|
id({ type: Uint8Array }),
|
|
277
462
|
__metadata("design:type", Uint8Array)
|
|
278
|
-
],
|
|
463
|
+
], ReplicationRangeIndexableU32.prototype, "id", void 0);
|
|
279
464
|
__decorate([
|
|
280
465
|
field({ type: "string" }),
|
|
281
466
|
__metadata("design:type", String)
|
|
282
|
-
],
|
|
467
|
+
], ReplicationRangeIndexableU32.prototype, "hash", void 0);
|
|
283
468
|
__decorate([
|
|
284
469
|
field({ type: "u64" }),
|
|
285
470
|
__metadata("design:type", BigInt)
|
|
286
|
-
],
|
|
471
|
+
], ReplicationRangeIndexableU32.prototype, "timestamp", void 0);
|
|
287
472
|
__decorate([
|
|
288
473
|
field({ type: "u32" }),
|
|
289
474
|
__metadata("design:type", Number)
|
|
290
|
-
],
|
|
475
|
+
], ReplicationRangeIndexableU32.prototype, "start1", void 0);
|
|
291
476
|
__decorate([
|
|
292
477
|
field({ type: "u32" }),
|
|
293
478
|
__metadata("design:type", Number)
|
|
294
|
-
],
|
|
479
|
+
], ReplicationRangeIndexableU32.prototype, "end1", void 0);
|
|
295
480
|
__decorate([
|
|
296
481
|
field({ type: "u32" }),
|
|
297
482
|
__metadata("design:type", Number)
|
|
298
|
-
],
|
|
483
|
+
], ReplicationRangeIndexableU32.prototype, "start2", void 0);
|
|
299
484
|
__decorate([
|
|
300
485
|
field({ type: "u32" }),
|
|
301
486
|
__metadata("design:type", Number)
|
|
302
|
-
],
|
|
487
|
+
], ReplicationRangeIndexableU32.prototype, "end2", void 0);
|
|
303
488
|
__decorate([
|
|
304
489
|
field({ type: "u32" }),
|
|
305
490
|
__metadata("design:type", Number)
|
|
306
|
-
],
|
|
491
|
+
], ReplicationRangeIndexableU32.prototype, "width", void 0);
|
|
307
492
|
__decorate([
|
|
308
493
|
field({ type: "u8" }),
|
|
309
494
|
__metadata("design:type", Number)
|
|
310
|
-
],
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
495
|
+
], ReplicationRangeIndexableU32.prototype, "mode", void 0);
|
|
496
|
+
export class ReplicationRangeIndexableU64 {
|
|
497
|
+
id;
|
|
498
|
+
hash;
|
|
499
|
+
timestamp;
|
|
500
|
+
start1;
|
|
501
|
+
end1;
|
|
502
|
+
start2;
|
|
503
|
+
end2;
|
|
504
|
+
width;
|
|
505
|
+
mode;
|
|
506
|
+
constructor(properties) {
|
|
507
|
+
this.id = properties.id ?? randomBytes(32);
|
|
508
|
+
this.hash =
|
|
509
|
+
properties.publicKeyHash ||
|
|
510
|
+
properties.publicKey.hashcode();
|
|
511
|
+
this.transform({ length: properties.length, offset: properties.offset });
|
|
512
|
+
this.mode = properties.mode ?? ReplicationIntent.NonStrict;
|
|
513
|
+
this.timestamp = properties.timestamp || BigInt(0);
|
|
514
|
+
}
|
|
515
|
+
transform(properties) {
|
|
516
|
+
const ranges = getSegmentsFromOffsetAndRange(BigInt(properties.offset), BigInt(properties.length), 0n, MAX_U64);
|
|
517
|
+
this.start1 = ranges[0][0];
|
|
518
|
+
this.end1 = ranges[0][1];
|
|
519
|
+
this.start2 = ranges[1][0];
|
|
520
|
+
this.end2 = ranges[1][1];
|
|
521
|
+
this.width =
|
|
522
|
+
this.end1 -
|
|
523
|
+
this.start1 +
|
|
524
|
+
(this.end2 < this.end1 ? this.end2 - this.start2 : 0n);
|
|
525
|
+
if (this.start1 > MAX_U64 ||
|
|
526
|
+
this.end1 > MAX_U64 ||
|
|
527
|
+
this.start2 > MAX_U64 ||
|
|
528
|
+
this.end2 > MAX_U64 ||
|
|
529
|
+
this.width > MAX_U64 ||
|
|
530
|
+
this.width < 0n) {
|
|
531
|
+
throw new Error("Segment coordinate out of bounds");
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
get idString() {
|
|
535
|
+
return toBase64(this.id);
|
|
536
|
+
}
|
|
537
|
+
contains(point) {
|
|
538
|
+
return ((point >= this.start1 && point < this.end1) ||
|
|
539
|
+
(point >= this.start2 && point < this.end2));
|
|
540
|
+
}
|
|
541
|
+
overlaps(other, checkOther = true) {
|
|
542
|
+
if (this.contains(other.start1) ||
|
|
543
|
+
this.contains(other.start2) ||
|
|
544
|
+
this.contains(other.end1 - 1n) ||
|
|
545
|
+
this.contains(other.end2 - 1n)) {
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
if (checkOther) {
|
|
549
|
+
return other.overlaps(this, false);
|
|
550
|
+
}
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
toReplicationRange() {
|
|
554
|
+
return new ReplicationRangeMessageU64({
|
|
555
|
+
id: this.id,
|
|
556
|
+
offset: this.start1,
|
|
557
|
+
factor: this.width,
|
|
558
|
+
timestamp: this.timestamp,
|
|
559
|
+
mode: this.mode,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
get wrapped() {
|
|
563
|
+
return this.end2 < this.end1;
|
|
564
|
+
}
|
|
565
|
+
get widthNormalized() {
|
|
566
|
+
return Number(this.width) / Number(MAX_U64);
|
|
567
|
+
}
|
|
568
|
+
equals(other) {
|
|
569
|
+
if (equals(this.id, other.id) &&
|
|
570
|
+
this.hash === other.hash &&
|
|
571
|
+
this.timestamp === other.timestamp &&
|
|
572
|
+
this.mode === other.mode &&
|
|
573
|
+
this.start1 === other.start1 &&
|
|
574
|
+
this.end1 === other.end1 &&
|
|
575
|
+
this.start2 === other.start2 &&
|
|
576
|
+
this.end2 === other.end2 &&
|
|
577
|
+
this.width === other.width) {
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
equalRange(other) {
|
|
583
|
+
return (this.start1 === other.start1 &&
|
|
584
|
+
this.end1 === other.end1 &&
|
|
585
|
+
this.start2 === other.start2 &&
|
|
586
|
+
this.end2 === other.end2);
|
|
587
|
+
}
|
|
588
|
+
toString() {
|
|
589
|
+
let roundToTwoDecimals = (num) => Math.round(num * 100) / 100;
|
|
590
|
+
if (Math.abs(Number(this.start1 - this.start2)) < 0.0001) {
|
|
591
|
+
return `([${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}])`;
|
|
592
|
+
}
|
|
593
|
+
return `([${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.start1) / Number(MAX_U64))}] [${roundToTwoDecimals(Number(this.start2) / Number(MAX_U64))}, ${roundToTwoDecimals(Number(this.end2) / Number(MAX_U64))}])`;
|
|
594
|
+
}
|
|
595
|
+
toStringDetailed() {
|
|
596
|
+
return `(hash ${this.hash} range: ${this.toString()})`;
|
|
597
|
+
}
|
|
598
|
+
toUniqueSegmentId() {
|
|
599
|
+
// return a unique id as a function of the segments location and the replication intent
|
|
600
|
+
const hashable = new HashableSegmentU64(this);
|
|
601
|
+
return sha256Base64Sync(serialize(hashable));
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
__decorate([
|
|
605
|
+
id({ type: Uint8Array }),
|
|
606
|
+
__metadata("design:type", Uint8Array)
|
|
607
|
+
], ReplicationRangeIndexableU64.prototype, "id", void 0);
|
|
608
|
+
__decorate([
|
|
609
|
+
field({ type: "string" }),
|
|
610
|
+
__metadata("design:type", String)
|
|
611
|
+
], ReplicationRangeIndexableU64.prototype, "hash", void 0);
|
|
612
|
+
__decorate([
|
|
613
|
+
field({ type: "u64" }),
|
|
614
|
+
__metadata("design:type", BigInt)
|
|
615
|
+
], ReplicationRangeIndexableU64.prototype, "timestamp", void 0);
|
|
616
|
+
__decorate([
|
|
617
|
+
field({ type: "u64" }),
|
|
618
|
+
__metadata("design:type", BigInt)
|
|
619
|
+
], ReplicationRangeIndexableU64.prototype, "start1", void 0);
|
|
620
|
+
__decorate([
|
|
621
|
+
field({ type: "u64" }),
|
|
622
|
+
__metadata("design:type", BigInt)
|
|
623
|
+
], ReplicationRangeIndexableU64.prototype, "end1", void 0);
|
|
624
|
+
__decorate([
|
|
625
|
+
field({ type: "u64" }),
|
|
626
|
+
__metadata("design:type", BigInt)
|
|
627
|
+
], ReplicationRangeIndexableU64.prototype, "start2", void 0);
|
|
628
|
+
__decorate([
|
|
629
|
+
field({ type: "u64" }),
|
|
630
|
+
__metadata("design:type", BigInt)
|
|
631
|
+
], ReplicationRangeIndexableU64.prototype, "end2", void 0);
|
|
632
|
+
__decorate([
|
|
633
|
+
field({ type: "u64" }),
|
|
634
|
+
__metadata("design:type", BigInt)
|
|
635
|
+
], ReplicationRangeIndexableU64.prototype, "width", void 0);
|
|
636
|
+
__decorate([
|
|
637
|
+
field({ type: "u8" }),
|
|
638
|
+
__metadata("design:type", Number)
|
|
639
|
+
], ReplicationRangeIndexableU64.prototype, "mode", void 0);
|
|
640
|
+
export const mergeRanges = (segments, numbers) => {
|
|
641
|
+
if (segments.length === 0) {
|
|
642
|
+
throw new Error("No segments to merge");
|
|
643
|
+
}
|
|
644
|
+
if (segments.length === 1) {
|
|
645
|
+
return segments[0];
|
|
646
|
+
}
|
|
647
|
+
// only allow merging from same publicKeyHash
|
|
648
|
+
const sameHash = segments.every((x) => x.hash === segments[0].hash);
|
|
649
|
+
if (!sameHash) {
|
|
650
|
+
throw new Error("Segments have different publicKeyHash");
|
|
651
|
+
}
|
|
652
|
+
// only allow merging segments with length 1 (trivial)
|
|
653
|
+
const sameLength = segments.every((x) => x.width === 1 || x.width === 1n);
|
|
654
|
+
if (!sameLength) {
|
|
655
|
+
throw new Error("Segments have different length, only merging of segments length 1 is supported");
|
|
656
|
+
}
|
|
657
|
+
const sorted = segments.sort((a, b) => Number(a.start1 - b.start1));
|
|
658
|
+
let calculateLargeGap = () => {
|
|
659
|
+
let last = sorted[sorted.length - 1];
|
|
660
|
+
let largestArc = numbers.zero;
|
|
661
|
+
let largestArcIndex = -1;
|
|
662
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
663
|
+
const current = sorted[i];
|
|
664
|
+
if (current.start1 !== last.start1) {
|
|
665
|
+
let arc = numbers.zero;
|
|
666
|
+
if (current.start1 < last.end2) {
|
|
667
|
+
arc += (numbers.maxValue - last.end2);
|
|
668
|
+
arc += (current.start1 - numbers.zero);
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
arc += (current.start1 - last.end2);
|
|
672
|
+
}
|
|
673
|
+
if (arc > largestArc) {
|
|
674
|
+
largestArc = arc;
|
|
675
|
+
largestArcIndex = i;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
last = current;
|
|
679
|
+
}
|
|
680
|
+
return [largestArc, largestArcIndex];
|
|
681
|
+
};
|
|
682
|
+
const [largestArc, largestArcIndex] = calculateLargeGap();
|
|
683
|
+
let totalLengthFinal = numbers.maxValue - largestArc;
|
|
684
|
+
if (largestArcIndex === -1) {
|
|
685
|
+
return segments[0]; // all ranges are the same
|
|
686
|
+
}
|
|
687
|
+
// use segments[0] constructor to create a new object
|
|
688
|
+
const proto = segments[0].constructor;
|
|
689
|
+
return new proto({
|
|
690
|
+
length: totalLengthFinal,
|
|
691
|
+
offset: segments[largestArcIndex].start1,
|
|
692
|
+
publicKeyHash: segments[0].hash,
|
|
693
|
+
});
|
|
694
|
+
};
|
|
695
|
+
const createContainingPointQuery = (points, options) => {
|
|
696
|
+
const or = [];
|
|
697
|
+
for (const point of Array.isArray(points) ? points : [points]) {
|
|
698
|
+
or.push(new And([
|
|
699
|
+
new IntegerCompare({
|
|
700
|
+
key: "start1",
|
|
701
|
+
compare: Compare.LessOrEqual,
|
|
702
|
+
value: point,
|
|
703
|
+
}),
|
|
704
|
+
new IntegerCompare({
|
|
705
|
+
key: "end1",
|
|
706
|
+
compare: Compare.Greater,
|
|
707
|
+
value: point,
|
|
708
|
+
}),
|
|
709
|
+
]));
|
|
710
|
+
or.push(new And([
|
|
711
|
+
new IntegerCompare({
|
|
712
|
+
key: "start2",
|
|
713
|
+
compare: Compare.LessOrEqual,
|
|
714
|
+
value: point,
|
|
715
|
+
}),
|
|
716
|
+
new IntegerCompare({
|
|
717
|
+
key: "end2",
|
|
718
|
+
compare: Compare.Greater,
|
|
719
|
+
value: point,
|
|
720
|
+
}),
|
|
721
|
+
]));
|
|
722
|
+
}
|
|
723
|
+
if (options?.time) {
|
|
724
|
+
let queries = [
|
|
725
|
+
new Or(or),
|
|
726
|
+
new IntegerCompare({
|
|
727
|
+
key: "timestamp",
|
|
728
|
+
compare: options.time.matured ? Compare.LessOrEqual : Compare.Greater,
|
|
729
|
+
value: BigInt(options.time.now - options.time.roleAgeLimit),
|
|
730
|
+
}),
|
|
731
|
+
];
|
|
732
|
+
return queries;
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
return new Or(or);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
const createContainingPartialPointQuery = (point, first, options) => {
|
|
739
|
+
let query;
|
|
740
|
+
if (first) {
|
|
741
|
+
query = [
|
|
742
|
+
new IntegerCompare({
|
|
743
|
+
key: "start1",
|
|
744
|
+
compare: Compare.LessOrEqual,
|
|
745
|
+
value: point,
|
|
746
|
+
}),
|
|
747
|
+
new IntegerCompare({
|
|
748
|
+
key: "end1",
|
|
749
|
+
compare: Compare.Greater,
|
|
750
|
+
value: point,
|
|
751
|
+
}),
|
|
752
|
+
];
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
query = [
|
|
756
|
+
new IntegerCompare({
|
|
757
|
+
key: "start2",
|
|
758
|
+
compare: Compare.LessOrEqual,
|
|
759
|
+
value: point,
|
|
760
|
+
}),
|
|
761
|
+
new IntegerCompare({
|
|
762
|
+
key: "end2",
|
|
763
|
+
compare: Compare.Greater,
|
|
764
|
+
value: point,
|
|
765
|
+
}),
|
|
766
|
+
];
|
|
767
|
+
}
|
|
768
|
+
if (options?.time) {
|
|
769
|
+
query.push(new IntegerCompare({
|
|
341
770
|
key: "timestamp",
|
|
342
|
-
compare: matured ? Compare.LessOrEqual : Compare.Greater,
|
|
343
|
-
value: BigInt(now - roleAgeLimit),
|
|
344
|
-
})
|
|
345
|
-
|
|
771
|
+
compare: options.time.matured ? Compare.LessOrEqual : Compare.Greater,
|
|
772
|
+
value: BigInt(options.time.now - options.time.roleAgeLimit),
|
|
773
|
+
}));
|
|
774
|
+
}
|
|
775
|
+
return query;
|
|
776
|
+
};
|
|
777
|
+
const iterateRangesContainingPoint = (rects, points, options) => {
|
|
778
|
+
// 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
|
|
346
779
|
return rects.iterate({
|
|
347
|
-
query:
|
|
780
|
+
query: createContainingPointQuery(points, {
|
|
781
|
+
time: options?.time,
|
|
782
|
+
}), // new Or(points.map(point => new And(createContainingPointQuery(point, roleAgeLimit, matured, now)))
|
|
348
783
|
sort: options?.sort,
|
|
349
784
|
}, options);
|
|
350
785
|
};
|
|
351
|
-
const
|
|
786
|
+
const allRangesContainingPoint = async (rects, points, options) => {
|
|
787
|
+
// 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
|
|
788
|
+
let allResults = [];
|
|
789
|
+
for (const point of Array.isArray(points) ? points : [points]) {
|
|
790
|
+
const firstIterator = rects.iterate({
|
|
791
|
+
query: createContainingPartialPointQuery(point, false, options),
|
|
792
|
+
sort: options?.sort,
|
|
793
|
+
}, options);
|
|
794
|
+
const secondIterator = rects.iterate({
|
|
795
|
+
query: createContainingPartialPointQuery(point, true, options),
|
|
796
|
+
sort: options?.sort,
|
|
797
|
+
}, options);
|
|
798
|
+
[...(await firstIterator.all()), ...(await secondIterator.all())].forEach((x) => allResults.push(x));
|
|
799
|
+
}
|
|
800
|
+
return allResults;
|
|
801
|
+
/* return [...await iterateRangesContainingPoint(rects, points, options).all()]; */
|
|
802
|
+
};
|
|
803
|
+
const countRangesContainingPoint = async (rects, point, options) => {
|
|
804
|
+
return rects.count({
|
|
805
|
+
query: createContainingPointQuery(point, options),
|
|
806
|
+
});
|
|
807
|
+
};
|
|
808
|
+
export const appromixateCoverage = async (properties) => {
|
|
809
|
+
const grid = properties.numbers.getGrid(properties.numbers.zero, properties.samples);
|
|
810
|
+
/* const now = +new Date(); */
|
|
811
|
+
let hits = 0;
|
|
812
|
+
for (const point of grid) {
|
|
813
|
+
const count = await countRangesContainingPoint(properties.peers, point);
|
|
814
|
+
hits += properties.normalized ? (count > 0 ? 1 : 0) : count;
|
|
815
|
+
}
|
|
816
|
+
return hits / properties.samples;
|
|
817
|
+
};
|
|
818
|
+
const getClosest = (direction, rects, point, roleAgeLimit, matured, now, includeStrict, numbers, options) => {
|
|
352
819
|
const createQueries = (p, equality) => {
|
|
353
820
|
let queries;
|
|
354
821
|
if (direction === "below") {
|
|
@@ -402,7 +869,7 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
|
|
|
402
869
|
],
|
|
403
870
|
}, options);
|
|
404
871
|
const iteratorWrapped = rects.iterate({
|
|
405
|
-
query: createQueries(direction === "below" ?
|
|
872
|
+
query: createQueries(direction === "below" ? numbers.maxValue : numbers.zero, true),
|
|
406
873
|
sort: [
|
|
407
874
|
direction === "below"
|
|
408
875
|
? new Sort({ key: ["end2"], direction: "desc" })
|
|
@@ -411,63 +878,68 @@ const getClosest = (direction, rects, point, roleAgeLimit, matured, now, include
|
|
|
411
878
|
sortByHash,
|
|
412
879
|
],
|
|
413
880
|
}, options);
|
|
414
|
-
return joinIterator([iterator, iteratorWrapped], point, direction);
|
|
881
|
+
return joinIterator([iterator, iteratorWrapped], point, direction, numbers);
|
|
415
882
|
};
|
|
416
|
-
export const
|
|
417
|
-
return
|
|
418
|
-
|
|
419
|
-
new
|
|
420
|
-
new
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
new
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
883
|
+
export const getCoveringRangeQuery = (range) => {
|
|
884
|
+
return [
|
|
885
|
+
new Or([
|
|
886
|
+
new And([
|
|
887
|
+
new IntegerCompare({
|
|
888
|
+
key: "start1",
|
|
889
|
+
compare: Compare.LessOrEqual,
|
|
890
|
+
value: range.start1,
|
|
891
|
+
}),
|
|
892
|
+
new IntegerCompare({
|
|
893
|
+
key: "end1",
|
|
894
|
+
compare: Compare.GreaterOrEqual,
|
|
895
|
+
value: range.end1,
|
|
896
|
+
}),
|
|
897
|
+
]),
|
|
898
|
+
new And([
|
|
899
|
+
new IntegerCompare({
|
|
900
|
+
key: "start2",
|
|
901
|
+
compare: Compare.LessOrEqual,
|
|
902
|
+
value: range.start1,
|
|
903
|
+
}),
|
|
904
|
+
new IntegerCompare({
|
|
905
|
+
key: "end2",
|
|
906
|
+
compare: Compare.GreaterOrEqual,
|
|
907
|
+
value: range.end1,
|
|
908
|
+
}),
|
|
909
|
+
]),
|
|
910
|
+
]),
|
|
911
|
+
new Or([
|
|
912
|
+
new And([
|
|
913
|
+
new IntegerCompare({
|
|
914
|
+
key: "start1",
|
|
915
|
+
compare: Compare.LessOrEqual,
|
|
916
|
+
value: range.start2,
|
|
917
|
+
}),
|
|
918
|
+
new IntegerCompare({
|
|
919
|
+
key: "end1",
|
|
920
|
+
compare: Compare.GreaterOrEqual,
|
|
921
|
+
value: range.end2,
|
|
922
|
+
}),
|
|
444
923
|
]),
|
|
445
|
-
new
|
|
446
|
-
new
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}),
|
|
457
|
-
]),
|
|
458
|
-
new And([
|
|
459
|
-
new IntegerCompare({
|
|
460
|
-
key: "start2",
|
|
461
|
-
compare: Compare.LessOrEqual,
|
|
462
|
-
value: range.start2,
|
|
463
|
-
}),
|
|
464
|
-
new IntegerCompare({
|
|
465
|
-
key: "end2",
|
|
466
|
-
compare: Compare.GreaterOrEqual,
|
|
467
|
-
value: range.end2,
|
|
468
|
-
}),
|
|
469
|
-
]),
|
|
924
|
+
new And([
|
|
925
|
+
new IntegerCompare({
|
|
926
|
+
key: "start2",
|
|
927
|
+
compare: Compare.LessOrEqual,
|
|
928
|
+
value: range.start2,
|
|
929
|
+
}),
|
|
930
|
+
new IntegerCompare({
|
|
931
|
+
key: "end2",
|
|
932
|
+
compare: Compare.GreaterOrEqual,
|
|
933
|
+
value: range.end2,
|
|
934
|
+
}),
|
|
470
935
|
]),
|
|
936
|
+
]),
|
|
937
|
+
];
|
|
938
|
+
};
|
|
939
|
+
export const iHaveCoveringRange = async (rects, range) => {
|
|
940
|
+
return ((await rects.count({
|
|
941
|
+
query: [
|
|
942
|
+
...getCoveringRangeQuery(range),
|
|
471
943
|
new StringMatch({
|
|
472
944
|
key: "hash",
|
|
473
945
|
value: range.hash,
|
|
@@ -480,34 +952,33 @@ export const hasCoveringRange = async (rects, range) => {
|
|
|
480
952
|
],
|
|
481
953
|
})) > 0);
|
|
482
954
|
};
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
// if direction is 'closest' then the shortest distance is the distance
|
|
488
|
-
// also from is 0.1 and to is 0.9, then distance should be 0.2 not 0.8
|
|
489
|
-
// same as for if from is 0.9 and to is 0.1, then distance should be 0.2 not 0.8
|
|
955
|
+
// TODO
|
|
956
|
+
export function getDistance(from, to, direction, end) {
|
|
957
|
+
const abs = (value) => value < 0 ? -value : value;
|
|
958
|
+
const diff = (a, b) => abs(a - b);
|
|
490
959
|
if (direction === "closest") {
|
|
491
960
|
if (from === to) {
|
|
492
|
-
return 0;
|
|
961
|
+
return typeof from === "number" ? 0 : 0n; // returns 0 of the correct type
|
|
493
962
|
}
|
|
494
|
-
return
|
|
963
|
+
return diff(from, to) < diff(end, diff(from, to))
|
|
964
|
+
? diff(from, to)
|
|
965
|
+
: diff(end, diff(from, to));
|
|
495
966
|
}
|
|
496
967
|
if (direction === "above") {
|
|
497
968
|
if (from <= to) {
|
|
498
|
-
return
|
|
969
|
+
return end - to + from;
|
|
499
970
|
}
|
|
500
971
|
return from - to;
|
|
501
972
|
}
|
|
502
973
|
if (direction === "below") {
|
|
503
974
|
if (from >= to) {
|
|
504
|
-
return
|
|
975
|
+
return end - from + to;
|
|
505
976
|
}
|
|
506
977
|
return to - from;
|
|
507
978
|
}
|
|
508
979
|
throw new Error("Invalid direction");
|
|
509
|
-
}
|
|
510
|
-
const joinIterator = (iterators, point, direction) => {
|
|
980
|
+
}
|
|
981
|
+
const joinIterator = (iterators, point, direction, numbers) => {
|
|
511
982
|
let queues = [];
|
|
512
983
|
return {
|
|
513
984
|
next: async (count) => {
|
|
@@ -525,13 +996,13 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
525
996
|
const closest = el.value;
|
|
526
997
|
let dist;
|
|
527
998
|
if (direction === "closest") {
|
|
528
|
-
dist =
|
|
999
|
+
dist = numbers.min(getDistance(closest.start1, point, direction, numbers.maxValue), getDistance(closest.end2, point, direction, numbers.maxValue));
|
|
529
1000
|
}
|
|
530
1001
|
else if (direction === "above") {
|
|
531
|
-
dist = getDistance(closest.start1, point, direction);
|
|
1002
|
+
dist = getDistance(closest.start1, point, direction, numbers.maxValue);
|
|
532
1003
|
}
|
|
533
1004
|
else if (direction === "below") {
|
|
534
|
-
dist = getDistance(closest.end2, point, direction);
|
|
1005
|
+
dist = getDistance(closest.end2, point, direction, numbers.maxValue);
|
|
535
1006
|
}
|
|
536
1007
|
else {
|
|
537
1008
|
throw new Error("Invalid direction");
|
|
@@ -543,7 +1014,7 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
543
1014
|
// pull the 'count' the closest element from one of the queue
|
|
544
1015
|
for (let i = 0; i < count; i++) {
|
|
545
1016
|
let closestQueue = -1;
|
|
546
|
-
let closestDist = Number.
|
|
1017
|
+
let closestDist = Number.MAX_VALUE;
|
|
547
1018
|
for (let j = 0; j < queues.length; j++) {
|
|
548
1019
|
let queue = queues[j];
|
|
549
1020
|
if (queue && queue.elements.length > 0) {
|
|
@@ -584,25 +1055,84 @@ const joinIterator = (iterators, point, direction) => {
|
|
|
584
1055
|
},
|
|
585
1056
|
};
|
|
586
1057
|
};
|
|
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 =
|
|
591
|
-
|
|
1058
|
+
const getClosestAround = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options) => {
|
|
1059
|
+
const closestBelow = getClosest("below", peers, point, roleAge, true, now, includeStrictBelow, numbers, options);
|
|
1060
|
+
const closestAbove = getClosest("above", peers, point, roleAge, true, now, includeStrictAbove, numbers, options);
|
|
1061
|
+
/* const containing = iterateRangesContainingPoint<S, R>(
|
|
1062
|
+
peers,
|
|
1063
|
+
point,
|
|
1064
|
+
{
|
|
1065
|
+
time: {
|
|
1066
|
+
roleAgeLimit: roleAge,
|
|
1067
|
+
matured: true,
|
|
1068
|
+
now,
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
);
|
|
1072
|
+
|
|
1073
|
+
return iteratorInSeries(
|
|
1074
|
+
containing,
|
|
1075
|
+
joinIterator<S, R>([closestBelow, closestAbove], point, "closest", numbers),
|
|
1076
|
+
); */
|
|
1077
|
+
return joinIterator([closestBelow, closestAbove], point, "closest", numbers);
|
|
1078
|
+
};
|
|
1079
|
+
export const isMatured = (segment, now, minAge) => {
|
|
1080
|
+
return now - Number(segment.timestamp) >= minAge;
|
|
592
1081
|
};
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
1082
|
+
/*
|
|
1083
|
+
|
|
1084
|
+
const collectNodesAroundPoint = async <R extends "u32" | "u64">(
|
|
1085
|
+
roleAge: number,
|
|
1086
|
+
peers: Index<ReplicationRangeIndexable<R>>,
|
|
1087
|
+
collector: (
|
|
1088
|
+
rect: { hash: string },
|
|
1089
|
+
matured: boolean,
|
|
1090
|
+
intersecting: boolean,
|
|
1091
|
+
) => void,
|
|
1092
|
+
point: NumberFromType<R>,
|
|
1093
|
+
now: number,
|
|
1094
|
+
numbers: Numbers<R>,
|
|
1095
|
+
done: () => boolean = () => true,
|
|
1096
|
+
) => {
|
|
1097
|
+
const containing = iterateRangesContainingPoint<
|
|
1098
|
+
{ timestamp: true, hash: true },
|
|
1099
|
+
R
|
|
1100
|
+
>(peers, point, 0, true, now, { shape: { timestamp: true, hash: true } as const });
|
|
596
1101
|
const allContaining = await containing.all();
|
|
597
1102
|
for (const rect of allContaining) {
|
|
598
1103
|
collector(rect.value, isMatured(rect.value, now, roleAge), true);
|
|
599
1104
|
}
|
|
1105
|
+
|
|
600
1106
|
if (done()) {
|
|
601
1107
|
return;
|
|
602
1108
|
}
|
|
603
|
-
|
|
604
|
-
const
|
|
605
|
-
|
|
1109
|
+
|
|
1110
|
+
const closestBelow = getClosest<undefined, R>(
|
|
1111
|
+
"below",
|
|
1112
|
+
peers,
|
|
1113
|
+
point,
|
|
1114
|
+
0,
|
|
1115
|
+
true,
|
|
1116
|
+
now,
|
|
1117
|
+
false,
|
|
1118
|
+
numbers
|
|
1119
|
+
);
|
|
1120
|
+
const closestAbove = getClosest<undefined, R>(
|
|
1121
|
+
"above",
|
|
1122
|
+
peers,
|
|
1123
|
+
point,
|
|
1124
|
+
0,
|
|
1125
|
+
true,
|
|
1126
|
+
now,
|
|
1127
|
+
false,
|
|
1128
|
+
numbers
|
|
1129
|
+
);
|
|
1130
|
+
const aroundIterator = joinIterator<undefined, R>(
|
|
1131
|
+
[closestBelow, closestAbove],
|
|
1132
|
+
point,
|
|
1133
|
+
"closest",
|
|
1134
|
+
numbers,
|
|
1135
|
+
);
|
|
606
1136
|
while (aroundIterator.done() !== true && done() !== true) {
|
|
607
1137
|
const res = await aroundIterator.next(1);
|
|
608
1138
|
for (const rect of res) {
|
|
@@ -613,45 +1143,87 @@ const collectNodesAroundPoint = async (roleAge, peers, collector, point, now, do
|
|
|
613
1143
|
}
|
|
614
1144
|
}
|
|
615
1145
|
};
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
1146
|
+
*/
|
|
1147
|
+
const collectClosestAround = async (roleAge, peers, collector, point, now, numbers, done = () => true) => {
|
|
1148
|
+
const closestBelow = getClosest("below", peers, point, 0, true, now, false, numbers);
|
|
1149
|
+
const closestAbove = getClosest("above", peers, point, 0, true, now, false, numbers);
|
|
1150
|
+
/* const containingIterator = iterateRangesContainingPoint<undefined, R>(
|
|
1151
|
+
peers,
|
|
1152
|
+
point,
|
|
1153
|
+
);
|
|
1154
|
+
*/
|
|
1155
|
+
const aroundIterator = joinIterator([/* containingIterator, */ closestBelow, closestAbove], point, "closest", numbers);
|
|
1156
|
+
let visited = new Set();
|
|
1157
|
+
while (aroundIterator.done() !== true && done() !== true) {
|
|
1158
|
+
const res = await aroundIterator.next(100);
|
|
1159
|
+
for (const rect of res) {
|
|
1160
|
+
visited.add(rect.value.idString);
|
|
1161
|
+
collector(rect.value, isMatured(rect.value, now, roleAge));
|
|
1162
|
+
if (done()) {
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
620
1166
|
}
|
|
621
|
-
return ret;
|
|
622
|
-
};
|
|
623
|
-
export const isMatured = (segment, now, minAge) => {
|
|
624
|
-
return now - Number(segment.timestamp) >= minAge;
|
|
625
1167
|
};
|
|
626
1168
|
// get peer sample that are responsible for the cursor point
|
|
627
1169
|
// will return a list of peers that want to replicate the data,
|
|
628
1170
|
// but also if necessary a list of peers that are responsible for the data
|
|
629
1171
|
// but have not explicitly replicating a range that cover the cursor point
|
|
630
|
-
export const getSamples = async (cursor, peers, roleAge) => {
|
|
1172
|
+
export const getSamples = async (cursor, peers, roleAge, numbers, options) => {
|
|
631
1173
|
const leaders = new Map();
|
|
632
1174
|
if (!peers) {
|
|
633
1175
|
return new Map();
|
|
634
1176
|
}
|
|
635
1177
|
const now = +new Date();
|
|
636
|
-
|
|
1178
|
+
let matured = 0;
|
|
1179
|
+
/* let missingForCursors: NumberFromType<R>[] = [] */
|
|
1180
|
+
let uniqueVisited = new Set();
|
|
637
1181
|
for (let i = 0; i < cursor.length; i++) {
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
1182
|
+
let point = cursor[i];
|
|
1183
|
+
const allContaining = await allRangesContainingPoint(peers, point);
|
|
1184
|
+
for (const rect of allContaining) {
|
|
1185
|
+
uniqueVisited.add(rect.value.hash);
|
|
1186
|
+
let prev = leaders.get(rect.value.hash);
|
|
1187
|
+
if (!prev) {
|
|
1188
|
+
if (isMatured(rect.value, now, roleAge)) {
|
|
1189
|
+
matured++;
|
|
1190
|
+
}
|
|
1191
|
+
leaders.set(rect.value.hash, { intersecting: true });
|
|
643
1192
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
leaders.set(rect.hash, { intersecting });
|
|
1193
|
+
else {
|
|
1194
|
+
prev.intersecting = true;
|
|
647
1195
|
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
|
|
1196
|
+
}
|
|
1197
|
+
if (options?.uniqueReplicators) {
|
|
1198
|
+
if (options.uniqueReplicators.size === leaders.size ||
|
|
1199
|
+
options.uniqueReplicators.size === uniqueVisited.size) {
|
|
1200
|
+
break; // nothing more to find
|
|
651
1201
|
}
|
|
652
|
-
|
|
653
|
-
|
|
1202
|
+
}
|
|
1203
|
+
if (options?.onlyIntersecting || matured > i) {
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
let foundOneUniqueMatured = false;
|
|
1207
|
+
await collectClosestAround(roleAge, peers, (rect, m) => {
|
|
1208
|
+
uniqueVisited.add(rect.hash);
|
|
1209
|
+
const prev = leaders.get(rect.hash);
|
|
1210
|
+
if (m) {
|
|
1211
|
+
if (!prev) {
|
|
1212
|
+
matured++;
|
|
1213
|
+
leaders.set(rect.hash, { intersecting: false });
|
|
1214
|
+
}
|
|
1215
|
+
if (matured > i) {
|
|
1216
|
+
foundOneUniqueMatured = true;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}, point, now, numbers, () => foundOneUniqueMatured);
|
|
1220
|
+
/* if (!foundOneUniqueMatured) {
|
|
1221
|
+
missingForCursors.push(point);
|
|
1222
|
+
} */
|
|
654
1223
|
}
|
|
1224
|
+
/* if (leaders.size < cursor.length) {
|
|
1225
|
+
throw new Error("Missing leaders got: " + leaders.size + " -- expected -- " + cursor.length + " role age " + roleAge + " missing " + missingForCursors.length + " replication index size: " + (await peers.count()));
|
|
1226
|
+
} */
|
|
655
1227
|
return leaders;
|
|
656
1228
|
};
|
|
657
1229
|
const fetchOne = async (iterator) => {
|
|
@@ -659,20 +1231,19 @@ const fetchOne = async (iterator) => {
|
|
|
659
1231
|
await iterator.close();
|
|
660
1232
|
return value[0]?.value;
|
|
661
1233
|
};
|
|
662
|
-
export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number
|
|
1234
|
+
export const minimumWidthToCover = async (minReplicas /* , replicatorCount: number */, numbers) => {
|
|
663
1235
|
/* minReplicas = Math.min(minReplicas, replicatorCount); */ // TODO do we need this?
|
|
664
1236
|
// If min replicas = 2
|
|
665
1237
|
// then we need to make sure we cover 0.5 of the total 'width' of the replication space
|
|
666
1238
|
// to make sure we reach sufficient amount of nodes such that at least one one has
|
|
667
1239
|
// the entry we are looking for
|
|
668
|
-
let widthToCoverScaled =
|
|
1240
|
+
let widthToCoverScaled = numbers.divRound(numbers.maxValue, minReplicas);
|
|
669
1241
|
return widthToCoverScaled;
|
|
670
1242
|
};
|
|
671
1243
|
export const getCoverSet = async (properties) => {
|
|
672
|
-
let intervalWidth = properties.intervalWidth ?? MAX_U32;
|
|
673
1244
|
const { peers, start, widthToCoverScaled, roleAge } = properties;
|
|
674
1245
|
const now = Date.now();
|
|
675
|
-
const { startNode, startLocation, endLocation } = await getStartAndEnd(peers, start, widthToCoverScaled, roleAge, now,
|
|
1246
|
+
const { startNode, startLocation, endLocation } = await getStartAndEnd(peers, start, widthToCoverScaled, roleAge, now, properties.numbers);
|
|
676
1247
|
let ret = new Set();
|
|
677
1248
|
// if start node (assume is self) and not mature, ask all known remotes if limited
|
|
678
1249
|
// TODO consider a more robust stragety here in a scenario where there are many nodes, lets say
|
|
@@ -705,14 +1276,19 @@ export const getCoverSet = async (properties) => {
|
|
|
705
1276
|
// push edges
|
|
706
1277
|
ret.add(current.hash);
|
|
707
1278
|
const resolveNextContaining = async (nextLocation, roleAge) => {
|
|
708
|
-
let next = await fetchOne(
|
|
1279
|
+
let next = await fetchOne(iterateRangesContainingPoint(peers, nextLocation, {
|
|
709
1280
|
sort: [new Sort({ key: "end2", direction: SortDirection.DESC })],
|
|
1281
|
+
time: {
|
|
1282
|
+
matured: true,
|
|
1283
|
+
roleAgeLimit: roleAge,
|
|
1284
|
+
now,
|
|
1285
|
+
},
|
|
710
1286
|
})); // get entersecting sort by largest end2
|
|
711
1287
|
return next;
|
|
712
1288
|
};
|
|
713
1289
|
const resolveNextAbove = async (nextLocation, roleAge) => {
|
|
714
1290
|
// if not get closest from above
|
|
715
|
-
let next = await fetchOne(getClosest("above", peers, nextLocation, roleAge, true, now, true));
|
|
1291
|
+
let next = await fetchOne(getClosest("above", peers, nextLocation, roleAge, true, now, true, properties.numbers));
|
|
716
1292
|
return next;
|
|
717
1293
|
};
|
|
718
1294
|
const resolveNext = async (nextLocation, roleAge) => {
|
|
@@ -724,14 +1300,17 @@ export const getCoverSet = async (properties) => {
|
|
|
724
1300
|
};
|
|
725
1301
|
// fill the middle
|
|
726
1302
|
let wrappedOnce = current.end2 < current.end1;
|
|
727
|
-
let coveredLength =
|
|
1303
|
+
let coveredLength = properties.numbers.zero;
|
|
728
1304
|
const addLength = (from) => {
|
|
729
1305
|
if (current.end2 < from || current.wrapped) {
|
|
730
1306
|
wrappedOnce = true;
|
|
731
|
-
|
|
1307
|
+
// @ts-ignore
|
|
1308
|
+
coveredLength += properties.numbers.maxValue - from;
|
|
1309
|
+
// @ts-ignore
|
|
732
1310
|
coveredLength += current.end2;
|
|
733
1311
|
}
|
|
734
1312
|
else {
|
|
1313
|
+
// @ts-ignore
|
|
735
1314
|
coveredLength += current.end1 - from;
|
|
736
1315
|
}
|
|
737
1316
|
};
|
|
@@ -739,7 +1318,7 @@ export const getCoverSet = async (properties) => {
|
|
|
739
1318
|
let maturedCoveredLength = coveredLength; /* TODO only increase matured length when startNode is matured? i.e. do isMatured(startNode, now, roleAge) ? coveredLength : 0; */
|
|
740
1319
|
let nextLocation = current.end2;
|
|
741
1320
|
while (maturedCoveredLength < widthToCoverScaled && // eslint-disable-line no-unmodified-loop-condition
|
|
742
|
-
coveredLength <=
|
|
1321
|
+
coveredLength <= properties.numbers.maxValue // eslint-disable-line no-unmodified-loop-condition
|
|
743
1322
|
) {
|
|
744
1323
|
let nextCandidate = await resolveNext(nextLocation, roleAge);
|
|
745
1324
|
/* let fromAbove = false; */
|
|
@@ -764,8 +1343,8 @@ export const getCoverSet = async (properties) => {
|
|
|
764
1343
|
coveredLength >= widthToCoverScaled;
|
|
765
1344
|
if (!isLast ||
|
|
766
1345
|
nextCandidate[1] ||
|
|
767
|
-
|
|
768
|
-
|
|
1346
|
+
properties.numbers.min(getDistance(last.start1, endLocation, "closest", properties.numbers.maxValue), getDistance(last.end2, endLocation, "closest", properties.numbers.maxValue)) >
|
|
1347
|
+
properties.numbers.min(getDistance(current.start1, endLocation, "closest", properties.numbers.maxValue), getDistance(current.end2, endLocation, "closest", properties.numbers.maxValue))) {
|
|
769
1348
|
ret.add(current.hash);
|
|
770
1349
|
}
|
|
771
1350
|
if (isLast && !nextCandidate[1] /* || equals(endRect.id, current.id) */) {
|
|
@@ -776,9 +1355,9 @@ export const getCoverSet = async (properties) => {
|
|
|
776
1355
|
}
|
|
777
1356
|
nextLocation = endIsWrapped
|
|
778
1357
|
? wrappedOnce
|
|
779
|
-
?
|
|
1358
|
+
? properties.numbers.min(current.end2, endLocation)
|
|
780
1359
|
: current.end2
|
|
781
|
-
:
|
|
1360
|
+
: properties.numbers.min(current.end2, endLocation);
|
|
782
1361
|
}
|
|
783
1362
|
start instanceof PublicSignKey && ret.add(start.hashcode());
|
|
784
1363
|
return ret;
|
|
@@ -787,53 +1366,58 @@ export const getCoverSet = async (properties) => {
|
|
|
787
1366
|
// reduce the change set to only regions that are changed for each peer
|
|
788
1367
|
// i.e. subtract removed regions from added regions, and vice versa
|
|
789
1368
|
const result = new Map<string, { range: ReplicationRangeIndexable, added: boolean }[]>();
|
|
790
|
-
|
|
1369
|
+
|
|
791
1370
|
for (const addedChange of changes.added ?? []) {
|
|
792
1371
|
let prev = result.get(addedChange.hash) ?? [];
|
|
793
1372
|
for (const [_hash, ranges] of result.entries()) {
|
|
794
1373
|
for (const r of ranges) {
|
|
795
|
-
|
|
1374
|
+
|
|
796
1375
|
}
|
|
797
1376
|
}
|
|
798
1377
|
}
|
|
799
1378
|
}
|
|
800
1379
|
*/
|
|
801
|
-
const
|
|
802
|
-
|
|
803
|
-
ors.push(new And([
|
|
1380
|
+
export const matchEntriesInRangeQuery = (range) => {
|
|
1381
|
+
const c1 = new And([
|
|
804
1382
|
new IntegerCompare({
|
|
805
|
-
key: "
|
|
1383
|
+
key: "coordinates",
|
|
806
1384
|
compare: "gte",
|
|
807
1385
|
value: range.start1,
|
|
808
1386
|
}),
|
|
809
1387
|
new IntegerCompare({
|
|
810
|
-
key: "
|
|
1388
|
+
key: "coordinates",
|
|
811
1389
|
compare: "lt",
|
|
812
1390
|
value: range.end1,
|
|
813
1391
|
}),
|
|
814
|
-
])
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
1392
|
+
]);
|
|
1393
|
+
if (range.start2 === range.end2) {
|
|
1394
|
+
return c1;
|
|
1395
|
+
}
|
|
1396
|
+
let ors = [
|
|
1397
|
+
c1,
|
|
1398
|
+
new And([
|
|
1399
|
+
new IntegerCompare({
|
|
1400
|
+
key: "coordinates",
|
|
1401
|
+
compare: "gte",
|
|
1402
|
+
value: range.start2,
|
|
1403
|
+
}),
|
|
1404
|
+
new IntegerCompare({
|
|
1405
|
+
key: "coordinates",
|
|
1406
|
+
compare: "lt",
|
|
1407
|
+
value: range.end2,
|
|
1408
|
+
}),
|
|
1409
|
+
]),
|
|
1410
|
+
];
|
|
827
1411
|
return new Or(ors);
|
|
828
1412
|
};
|
|
829
1413
|
export const toRebalance = (changes, index) => {
|
|
830
1414
|
const assignedRangesQuery = (changes) => {
|
|
831
1415
|
let ors = [];
|
|
832
1416
|
for (const change of changes) {
|
|
833
|
-
const matchRange =
|
|
1417
|
+
const matchRange = matchEntriesInRangeQuery(change.range);
|
|
834
1418
|
if (change.type === "updated") {
|
|
835
1419
|
// assuming a range is to be removed, is this entry still enoughly replicated
|
|
836
|
-
const prevMatchRange =
|
|
1420
|
+
const prevMatchRange = matchEntriesInRangeQuery(change.prev);
|
|
837
1421
|
ors.push(prevMatchRange);
|
|
838
1422
|
ors.push(matchRange);
|
|
839
1423
|
}
|
|
@@ -855,17 +1439,19 @@ export const toRebalance = (changes, index) => {
|
|
|
855
1439
|
query: assignedRangesQuery(changes),
|
|
856
1440
|
});
|
|
857
1441
|
while (iterator.done() !== true) {
|
|
858
|
-
const entries = await iterator.
|
|
859
|
-
|
|
860
|
-
const grouped = await groupByGidSync(entries.map((x) => x.value));
|
|
1442
|
+
const entries = await iterator.all(); // TODO choose right batch sizes here for optimal memory usage / speed
|
|
1443
|
+
/* const grouped = await groupByGidSync(entries.map((x) => x.value));
|
|
861
1444
|
for (const [gid, entries] of grouped.entries()) {
|
|
862
1445
|
yield { gid, entries };
|
|
1446
|
+
} */
|
|
1447
|
+
for (const entry of entries) {
|
|
1448
|
+
yield entry.value;
|
|
863
1449
|
}
|
|
864
1450
|
}
|
|
865
1451
|
},
|
|
866
1452
|
};
|
|
867
1453
|
};
|
|
868
|
-
export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, options) => {
|
|
1454
|
+
export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, numbers, options) => {
|
|
869
1455
|
let iterator = index.iterate({
|
|
870
1456
|
query: [new StringMatch({ key: "hash", value: publicKey.hashcode() })],
|
|
871
1457
|
}, options);
|
|
@@ -874,7 +1460,7 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, opti
|
|
|
874
1460
|
let node = result[0]?.value;
|
|
875
1461
|
if (node) {
|
|
876
1462
|
if (!isMatured(node, now, roleAge)) {
|
|
877
|
-
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, options));
|
|
1463
|
+
const matured = await fetchOne(getClosestAround(index, node.start1, roleAge, now, false, false, numbers, options));
|
|
878
1464
|
if (matured) {
|
|
879
1465
|
node = matured;
|
|
880
1466
|
}
|
|
@@ -882,17 +1468,17 @@ export const fetchOneFromPublicKey = async (publicKey, index, roleAge, now, opti
|
|
|
882
1468
|
}
|
|
883
1469
|
return node;
|
|
884
1470
|
};
|
|
885
|
-
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now,
|
|
1471
|
+
export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge, now, numbers, options) => {
|
|
886
1472
|
// find a good starting point
|
|
887
1473
|
let startNode = undefined;
|
|
888
1474
|
let startLocation = undefined;
|
|
889
|
-
const nodeFromPoint = async (point =
|
|
1475
|
+
const nodeFromPoint = async (point = numbers.random()) => {
|
|
890
1476
|
startLocation = point;
|
|
891
|
-
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, options);
|
|
1477
|
+
startNode = await fetchOneClosest(peers, startLocation, roleAge, now, false, true, numbers, options);
|
|
892
1478
|
};
|
|
893
1479
|
if (start instanceof PublicSignKey) {
|
|
894
1480
|
// start at our node (local first)
|
|
895
|
-
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, options);
|
|
1481
|
+
startNode = await fetchOneFromPublicKey(start, peers, roleAge, now, numbers, options);
|
|
896
1482
|
if (!startNode) {
|
|
897
1483
|
// fetch randomly
|
|
898
1484
|
await nodeFromPoint();
|
|
@@ -901,38 +1487,49 @@ export const getStartAndEnd = async (peers, start, widthToCoverScaled, roleAge,
|
|
|
901
1487
|
startLocation = startNode.start1;
|
|
902
1488
|
}
|
|
903
1489
|
}
|
|
904
|
-
else if (typeof start === "number") {
|
|
1490
|
+
else if (typeof start === "number" || typeof start === "bigint") {
|
|
905
1491
|
await nodeFromPoint(start);
|
|
906
1492
|
}
|
|
907
1493
|
else {
|
|
908
1494
|
await nodeFromPoint();
|
|
909
1495
|
}
|
|
910
1496
|
if (!startNode || startLocation == null) {
|
|
911
|
-
return {
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
}
|
|
917
|
-
// if start location is after endLocation and startNode is strict then return undefined because this is not a node we want to choose
|
|
918
|
-
let coveredDistanceToStart = 0;
|
|
919
|
-
if (startNode.start1 < startLocation) {
|
|
920
|
-
coveredDistanceToStart += intervalWidth - startLocation + startNode.start1;
|
|
1497
|
+
return {
|
|
1498
|
+
startNode: undefined,
|
|
1499
|
+
startLocation: numbers.zero,
|
|
1500
|
+
endLocation: numbers.zero,
|
|
1501
|
+
};
|
|
921
1502
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
if (startNode.
|
|
926
|
-
coveredDistanceToStart
|
|
927
|
-
|
|
1503
|
+
// @ts-ignore
|
|
1504
|
+
let endLocation = (startLocation + widthToCoverScaled) % numbers.maxValue;
|
|
1505
|
+
// if the start node range is not containing the start point, then figure out if the startNode is ideal
|
|
1506
|
+
if (!startNode.contains(startLocation)) {
|
|
1507
|
+
let coveredDistanceToStart = numbers.zero;
|
|
1508
|
+
if (startNode.start1 < startLocation) {
|
|
1509
|
+
coveredDistanceToStart +=
|
|
1510
|
+
numbers.maxValue - startLocation + startNode.start1;
|
|
1511
|
+
}
|
|
1512
|
+
else {
|
|
1513
|
+
coveredDistanceToStart += (startNode.start1 -
|
|
1514
|
+
startLocation);
|
|
1515
|
+
}
|
|
1516
|
+
// in this case, the gap to the start point is larger than the width we want to cover. Assume there are no good points
|
|
1517
|
+
if (startNode.mode === ReplicationIntent.Strict &&
|
|
1518
|
+
coveredDistanceToStart > widthToCoverScaled) {
|
|
1519
|
+
return {
|
|
1520
|
+
startNode: undefined,
|
|
1521
|
+
startLocation: numbers.zero,
|
|
1522
|
+
endLocation: numbers.zero,
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
928
1525
|
}
|
|
929
1526
|
return {
|
|
930
1527
|
startNode,
|
|
931
|
-
startLocation
|
|
932
|
-
endLocation
|
|
1528
|
+
startLocation,
|
|
1529
|
+
endLocation,
|
|
933
1530
|
};
|
|
934
1531
|
};
|
|
935
|
-
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options) => {
|
|
936
|
-
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, options));
|
|
1532
|
+
export const fetchOneClosest = (peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options) => {
|
|
1533
|
+
return fetchOne(getClosestAround(peers, point, roleAge, now, includeStrictBelow, includeStrictAbove, numbers, options));
|
|
937
1534
|
};
|
|
938
1535
|
//# sourceMappingURL=ranges.js.map
|