@peerbit/document 13.1.6 → 13.1.7
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/src/program.d.ts.map +1 -1
- package/dist/src/program.js +1 -0
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +338 -162
- package/dist/src/search.js.map +1 -1
- package/package.json +19 -19
- package/src/program.ts +4 -0
- package/src/search.ts +310 -118
package/dist/src/search.js
CHANGED
|
@@ -48,7 +48,7 @@ import { SharedLog, } from "@peerbit/shared-log";
|
|
|
48
48
|
import { DataMessage, FOREGROUND_READ_MESSAGE_PRIORITY, SilentDelivery, } from "@peerbit/stream-interface";
|
|
49
49
|
import { AbortError, TimeoutError, waitFor } from "@peerbit/time";
|
|
50
50
|
import pDefer, {} from "p-defer";
|
|
51
|
-
import { concat, fromString } from "uint8arrays";
|
|
51
|
+
import { concat, equals, fromString } from "uint8arrays";
|
|
52
52
|
import { copySerialization } from "./borsh.js";
|
|
53
53
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
54
54
|
import MostCommonQueryPredictor, { idAgnosticQueryKey, } from "./most-common-query-predictor.js";
|
|
@@ -377,6 +377,7 @@ function isSubclassOf(SubClass, SuperClass) {
|
|
|
377
377
|
const DEFAULT_TIMEOUT = 1e4;
|
|
378
378
|
const DEFAULT_KEEP_REMOTE_ITERATOR_TIMEOUT = 3e5;
|
|
379
379
|
const DISCOVER_TIMEOUT_FALLBACK = 500;
|
|
380
|
+
const CLOSE_ITERATOR_REQUEST_TIMEOUT = 5e3;
|
|
380
381
|
const DEFAULT_INDEX_BY = "id";
|
|
381
382
|
export const INDEX_CONTEXT_SHAPE = {
|
|
382
383
|
__context: {
|
|
@@ -2794,6 +2795,7 @@ let DocumentIndex = (() => {
|
|
|
2794
2795
|
};
|
|
2795
2796
|
let extraPromises = undefined;
|
|
2796
2797
|
const seenRemoteHashes = new Set();
|
|
2798
|
+
const selectedRemoteHashes = [];
|
|
2797
2799
|
const groupHashes = replicatorGroups
|
|
2798
2800
|
.filter((hash) => {
|
|
2799
2801
|
if (hash === this.node.identity.publicKey.hashcode()) {
|
|
@@ -2808,6 +2810,7 @@ let DocumentIndex = (() => {
|
|
|
2808
2810
|
return false;
|
|
2809
2811
|
}
|
|
2810
2812
|
fetchFirstForRemote?.add(hash);
|
|
2813
|
+
selectedRemoteHashes.push(hash);
|
|
2811
2814
|
const resultAlready = this._prefetch?.accumulator.consume(queryRequest, hash);
|
|
2812
2815
|
if (resultAlready) {
|
|
2813
2816
|
(extraPromises || (extraPromises = [])).push((async () => {
|
|
@@ -2826,6 +2829,7 @@ let DocumentIndex = (() => {
|
|
|
2826
2829
|
return true;
|
|
2827
2830
|
})
|
|
2828
2831
|
.map((x) => [x]);
|
|
2832
|
+
options?.onRemoteTargets?.(selectedRemoteHashes);
|
|
2829
2833
|
extraPromises && (await Promise.all(extraPromises));
|
|
2830
2834
|
let tearDown = undefined;
|
|
2831
2835
|
const search = this;
|
|
@@ -2930,16 +2934,20 @@ let DocumentIndex = (() => {
|
|
|
2930
2934
|
// Use an iterator so large results respect message size limits.
|
|
2931
2935
|
const iterator = this.iterate(coercedRequest, searchOptions);
|
|
2932
2936
|
const allResults = [];
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
allResults.
|
|
2937
|
+
try {
|
|
2938
|
+
while (iterator.done() !== true &&
|
|
2939
|
+
coercedRequest.fetch > allResults.length) {
|
|
2940
|
+
// We might need to pull .next multiple time due to data message size limitations
|
|
2941
|
+
for (const result of await iterator.next(coercedRequest.fetch - allResults.length)) {
|
|
2942
|
+
allResults.push(result);
|
|
2943
|
+
}
|
|
2938
2944
|
}
|
|
2945
|
+
// Deduplicate and return values directly
|
|
2946
|
+
return dedup(allResults, this.indexByResolver);
|
|
2947
|
+
}
|
|
2948
|
+
finally {
|
|
2949
|
+
await iterator.close();
|
|
2939
2950
|
}
|
|
2940
|
-
await iterator.close();
|
|
2941
|
-
// Deduplicate and return values directly
|
|
2942
|
-
return dedup(allResults, this.indexByResolver);
|
|
2943
2951
|
}
|
|
2944
2952
|
resolveIndexed(result, results) {
|
|
2945
2953
|
if (isResultIndexedValue(result)) {
|
|
@@ -3135,6 +3143,48 @@ let DocumentIndex = (() => {
|
|
|
3135
3143
|
return tracked;
|
|
3136
3144
|
};
|
|
3137
3145
|
const peerBufferMap = new Map();
|
|
3146
|
+
const remoteIteratorPeersToClose = new Set();
|
|
3147
|
+
const staleRemoteIteratorIdsToClose = new Map();
|
|
3148
|
+
const retiredRemoteIteratorPeers = new Set();
|
|
3149
|
+
const pendingMissingResponseRetryPeers = new Set();
|
|
3150
|
+
const missingResponseRetryAttempts = new Map();
|
|
3151
|
+
const maxMissingResponseRetryAttempts = 2;
|
|
3152
|
+
const retireRemoteIteratorPeer = (peer) => {
|
|
3153
|
+
remoteIteratorPeersToClose.add(peer);
|
|
3154
|
+
retiredRemoteIteratorPeers.add(peer);
|
|
3155
|
+
const peerBuffer = peerBufferMap.get(peer);
|
|
3156
|
+
if (!peerBuffer || peerBuffer.buffer.length === 0) {
|
|
3157
|
+
peerBufferMap.delete(peer);
|
|
3158
|
+
}
|
|
3159
|
+
else {
|
|
3160
|
+
// Keep already-received values available to the caller, but do not
|
|
3161
|
+
// issue another CollectNextRequest until a fresh iteration succeeds.
|
|
3162
|
+
peerBuffer.kept = 0;
|
|
3163
|
+
}
|
|
3164
|
+
};
|
|
3165
|
+
const recordMissingResponseGroups = (missingGroups) => {
|
|
3166
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3167
|
+
for (const group of missingGroups) {
|
|
3168
|
+
for (const hash of group) {
|
|
3169
|
+
if (hash && hash !== selfHash) {
|
|
3170
|
+
retireRemoteIteratorPeer(hash);
|
|
3171
|
+
}
|
|
3172
|
+
}
|
|
3173
|
+
if (!retryMissingResponseGroups) {
|
|
3174
|
+
continue;
|
|
3175
|
+
}
|
|
3176
|
+
const target = group.find((hash) => {
|
|
3177
|
+
if (!hash || hash === selfHash)
|
|
3178
|
+
return false;
|
|
3179
|
+
const attempts = missingResponseRetryAttempts.get(hash) ?? 0;
|
|
3180
|
+
return attempts < maxMissingResponseRetryAttempts;
|
|
3181
|
+
});
|
|
3182
|
+
if (!target)
|
|
3183
|
+
continue;
|
|
3184
|
+
pendingMissingResponseRetryPeers.add(target);
|
|
3185
|
+
missingResponseRetryAttempts.set(target, (missingResponseRetryAttempts.get(target) ?? 0) + 1);
|
|
3186
|
+
}
|
|
3187
|
+
};
|
|
3138
3188
|
const visited = new Set();
|
|
3139
3189
|
let indexedPlaceholders;
|
|
3140
3190
|
const ensureIndexedPlaceholders = () => {
|
|
@@ -3314,6 +3364,15 @@ let DocumentIndex = (() => {
|
|
|
3314
3364
|
}
|
|
3315
3365
|
}
|
|
3316
3366
|
const fetchFirst = async (n, fetchOptions) => {
|
|
3367
|
+
const remoteRequestOptions = typeof options?.remote === "object" ? options.remote : undefined;
|
|
3368
|
+
const fetchSignals = [
|
|
3369
|
+
options?.signal,
|
|
3370
|
+
remoteRequestOptions?.signal,
|
|
3371
|
+
ensureController().signal,
|
|
3372
|
+
].filter((signal) => signal != null);
|
|
3373
|
+
const fetchSignal = fetchSignals.length === 1
|
|
3374
|
+
? fetchSignals[0]
|
|
3375
|
+
: AbortSignal.any(fetchSignals);
|
|
3317
3376
|
await warmupPromise;
|
|
3318
3377
|
let hasMore = false;
|
|
3319
3378
|
let missingResponses = false;
|
|
@@ -3326,43 +3385,56 @@ let DocumentIndex = (() => {
|
|
|
3326
3385
|
const skipRemoteDueToDiscovery = typeof options?.remote === "object" &&
|
|
3327
3386
|
options.remote.reach?.discover &&
|
|
3328
3387
|
discoveredTargetHashes?.length === 0;
|
|
3388
|
+
const queryRemote = options?.remote !== false && !skipRemoteDueToDiscovery;
|
|
3389
|
+
const remoteFrom = fetchOptions?.from ??
|
|
3390
|
+
initialRemoteTargets ??
|
|
3391
|
+
remoteRequestOptions?.from;
|
|
3392
|
+
if (queryRemote) {
|
|
3393
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3394
|
+
for (const peer of remoteFrom ?? []) {
|
|
3395
|
+
if (peer !== selfHash) {
|
|
3396
|
+
remoteIteratorPeersToClose.add(peer);
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3329
3400
|
queryRequestCoerced.fetch = n;
|
|
3330
3401
|
await this.queryCommence(queryRequestCoerced, {
|
|
3331
3402
|
local: fetchOptions?.from != null ? false : options?.local,
|
|
3332
|
-
remote:
|
|
3403
|
+
remote: queryRemote
|
|
3333
3404
|
? {
|
|
3334
|
-
...
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
from: fetchOptions?.from ??
|
|
3338
|
-
initialRemoteTargets ??
|
|
3339
|
-
(typeof options?.remote === "object"
|
|
3340
|
-
? options.remote.from
|
|
3341
|
-
: undefined),
|
|
3405
|
+
...remoteRequestOptions,
|
|
3406
|
+
from: remoteFrom,
|
|
3407
|
+
signal: fetchSignal,
|
|
3342
3408
|
}
|
|
3343
3409
|
: false,
|
|
3344
3410
|
resolve,
|
|
3345
|
-
signal:
|
|
3411
|
+
signal: fetchSignal,
|
|
3346
3412
|
onResponse: async (response, from) => {
|
|
3347
3413
|
if (!from) {
|
|
3348
3414
|
logger.error("Missing response from");
|
|
3349
3415
|
return;
|
|
3350
3416
|
}
|
|
3417
|
+
const fromHash = from.hashcode();
|
|
3418
|
+
remoteIteratorPeersToClose.add(fromHash);
|
|
3419
|
+
retiredRemoteIteratorPeers.delete(fromHash);
|
|
3351
3420
|
if (response instanceof types.NoAccess) {
|
|
3352
3421
|
logger.error("Dont have access");
|
|
3353
3422
|
return;
|
|
3354
3423
|
}
|
|
3355
3424
|
else if (isResults(response)) {
|
|
3356
3425
|
const results = response;
|
|
3357
|
-
const existingBuffer = peerBufferMap.get(
|
|
3426
|
+
const existingBuffer = peerBufferMap.get(fromHash);
|
|
3358
3427
|
const buffer = existingBuffer?.buffer || [];
|
|
3359
3428
|
if (results.kept === 0n && results.results.length === 0) {
|
|
3360
3429
|
if (keepRemoteAlive) {
|
|
3361
|
-
peerBufferMap.set(
|
|
3430
|
+
peerBufferMap.set(fromHash, {
|
|
3362
3431
|
buffer,
|
|
3363
3432
|
kept: 0,
|
|
3364
3433
|
});
|
|
3365
3434
|
}
|
|
3435
|
+
else {
|
|
3436
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
3437
|
+
}
|
|
3366
3438
|
return;
|
|
3367
3439
|
}
|
|
3368
3440
|
const reqFetch = queryRequestCoerced.fetch ?? 0;
|
|
@@ -3371,6 +3443,9 @@ let DocumentIndex = (() => {
|
|
|
3371
3443
|
if (effectiveKept > 0) {
|
|
3372
3444
|
hasMore = true;
|
|
3373
3445
|
}
|
|
3446
|
+
else if (!keepRemoteAlive) {
|
|
3447
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
3448
|
+
}
|
|
3374
3449
|
for (const result of results.results) {
|
|
3375
3450
|
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
3376
3451
|
if (isResultValue(result)) {
|
|
@@ -3415,7 +3490,7 @@ let DocumentIndex = (() => {
|
|
|
3415
3490
|
ensureIndexedPlaceholders().set(indexKey, placeholder);
|
|
3416
3491
|
}
|
|
3417
3492
|
}
|
|
3418
|
-
peerBufferMap.set(
|
|
3493
|
+
peerBufferMap.set(fromHash, {
|
|
3419
3494
|
buffer,
|
|
3420
3495
|
kept: effectiveKept,
|
|
3421
3496
|
});
|
|
@@ -3426,29 +3501,21 @@ let DocumentIndex = (() => {
|
|
|
3426
3501
|
},
|
|
3427
3502
|
onMissingResponses: (error) => {
|
|
3428
3503
|
missingResponses = true;
|
|
3429
|
-
if (!retryMissingResponseGroups) {
|
|
3430
|
-
return;
|
|
3431
|
-
}
|
|
3432
3504
|
const missingGroups = error.missingGroups;
|
|
3433
3505
|
if (!missingGroups?.length) {
|
|
3434
3506
|
return;
|
|
3435
3507
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
const attempts = missingResponseRetryAttempts.get(hash) ?? 0;
|
|
3442
|
-
return attempts < maxMissingResponseRetryAttempts;
|
|
3443
|
-
});
|
|
3444
|
-
if (!target)
|
|
3445
|
-
continue;
|
|
3446
|
-
pendingMissingResponseRetryPeers.add(target);
|
|
3447
|
-
missingResponseRetryAttempts.set(target, (missingResponseRetryAttempts.get(target) ?? 0) + 1);
|
|
3508
|
+
recordMissingResponseGroups(missingGroups);
|
|
3509
|
+
},
|
|
3510
|
+
onRemoteTargets: (targets) => {
|
|
3511
|
+
for (const peer of targets) {
|
|
3512
|
+
remoteIteratorPeersToClose.add(peer);
|
|
3448
3513
|
}
|
|
3449
3514
|
},
|
|
3450
3515
|
}, fetchOptions?.fetchedFirstForRemote);
|
|
3451
|
-
if (missingResponses &&
|
|
3516
|
+
if (missingResponses &&
|
|
3517
|
+
retryMissingResponseGroups &&
|
|
3518
|
+
pendingMissingResponseRetryPeers.size > 0) {
|
|
3452
3519
|
hasMore = true;
|
|
3453
3520
|
unsetDone();
|
|
3454
3521
|
}
|
|
@@ -3473,6 +3540,18 @@ let DocumentIndex = (() => {
|
|
|
3473
3540
|
if (pendingMissingResponseRetryPeers.size > 0) {
|
|
3474
3541
|
const retryTargets = [...pendingMissingResponseRetryPeers];
|
|
3475
3542
|
pendingMissingResponseRetryPeers.clear();
|
|
3543
|
+
const idTranslation = this._prefetch?.accumulator.getTranslationMap(queryRequestCoerced);
|
|
3544
|
+
for (const peer of retryTargets) {
|
|
3545
|
+
const staleRemoteIteratorId = idTranslation?.get(peer);
|
|
3546
|
+
if (staleRemoteIteratorId) {
|
|
3547
|
+
const staleIds = staleRemoteIteratorIdsToClose.get(peer) ?? [];
|
|
3548
|
+
if (!staleIds.some((id) => equals(id, staleRemoteIteratorId))) {
|
|
3549
|
+
staleIds.push(staleRemoteIteratorId);
|
|
3550
|
+
staleRemoteIteratorIdsToClose.set(peer, staleIds);
|
|
3551
|
+
}
|
|
3552
|
+
idTranslation.delete(peer);
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3476
3555
|
return setFetchPromise(fetchFirst(n, {
|
|
3477
3556
|
from: retryTargets,
|
|
3478
3557
|
// retries for missing groups should not be suppressed by first-fetch dedupe
|
|
@@ -3482,6 +3561,12 @@ let DocumentIndex = (() => {
|
|
|
3482
3561
|
const promises = [];
|
|
3483
3562
|
let resultsLeft = 0;
|
|
3484
3563
|
for (const [peer, buffer] of peerBufferMap) {
|
|
3564
|
+
if (retiredRemoteIteratorPeers.has(peer)) {
|
|
3565
|
+
if (buffer.buffer.length === 0) {
|
|
3566
|
+
peerBufferMap.delete(peer);
|
|
3567
|
+
}
|
|
3568
|
+
continue;
|
|
3569
|
+
}
|
|
3485
3570
|
if (buffer.buffer.length < n) {
|
|
3486
3571
|
const hasExistingRemoteResults = buffer.kept > 0;
|
|
3487
3572
|
if (!hasExistingRemoteResults && !keepRemoteAlive) {
|
|
@@ -3576,6 +3661,7 @@ let DocumentIndex = (() => {
|
|
|
3576
3661
|
}
|
|
3577
3662
|
else {
|
|
3578
3663
|
// Fetch remotely
|
|
3664
|
+
remoteIteratorPeersToClose.add(peer);
|
|
3579
3665
|
const idTranslation = this._prefetch?.accumulator.getTranslationMap(queryRequestCoerced);
|
|
3580
3666
|
let remoteCollectRequest = collectRequest;
|
|
3581
3667
|
if (idTranslation) {
|
|
@@ -3584,97 +3670,118 @@ let DocumentIndex = (() => {
|
|
|
3584
3670
|
amount: collectRequest.amount,
|
|
3585
3671
|
});
|
|
3586
3672
|
}
|
|
3673
|
+
const remoteRequestOptions = typeof options?.remote === "object" ? options.remote : undefined;
|
|
3674
|
+
const collectSignals = [
|
|
3675
|
+
options?.signal,
|
|
3676
|
+
remoteRequestOptions?.signal,
|
|
3677
|
+
ensureController().signal,
|
|
3678
|
+
].filter((signal) => signal != null);
|
|
3679
|
+
const collectSignal = collectSignals.length === 1
|
|
3680
|
+
? collectSignals[0]
|
|
3681
|
+
: AbortSignal.any(collectSignals);
|
|
3587
3682
|
promises.push(this._query
|
|
3588
3683
|
.request(remoteCollectRequest, {
|
|
3589
3684
|
...options,
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
options.signal,
|
|
3593
|
-
ensureController().signal,
|
|
3594
|
-
])
|
|
3595
|
-
: ensureController().signal,
|
|
3685
|
+
...remoteRequestOptions,
|
|
3686
|
+
signal: collectSignal,
|
|
3596
3687
|
priority: getRemoteQueryPriority(options?.remote),
|
|
3597
3688
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
3598
3689
|
})
|
|
3599
|
-
.then((response) =>
|
|
3600
|
-
.
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
return;
|
|
3690
|
+
.then((response) => {
|
|
3691
|
+
if (!response.some((result) => result.from?.hashcode() === peer)) {
|
|
3692
|
+
const missingGroups = [[peer]];
|
|
3693
|
+
if (remoteRequestOptions?.throwOnMissing) {
|
|
3694
|
+
retireRemoteIteratorPeer(peer);
|
|
3695
|
+
throw new MissingResponsesError("Did not receive responses from all shards: " +
|
|
3696
|
+
JSON.stringify(missingGroups), missingGroups);
|
|
3607
3697
|
}
|
|
3608
|
-
|
|
3698
|
+
recordMissingResponseGroups(missingGroups);
|
|
3699
|
+
return;
|
|
3700
|
+
}
|
|
3701
|
+
return introduceEntries(queryRequestCoerced, response, this.documentType, this.indexedType, this._sync, options)
|
|
3702
|
+
.then(async (responses) => {
|
|
3703
|
+
return Promise.all(responses.map(async (response, i) => {
|
|
3704
|
+
resultsLeft += Number(response.response.kept);
|
|
3705
|
+
const from = responses[i].from;
|
|
3706
|
+
if (!from) {
|
|
3707
|
+
logger.error("Missing from for sorted query");
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3609
3710
|
if (!keepRemoteAlive &&
|
|
3610
|
-
|
|
3611
|
-
|
|
3711
|
+
response.response.kept === 0n) {
|
|
3712
|
+
remoteIteratorPeersToClose.delete(peer);
|
|
3612
3713
|
}
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3714
|
+
if (response.response.results.length === 0) {
|
|
3715
|
+
if (!keepRemoteAlive &&
|
|
3716
|
+
peerBufferMap.get(peer)?.buffer.length === 0) {
|
|
3717
|
+
peerBufferMap.delete(peer); // No more results
|
|
3718
|
+
}
|
|
3618
3719
|
}
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
const existingIndexed = indexedPlaceholders?.get(indexKey);
|
|
3624
|
-
if (existingIndexed) {
|
|
3625
|
-
existingIndexed.value =
|
|
3626
|
-
result.value;
|
|
3627
|
-
existingIndexed.context = result.context;
|
|
3628
|
-
existingIndexed.from = from;
|
|
3629
|
-
existingIndexed.indexed =
|
|
3630
|
-
await this.resolveIndexed(result, response.response
|
|
3631
|
-
.results);
|
|
3632
|
-
indexedPlaceholders?.delete(indexKey);
|
|
3633
|
-
continue;
|
|
3634
|
-
}
|
|
3635
|
-
if (visited.has(indexKey) &&
|
|
3636
|
-
!evictStaleBuffered(indexKey, result.context)) {
|
|
3637
|
-
continue;
|
|
3638
|
-
}
|
|
3639
|
-
visited.add(indexKey);
|
|
3640
|
-
const indexed = await this.resolveIndexed(result, response.response
|
|
3641
|
-
.results);
|
|
3642
|
-
peerBuffer.buffer.push({
|
|
3643
|
-
value: result.value,
|
|
3644
|
-
context: result.context,
|
|
3645
|
-
from: from,
|
|
3646
|
-
indexed,
|
|
3647
|
-
});
|
|
3720
|
+
else {
|
|
3721
|
+
const peerBuffer = peerBufferMap.get(peer);
|
|
3722
|
+
if (!peerBuffer) {
|
|
3723
|
+
return;
|
|
3648
3724
|
}
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3725
|
+
peerBuffer.kept = Number(response.response.kept);
|
|
3726
|
+
for (const result of response.response.results) {
|
|
3727
|
+
const indexKey = indexerTypes.toId(this.indexByResolver(result.value)).primitive;
|
|
3728
|
+
if (isResultValue(result)) {
|
|
3729
|
+
const existingIndexed = indexedPlaceholders?.get(indexKey);
|
|
3730
|
+
if (existingIndexed) {
|
|
3731
|
+
existingIndexed.value =
|
|
3732
|
+
result.value;
|
|
3733
|
+
existingIndexed.context = result.context;
|
|
3734
|
+
existingIndexed.from = from;
|
|
3735
|
+
existingIndexed.indexed =
|
|
3736
|
+
await this.resolveIndexed(result, response.response
|
|
3737
|
+
.results);
|
|
3738
|
+
indexedPlaceholders?.delete(indexKey);
|
|
3739
|
+
continue;
|
|
3740
|
+
}
|
|
3741
|
+
if (visited.has(indexKey) &&
|
|
3742
|
+
!evictStaleBuffered(indexKey, result.context)) {
|
|
3743
|
+
continue;
|
|
3744
|
+
}
|
|
3745
|
+
visited.add(indexKey);
|
|
3746
|
+
const indexed = await this.resolveIndexed(result, response.response
|
|
3747
|
+
.results);
|
|
3748
|
+
peerBuffer.buffer.push({
|
|
3749
|
+
value: result.value,
|
|
3750
|
+
context: result.context,
|
|
3751
|
+
from: from,
|
|
3752
|
+
indexed,
|
|
3753
|
+
});
|
|
3754
|
+
}
|
|
3755
|
+
else {
|
|
3756
|
+
const indexedResult = result;
|
|
3757
|
+
if (visited.has(indexKey) &&
|
|
3758
|
+
!indexedPlaceholders?.has(indexKey) &&
|
|
3759
|
+
!evictStaleBuffered(indexKey, indexedResult.context)) {
|
|
3760
|
+
continue;
|
|
3761
|
+
}
|
|
3762
|
+
visited.add(indexKey);
|
|
3763
|
+
const indexed = coerceWithContext(indexedResult.value, indexedResult.context);
|
|
3764
|
+
const placeholder = {
|
|
3765
|
+
value: indexedResult.value,
|
|
3766
|
+
context: indexedResult.context,
|
|
3767
|
+
from: from,
|
|
3768
|
+
indexed,
|
|
3769
|
+
};
|
|
3770
|
+
peerBuffer.buffer.push(placeholder);
|
|
3771
|
+
ensureIndexedPlaceholders().set(indexKey, placeholder);
|
|
3655
3772
|
}
|
|
3656
|
-
visited.add(indexKey);
|
|
3657
|
-
const indexed = coerceWithContext(indexedResult.value, indexedResult.context);
|
|
3658
|
-
const placeholder = {
|
|
3659
|
-
value: indexedResult.value,
|
|
3660
|
-
context: indexedResult.context,
|
|
3661
|
-
from: from,
|
|
3662
|
-
indexed,
|
|
3663
|
-
};
|
|
3664
|
-
peerBuffer.buffer.push(placeholder);
|
|
3665
|
-
ensureIndexedPlaceholders().set(indexKey, placeholder);
|
|
3666
3773
|
}
|
|
3667
3774
|
}
|
|
3668
|
-
}
|
|
3669
|
-
})
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
}))
|
|
3775
|
+
}));
|
|
3776
|
+
})
|
|
3777
|
+
.catch((e) => {
|
|
3778
|
+
logger.error("Failed to collect sorted results from: " +
|
|
3779
|
+
peer +
|
|
3780
|
+
". " +
|
|
3781
|
+
e?.message);
|
|
3782
|
+
peerBufferMap.delete(peer);
|
|
3783
|
+
});
|
|
3784
|
+
}));
|
|
3678
3785
|
}
|
|
3679
3786
|
}
|
|
3680
3787
|
else {
|
|
@@ -3697,7 +3804,7 @@ let DocumentIndex = (() => {
|
|
|
3697
3804
|
}
|
|
3698
3805
|
}
|
|
3699
3806
|
}
|
|
3700
|
-
return resultsLeft === 0; // 0 results left to fetch and 0 pending results
|
|
3807
|
+
return (resultsLeft === 0 && pendingMissingResponseRetryPeers.size === 0); // 0 results left to fetch and 0 pending results
|
|
3701
3808
|
}));
|
|
3702
3809
|
};
|
|
3703
3810
|
const next = async (n) => {
|
|
@@ -3779,35 +3886,83 @@ let DocumentIndex = (() => {
|
|
|
3779
3886
|
this.processCloseIteratorRequest(queryRequestCoerced, this.node.identity.publicKey);
|
|
3780
3887
|
done = true;
|
|
3781
3888
|
};
|
|
3782
|
-
|
|
3889
|
+
const outerSignal = options?.signal;
|
|
3890
|
+
let outerAbortListener;
|
|
3891
|
+
let closeStarted = false;
|
|
3892
|
+
let closePromise;
|
|
3893
|
+
const performClose = async () => {
|
|
3894
|
+
const idTranslation = this._prefetch?.accumulator.getTranslationMap(queryRequestCoerced);
|
|
3895
|
+
const remoteIteratorIds = idTranslation
|
|
3896
|
+
? new Map(idTranslation)
|
|
3897
|
+
: undefined;
|
|
3783
3898
|
cleanupAndDone();
|
|
3784
3899
|
// Keep-open iterators can still have active remote state even when
|
|
3785
3900
|
// their pending count has already drained to zero.
|
|
3786
|
-
const closeRequest = new types.CloseIteratorRequest({
|
|
3787
|
-
id: queryRequestCoerced.id,
|
|
3788
|
-
});
|
|
3789
3901
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3790
|
-
const
|
|
3902
|
+
const activeRemotePeers = new Set(keepRemoteAlive
|
|
3791
3903
|
? [...peerBufferMap.keys()].filter((peer) => peer !== selfHash)
|
|
3792
3904
|
: [...peerBufferMap.entries()]
|
|
3793
3905
|
.filter(([peer, buffer]) => peer !== selfHash && buffer.kept > 0)
|
|
3794
|
-
.map(([peer]) => peer);
|
|
3906
|
+
.map(([peer]) => peer));
|
|
3907
|
+
for (const peer of remoteIteratorPeersToClose) {
|
|
3908
|
+
if (peer !== selfHash) {
|
|
3909
|
+
activeRemotePeers.add(peer);
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
const staleRemoteIteratorIds = new Map([...staleRemoteIteratorIdsToClose].map(([peer, ids]) => [
|
|
3913
|
+
peer,
|
|
3914
|
+
[...ids],
|
|
3915
|
+
]));
|
|
3916
|
+
const remotePeers = new Set([
|
|
3917
|
+
...activeRemotePeers,
|
|
3918
|
+
...staleRemoteIteratorIds.keys(),
|
|
3919
|
+
]);
|
|
3795
3920
|
peerBufferMap.clear();
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3921
|
+
retiredRemoteIteratorPeers.clear();
|
|
3922
|
+
remoteIteratorPeersToClose.clear();
|
|
3923
|
+
staleRemoteIteratorIdsToClose.clear();
|
|
3924
|
+
if (remotePeers.size === 0) {
|
|
3925
|
+
return;
|
|
3926
|
+
}
|
|
3927
|
+
const remoteCloseOptions = typeof options?.remote === "object" ? options.remote : undefined;
|
|
3928
|
+
const closeSignal = AbortSignal.timeout(CLOSE_ITERATOR_REQUEST_TIMEOUT);
|
|
3929
|
+
await Promise.allSettled([...remotePeers].flatMap((peer) => {
|
|
3930
|
+
const ids = [];
|
|
3931
|
+
if (activeRemotePeers.has(peer)) {
|
|
3932
|
+
ids.push(remoteIteratorIds?.get(peer) ?? queryRequestCoerced.id);
|
|
3933
|
+
}
|
|
3934
|
+
for (const staleRemoteIteratorId of staleRemoteIteratorIds.get(peer) ?? []) {
|
|
3935
|
+
if (!ids.some((id) => equals(id, staleRemoteIteratorId))) {
|
|
3936
|
+
ids.push(staleRemoteIteratorId);
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
return ids.map((id) => {
|
|
3940
|
+
const closeRequest = new types.CloseIteratorRequest({ id });
|
|
3941
|
+
return this._query.send(closeRequest, {
|
|
3942
|
+
...remoteCloseOptions,
|
|
3943
|
+
signal: closeSignal,
|
|
3944
|
+
priority: getRemoteQueryPriority(options?.remote),
|
|
3945
|
+
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
3946
|
+
});
|
|
3947
|
+
});
|
|
3948
|
+
}));
|
|
3949
|
+
};
|
|
3950
|
+
const close = () => {
|
|
3951
|
+
if (closeStarted)
|
|
3952
|
+
return closePromise;
|
|
3953
|
+
closeStarted = true;
|
|
3954
|
+
if (outerAbortListener) {
|
|
3955
|
+
outerSignal?.removeEventListener("abort", outerAbortListener);
|
|
3956
|
+
outerAbortListener = undefined;
|
|
3957
|
+
}
|
|
3958
|
+
closePromise = performClose();
|
|
3959
|
+
return closePromise;
|
|
3801
3960
|
};
|
|
3802
|
-
options?.signal && options.signal.addEventListener("abort", close);
|
|
3803
3961
|
let doneFn = () => {
|
|
3804
3962
|
return done;
|
|
3805
3963
|
};
|
|
3806
3964
|
let joinListener;
|
|
3807
3965
|
let fetchedFirstForRemote = undefined;
|
|
3808
|
-
const pendingMissingResponseRetryPeers = new Set();
|
|
3809
|
-
const missingResponseRetryAttempts = new Map();
|
|
3810
|
-
const maxMissingResponseRetryAttempts = 2;
|
|
3811
3966
|
let joinFetchesInFlight = 0;
|
|
3812
3967
|
let updateDeferred;
|
|
3813
3968
|
const updateWaiters = new Set();
|
|
@@ -4460,6 +4615,15 @@ let DocumentIndex = (() => {
|
|
|
4460
4615
|
}
|
|
4461
4616
|
}
|
|
4462
4617
|
};
|
|
4618
|
+
if (outerSignal) {
|
|
4619
|
+
outerAbortListener = () => {
|
|
4620
|
+
void close();
|
|
4621
|
+
};
|
|
4622
|
+
outerSignal.addEventListener("abort", outerAbortListener, { once: true });
|
|
4623
|
+
if (outerSignal.aborted) {
|
|
4624
|
+
void close();
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4463
4627
|
return {
|
|
4464
4628
|
close,
|
|
4465
4629
|
next,
|
|
@@ -4529,49 +4693,61 @@ let DocumentIndex = (() => {
|
|
|
4529
4693
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
4530
4694
|
let result = [];
|
|
4531
4695
|
let c = 0;
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4696
|
+
try {
|
|
4697
|
+
while (doneFn() !== true) {
|
|
4698
|
+
let batch = await next(drainBatchSize);
|
|
4699
|
+
c += batch.length;
|
|
4700
|
+
if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
|
|
4701
|
+
warn("Iterating for more than " +
|
|
4702
|
+
WARNING_WHEN_ITERATING_FOR_MORE_THAN +
|
|
4703
|
+
" results");
|
|
4704
|
+
}
|
|
4705
|
+
if (batch.length > 0) {
|
|
4706
|
+
result.push(...batch);
|
|
4707
|
+
continue;
|
|
4708
|
+
}
|
|
4709
|
+
await waitForUpdateAndResetDeferred();
|
|
4543
4710
|
}
|
|
4544
|
-
|
|
4711
|
+
return result;
|
|
4712
|
+
}
|
|
4713
|
+
finally {
|
|
4714
|
+
await close();
|
|
4545
4715
|
}
|
|
4546
|
-
cleanupAndDone();
|
|
4547
|
-
return result;
|
|
4548
4716
|
},
|
|
4549
4717
|
first: async () => {
|
|
4550
|
-
|
|
4551
|
-
|
|
4718
|
+
try {
|
|
4719
|
+
if (doneFn()) {
|
|
4720
|
+
return undefined;
|
|
4721
|
+
}
|
|
4722
|
+
let batch = await next(1);
|
|
4723
|
+
return batch[0];
|
|
4724
|
+
}
|
|
4725
|
+
finally {
|
|
4726
|
+
await close();
|
|
4552
4727
|
}
|
|
4553
|
-
let batch = await next(1);
|
|
4554
|
-
cleanupAndDone();
|
|
4555
|
-
return batch[0];
|
|
4556
4728
|
},
|
|
4557
4729
|
[Symbol.asyncIterator]: async function* () {
|
|
4558
4730
|
drain = true;
|
|
4559
4731
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
4560
4732
|
let c = 0;
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4733
|
+
try {
|
|
4734
|
+
while (doneFn() !== true) {
|
|
4735
|
+
const batch = await next(drainBatchSize);
|
|
4736
|
+
c += batch.length;
|
|
4737
|
+
if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
|
|
4738
|
+
warn("Iterating for more than " +
|
|
4739
|
+
WARNING_WHEN_ITERATING_FOR_MORE_THAN +
|
|
4740
|
+
" results");
|
|
4741
|
+
}
|
|
4742
|
+
for (const entry of batch) {
|
|
4743
|
+
yield entry;
|
|
4744
|
+
}
|
|
4745
|
+
await waitForUpdateAndResetDeferred();
|
|
4571
4746
|
}
|
|
4572
|
-
await waitForUpdateAndResetDeferred();
|
|
4573
4747
|
}
|
|
4574
|
-
|
|
4748
|
+
finally {
|
|
4749
|
+
await close();
|
|
4750
|
+
}
|
|
4575
4751
|
},
|
|
4576
4752
|
};
|
|
4577
4753
|
}
|