@peerbit/document 13.1.5 → 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/resumable-iterator.d.ts +5 -0
- package/dist/src/resumable-iterator.d.ts.map +1 -1
- package/dist/src/resumable-iterator.js +58 -20
- package/dist/src/resumable-iterator.js.map +1 -1
- package/dist/src/search.d.ts +7 -7
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +454 -203
- package/dist/src/search.js.map +1 -1
- package/package.json +20 -20
- package/src/program.ts +4 -0
- package/src/resumable-iterator.ts +68 -20
- package/src/search.ts +475 -160
package/src/search.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import { CachedIndex, type QueryCacheOptions } from "@peerbit/indexer-cache";
|
|
25
25
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
26
26
|
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
27
|
-
import { BORSH_ENCODING, type Encoding, Entry } from "@peerbit/log";
|
|
27
|
+
import { BORSH_ENCODING, type Encoding, type Entry } from "@peerbit/log";
|
|
28
28
|
import { logger as loggerFn } from "@peerbit/logger";
|
|
29
29
|
import { ClosedError, Program } from "@peerbit/program";
|
|
30
30
|
import {
|
|
@@ -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
|
|
|
@@ -1179,26 +1181,56 @@ export class DocumentIndex<
|
|
|
1179
1181
|
}
|
|
1180
1182
|
}
|
|
1181
1183
|
|
|
1182
|
-
/**
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1186
|
-
|
|
1187
|
-
private async
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1184
|
+
/**
|
|
1185
|
+
* Resolve documents without bypassing the resolver/program caches. Cache and
|
|
1186
|
+
* identity-index hits are collected first; only the remaining heads cross the
|
|
1187
|
+
* log read boundary, and those reads stay aligned in one batch.
|
|
1188
|
+
*/
|
|
1189
|
+
private async resolveDocumentsWithBatchedHeads(
|
|
1190
|
+
values: Array<{
|
|
1191
|
+
id?: indexerTypes.IdPrimitive;
|
|
1192
|
+
indexed: I;
|
|
1193
|
+
head: string;
|
|
1194
|
+
}>,
|
|
1195
|
+
): Promise<{
|
|
1196
|
+
resolved: Array<{ value: T } | undefined>;
|
|
1197
|
+
heads: Array<Entry<Operation> | undefined>;
|
|
1198
|
+
}> {
|
|
1199
|
+
const resolved: Array<{ value: T } | undefined> = new Array(values.length);
|
|
1200
|
+
const heads: Array<Entry<Operation> | undefined> = new Array(values.length);
|
|
1201
|
+
const unresolvedPositions: number[] = [];
|
|
1202
|
+
|
|
1203
|
+
for (let i = 0; i < values.length; i++) {
|
|
1204
|
+
const value = values[i]!;
|
|
1205
|
+
const cached = await this.resolveDocument({
|
|
1206
|
+
...value,
|
|
1207
|
+
headEntry: null,
|
|
1208
|
+
});
|
|
1209
|
+
if (cached) {
|
|
1210
|
+
resolved[i] = cached;
|
|
1211
|
+
} else {
|
|
1212
|
+
unresolvedPositions.push(i);
|
|
1200
1213
|
}
|
|
1201
1214
|
}
|
|
1215
|
+
|
|
1216
|
+
if (unresolvedPositions.length === 0) {
|
|
1217
|
+
return { resolved, heads };
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
const unresolvedHeads = await this._log.log.getMany(
|
|
1221
|
+
unresolvedPositions.map((position) => values[position]!.head),
|
|
1222
|
+
);
|
|
1223
|
+
for (let i = 0; i < unresolvedPositions.length; i++) {
|
|
1224
|
+
const position = unresolvedPositions[i]!;
|
|
1225
|
+
const head = unresolvedHeads[i];
|
|
1226
|
+
heads[position] = head;
|
|
1227
|
+
resolved[position] = await this.resolveDocument({
|
|
1228
|
+
...values[position]!,
|
|
1229
|
+
headEntry: head ?? null,
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
return { resolved, heads };
|
|
1202
1234
|
}
|
|
1203
1235
|
|
|
1204
1236
|
private async wrapPushResults(
|
|
@@ -1206,8 +1238,41 @@ export class DocumentIndex<
|
|
|
1206
1238
|
resolve: boolean,
|
|
1207
1239
|
): Promise<types.Result[]> {
|
|
1208
1240
|
if (!matches.length) return [];
|
|
1241
|
+
const headsByMatch: Array<Entry<Operation> | undefined> = [];
|
|
1242
|
+
const resolvedByMatch: Array<{ value: T } | undefined> = [];
|
|
1243
|
+
if (!resolve) {
|
|
1244
|
+
headsByMatch.push(
|
|
1245
|
+
...(await this._log.log.getMany(
|
|
1246
|
+
matches.map((match) => match.__context.head),
|
|
1247
|
+
)),
|
|
1248
|
+
);
|
|
1249
|
+
} else {
|
|
1250
|
+
const indexedPositions: number[] = [];
|
|
1251
|
+
for (let i = 0; i < matches.length; i++) {
|
|
1252
|
+
if (!(matches[i] instanceof this.documentType)) {
|
|
1253
|
+
indexedPositions.push(i);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
const indexedBatch = indexedPositions.length
|
|
1257
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
1258
|
+
indexedPositions.map((position) => {
|
|
1259
|
+
const indexed = matches[position] as WithContext<I>;
|
|
1260
|
+
return {
|
|
1261
|
+
indexed,
|
|
1262
|
+
head: indexed.__context.head,
|
|
1263
|
+
};
|
|
1264
|
+
}),
|
|
1265
|
+
)
|
|
1266
|
+
: { resolved: [], heads: [] };
|
|
1267
|
+
for (let i = 0; i < indexedPositions.length; i++) {
|
|
1268
|
+
const position = indexedPositions[i]!;
|
|
1269
|
+
resolvedByMatch[position] = indexedBatch.resolved[i];
|
|
1270
|
+
headsByMatch[position] = indexedBatch.heads[i];
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1209
1273
|
const results: types.Result[] = [];
|
|
1210
|
-
for (
|
|
1274
|
+
for (let i = 0; i < matches.length; i++) {
|
|
1275
|
+
const match = matches[i]!;
|
|
1211
1276
|
if (resolve) {
|
|
1212
1277
|
if (match instanceof this.documentType) {
|
|
1213
1278
|
const doc = match as WithContext<T>;
|
|
@@ -1225,10 +1290,7 @@ export class DocumentIndex<
|
|
|
1225
1290
|
}
|
|
1226
1291
|
|
|
1227
1292
|
const indexed = match as WithContext<I>;
|
|
1228
|
-
const resolved =
|
|
1229
|
-
indexed,
|
|
1230
|
-
head: indexed.__context.head,
|
|
1231
|
-
});
|
|
1293
|
+
const resolved = resolvedByMatch[i];
|
|
1232
1294
|
|
|
1233
1295
|
if (resolved) {
|
|
1234
1296
|
results.push(
|
|
@@ -1242,7 +1304,7 @@ export class DocumentIndex<
|
|
|
1242
1304
|
continue;
|
|
1243
1305
|
}
|
|
1244
1306
|
|
|
1245
|
-
const head =
|
|
1307
|
+
const head = headsByMatch[i];
|
|
1246
1308
|
results.push(
|
|
1247
1309
|
new types.ResultIndexedValue({
|
|
1248
1310
|
context: indexed.__context,
|
|
@@ -1253,7 +1315,7 @@ export class DocumentIndex<
|
|
|
1253
1315
|
);
|
|
1254
1316
|
} else {
|
|
1255
1317
|
const indexed = match as WithContext<I>;
|
|
1256
|
-
const head =
|
|
1318
|
+
const head = headsByMatch[i];
|
|
1257
1319
|
results.push(
|
|
1258
1320
|
new types.ResultIndexedValue({
|
|
1259
1321
|
context: indexed.__context,
|
|
@@ -1275,17 +1337,28 @@ export class DocumentIndex<
|
|
|
1275
1337
|
return [];
|
|
1276
1338
|
}
|
|
1277
1339
|
const drained = queueEntries.splice(0);
|
|
1340
|
+
const resolvedBatch = resolve
|
|
1341
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
1342
|
+
drained.map((entry) => ({
|
|
1343
|
+
indexed: entry.value,
|
|
1344
|
+
head: entry.value.__context.head,
|
|
1345
|
+
})),
|
|
1346
|
+
)
|
|
1347
|
+
: undefined;
|
|
1348
|
+
const heads = resolvedBatch
|
|
1349
|
+
? resolvedBatch.heads
|
|
1350
|
+
: await this._log.log.getMany(
|
|
1351
|
+
drained.map((entry) => entry.value.__context.head),
|
|
1352
|
+
);
|
|
1278
1353
|
const results: types.Result[] = [];
|
|
1279
|
-
for (
|
|
1354
|
+
for (let i = 0; i < drained.length; i++) {
|
|
1355
|
+
const entry = drained[i]!;
|
|
1280
1356
|
const indexedUnwrapped = Object.assign(
|
|
1281
1357
|
Object.create(this.indexedType.prototype),
|
|
1282
1358
|
entry.value,
|
|
1283
1359
|
);
|
|
1284
1360
|
if (resolve) {
|
|
1285
|
-
const value =
|
|
1286
|
-
indexed: entry.value,
|
|
1287
|
-
head: entry.value.__context.head,
|
|
1288
|
-
});
|
|
1361
|
+
const value = resolvedBatch!.resolved[i];
|
|
1289
1362
|
if (value) {
|
|
1290
1363
|
results.push(
|
|
1291
1364
|
new types.ResultValue({
|
|
@@ -1298,7 +1371,7 @@ export class DocumentIndex<
|
|
|
1298
1371
|
continue;
|
|
1299
1372
|
}
|
|
1300
1373
|
|
|
1301
|
-
const head =
|
|
1374
|
+
const head = heads[i];
|
|
1302
1375
|
results.push(
|
|
1303
1376
|
new types.ResultIndexedValue({
|
|
1304
1377
|
context: entry.value.__context,
|
|
@@ -1308,7 +1381,7 @@ export class DocumentIndex<
|
|
|
1308
1381
|
}),
|
|
1309
1382
|
);
|
|
1310
1383
|
} else {
|
|
1311
|
-
const head =
|
|
1384
|
+
const head = heads[i];
|
|
1312
1385
|
results.push(
|
|
1313
1386
|
new types.ResultIndexedValue({
|
|
1314
1387
|
context: entry.value.__context,
|
|
@@ -1358,6 +1431,7 @@ export class DocumentIndex<
|
|
|
1358
1431
|
let pendingAdded = added;
|
|
1359
1432
|
do {
|
|
1360
1433
|
const batches: types.Result[] = [];
|
|
1434
|
+
let claimedIds: indexerTypes.IdKey[] = [];
|
|
1361
1435
|
const queued = await this.drainQueuedResults(
|
|
1362
1436
|
queue.queue,
|
|
1363
1437
|
resolveFlag,
|
|
@@ -1379,6 +1453,21 @@ export class DocumentIndex<
|
|
|
1379
1453
|
const wrapped = await this.wrapPushResults(matches, resolveFlag);
|
|
1380
1454
|
if (wrapped.length) {
|
|
1381
1455
|
batches.push(...wrapped);
|
|
1456
|
+
claimedIds = wrapped
|
|
1457
|
+
.map((result) =>
|
|
1458
|
+
result instanceof types.ResultValue && result.indexed
|
|
1459
|
+
? indexerTypes.toId(
|
|
1460
|
+
this.indexByResolver(result.indexed),
|
|
1461
|
+
)
|
|
1462
|
+
: result instanceof types.ResultIndexedValue
|
|
1463
|
+
? indexerTypes.toId(
|
|
1464
|
+
this.indexByResolver(result.value),
|
|
1465
|
+
)
|
|
1466
|
+
: undefined,
|
|
1467
|
+
)
|
|
1468
|
+
.filter(
|
|
1469
|
+
(id): id is indexerTypes.IdKey => id !== undefined,
|
|
1470
|
+
);
|
|
1382
1471
|
}
|
|
1383
1472
|
}
|
|
1384
1473
|
if (batches.length) {
|
|
@@ -1396,6 +1485,12 @@ export class DocumentIndex<
|
|
|
1396
1485
|
redundancy: 1,
|
|
1397
1486
|
}),
|
|
1398
1487
|
});
|
|
1488
|
+
if (claimedIds.length) {
|
|
1489
|
+
await this._resumableIterators.markYielded(
|
|
1490
|
+
_iteratorId,
|
|
1491
|
+
claimedIds,
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1399
1494
|
}
|
|
1400
1495
|
pendingAdded = queue.pendingAdded ?? [];
|
|
1401
1496
|
queue.pendingAdded = undefined;
|
|
@@ -3474,6 +3569,7 @@ export class DocumentIndex<
|
|
|
3474
3569
|
id?: indexerTypes.IdPrimitive;
|
|
3475
3570
|
indexed: I;
|
|
3476
3571
|
head: string;
|
|
3572
|
+
headEntry?: Entry<Operation> | null;
|
|
3477
3573
|
}): Promise<{ value: T } | undefined> {
|
|
3478
3574
|
const id =
|
|
3479
3575
|
value.id ??
|
|
@@ -3495,7 +3591,10 @@ export class DocumentIndex<
|
|
|
3495
3591
|
return { value: obj as T };
|
|
3496
3592
|
}
|
|
3497
3593
|
|
|
3498
|
-
const head =
|
|
3594
|
+
const head =
|
|
3595
|
+
value.headEntry === undefined
|
|
3596
|
+
? await this._log.log.get(value.head)
|
|
3597
|
+
: (value.headEntry ?? undefined);
|
|
3499
3598
|
if (!head) {
|
|
3500
3599
|
return undefined; // we could end up here if we recently pruned the document and other peers never persisted the entry
|
|
3501
3600
|
// TODO update changes in index before removing entries from log entry storage
|
|
@@ -3633,7 +3732,10 @@ export class DocumentIndex<
|
|
|
3633
3732
|
this._resultQueue.set(query.idString, prevQueued);
|
|
3634
3733
|
}
|
|
3635
3734
|
|
|
3636
|
-
const
|
|
3735
|
+
const candidates: Array<{
|
|
3736
|
+
result: indexerTypes.IndexedResult<WithContext<I>>;
|
|
3737
|
+
indexed: I;
|
|
3738
|
+
}> = [];
|
|
3637
3739
|
const resolveDocumentsFlag = resolvesDocuments(fromQuery);
|
|
3638
3740
|
const replicateIndexFlag = replicatesIndex(fromQuery);
|
|
3639
3741
|
for (const result of toIterate) {
|
|
@@ -3655,11 +3757,29 @@ export class DocumentIndex<
|
|
|
3655
3757
|
) {
|
|
3656
3758
|
continue;
|
|
3657
3759
|
}
|
|
3760
|
+
candidates.push({ result, indexed: indexedUnwrapped });
|
|
3761
|
+
}
|
|
3762
|
+
|
|
3763
|
+
const resolvedBatch = resolveDocumentsFlag
|
|
3764
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
3765
|
+
candidates.map(({ result }) => ({
|
|
3766
|
+
indexed: result.value,
|
|
3767
|
+
head: result.value.__context.head,
|
|
3768
|
+
})),
|
|
3769
|
+
)
|
|
3770
|
+
: undefined;
|
|
3771
|
+
const heads = resolvedBatch
|
|
3772
|
+
? resolvedBatch.heads
|
|
3773
|
+
: candidates.length > 0
|
|
3774
|
+
? await this._log.log.getMany(
|
|
3775
|
+
candidates.map(({ result }) => result.value.__context.head),
|
|
3776
|
+
)
|
|
3777
|
+
: [];
|
|
3778
|
+
const filteredResults: types.Result[] = [];
|
|
3779
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
3780
|
+
const { result, indexed: indexedUnwrapped } = candidates[i]!;
|
|
3658
3781
|
if (resolveDocumentsFlag) {
|
|
3659
|
-
const value =
|
|
3660
|
-
indexed: result.value,
|
|
3661
|
-
head: result.value.__context.head,
|
|
3662
|
-
});
|
|
3782
|
+
const value = resolvedBatch!.resolved[i];
|
|
3663
3783
|
|
|
3664
3784
|
if (!value) {
|
|
3665
3785
|
continue;
|
|
@@ -3675,7 +3795,7 @@ export class DocumentIndex<
|
|
|
3675
3795
|
);
|
|
3676
3796
|
} else {
|
|
3677
3797
|
const context = result.value.__context;
|
|
3678
|
-
const head =
|
|
3798
|
+
const head = heads[i];
|
|
3679
3799
|
if (replicateIndexFlag) {
|
|
3680
3800
|
if (!head) {
|
|
3681
3801
|
continue;
|
|
@@ -4165,6 +4285,7 @@ export class DocumentIndex<
|
|
|
4165
4285
|
let extraPromises: Promise<void>[] | undefined = undefined;
|
|
4166
4286
|
|
|
4167
4287
|
const seenRemoteHashes = new Set<string>();
|
|
4288
|
+
const selectedRemoteHashes: string[] = [];
|
|
4168
4289
|
const groupHashes: string[][] = replicatorGroups
|
|
4169
4290
|
.filter((hash) => {
|
|
4170
4291
|
if (hash === this.node.identity.publicKey.hashcode()) {
|
|
@@ -4181,6 +4302,7 @@ export class DocumentIndex<
|
|
|
4181
4302
|
return false;
|
|
4182
4303
|
}
|
|
4183
4304
|
fetchFirstForRemote?.add(hash);
|
|
4305
|
+
selectedRemoteHashes.push(hash);
|
|
4184
4306
|
|
|
4185
4307
|
const resultAlready = this._prefetch?.accumulator.consume(
|
|
4186
4308
|
queryRequest,
|
|
@@ -4206,6 +4328,7 @@ export class DocumentIndex<
|
|
|
4206
4328
|
})
|
|
4207
4329
|
.map((x) => [x]);
|
|
4208
4330
|
|
|
4331
|
+
options?.onRemoteTargets?.(selectedRemoteHashes);
|
|
4209
4332
|
extraPromises && (await Promise.all(extraPromises));
|
|
4210
4333
|
let tearDown: (() => void) | undefined = undefined;
|
|
4211
4334
|
const search = this;
|
|
@@ -4364,23 +4487,25 @@ export class DocumentIndex<
|
|
|
4364
4487
|
|
|
4365
4488
|
const allResults: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
4366
4489
|
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
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
|
|
4372
4496
|
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4497
|
+
for (const result of await iterator.next(
|
|
4498
|
+
coercedRequest.fetch - allResults.length,
|
|
4499
|
+
)) {
|
|
4500
|
+
allResults.push(result as ValueTypeFromRequest<Resolve, T, I>);
|
|
4501
|
+
}
|
|
4377
4502
|
}
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
await iterator.close();
|
|
4381
4503
|
|
|
4382
|
-
|
|
4383
|
-
|
|
4504
|
+
// Deduplicate and return values directly
|
|
4505
|
+
return dedup(allResults, this.indexByResolver);
|
|
4506
|
+
} finally {
|
|
4507
|
+
await iterator.close();
|
|
4508
|
+
}
|
|
4384
4509
|
}
|
|
4385
4510
|
|
|
4386
4511
|
private resolveIndexed<R>(
|
|
@@ -4672,6 +4797,50 @@ export class DocumentIndex<
|
|
|
4672
4797
|
buffer: BufferedResult<types.ResultTypeFromRequest<R, T, I> | I, I>[];
|
|
4673
4798
|
}
|
|
4674
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
|
+
};
|
|
4675
4844
|
const visited = new Set<indexerTypes.IdPrimitive>();
|
|
4676
4845
|
let indexedPlaceholders:
|
|
4677
4846
|
| Map<
|
|
@@ -4903,6 +5072,17 @@ export class DocumentIndex<
|
|
|
4903
5072
|
n: number,
|
|
4904
5073
|
fetchOptions?: { from?: string[]; fetchedFirstForRemote?: Set<string> },
|
|
4905
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);
|
|
4906
5086
|
await warmupPromise;
|
|
4907
5087
|
let hasMore = false;
|
|
4908
5088
|
let missingResponses = false;
|
|
@@ -4918,33 +5098,43 @@ export class DocumentIndex<
|
|
|
4918
5098
|
typeof options?.remote === "object" &&
|
|
4919
5099
|
options.remote.reach?.discover &&
|
|
4920
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
|
+
}
|
|
4921
5115
|
|
|
4922
5116
|
queryRequestCoerced.fetch = n;
|
|
4923
5117
|
await this.queryCommence(
|
|
4924
5118
|
queryRequestCoerced,
|
|
4925
5119
|
{
|
|
4926
5120
|
local: fetchOptions?.from != null ? false : options?.local,
|
|
4927
|
-
remote:
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
fetchOptions?.from ??
|
|
4935
|
-
initialRemoteTargets ??
|
|
4936
|
-
(typeof options?.remote === "object"
|
|
4937
|
-
? options.remote.from
|
|
4938
|
-
: undefined),
|
|
4939
|
-
}
|
|
4940
|
-
: false,
|
|
5121
|
+
remote: queryRemote
|
|
5122
|
+
? {
|
|
5123
|
+
...remoteRequestOptions,
|
|
5124
|
+
from: remoteFrom,
|
|
5125
|
+
signal: fetchSignal,
|
|
5126
|
+
}
|
|
5127
|
+
: false,
|
|
4941
5128
|
resolve,
|
|
4942
|
-
signal:
|
|
5129
|
+
signal: fetchSignal,
|
|
4943
5130
|
onResponse: async (response, from) => {
|
|
4944
5131
|
if (!from) {
|
|
4945
5132
|
logger.error("Missing response from");
|
|
4946
5133
|
return;
|
|
4947
5134
|
}
|
|
5135
|
+
const fromHash = from.hashcode();
|
|
5136
|
+
remoteIteratorPeersToClose.add(fromHash);
|
|
5137
|
+
retiredRemoteIteratorPeers.delete(fromHash);
|
|
4948
5138
|
if (response instanceof types.NoAccess) {
|
|
4949
5139
|
logger.error("Dont have access");
|
|
4950
5140
|
return;
|
|
@@ -4953,7 +5143,7 @@ export class DocumentIndex<
|
|
|
4953
5143
|
types.ResultTypeFromRequest<R, T, I>
|
|
4954
5144
|
>;
|
|
4955
5145
|
|
|
4956
|
-
const existingBuffer = peerBufferMap.get(
|
|
5146
|
+
const existingBuffer = peerBufferMap.get(fromHash);
|
|
4957
5147
|
const buffer: BufferedResult<
|
|
4958
5148
|
types.ResultTypeFromRequest<R, T, I> | I,
|
|
4959
5149
|
I
|
|
@@ -4961,10 +5151,12 @@ export class DocumentIndex<
|
|
|
4961
5151
|
|
|
4962
5152
|
if (results.kept === 0n && results.results.length === 0) {
|
|
4963
5153
|
if (keepRemoteAlive) {
|
|
4964
|
-
peerBufferMap.set(
|
|
5154
|
+
peerBufferMap.set(fromHash, {
|
|
4965
5155
|
buffer,
|
|
4966
5156
|
kept: 0,
|
|
4967
5157
|
});
|
|
5158
|
+
} else {
|
|
5159
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
4968
5160
|
}
|
|
4969
5161
|
return;
|
|
4970
5162
|
}
|
|
@@ -4979,6 +5171,8 @@ export class DocumentIndex<
|
|
|
4979
5171
|
|
|
4980
5172
|
if (effectiveKept > 0) {
|
|
4981
5173
|
hasMore = true;
|
|
5174
|
+
} else if (!keepRemoteAlive) {
|
|
5175
|
+
remoteIteratorPeersToClose.delete(fromHash);
|
|
4982
5176
|
}
|
|
4983
5177
|
|
|
4984
5178
|
for (const result of results.results) {
|
|
@@ -5042,7 +5236,7 @@ export class DocumentIndex<
|
|
|
5042
5236
|
}
|
|
5043
5237
|
}
|
|
5044
5238
|
|
|
5045
|
-
peerBufferMap.set(
|
|
5239
|
+
peerBufferMap.set(fromHash, {
|
|
5046
5240
|
buffer,
|
|
5047
5241
|
kept: effectiveKept,
|
|
5048
5242
|
});
|
|
@@ -5054,9 +5248,6 @@ export class DocumentIndex<
|
|
|
5054
5248
|
},
|
|
5055
5249
|
onMissingResponses: (error) => {
|
|
5056
5250
|
missingResponses = true;
|
|
5057
|
-
if (!retryMissingResponseGroups) {
|
|
5058
|
-
return;
|
|
5059
|
-
}
|
|
5060
5251
|
const missingGroups = (
|
|
5061
5252
|
error as MissingResponsesError & {
|
|
5062
5253
|
missingGroups?: string[][];
|
|
@@ -5065,27 +5256,22 @@ export class DocumentIndex<
|
|
|
5065
5256
|
if (!missingGroups?.length) {
|
|
5066
5257
|
return;
|
|
5067
5258
|
}
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
const attempts = missingResponseRetryAttempts.get(hash) ?? 0;
|
|
5074
|
-
return attempts < maxMissingResponseRetryAttempts;
|
|
5075
|
-
});
|
|
5076
|
-
if (!target) continue;
|
|
5077
|
-
pendingMissingResponseRetryPeers.add(target);
|
|
5078
|
-
missingResponseRetryAttempts.set(
|
|
5079
|
-
target,
|
|
5080
|
-
(missingResponseRetryAttempts.get(target) ?? 0) + 1,
|
|
5081
|
-
);
|
|
5259
|
+
recordMissingResponseGroups(missingGroups);
|
|
5260
|
+
},
|
|
5261
|
+
onRemoteTargets: (targets) => {
|
|
5262
|
+
for (const peer of targets) {
|
|
5263
|
+
remoteIteratorPeersToClose.add(peer);
|
|
5082
5264
|
}
|
|
5083
5265
|
},
|
|
5084
5266
|
},
|
|
5085
5267
|
fetchOptions?.fetchedFirstForRemote,
|
|
5086
5268
|
);
|
|
5087
5269
|
|
|
5088
|
-
if (
|
|
5270
|
+
if (
|
|
5271
|
+
missingResponses &&
|
|
5272
|
+
retryMissingResponseGroups &&
|
|
5273
|
+
pendingMissingResponseRetryPeers.size > 0
|
|
5274
|
+
) {
|
|
5089
5275
|
hasMore = true;
|
|
5090
5276
|
unsetDone();
|
|
5091
5277
|
}
|
|
@@ -5117,6 +5303,19 @@ export class DocumentIndex<
|
|
|
5117
5303
|
if (pendingMissingResponseRetryPeers.size > 0) {
|
|
5118
5304
|
const retryTargets = [...pendingMissingResponseRetryPeers];
|
|
5119
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
|
+
}
|
|
5120
5319
|
return setFetchPromise(
|
|
5121
5320
|
fetchFirst(n, {
|
|
5122
5321
|
from: retryTargets,
|
|
@@ -5130,6 +5329,12 @@ export class DocumentIndex<
|
|
|
5130
5329
|
let resultsLeft = 0;
|
|
5131
5330
|
|
|
5132
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
|
+
}
|
|
5133
5338
|
if (buffer.buffer.length < n) {
|
|
5134
5339
|
const hasExistingRemoteResults = buffer.kept > 0;
|
|
5135
5340
|
if (!hasExistingRemoteResults && !keepRemoteAlive) {
|
|
@@ -5272,10 +5477,11 @@ export class DocumentIndex<
|
|
|
5272
5477
|
"Failed to collect sorted results from self. " + e?.message,
|
|
5273
5478
|
);
|
|
5274
5479
|
peerBufferMap.delete(peer);
|
|
5275
|
-
|
|
5480
|
+
}),
|
|
5276
5481
|
);
|
|
5277
5482
|
} else {
|
|
5278
5483
|
// Fetch remotely
|
|
5484
|
+
remoteIteratorPeersToClose.add(peer);
|
|
5279
5485
|
const idTranslation =
|
|
5280
5486
|
this._prefetch?.accumulator.getTranslationMap(
|
|
5281
5487
|
queryRequestCoerced,
|
|
@@ -5287,22 +5493,45 @@ export class DocumentIndex<
|
|
|
5287
5493
|
amount: collectRequest.amount,
|
|
5288
5494
|
});
|
|
5289
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);
|
|
5290
5507
|
|
|
5291
5508
|
promises.push(
|
|
5292
5509
|
this._query
|
|
5293
5510
|
.request(remoteCollectRequest, {
|
|
5294
5511
|
...options,
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
options.signal,
|
|
5298
|
-
ensureController().signal,
|
|
5299
|
-
])
|
|
5300
|
-
: ensureController().signal,
|
|
5512
|
+
...remoteRequestOptions,
|
|
5513
|
+
signal: collectSignal,
|
|
5301
5514
|
priority: getRemoteQueryPriority(options?.remote),
|
|
5302
5515
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
5303
5516
|
})
|
|
5304
|
-
.then((response) =>
|
|
5305
|
-
|
|
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(
|
|
5306
5535
|
queryRequestCoerced,
|
|
5307
5536
|
response,
|
|
5308
5537
|
this.documentType,
|
|
@@ -5319,6 +5548,12 @@ export class DocumentIndex<
|
|
|
5319
5548
|
logger.error("Missing from for sorted query");
|
|
5320
5549
|
return;
|
|
5321
5550
|
}
|
|
5551
|
+
if (
|
|
5552
|
+
!keepRemoteAlive &&
|
|
5553
|
+
response.response.kept === 0n
|
|
5554
|
+
) {
|
|
5555
|
+
remoteIteratorPeersToClose.delete(peer);
|
|
5556
|
+
}
|
|
5322
5557
|
|
|
5323
5558
|
if (response.response.results.length === 0) {
|
|
5324
5559
|
if (
|
|
@@ -5439,8 +5674,8 @@ export class DocumentIndex<
|
|
|
5439
5674
|
e?.message,
|
|
5440
5675
|
);
|
|
5441
5676
|
peerBufferMap.delete(peer);
|
|
5442
|
-
})
|
|
5443
|
-
),
|
|
5677
|
+
});
|
|
5678
|
+
}),
|
|
5444
5679
|
);
|
|
5445
5680
|
}
|
|
5446
5681
|
} else {
|
|
@@ -5466,7 +5701,9 @@ export class DocumentIndex<
|
|
|
5466
5701
|
}
|
|
5467
5702
|
}
|
|
5468
5703
|
}
|
|
5469
|
-
return
|
|
5704
|
+
return (
|
|
5705
|
+
resultsLeft === 0 && pendingMissingResponseRetryPeers.size === 0
|
|
5706
|
+
); // 0 results left to fetch and 0 pending results
|
|
5470
5707
|
}),
|
|
5471
5708
|
);
|
|
5472
5709
|
};
|
|
@@ -5587,32 +5824,89 @@ export class DocumentIndex<
|
|
|
5587
5824
|
done = true;
|
|
5588
5825
|
};
|
|
5589
5826
|
|
|
5590
|
-
|
|
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;
|
|
5591
5837
|
cleanupAndDone();
|
|
5592
5838
|
|
|
5593
5839
|
// Keep-open iterators can still have active remote state even when
|
|
5594
5840
|
// their pending count has already drained to zero.
|
|
5595
|
-
const closeRequest = new types.CloseIteratorRequest({
|
|
5596
|
-
id: queryRequestCoerced.id,
|
|
5597
|
-
});
|
|
5598
5841
|
const selfHash = this.node.identity.publicKey.hashcode();
|
|
5599
|
-
const
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
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
|
+
]);
|
|
5604
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);
|
|
5605
5876
|
await Promise.allSettled(
|
|
5606
|
-
remotePeers.
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
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
|
+
}),
|
|
5613
5898
|
);
|
|
5614
5899
|
};
|
|
5615
|
-
|
|
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
|
+
};
|
|
5616
5910
|
|
|
5617
5911
|
let doneFn = () => {
|
|
5618
5912
|
return done;
|
|
@@ -5621,9 +5915,6 @@ export class DocumentIndex<
|
|
|
5621
5915
|
let joinListener: (() => void) | undefined;
|
|
5622
5916
|
|
|
5623
5917
|
let fetchedFirstForRemote: Set<string> | undefined = undefined;
|
|
5624
|
-
const pendingMissingResponseRetryPeers = new Set<string>();
|
|
5625
|
-
const missingResponseRetryAttempts = new Map<string, number>();
|
|
5626
|
-
const maxMissingResponseRetryAttempts = 2;
|
|
5627
5918
|
let joinFetchesInFlight = 0;
|
|
5628
5919
|
|
|
5629
5920
|
let updateDeferred: ReturnType<typeof pDefer> | undefined;
|
|
@@ -6144,9 +6435,10 @@ export class DocumentIndex<
|
|
|
6144
6435
|
continue;
|
|
6145
6436
|
}
|
|
6146
6437
|
}
|
|
6147
|
-
const
|
|
6438
|
+
const indexId = indexerTypes.toId(
|
|
6148
6439
|
this.indexByResolver(indexedCandidate),
|
|
6149
|
-
)
|
|
6440
|
+
);
|
|
6441
|
+
const id = indexId.primitive;
|
|
6150
6442
|
const existingIndexed = indexedPlaceholders?.get(id);
|
|
6151
6443
|
if (existingIndexed) {
|
|
6152
6444
|
if (resolve) {
|
|
@@ -6187,6 +6479,10 @@ export class DocumentIndex<
|
|
|
6187
6479
|
if (!resolve) {
|
|
6188
6480
|
ensureIndexedPlaceholders().set(id, placeholder);
|
|
6189
6481
|
}
|
|
6482
|
+
await this._resumableIterators.markYielded(
|
|
6483
|
+
queryRequestCoerced.idString,
|
|
6484
|
+
[indexId],
|
|
6485
|
+
);
|
|
6190
6486
|
hasRelevantChange = true;
|
|
6191
6487
|
}
|
|
6192
6488
|
}
|
|
@@ -6458,6 +6754,16 @@ export class DocumentIndex<
|
|
|
6458
6754
|
}
|
|
6459
6755
|
};
|
|
6460
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
|
+
|
|
6461
6767
|
return {
|
|
6462
6768
|
close,
|
|
6463
6769
|
next,
|
|
@@ -6531,53 +6837,62 @@ export class DocumentIndex<
|
|
|
6531
6837
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
6532
6838
|
let result: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
6533
6839
|
let c = 0;
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
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();
|
|
6547
6856
|
}
|
|
6548
|
-
|
|
6857
|
+
return result;
|
|
6858
|
+
} finally {
|
|
6859
|
+
await close();
|
|
6549
6860
|
}
|
|
6550
|
-
cleanupAndDone();
|
|
6551
|
-
return result;
|
|
6552
6861
|
},
|
|
6553
6862
|
first: async () => {
|
|
6554
|
-
|
|
6555
|
-
|
|
6863
|
+
try {
|
|
6864
|
+
if (doneFn()) {
|
|
6865
|
+
return undefined;
|
|
6866
|
+
}
|
|
6867
|
+
let batch = await next(1);
|
|
6868
|
+
return batch[0];
|
|
6869
|
+
} finally {
|
|
6870
|
+
await close();
|
|
6556
6871
|
}
|
|
6557
|
-
let batch = await next(1);
|
|
6558
|
-
cleanupAndDone();
|
|
6559
|
-
return batch[0];
|
|
6560
6872
|
},
|
|
6561
6873
|
[Symbol.asyncIterator]: async function* () {
|
|
6562
6874
|
drain = true;
|
|
6563
6875
|
const drainBatchSize = replicate ? 1000 : 100;
|
|
6564
6876
|
let c = 0;
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
|
|
6574
|
-
|
|
6575
|
-
|
|
6576
|
-
|
|
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();
|
|
6577
6892
|
}
|
|
6578
|
-
|
|
6893
|
+
} finally {
|
|
6894
|
+
await close();
|
|
6579
6895
|
}
|
|
6580
|
-
cleanupAndDone();
|
|
6581
6896
|
},
|
|
6582
6897
|
};
|
|
6583
6898
|
}
|