@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/src/search.ts
CHANGED
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
} from "@peerbit/stream-interface";
|
|
48
48
|
import { AbortError, TimeoutError, waitFor } from "@peerbit/time";
|
|
49
49
|
import pDefer, { type DeferredPromise } from "p-defer";
|
|
50
|
-
import { concat, fromString } from "uint8arrays";
|
|
50
|
+
import { concat, equals, fromString } from "uint8arrays";
|
|
51
51
|
import { copySerialization } from "./borsh.js";
|
|
52
52
|
import { MAX_BATCH_SIZE } from "./constants.js";
|
|
53
53
|
import type { DocumentEvents, DocumentsChange } from "./events.js";
|
|
@@ -511,6 +511,7 @@ type QueryDetailedOptions<
|
|
|
511
511
|
from: PublicSignKey,
|
|
512
512
|
) => void | Promise<void>;
|
|
513
513
|
onMissingResponses?: (error: MissingResponsesError) => void | Promise<void>;
|
|
514
|
+
onRemoteTargets?: (targets: string[]) => void;
|
|
514
515
|
remote?: {
|
|
515
516
|
from?: string[]; // if specified, only query these peers
|
|
516
517
|
};
|
|
@@ -742,6 +743,7 @@ function isSubclassOf(
|
|
|
742
743
|
const DEFAULT_TIMEOUT = 1e4;
|
|
743
744
|
const DEFAULT_KEEP_REMOTE_ITERATOR_TIMEOUT = 3e5;
|
|
744
745
|
const DISCOVER_TIMEOUT_FALLBACK = 500;
|
|
746
|
+
const CLOSE_ITERATOR_REQUEST_TIMEOUT = 5e3;
|
|
745
747
|
|
|
746
748
|
const DEFAULT_INDEX_BY = "id";
|
|
747
749
|
|
|
@@ -4283,6 +4285,7 @@ export class DocumentIndex<
|
|
|
4283
4285
|
let extraPromises: Promise<void>[] | undefined = undefined;
|
|
4284
4286
|
|
|
4285
4287
|
const seenRemoteHashes = new Set<string>();
|
|
4288
|
+
const selectedRemoteHashes: string[] = [];
|
|
4286
4289
|
const groupHashes: string[][] = replicatorGroups
|
|
4287
4290
|
.filter((hash) => {
|
|
4288
4291
|
if (hash === this.node.identity.publicKey.hashcode()) {
|
|
@@ -4299,6 +4302,7 @@ export class DocumentIndex<
|
|
|
4299
4302
|
return false;
|
|
4300
4303
|
}
|
|
4301
4304
|
fetchFirstForRemote?.add(hash);
|
|
4305
|
+
selectedRemoteHashes.push(hash);
|
|
4302
4306
|
|
|
4303
4307
|
const resultAlready = this._prefetch?.accumulator.consume(
|
|
4304
4308
|
queryRequest,
|
|
@@ -4324,6 +4328,7 @@ export class DocumentIndex<
|
|
|
4324
4328
|
})
|
|
4325
4329
|
.map((x) => [x]);
|
|
4326
4330
|
|
|
4331
|
+
options?.onRemoteTargets?.(selectedRemoteHashes);
|
|
4327
4332
|
extraPromises && (await Promise.all(extraPromises));
|
|
4328
4333
|
let tearDown: (() => void) | undefined = undefined;
|
|
4329
4334
|
const search = this;
|
|
@@ -4482,23 +4487,25 @@ export class DocumentIndex<
|
|
|
4482
4487
|
|
|
4483
4488
|
const allResults: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
4484
4489
|
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
+
try {
|
|
4491
|
+
while (
|
|
4492
|
+
iterator.done() !== true &&
|
|
4493
|
+
coercedRequest.fetch > allResults.length
|
|
4494
|
+
) {
|
|
4495
|
+
// We might need to pull .next multiple time due to data message size limitations
|
|
4490
4496
|
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4497
|
+
for (const result of await iterator.next(
|
|
4498
|
+
coercedRequest.fetch - allResults.length,
|
|
4499
|
+
)) {
|
|
4500
|
+
allResults.push(result as ValueTypeFromRequest<Resolve, T, I>);
|
|
4501
|
+
}
|
|
4495
4502
|
}
|
|
4496
|
-
}
|
|
4497
|
-
|
|
4498
|
-
await iterator.close();
|
|
4499
4503
|
|
|
4500
|
-
|
|
4501
|
-
|
|
4504
|
+
// Deduplicate and return values directly
|
|
4505
|
+
return dedup(allResults, this.indexByResolver);
|
|
4506
|
+
} finally {
|
|
4507
|
+
await iterator.close();
|
|
4508
|
+
}
|
|
4502
4509
|
}
|
|
4503
4510
|
|
|
4504
4511
|
private resolveIndexed<R>(
|
|
@@ -4790,6 +4797,50 @@ export class DocumentIndex<
|
|
|
4790
4797
|
buffer: BufferedResult<types.ResultTypeFromRequest<R, T, I> | I, I>[];
|
|
4791
4798
|
}
|
|
4792
4799
|
> = new Map();
|
|
4800
|
+
const remoteIteratorPeersToClose = new Set<string>();
|
|
4801
|
+
const staleRemoteIteratorIdsToClose = new Map<string, Uint8Array[]>();
|
|
4802
|
+
const retiredRemoteIteratorPeers = new Set<string>();
|
|
4803
|
+
const pendingMissingResponseRetryPeers = new Set<string>();
|
|
4804
|
+
const missingResponseRetryAttempts = new Map<string, number>();
|
|
4805
|
+
const maxMissingResponseRetryAttempts = 2;
|
|
4806
|
+
const retireRemoteIteratorPeer = (peer: string) => {
|
|
4807
|
+
remoteIteratorPeersToClose.add(peer);
|
|
4808
|
+
retiredRemoteIteratorPeers.add(peer);
|
|
4809
|
+
const peerBuffer = peerBufferMap.get(peer);
|
|
4810
|
+
if (!peerBuffer || peerBuffer.buffer.length === 0) {
|
|
4811
|
+
peerBufferMap.delete(peer);
|
|
4812
|
+
} else {
|
|
4813
|
+
// Keep already-received values available to the caller, but do not
|
|
4814
|
+
// issue another CollectNextRequest until a fresh iteration succeeds.
|
|
4815
|
+
peerBuffer.kept = 0;
|
|
4816
|
+
}
|
|
4817
|
+
};
|
|
4818
|
+
const recordMissingResponseGroups = (missingGroups: string[][]) => {
|
|
4819
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
4820
|
+
for (const group of missingGroups) {
|
|
4821
|
+
for (const hash of group) {
|
|
4822
|
+
if (hash && hash !== selfHash) {
|
|
4823
|
+
retireRemoteIteratorPeer(hash);
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4827
|
+
if (!retryMissingResponseGroups) {
|
|
4828
|
+
continue;
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
const target = group.find((hash) => {
|
|
4832
|
+
if (!hash || hash === selfHash) return false;
|
|
4833
|
+
const attempts = missingResponseRetryAttempts.get(hash) ?? 0;
|
|
4834
|
+
return attempts < maxMissingResponseRetryAttempts;
|
|
4835
|
+
});
|
|
4836
|
+
if (!target) continue;
|
|
4837
|
+
pendingMissingResponseRetryPeers.add(target);
|
|
4838
|
+
missingResponseRetryAttempts.set(
|
|
4839
|
+
target,
|
|
4840
|
+
(missingResponseRetryAttempts.get(target) ?? 0) + 1,
|
|
4841
|
+
);
|
|
4842
|
+
}
|
|
4843
|
+
};
|
|
4793
4844
|
const visited = new Set<indexerTypes.IdPrimitive>();
|
|
4794
4845
|
let indexedPlaceholders:
|
|
4795
4846
|
| Map<
|
|
@@ -5021,6 +5072,17 @@ export class DocumentIndex<
|
|
|
5021
5072
|
n: number,
|
|
5022
5073
|
fetchOptions?: { from?: string[]; fetchedFirstForRemote?: Set<string> },
|
|
5023
5074
|
): Promise<boolean> => {
|
|
5075
|
+
const remoteRequestOptions =
|
|
5076
|
+
typeof options?.remote === "object" ? options.remote : undefined;
|
|
5077
|
+
const fetchSignals = [
|
|
5078
|
+
options?.signal,
|
|
5079
|
+
remoteRequestOptions?.signal,
|
|
5080
|
+
ensureController().signal,
|
|
5081
|
+
].filter((signal): signal is AbortSignal => signal != null);
|
|
5082
|
+
const fetchSignal =
|
|
5083
|
+
fetchSignals.length === 1
|
|
5084
|
+
? fetchSignals[0]
|
|
5085
|
+
: AbortSignal.any(fetchSignals);
|
|
5024
5086
|
await warmupPromise;
|
|
5025
5087
|
let hasMore = false;
|
|
5026
5088
|
let missingResponses = false;
|
|
@@ -5036,33 +5098,43 @@ export class DocumentIndex<
|
|
|
5036
5098
|
typeof options?.remote === "object" &&
|
|
5037
5099
|
options.remote.reach?.discover &&
|
|
5038
5100
|
discoveredTargetHashes?.length === 0;
|
|
5101
|
+
const queryRemote =
|
|
5102
|
+
options?.remote !== false && !skipRemoteDueToDiscovery;
|
|
5103
|
+
const remoteFrom =
|
|
5104
|
+
fetchOptions?.from ??
|
|
5105
|
+
initialRemoteTargets ??
|
|
5106
|
+
remoteRequestOptions?.from;
|
|
5107
|
+
if (queryRemote) {
|
|
5108
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
5109
|
+
for (const peer of remoteFrom ?? []) {
|
|
5110
|
+
if (peer !== selfHash) {
|
|
5111
|
+
remoteIteratorPeersToClose.add(peer);
|
|
5112
|
+
}
|
|
5113
|
+
}
|
|
5114
|
+
}
|
|
5039
5115
|
|
|
5040
5116
|
queryRequestCoerced.fetch = n;
|
|
5041
5117
|
await this.queryCommence(
|
|
5042
5118
|
queryRequestCoerced,
|
|
5043
5119
|
{
|
|
5044
5120
|
local: fetchOptions?.from != null ? false : options?.local,
|
|
5045
|
-
remote:
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
fetchOptions?.from ??
|
|
5053
|
-
initialRemoteTargets ??
|
|
5054
|
-
(typeof options?.remote === "object"
|
|
5055
|
-
? options.remote.from
|
|
5056
|
-
: undefined),
|
|
5057
|
-
}
|
|
5058
|
-
: false,
|
|
5121
|
+
remote: queryRemote
|
|
5122
|
+
? {
|
|
5123
|
+
...remoteRequestOptions,
|
|
5124
|
+
from: remoteFrom,
|
|
5125
|
+
signal: fetchSignal,
|
|
5126
|
+
}
|
|
5127
|
+
: false,
|
|
5059
5128
|
resolve,
|
|
5060
|
-
signal:
|
|
5129
|
+
signal: fetchSignal,
|
|
5061
5130
|
onResponse: async (response, from) => {
|
|
5062
5131
|
if (!from) {
|
|
5063
5132
|
logger.error("Missing response from");
|
|
5064
5133
|
return;
|
|
5065
5134
|
}
|
|
5135
|
+
const fromHash = from.hashcode();
|
|
5136
|
+
remoteIteratorPeersToClose.add(fromHash);
|
|
5137
|
+
retiredRemoteIteratorPeers.delete(fromHash);
|
|
5066
5138
|
if (response instanceof types.NoAccess) {
|
|
5067
5139
|
logger.error("Dont have access");
|
|
5068
5140
|
return;
|
|
@@ -5071,7 +5143,7 @@ export class DocumentIndex<
|
|
|
5071
5143
|
types.ResultTypeFromRequest<R, T, I>
|
|
5072
5144
|
>;
|
|
5073
5145
|
|
|
5074
|
-
const existingBuffer = peerBufferMap.get(
|
|
5146
|
+
const existingBuffer = peerBufferMap.get(fromHash);
|
|
5075
5147
|
const buffer: BufferedResult<
|
|
5076
5148
|
types.ResultTypeFromRequest<R, T, I> | I,
|
|
5077
5149
|
I
|
|
@@ -5079,10 +5151,12 @@ export class DocumentIndex<
|
|
|
5079
5151
|
|
|
5080
5152
|
if (results.kept === 0n && results.results.length === 0) {
|
|
5081
5153
|
if (keepRemoteAlive) {
|
|
5082
|
-
peerBufferMap.set(
|
|
5154
|
+
peerBufferMap.set(fromHash, {
|
|
5083
5155
|
buffer,
|
|
5084
5156
|
kept: 0,
|
|
5085
5157
|
});
|
|
5158
|
+
} else {
|
|
5159
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
5086
5160
|
}
|
|
5087
5161
|
return;
|
|
5088
5162
|
}
|
|
@@ -5097,6 +5171,8 @@ export class DocumentIndex<
|
|
|
5097
5171
|
|
|
5098
5172
|
if (effectiveKept > 0) {
|
|
5099
5173
|
hasMore = true;
|
|
5174
|
+
} else if (!keepRemoteAlive) {
|
|
5175
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
5100
5176
|
}
|
|
5101
5177
|
|
|
5102
5178
|
for (const result of results.results) {
|
|
@@ -5160,7 +5236,7 @@ export class DocumentIndex<
|
|
|
5160
5236
|
}
|
|
5161
5237
|
}
|
|
5162
5238
|
|
|
5163
|
-
peerBufferMap.set(
|
|
5239
|
+
peerBufferMap.set(fromHash, {
|
|
5164
5240
|
buffer,
|
|
5165
5241
|
kept: effectiveKept,
|
|
5166
5242
|
});
|
|
@@ -5172,9 +5248,6 @@ export class DocumentIndex<
|
|
|
5172
5248
|
},
|
|
5173
5249
|
onMissingResponses: (error) => {
|
|
5174
5250
|
missingResponses = true;
|
|
5175
|
-
if (!retryMissingResponseGroups) {
|
|
5176
|
-
return;
|
|
5177
|
-
}
|
|
5178
5251
|
const missingGroups = (
|
|
5179
5252
|
error as MissingResponsesError & {
|
|
5180
5253
|
missingGroups?: string[][];
|
|
@@ -5183,27 +5256,22 @@ export class DocumentIndex<
|
|
|
5183
5256
|
if (!missingGroups?.length) {
|
|
5184
5257
|
return;
|
|
5185
5258
|
}
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
const attempts = missingResponseRetryAttempts.get(hash) ?? 0;
|
|
5192
|
-
return attempts < maxMissingResponseRetryAttempts;
|
|
5193
|
-
});
|
|
5194
|
-
if (!target) continue;
|
|
5195
|
-
pendingMissingResponseRetryPeers.add(target);
|
|
5196
|
-
missingResponseRetryAttempts.set(
|
|
5197
|
-
target,
|
|
5198
|
-
(missingResponseRetryAttempts.get(target) ?? 0) + 1,
|
|
5199
|
-
);
|
|
5259
|
+
recordMissingResponseGroups(missingGroups);
|
|
5260
|
+
},
|
|
5261
|
+
onRemoteTargets: (targets) => {
|
|
5262
|
+
for (const peer of targets) {
|
|
5263
|
+
remoteIteratorPeersToClose.add(peer);
|
|
5200
5264
|
}
|
|
5201
5265
|
},
|
|
5202
5266
|
},
|
|
5203
5267
|
fetchOptions?.fetchedFirstForRemote,
|
|
5204
5268
|
);
|
|
5205
5269
|
|
|
5206
|
-
if (
|
|
5270
|
+
if (
|
|
5271
|
+
missingResponses &&
|
|
5272
|
+
retryMissingResponseGroups &&
|
|
5273
|
+
pendingMissingResponseRetryPeers.size > 0
|
|
5274
|
+
) {
|
|
5207
5275
|
hasMore = true;
|
|
5208
5276
|
unsetDone();
|
|
5209
5277
|
}
|
|
@@ -5235,6 +5303,19 @@ export class DocumentIndex<
|
|
|
5235
5303
|
if (pendingMissingResponseRetryPeers.size > 0) {
|
|
5236
5304
|
const retryTargets = [...pendingMissingResponseRetryPeers];
|
|
5237
5305
|
pendingMissingResponseRetryPeers.clear();
|
|
5306
|
+
const idTranslation =
|
|
5307
|
+
this._prefetch?.accumulator.getTranslationMap(queryRequestCoerced);
|
|
5308
|
+
for (const peer of retryTargets) {
|
|
5309
|
+
const staleRemoteIteratorId = idTranslation?.get(peer);
|
|
5310
|
+
if (staleRemoteIteratorId) {
|
|
5311
|
+
const staleIds = staleRemoteIteratorIdsToClose.get(peer) ?? [];
|
|
5312
|
+
if (!staleIds.some((id) => equals(id, staleRemoteIteratorId))) {
|
|
5313
|
+
staleIds.push(staleRemoteIteratorId);
|
|
5314
|
+
staleRemoteIteratorIdsToClose.set(peer, staleIds);
|
|
5315
|
+
}
|
|
5316
|
+
idTranslation!.delete(peer);
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5238
5319
|
return setFetchPromise(
|
|
5239
5320
|
fetchFirst(n, {
|
|
5240
5321
|
from: retryTargets,
|
|
@@ -5248,6 +5329,12 @@ export class DocumentIndex<
|
|
|
5248
5329
|
let resultsLeft = 0;
|
|
5249
5330
|
|
|
5250
5331
|
for (const [peer, buffer] of peerBufferMap) {
|
|
5332
|
+
if (retiredRemoteIteratorPeers.has(peer)) {
|
|
5333
|
+
if (buffer.buffer.length === 0) {
|
|
5334
|
+
peerBufferMap.delete(peer);
|
|
5335
|
+
}
|
|
5336
|
+
continue;
|
|
5337
|
+
}
|
|
5251
5338
|
if (buffer.buffer.length < n) {
|
|
5252
5339
|
const hasExistingRemoteResults = buffer.kept > 0;
|
|
5253
5340
|
if (!hasExistingRemoteResults && !keepRemoteAlive) {
|
|
@@ -5390,10 +5477,11 @@ export class DocumentIndex<
|
|
|
5390
5477
|
"Failed to collect sorted results from self. " + e?.message,
|
|
5391
5478
|
);
|
|
5392
5479
|
peerBufferMap.delete(peer);
|
|
5393
|
-
|
|
5480
|
+
}),
|
|
5394
5481
|
);
|
|
5395
5482
|
} else {
|
|
5396
5483
|
// Fetch remotely
|
|
5484
|
+
remoteIteratorPeersToClose.add(peer);
|
|
5397
5485
|
const idTranslation =
|
|
5398
5486
|
this._prefetch?.accumulator.getTranslationMap(
|
|
5399
5487
|
queryRequestCoerced,
|
|
@@ -5405,22 +5493,45 @@ export class DocumentIndex<
|
|
|
5405
5493
|
amount: collectRequest.amount,
|
|
5406
5494
|
});
|
|
5407
5495
|
}
|
|
5496
|
+
const remoteRequestOptions =
|
|
5497
|
+
typeof options?.remote === "object" ? options.remote : undefined;
|
|
5498
|
+
const collectSignals = [
|
|
5499
|
+
options?.signal,
|
|
5500
|
+
remoteRequestOptions?.signal,
|
|
5501
|
+
ensureController().signal,
|
|
5502
|
+
].filter((signal): signal is AbortSignal => signal != null);
|
|
5503
|
+
const collectSignal =
|
|
5504
|
+
collectSignals.length === 1
|
|
5505
|
+
? collectSignals[0]
|
|
5506
|
+
: AbortSignal.any(collectSignals);
|
|
5408
5507
|
|
|
5409
5508
|
promises.push(
|
|
5410
5509
|
this._query
|
|
5411
5510
|
.request(remoteCollectRequest, {
|
|
5412
5511
|
...options,
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
options.signal,
|
|
5416
|
-
ensureController().signal,
|
|
5417
|
-
])
|
|
5418
|
-
: ensureController().signal,
|
|
5512
|
+
...remoteRequestOptions,
|
|
5513
|
+
signal: collectSignal,
|
|
5419
5514
|
priority: getRemoteQueryPriority(options?.remote),
|
|
5420
5515
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
5421
5516
|
})
|
|
5422
|
-
.then((response) =>
|
|
5423
|
-
|
|
5517
|
+
.then((response) => {
|
|
5518
|
+
if (
|
|
5519
|
+
!response.some((result) => result.from?.hashcode() === peer)
|
|
5520
|
+
) {
|
|
5521
|
+
const missingGroups = [[peer]];
|
|
5522
|
+
if (remoteRequestOptions?.throwOnMissing) {
|
|
5523
|
+
retireRemoteIteratorPeer(peer);
|
|
5524
|
+
throw new MissingResponsesError(
|
|
5525
|
+
"Did not receive responses from all shards: " +
|
|
5526
|
+
JSON.stringify(missingGroups),
|
|
5527
|
+
missingGroups,
|
|
5528
|
+
);
|
|
5529
|
+
}
|
|
5530
|
+
recordMissingResponseGroups(missingGroups);
|
|
5531
|
+
return;
|
|
5532
|
+
}
|
|
5533
|
+
|
|
5534
|
+
return introduceEntries(
|
|
5424
5535
|
queryRequestCoerced,
|
|
5425
5536
|
response,
|
|
5426
5537
|
this.documentType,
|
|
@@ -5437,6 +5548,12 @@ export class DocumentIndex<
|
|
|
5437
5548
|
logger.error("Missing from for sorted query");
|
|
5438
5549
|
return;
|
|
5439
5550
|
}
|
|
5551
|
+
if (
|
|
5552
|
+
!keepRemoteAlive &&
|
|
5553
|
+
response.response.kept === 0n
|
|
5554
|
+
) {
|
|
5555
|
+
remoteIteratorPeersToClose.delete(peer);
|
|
5556
|
+
}
|
|
5440
5557
|
|
|
5441
5558
|
if (response.response.results.length === 0) {
|
|
5442
5559
|
if (
|
|
@@ -5557,8 +5674,8 @@ export class DocumentIndex<
|
|
|
5557
5674
|
e?.message,
|
|
5558
5675
|
);
|
|
5559
5676
|
peerBufferMap.delete(peer);
|
|
5560
|
-
})
|
|
5561
|
-
),
|
|
5677
|
+
});
|
|
5678
|
+
}),
|
|
5562
5679
|
);
|
|
5563
5680
|
}
|
|
5564
5681
|
} else {
|
|
@@ -5584,7 +5701,9 @@ export class DocumentIndex<
|
|
|
5584
5701
|
}
|
|
5585
5702
|
}
|
|
5586
5703
|
}
|
|
5587
|
-
return
|
|
5704
|
+
return (
|
|
5705
|
+
resultsLeft === 0 && pendingMissingResponseRetryPeers.size === 0
|
|
5706
|
+
); // 0 results left to fetch and 0 pending results
|
|
5588
5707
|
}),
|
|
5589
5708
|
);
|
|
5590
5709
|
};
|
|
@@ -5705,32 +5824,89 @@ export class DocumentIndex<
|
|
|
5705
5824
|
done = true;
|
|
5706
5825
|
};
|
|
5707
5826
|
|
|
5708
|
-
|
|
5827
|
+
const outerSignal = options?.signal;
|
|
5828
|
+
let outerAbortListener: (() => void) | undefined;
|
|
5829
|
+
let closeStarted = false;
|
|
5830
|
+
let closePromise: Promise<void> | undefined;
|
|
5831
|
+
const performClose = async () => {
|
|
5832
|
+
const idTranslation =
|
|
5833
|
+
this._prefetch?.accumulator.getTranslationMap(queryRequestCoerced);
|
|
5834
|
+
const remoteIteratorIds = idTranslation
|
|
5835
|
+
? new Map(idTranslation)
|
|
5836
|
+
: undefined;
|
|
5709
5837
|
cleanupAndDone();
|
|
5710
5838
|
|
|
5711
5839
|
// Keep-open iterators can still have active remote state even when
|
|
5712
5840
|
// their pending count has already drained to zero.
|
|
5713
|
-
const closeRequest = new types.CloseIteratorRequest({
|
|
5714
|
-
id: queryRequestCoerced.id,
|
|
5715
|
-
});
|
|
5716
5841
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
5717
|
-
const
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5842
|
+
const activeRemotePeers = new Set(
|
|
5843
|
+
keepRemoteAlive
|
|
5844
|
+
? [...peerBufferMap.keys()].filter((peer) => peer !== selfHash)
|
|
5845
|
+
: [...peerBufferMap.entries()]
|
|
5846
|
+
.filter(
|
|
5847
|
+
([peer, buffer]) => peer !== selfHash && buffer.kept > 0,
|
|
5848
|
+
)
|
|
5849
|
+
.map(([peer]) => peer),
|
|
5850
|
+
);
|
|
5851
|
+
for (const peer of remoteIteratorPeersToClose) {
|
|
5852
|
+
if (peer !== selfHash) {
|
|
5853
|
+
activeRemotePeers.add(peer);
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
const staleRemoteIteratorIds = new Map(
|
|
5857
|
+
[...staleRemoteIteratorIdsToClose].map(([peer, ids]) => [
|
|
5858
|
+
peer,
|
|
5859
|
+
[...ids],
|
|
5860
|
+
]),
|
|
5861
|
+
);
|
|
5862
|
+
const remotePeers = new Set([
|
|
5863
|
+
...activeRemotePeers,
|
|
5864
|
+
...staleRemoteIteratorIds.keys(),
|
|
5865
|
+
]);
|
|
5722
5866
|
peerBufferMap.clear();
|
|
5867
|
+
retiredRemoteIteratorPeers.clear();
|
|
5868
|
+
remoteIteratorPeersToClose.clear();
|
|
5869
|
+
staleRemoteIteratorIdsToClose.clear();
|
|
5870
|
+
if (remotePeers.size === 0) {
|
|
5871
|
+
return;
|
|
5872
|
+
}
|
|
5873
|
+
const remoteCloseOptions =
|
|
5874
|
+
typeof options?.remote === "object" ? options.remote : undefined;
|
|
5875
|
+
const closeSignal = AbortSignal.timeout(CLOSE_ITERATOR_REQUEST_TIMEOUT);
|
|
5723
5876
|
await Promise.allSettled(
|
|
5724
|
-
remotePeers.
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5877
|
+
[...remotePeers].flatMap((peer) => {
|
|
5878
|
+
const ids: Uint8Array[] = [];
|
|
5879
|
+
if (activeRemotePeers.has(peer)) {
|
|
5880
|
+
ids.push(remoteIteratorIds?.get(peer) ?? queryRequestCoerced.id);
|
|
5881
|
+
}
|
|
5882
|
+
for (const staleRemoteIteratorId of
|
|
5883
|
+
staleRemoteIteratorIds.get(peer) ?? []) {
|
|
5884
|
+
if (!ids.some((id) => equals(id, staleRemoteIteratorId))) {
|
|
5885
|
+
ids.push(staleRemoteIteratorId);
|
|
5886
|
+
}
|
|
5887
|
+
}
|
|
5888
|
+
return ids.map((id) => {
|
|
5889
|
+
const closeRequest = new types.CloseIteratorRequest({ id });
|
|
5890
|
+
return this._query.send(closeRequest, {
|
|
5891
|
+
...remoteCloseOptions,
|
|
5892
|
+
signal: closeSignal,
|
|
5893
|
+
priority: getRemoteQueryPriority(options?.remote),
|
|
5894
|
+
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
5895
|
+
});
|
|
5896
|
+
});
|
|
5897
|
+
}),
|
|
5731
5898
|
);
|
|
5732
5899
|
};
|
|
5733
|
-
|
|
5900
|
+
const close = () => {
|
|
5901
|
+
if (closeStarted) return closePromise!;
|
|
5902
|
+
closeStarted = true;
|
|
5903
|
+
if (outerAbortListener) {
|
|
5904
|
+
outerSignal?.removeEventListener("abort", outerAbortListener);
|
|
5905
|
+
outerAbortListener = undefined;
|
|
5906
|
+
}
|
|
5907
|
+
closePromise = performClose();
|
|
5908
|
+
return closePromise;
|
|
5909
|
+
};
|
|
5734
5910
|
|
|
5735
5911
|
let doneFn = () => {
|
|
5736
5912
|
return done;
|
|
@@ -5739,9 +5915,6 @@ export class DocumentIndex<
|
|
|
5739
5915
|
let joinListener: (() => void) | undefined;
|
|
5740
5916
|
|
|
5741
5917
|
let fetchedFirstForRemote: Set<string> | undefined = undefined;
|
|
5742
|
-
const pendingMissingResponseRetryPeers = new Set<string>();
|
|
5743
|
-
const missingResponseRetryAttempts = new Map<string, number>();
|
|
5744
|
-
const maxMissingResponseRetryAttempts = 2;
|
|
5745
5918
|
let joinFetchesInFlight = 0;
|
|
5746
5919
|
|
|
5747
5920
|
let updateDeferred: ReturnType<typeof pDefer> | undefined;
|
|
@@ -6581,6 +6754,16 @@ export class DocumentIndex<
|
|
|
6581
6754
|
}
|
|
6582
6755
|
};
|
|
6583
6756
|
|
|
6757
|
+
if (outerSignal) {
|
|
6758
|
+
outerAbortListener = () => {
|
|
6759
|
+
void close();
|
|
6760
|
+
};
|
|
6761
|
+
outerSignal.addEventListener("abort", outerAbortListener, { once: true });
|
|
6762
|
+
if (outerSignal.aborted) {
|
|
6763
|
+
void close();
|
|
6764
|
+
}
|
|
6765
|
+
}
|
|
6766
|
+
|
|
6584
6767
|
return {
|
|
6585
6768
|
close,
|
|
6586
6769
|
next,
|
|
@@ -6654,53 +6837,62 @@ export class DocumentIndex<
|
|
|
6654
6837
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
6655
6838
|
let result: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
6656
6839
|
let c = 0;
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6840
|
+
try {
|
|
6841
|
+
while (doneFn() !== true) {
|
|
6842
|
+
let batch = await next(drainBatchSize);
|
|
6843
|
+
c += batch.length;
|
|
6844
|
+
if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
|
|
6845
|
+
warn(
|
|
6846
|
+
"Iterating for more than " +
|
|
6847
|
+
WARNING_WHEN_ITERATING_FOR_MORE_THAN +
|
|
6848
|
+
" results",
|
|
6849
|
+
);
|
|
6850
|
+
}
|
|
6851
|
+
if (batch.length > 0) {
|
|
6852
|
+
result.push(...batch);
|
|
6853
|
+
continue;
|
|
6854
|
+
}
|
|
6855
|
+
await waitForUpdateAndResetDeferred();
|
|
6670
6856
|
}
|
|
6671
|
-
|
|
6857
|
+
return result;
|
|
6858
|
+
} finally {
|
|
6859
|
+
await close();
|
|
6672
6860
|
}
|
|
6673
|
-
cleanupAndDone();
|
|
6674
|
-
return result;
|
|
6675
6861
|
},
|
|
6676
6862
|
first: async () => {
|
|
6677
|
-
|
|
6678
|
-
|
|
6863
|
+
try {
|
|
6864
|
+
if (doneFn()) {
|
|
6865
|
+
return undefined;
|
|
6866
|
+
}
|
|
6867
|
+
let batch = await next(1);
|
|
6868
|
+
return batch[0];
|
|
6869
|
+
} finally {
|
|
6870
|
+
await close();
|
|
6679
6871
|
}
|
|
6680
|
-
let batch = await next(1);
|
|
6681
|
-
cleanupAndDone();
|
|
6682
|
-
return batch[0];
|
|
6683
6872
|
},
|
|
6684
6873
|
[Symbol.asyncIterator]: async function* () {
|
|
6685
6874
|
drain = true;
|
|
6686
6875
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
6687
6876
|
let c = 0;
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6877
|
+
try {
|
|
6878
|
+
while (doneFn() !== true) {
|
|
6879
|
+
const batch = await next(drainBatchSize);
|
|
6880
|
+
c += batch.length;
|
|
6881
|
+
if (c > WARNING_WHEN_ITERATING_FOR_MORE_THAN) {
|
|
6882
|
+
warn(
|
|
6883
|
+
"Iterating for more than " +
|
|
6884
|
+
WARNING_WHEN_ITERATING_FOR_MORE_THAN +
|
|
6885
|
+
" results",
|
|
6886
|
+
);
|
|
6887
|
+
}
|
|
6888
|
+
for (const entry of batch) {
|
|
6889
|
+
yield entry;
|
|
6890
|
+
}
|
|
6891
|
+
await waitForUpdateAndResetDeferred();
|
|
6700
6892
|
}
|
|
6701
|
-
|
|
6893
|
+
} finally {
|
|
6894
|
+
await close();
|
|
6702
6895
|
}
|
|
6703
|
-
cleanupAndDone();
|
|
6704
6896
|
},
|
|
6705
6897
|
};
|
|
6706
6898
|
}
|