@peerbit/document 12.3.4 → 12.3.5-3f16953
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/benchmark/iterate-replicate-2.js +0 -13
- package/dist/benchmark/iterate-replicate-2.js.map +1 -1
- package/dist/benchmark/iterate-replicate.js +0 -13
- package/dist/benchmark/iterate-replicate.js.map +1 -1
- package/dist/benchmark/replication-network.d.ts +2 -0
- package/dist/benchmark/replication-network.d.ts.map +1 -0
- package/dist/benchmark/replication-network.js +872 -0
- package/dist/benchmark/replication-network.js.map +1 -0
- package/dist/benchmark/replication.js +0 -19
- package/dist/benchmark/replication.js.map +1 -1
- 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 +1 -0
- package/dist/src/resumable-iterator.d.ts.map +1 -1
- package/dist/src/resumable-iterator.js +29 -0
- package/dist/src/resumable-iterator.js.map +1 -1
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +167 -67
- package/dist/src/search.js.map +1 -1
- package/package.json +20 -20
- package/src/program.ts +1 -0
- package/src/resumable-iterator.ts +33 -0
- package/src/search.ts +271 -162
package/src/search.ts
CHANGED
|
@@ -1338,7 +1338,23 @@ export class DocumentIndex<
|
|
|
1338
1338
|
);
|
|
1339
1339
|
}
|
|
1340
1340
|
this.clearAllResultQueues();
|
|
1341
|
-
await this.
|
|
1341
|
+
await this._resumableIterators.clearAll();
|
|
1342
|
+
if (this.iteratorKeepAliveTimers) {
|
|
1343
|
+
for (const timer of this.iteratorKeepAliveTimers.values()) {
|
|
1344
|
+
clearTimeout(timer);
|
|
1345
|
+
}
|
|
1346
|
+
this.iteratorKeepAliveTimers.clear();
|
|
1347
|
+
}
|
|
1348
|
+
try {
|
|
1349
|
+
await this.index?.stop?.();
|
|
1350
|
+
} catch (error) {
|
|
1351
|
+
// Be defensive during teardown: stopping an already-stopped index shouldn't
|
|
1352
|
+
// prevent closing the program and releasing timers/iterators.
|
|
1353
|
+
if (error instanceof indexerTypes.NotStartedError) {
|
|
1354
|
+
return closed;
|
|
1355
|
+
}
|
|
1356
|
+
throw error;
|
|
1357
|
+
}
|
|
1342
1358
|
}
|
|
1343
1359
|
return closed;
|
|
1344
1360
|
}
|
|
@@ -1351,8 +1367,27 @@ export class DocumentIndex<
|
|
|
1351
1367
|
this.handleDocumentChange,
|
|
1352
1368
|
);
|
|
1353
1369
|
this.clearAllResultQueues();
|
|
1354
|
-
await this.
|
|
1355
|
-
|
|
1370
|
+
await this._resumableIterators.clearAll();
|
|
1371
|
+
if (this.iteratorKeepAliveTimers) {
|
|
1372
|
+
for (const timer of this.iteratorKeepAliveTimers.values()) {
|
|
1373
|
+
clearTimeout(timer);
|
|
1374
|
+
}
|
|
1375
|
+
this.iteratorKeepAliveTimers.clear();
|
|
1376
|
+
}
|
|
1377
|
+
try {
|
|
1378
|
+
await this.index?.drop?.();
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
if (!(error instanceof indexerTypes.NotStartedError)) {
|
|
1381
|
+
throw error;
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
try {
|
|
1385
|
+
await this.index?.stop?.();
|
|
1386
|
+
} catch (error) {
|
|
1387
|
+
if (!(error instanceof indexerTypes.NotStartedError)) {
|
|
1388
|
+
throw error;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1356
1391
|
}
|
|
1357
1392
|
return dropped;
|
|
1358
1393
|
}
|
|
@@ -1367,17 +1402,24 @@ export class DocumentIndex<
|
|
|
1367
1402
|
options?: Options,
|
|
1368
1403
|
): Promise<WithContext<I>>;
|
|
1369
1404
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1405
|
+
public async get<
|
|
1406
|
+
Options extends GetOptions<T, I, D, Resolve>,
|
|
1407
|
+
Resolve extends boolean | undefined = ExtractResolveFromOptions<Options>,
|
|
1408
|
+
>(key: indexerTypes.Ideable | indexerTypes.IdKey, options?: Options) {
|
|
1409
|
+
let deferred:
|
|
1410
|
+
| DeferredPromise<WithIndexedContext<T, I> | WithContext<I>>
|
|
1411
|
+
| undefined;
|
|
1412
|
+
let baseRemote:
|
|
1413
|
+
| RemoteQueryOptions<
|
|
1414
|
+
types.AbstractSearchRequest,
|
|
1415
|
+
types.AbstractSearchResult,
|
|
1416
|
+
D
|
|
1417
|
+
>
|
|
1418
|
+
| undefined;
|
|
1419
|
+
|
|
1420
|
+
// Normalize the id key early so listeners can use it
|
|
1421
|
+
let idKey =
|
|
1422
|
+
key instanceof indexerTypes.IdKey ? key : indexerTypes.toId(key);
|
|
1381
1423
|
|
|
1382
1424
|
if (options?.waitFor) {
|
|
1383
1425
|
// add change listener before query because we might get a concurrent change that matches the query,
|
|
@@ -1410,16 +1452,16 @@ export class DocumentIndex<
|
|
|
1410
1452
|
|
|
1411
1453
|
let timeout = setTimeout(resolveUndefined, options.waitFor);
|
|
1412
1454
|
this.events.addEventListener("close", resolveUndefined);
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1455
|
+
this.documentEvents.addEventListener("change", listener);
|
|
1456
|
+
deferred.promise.then(cleanup);
|
|
1457
|
+
|
|
1458
|
+
// Prepare remote options without mutating caller options
|
|
1459
|
+
baseRemote =
|
|
1460
|
+
options?.remote === false
|
|
1461
|
+
? undefined
|
|
1462
|
+
: typeof options?.remote === "object"
|
|
1463
|
+
? { ...options.remote }
|
|
1464
|
+
: {};
|
|
1423
1465
|
if (baseRemote) {
|
|
1424
1466
|
const waitPolicy = baseRemote.wait;
|
|
1425
1467
|
if (
|
|
@@ -1455,16 +1497,20 @@ export class DocumentIndex<
|
|
|
1455
1497
|
deferred!.resolve(first.value as any);
|
|
1456
1498
|
}
|
|
1457
1499
|
},
|
|
1458
|
-
|
|
1500
|
+
});
|
|
1501
|
+
}
|
|
1459
1502
|
}
|
|
1460
|
-
}
|
|
1461
1503
|
|
|
1462
|
-
|
|
1504
|
+
const initialOptions = baseRemote
|
|
1505
|
+
? ({ ...(options as any), remote: baseRemote } as Options)
|
|
1506
|
+
: options;
|
|
1507
|
+
const result =
|
|
1508
|
+
(await this.getDetailed(idKey, initialOptions))?.[0]?.results[0];
|
|
1463
1509
|
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1510
|
+
// if no results, and we have remote joining options, we wait for the timout and if there are joining peers we re-query
|
|
1511
|
+
if (!result) {
|
|
1512
|
+
return deferred?.promise;
|
|
1513
|
+
} else if (deferred) {
|
|
1468
1514
|
deferred.resolve(undefined);
|
|
1469
1515
|
}
|
|
1470
1516
|
return result?.value;
|
|
@@ -1855,24 +1901,26 @@ export class DocumentIndex<
|
|
|
1855
1901
|
const resolveFlag = resolvesDocuments(
|
|
1856
1902
|
(fromQuery || query) as AnyIterationRequest,
|
|
1857
1903
|
);
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1904
|
+
prevQueued = {
|
|
1905
|
+
from,
|
|
1906
|
+
queue: [],
|
|
1907
|
+
timeout: setTimeout(() => {
|
|
1908
|
+
this._resultQueue.delete(query.idString);
|
|
1909
|
+
}, 6e4),
|
|
1910
|
+
keptInIndex: kept,
|
|
1911
|
+
fromQuery: (fromQuery || query) as
|
|
1912
|
+
| types.SearchRequest
|
|
1913
|
+
| types.SearchRequestIndexed
|
|
1914
|
+
| types.IterationRequest,
|
|
1915
|
+
resolveResults: resolveFlag,
|
|
1916
|
+
};
|
|
1917
|
+
// Don't keep Node alive just to GC old remote iterator state.
|
|
1918
|
+
prevQueued.timeout.unref?.();
|
|
1919
|
+
if (
|
|
1920
|
+
fromQuery instanceof types.IterationRequest &&
|
|
1921
|
+
fromQuery.pushUpdates
|
|
1922
|
+
) {
|
|
1923
|
+
prevQueued.pushMode = fromQuery.pushUpdates;
|
|
1876
1924
|
}
|
|
1877
1925
|
this._resultQueue.set(query.idString, prevQueued);
|
|
1878
1926
|
}
|
|
@@ -1970,17 +2018,19 @@ export class DocumentIndex<
|
|
|
1970
2018
|
string,
|
|
1971
2019
|
ReturnType<typeof setTimeout>
|
|
1972
2020
|
>());
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
2021
|
+
const timer = setTimeout(() => {
|
|
2022
|
+
timers.delete(idString);
|
|
2023
|
+
const queued = this._resultQueue.get(idString);
|
|
2024
|
+
if (queued) {
|
|
2025
|
+
clearTimeout(queued.timeout);
|
|
2026
|
+
this._resultQueue.delete(idString);
|
|
2027
|
+
}
|
|
2028
|
+
this._resumableIterators.close({ idString });
|
|
2029
|
+
}, delay);
|
|
2030
|
+
// This is a best-effort cleanup timer; it should not keep Node alive.
|
|
2031
|
+
timer.unref?.();
|
|
2032
|
+
timers.set(idString, timer);
|
|
2033
|
+
}
|
|
1984
2034
|
|
|
1985
2035
|
private cancelIteratorKeepAlive(idString: string) {
|
|
1986
2036
|
const timers = this.iteratorKeepAliveTimers;
|
|
@@ -2213,24 +2263,20 @@ export class DocumentIndex<
|
|
|
2213
2263
|
queryRequest: R,
|
|
2214
2264
|
options?: QueryDetailedOptions<T, I, D, boolean | undefined>,
|
|
2215
2265
|
fetchFirstForRemote?: Set<string>,
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
remote = {};
|
|
2266
|
+
): Promise<types.Results<RT>[]> {
|
|
2267
|
+
const local = typeof options?.local === "boolean" ? options?.local : true;
|
|
2268
|
+
let remote:
|
|
2269
|
+
| RemoteQueryOptions<
|
|
2270
|
+
types.AbstractSearchRequest,
|
|
2271
|
+
types.AbstractSearchResult,
|
|
2272
|
+
D
|
|
2273
|
+
>
|
|
2274
|
+
| undefined = undefined;
|
|
2275
|
+
if (typeof options?.remote === "boolean") {
|
|
2276
|
+
remote = options.remote ? {} : undefined;
|
|
2228
2277
|
} else {
|
|
2229
|
-
remote =
|
|
2278
|
+
remote = options?.remote || {};
|
|
2230
2279
|
}
|
|
2231
|
-
} else {
|
|
2232
|
-
remote = options?.remote || {};
|
|
2233
|
-
}
|
|
2234
2280
|
if (remote && remote.priority == null) {
|
|
2235
2281
|
// give queries higher priority than other "normal" data activities
|
|
2236
2282
|
// without this, we might have a scenario that a peer joina network with large amount of data to be synced, but can not query anything before that is done
|
|
@@ -2266,19 +2312,76 @@ export class DocumentIndex<
|
|
|
2266
2312
|
throw new Error("Unexpected");
|
|
2267
2313
|
}
|
|
2268
2314
|
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2315
|
+
const coverProps = remote.domain ?? { args: undefined };
|
|
2316
|
+
const isDefaultDomainArgs =
|
|
2317
|
+
!("range" in coverProps) &&
|
|
2318
|
+
(!("args" in coverProps) || (coverProps as any).args == null);
|
|
2319
|
+
|
|
2320
|
+
let replicatorGroups = options?.remote?.from
|
|
2321
|
+
? options?.remote?.from
|
|
2322
|
+
: await this._log.getCover(coverProps, {
|
|
2323
|
+
roleAge: remote.minAge,
|
|
2324
|
+
eager: remote.reach?.eager,
|
|
2325
|
+
reachableOnly: !!remote.wait, // when we want to merge joining we can ignore pending to be online peers and instead consider them once they become online
|
|
2326
|
+
signal: options?.signal,
|
|
2327
|
+
});
|
|
2328
|
+
|
|
2329
|
+
// Cold start: cover can be temporarily empty/self-only while replication metadata
|
|
2330
|
+
// converges. For remote search, it's sometimes better to at least try currently
|
|
2331
|
+
// connected peers, but only if we have evidence that a remote replicator exists.
|
|
2332
|
+
if (!options?.remote?.from && isDefaultDomainArgs) {
|
|
2333
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
2334
|
+
const remoteCount = replicatorGroups.filter((h) => h !== selfHash).length;
|
|
2335
|
+
if (remoteCount === 0) {
|
|
2336
|
+
const waitEnabled = Boolean(remote.wait);
|
|
2337
|
+
const coverIsSelfOnly =
|
|
2338
|
+
replicatorGroups.length === 1 && replicatorGroups[0] === selfHash;
|
|
2339
|
+
|
|
2340
|
+
// If the cover is explicitly empty (no shards), don't override it unless
|
|
2341
|
+
// the caller requested waiting for joins (e.g. get(waitFor)).
|
|
2342
|
+
if (!waitEnabled && !coverIsSelfOnly) {
|
|
2343
|
+
// no-op
|
|
2344
|
+
} else {
|
|
2345
|
+
let hasKnownRemoteReplicator = false;
|
|
2346
|
+
if (!waitEnabled) {
|
|
2347
|
+
try {
|
|
2348
|
+
const replicators = await this._log.getReplicators();
|
|
2349
|
+
for (const hash of replicators.keys()) {
|
|
2350
|
+
if (hash !== selfHash) {
|
|
2351
|
+
hasKnownRemoteReplicator = true;
|
|
2352
|
+
break;
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
} catch {
|
|
2356
|
+
// Best-effort only.
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
if (waitEnabled || hasKnownRemoteReplicator) {
|
|
2361
|
+
const peerMap: Map<string, unknown> | undefined = (this.node.services
|
|
2362
|
+
.pubsub as any)?.peers;
|
|
2363
|
+
if (peerMap?.keys) {
|
|
2364
|
+
const extra: string[] = [];
|
|
2365
|
+
for (const hash of peerMap.keys()) {
|
|
2366
|
+
if (!hash || hash === selfHash) continue;
|
|
2367
|
+
extra.push(hash);
|
|
2368
|
+
if (extra.length >= 8) break;
|
|
2369
|
+
}
|
|
2370
|
+
if (extra.length > 0) {
|
|
2371
|
+
replicatorGroups = [
|
|
2372
|
+
...new Set([...replicatorGroups, ...extra]),
|
|
2373
|
+
];
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2277
2380
|
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2381
|
+
if (replicatorGroups) {
|
|
2382
|
+
const responseHandler = async (
|
|
2383
|
+
results: {
|
|
2384
|
+
response: types.AbstractSearchResult;
|
|
2282
2385
|
from?: PublicSignKey;
|
|
2283
2386
|
}[],
|
|
2284
2387
|
) => {
|
|
@@ -2464,18 +2567,17 @@ export class DocumentIndex<
|
|
|
2464
2567
|
options?: O,
|
|
2465
2568
|
): Promise<ValueTypeFromRequest<Resolve, T, I>[]> {
|
|
2466
2569
|
// Set fetch to search size, or max value (default to max u32 (4294967295))
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2570
|
+
const coercedRequest = coerceQuery(
|
|
2571
|
+
queryRequest,
|
|
2572
|
+
options,
|
|
2573
|
+
this.compatibility,
|
|
2574
|
+
);
|
|
2575
|
+
coercedRequest.fetch = coercedRequest.fetch ?? 0xffffffff;
|
|
2473
2576
|
|
|
2474
|
-
|
|
2475
|
-
|
|
2577
|
+
// Use an iterator so large results respect message size limits.
|
|
2578
|
+
const iterator = this.iterate<Resolve>(coercedRequest, options);
|
|
2476
2579
|
|
|
2477
|
-
|
|
2478
|
-
const allResults: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
2580
|
+
const allResults: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
2479
2581
|
|
|
2480
2582
|
while (
|
|
2481
2583
|
iterator.done() !== true &&
|
|
@@ -2876,37 +2978,43 @@ export class DocumentIndex<
|
|
|
2876
2978
|
|
|
2877
2979
|
if (typeof options?.remote === "object") {
|
|
2878
2980
|
let waitForTime: number | undefined = undefined;
|
|
2981
|
+
const waitPolicy =
|
|
2982
|
+
typeof options.remote.wait === "object"
|
|
2983
|
+
? options.remote.wait
|
|
2984
|
+
: undefined;
|
|
2985
|
+
const waitBehavior: WaitBehavior = waitPolicy?.behavior ?? "keep-open";
|
|
2879
2986
|
if (options.remote.wait) {
|
|
2880
|
-
let t0 = +new Date();
|
|
2881
|
-
|
|
2882
2987
|
waitForTime =
|
|
2883
2988
|
typeof options.remote.wait === "boolean"
|
|
2884
2989
|
? DEFAULT_TIMEOUT
|
|
2885
2990
|
: (options.remote.wait.timeout ?? DEFAULT_TIMEOUT);
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2991
|
+
if (waitBehavior === "keep-open") {
|
|
2992
|
+
let t0 = +new Date();
|
|
2993
|
+
let setDoneIfTimeout = false;
|
|
2994
|
+
maybeSetDone = () => {
|
|
2995
|
+
if (t0 + waitForTime! < +new Date()) {
|
|
2996
|
+
cleanup();
|
|
2997
|
+
done = true;
|
|
2998
|
+
} else {
|
|
2999
|
+
setDoneIfTimeout = true;
|
|
3000
|
+
}
|
|
3001
|
+
};
|
|
3002
|
+
unsetDone = () => {
|
|
3003
|
+
setDoneIfTimeout = false;
|
|
3004
|
+
done = false;
|
|
3005
|
+
};
|
|
3006
|
+
let timeout = setTimeout(() => {
|
|
3007
|
+
if (setDoneIfTimeout) {
|
|
3008
|
+
cleanup();
|
|
3009
|
+
done = true;
|
|
3010
|
+
}
|
|
3011
|
+
}, waitForTime);
|
|
2905
3012
|
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
3013
|
+
cleanup = () => {
|
|
3014
|
+
this.clearResultsQueue(queryRequestCoerced);
|
|
3015
|
+
clearTimeout(timeout);
|
|
3016
|
+
};
|
|
3017
|
+
}
|
|
2910
3018
|
}
|
|
2911
3019
|
|
|
2912
3020
|
if (options.remote.reach?.discover) {
|
|
@@ -2933,10 +3041,6 @@ export class DocumentIndex<
|
|
|
2933
3041
|
options.remote.reach.eager = true; // include the results from the discovered peer even if it is not mature
|
|
2934
3042
|
}
|
|
2935
3043
|
|
|
2936
|
-
const waitPolicy =
|
|
2937
|
-
typeof options.remote.wait === "object"
|
|
2938
|
-
? options.remote.wait
|
|
2939
|
-
: undefined;
|
|
2940
3044
|
if (
|
|
2941
3045
|
waitPolicy?.behavior === "block" &&
|
|
2942
3046
|
(waitPolicy.until ?? "any") === "any"
|
|
@@ -2977,14 +3081,14 @@ export class DocumentIndex<
|
|
|
2977
3081
|
queryRequestCoerced.fetch = n;
|
|
2978
3082
|
await this.queryCommence(
|
|
2979
3083
|
queryRequestCoerced,
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
3084
|
+
{
|
|
3085
|
+
local: fetchOptions?.from != null ? false : options?.local,
|
|
3086
|
+
remote:
|
|
3087
|
+
options?.remote !== false && !skipRemoteDueToDiscovery
|
|
3088
|
+
? {
|
|
3089
|
+
...(typeof options?.remote === "object"
|
|
3090
|
+
? options.remote
|
|
3091
|
+
: {}),
|
|
2988
3092
|
from: fetchOptions?.from ?? initialRemoteTargets,
|
|
2989
3093
|
}
|
|
2990
3094
|
: false,
|
|
@@ -3533,32 +3637,27 @@ export class DocumentIndex<
|
|
|
3533
3637
|
done = true;
|
|
3534
3638
|
};
|
|
3535
3639
|
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
// send close to remote
|
|
3540
|
-
const closeRequest = new types.CloseIteratorRequest({
|
|
3541
|
-
id: queryRequestCoerced.id,
|
|
3542
|
-
});
|
|
3543
|
-
const promises: Promise<any>[] = [];
|
|
3640
|
+
let close = async () => {
|
|
3641
|
+
cleanupAndDone();
|
|
3544
3642
|
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3643
|
+
// send close to remote (only peers that actually served results / had an active buffer)
|
|
3644
|
+
const closeRequest = new types.CloseIteratorRequest({
|
|
3645
|
+
id: queryRequestCoerced.id,
|
|
3646
|
+
});
|
|
3647
|
+
const selfHash = this.node.identity.publicKey.hashcode();
|
|
3648
|
+
const remotePeers = [...peerBufferMap.entries()]
|
|
3649
|
+
.filter(([peer, buffer]) => peer !== selfHash && buffer.kept > 0)
|
|
3650
|
+
.map(([peer]) => peer);
|
|
3651
|
+
peerBufferMap.clear();
|
|
3652
|
+
await Promise.allSettled(
|
|
3653
|
+
remotePeers.map((peer) =>
|
|
3553
3654
|
this._query.send(closeRequest, {
|
|
3554
3655
|
...options,
|
|
3555
3656
|
mode: new SilentDelivery({ to: [peer], redundancy: 1 }),
|
|
3556
3657
|
}),
|
|
3557
|
-
)
|
|
3558
|
-
|
|
3559
|
-
}
|
|
3560
|
-
await Promise.all(promises);
|
|
3561
|
-
};
|
|
3658
|
+
),
|
|
3659
|
+
);
|
|
3660
|
+
};
|
|
3562
3661
|
options?.signal && options.signal.addEventListener("abort", close);
|
|
3563
3662
|
|
|
3564
3663
|
let doneFn = () => {
|
|
@@ -4144,13 +4243,24 @@ export class DocumentIndex<
|
|
|
4144
4243
|
};
|
|
4145
4244
|
}
|
|
4146
4245
|
|
|
4147
|
-
|
|
4246
|
+
const remoteConfig =
|
|
4247
|
+
options && typeof options.remote === "object" ? options.remote : undefined;
|
|
4248
|
+
const remoteWaitPolicy =
|
|
4249
|
+
remoteConfig && typeof remoteConfig.wait === "object"
|
|
4250
|
+
? remoteConfig.wait
|
|
4251
|
+
: undefined;
|
|
4252
|
+
const remoteWaitBehavior: WaitBehavior =
|
|
4253
|
+
remoteWaitPolicy?.behavior ?? "keep-open";
|
|
4254
|
+
const keepRemoteWaitOpen =
|
|
4255
|
+
!!remoteConfig?.wait &&
|
|
4256
|
+
remoteWaitBehavior === "keep-open";
|
|
4257
|
+
|
|
4258
|
+
if (keepRemoteWaitOpen) {
|
|
4148
4259
|
// was used to account for missed results when a peer joins; omitted in this minimal handler
|
|
4149
4260
|
|
|
4150
4261
|
updateDeferred = pDefer<void>();
|
|
4151
4262
|
|
|
4152
|
-
const waitForTime =
|
|
4153
|
-
typeof options.remote.wait === "object" && options.remote.wait.timeout;
|
|
4263
|
+
const waitForTime = remoteWaitPolicy?.timeout;
|
|
4154
4264
|
|
|
4155
4265
|
const prevMaybeSetDone = maybeSetDone;
|
|
4156
4266
|
maybeSetDone = () => {
|
|
@@ -4167,7 +4277,7 @@ export class DocumentIndex<
|
|
|
4167
4277
|
fetchedFirstForRemote = new Set<string>();
|
|
4168
4278
|
joinListener = this.createReplicatorJoinListener({
|
|
4169
4279
|
signal: ensureController().signal,
|
|
4170
|
-
eager:
|
|
4280
|
+
eager: remoteConfig?.reach?.eager,
|
|
4171
4281
|
onPeer: async (pk) => {
|
|
4172
4282
|
if (done) return;
|
|
4173
4283
|
const hash = pk.hashcode();
|
|
@@ -4240,8 +4350,7 @@ export class DocumentIndex<
|
|
|
4240
4350
|
}
|
|
4241
4351
|
};
|
|
4242
4352
|
}
|
|
4243
|
-
const remoteWaitActive =
|
|
4244
|
-
typeof options?.remote === "object" && !!options.remote.wait;
|
|
4353
|
+
const remoteWaitActive = keepRemoteWaitOpen;
|
|
4245
4354
|
|
|
4246
4355
|
const waitForUpdateAndResetDeferred = async () => {
|
|
4247
4356
|
if (remoteWaitActive) {
|