@peerbit/document 15.0.4 → 15.0.6
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 +57 -0
- package/dist/src/program.d.ts.map +1 -1
- package/dist/src/program.js +75 -1
- package/dist/src/program.js.map +1 -1
- package/dist/src/search.d.ts +17 -0
- package/dist/src/search.d.ts.map +1 -1
- package/dist/src/search.js +56 -20
- package/dist/src/search.js.map +1 -1
- package/package.json +22 -22
- package/src/program.ts +91 -1
- package/src/search.ts +101 -78
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/document",
|
|
3
|
-
"version": "15.0.
|
|
3
|
+
"version": "15.0.6",
|
|
4
4
|
"description": "Document store implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -55,40 +55,40 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@chainsafe/libp2p-yamux": "^8.0.1",
|
|
57
57
|
"@dao-xyz/borsh": "^6.0.0",
|
|
58
|
-
"@libp2p/interface": "^3.
|
|
59
|
-
"@libp2p/tcp": "^11.0.
|
|
60
|
-
"@multiformats/multiaddr": "^13.0.
|
|
58
|
+
"@libp2p/interface": "^3.2.5",
|
|
59
|
+
"@libp2p/tcp": "^11.0.26",
|
|
60
|
+
"@multiformats/multiaddr": "^13.0.3",
|
|
61
61
|
"p-defer": "^4.0.0",
|
|
62
62
|
"uint8arrays": "^5.1.0",
|
|
63
63
|
"@peerbit/cache": "3.1.1",
|
|
64
|
-
"@peerbit/crypto": "3.1.
|
|
65
|
-
"@peerbit/document-interface": "3.2.
|
|
66
|
-
"@peerbit/indexer-
|
|
67
|
-
"@peerbit/indexer-
|
|
68
|
-
"@peerbit/indexer-simple": "1.2.
|
|
69
|
-
"@peerbit/indexer-sqlite3": "3.0.
|
|
70
|
-
"@peerbit/
|
|
71
|
-
"@peerbit/
|
|
72
|
-
"@peerbit/
|
|
73
|
-
"@peerbit/
|
|
74
|
-
"@peerbit/
|
|
75
|
-
"@peerbit/
|
|
76
|
-
"@peerbit/
|
|
77
|
-
"@peerbit/
|
|
64
|
+
"@peerbit/crypto": "3.1.6",
|
|
65
|
+
"@peerbit/document-interface": "3.2.62",
|
|
66
|
+
"@peerbit/indexer-interface": "3.0.10",
|
|
67
|
+
"@peerbit/indexer-cache": "0.2.13",
|
|
68
|
+
"@peerbit/indexer-simple": "1.2.14",
|
|
69
|
+
"@peerbit/indexer-sqlite3": "3.0.15",
|
|
70
|
+
"@peerbit/logger": "2.0.2",
|
|
71
|
+
"@peerbit/program": "6.0.51",
|
|
72
|
+
"@peerbit/pubsub": "5.4.2",
|
|
73
|
+
"@peerbit/log": "6.2.19",
|
|
74
|
+
"@peerbit/rpc": "6.1.19",
|
|
75
|
+
"@peerbit/shared-log": "16.0.6",
|
|
76
|
+
"@peerbit/stream-interface": "6.0.16",
|
|
77
|
+
"@peerbit/time": "3.0.1"
|
|
78
78
|
},
|
|
79
79
|
"optionalDependencies": {
|
|
80
80
|
"@peerbit/document-rust": "0.1.1"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@chainsafe/libp2p-noise": "^17.0.0",
|
|
84
|
-
"@libp2p/websockets": "^10.1.
|
|
84
|
+
"@libp2p/websockets": "^10.1.19",
|
|
85
85
|
"@types/pidusage": "^2.0.5",
|
|
86
86
|
"pidusage": "^4.0.1",
|
|
87
87
|
"uuid": "^11.1.1",
|
|
88
88
|
"@peerbit/log-rust": "1.1.3",
|
|
89
|
-
"@peerbit/native-backbone": "0.2.
|
|
90
|
-
"@peerbit/test-utils": "3.1.
|
|
91
|
-
"peerbit": "5.3.
|
|
89
|
+
"@peerbit/native-backbone": "0.2.6",
|
|
90
|
+
"@peerbit/test-utils": "3.1.25",
|
|
91
|
+
"peerbit": "5.3.25"
|
|
92
92
|
},
|
|
93
93
|
"repository": {
|
|
94
94
|
"type": "git",
|
package/src/program.ts
CHANGED
|
@@ -1991,6 +1991,75 @@ export class Documents<
|
|
|
1991
1991
|
>;
|
|
1992
1992
|
}
|
|
1993
1993
|
|
|
1994
|
+
/**
|
|
1995
|
+
* The change-delivery variant of `getLocalIndexedContext`, and the ONLY caller
|
|
1996
|
+
* allowed to treat a closed index as "no prior version".
|
|
1997
|
+
*
|
|
1998
|
+
* `getLocalIndexedContext` reaches the backing indexer directly, bypassing
|
|
1999
|
+
* `DocumentIndex`'s guarded wrappers. `terminalChildOrder` now tears the index
|
|
2000
|
+
* down after the log, but a change can still be delivered against a closed
|
|
2001
|
+
* index on paths that do not go through that ordering: a `DocumentIndex` closed
|
|
2002
|
+
* on its own rather than through its parent, and a log teardown that fails,
|
|
2003
|
+
* which opens the rank gate without having drained. For a change that the log
|
|
2004
|
+
* has ALREADY committed, "there is no prior version to compare against" is the
|
|
2005
|
+
* right reading, and the write leg - which already returns without persisting
|
|
2006
|
+
* once the index is closed, see `DocumentIndex.putWithContext` - drops it.
|
|
2007
|
+
*
|
|
2008
|
+
* WHY THIS IS NOT ON THE SHARED HELPER. It was, and that was wrong. The helper
|
|
2009
|
+
* has five callers and only this one is a post-commit change:
|
|
2010
|
+
*
|
|
2011
|
+
* :2689 resolveCanPerformDeleteValue - feeds the user's canPerform policy
|
|
2012
|
+
* :2794 _canAppend PUT - immutable-overwrite protection
|
|
2013
|
+
* :2863 _canAppend DELETE - delete-history validation
|
|
2014
|
+
* :3124 putCompatDocumentBackend - the user-initiated put() path
|
|
2015
|
+
*
|
|
2016
|
+
* Swallowing there is actively harmful rather than merely broad. On :3124 a
|
|
2017
|
+
* put() against a closed index returned SUCCESS with the entry committed to the
|
|
2018
|
+
* log and silently absent from the index - the exact log/index divergence this
|
|
2019
|
+
* recovery exists to avoid, manufactured on the public write path with no error
|
|
2020
|
+
* signal. On :2863 a swallowed read reads as "already deleted" and returns
|
|
2021
|
+
* `assume ok`, turning a REJECT into an ALLOW for inbound remote deletes.
|
|
2022
|
+
*
|
|
2023
|
+
* Those callers must keep throwing: outside change delivery, a closed index is
|
|
2024
|
+
* a caller error, not a state to paper over.
|
|
2025
|
+
*/
|
|
2026
|
+
private getLocalIndexedContextForChange(
|
|
2027
|
+
key: indexerTypes.IdKey,
|
|
2028
|
+
): Promise<indexerTypes.IndexedResult<IndexedContextOnly<I>> | undefined> {
|
|
2029
|
+
// Not every backing index resolves asynchronously (the native one answers
|
|
2030
|
+
// synchronously, and may throw synchronously), so guard both shapes without
|
|
2031
|
+
// forcing a promise on the fast path.
|
|
2032
|
+
type LocalIndexedContext =
|
|
2033
|
+
| indexerTypes.IndexedResult<IndexedContextOnly<I>>
|
|
2034
|
+
| undefined;
|
|
2035
|
+
try {
|
|
2036
|
+
const result = this.getLocalIndexedContext(
|
|
2037
|
+
key,
|
|
2038
|
+
) as MaybePromise<LocalIndexedContext>;
|
|
2039
|
+
return (
|
|
2040
|
+
isPromiseLike(result)
|
|
2041
|
+
? result.catch((error) => this.recoverClosedIndexContextRead(error))
|
|
2042
|
+
: result
|
|
2043
|
+
) as Promise<LocalIndexedContext>;
|
|
2044
|
+
} catch (error) {
|
|
2045
|
+
return this.recoverClosedIndexContextRead(
|
|
2046
|
+
error,
|
|
2047
|
+
) as unknown as Promise<LocalIndexedContext>;
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
/**
|
|
2052
|
+
* Deliberately narrow: only `NotStartedError`, and only once the document index
|
|
2053
|
+
* is actually closed. An indexer that breaks while the index is open still
|
|
2054
|
+
* throws. Reachable only from `getLocalIndexedContextForChange`.
|
|
2055
|
+
*/
|
|
2056
|
+
private recoverClosedIndexContextRead(error: unknown): undefined {
|
|
2057
|
+
if (error instanceof indexerTypes.NotStartedError && this._index.closed) {
|
|
2058
|
+
return undefined;
|
|
2059
|
+
}
|
|
2060
|
+
throw error;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
1994
2063
|
private getNativeEntrySignerPublicKeys(
|
|
1995
2064
|
hashes: string[],
|
|
1996
2065
|
): Array<Uint8Array | undefined> | undefined {
|
|
@@ -2442,6 +2511,27 @@ export class Documents<
|
|
|
2442
2511
|
return this.log.recover();
|
|
2443
2512
|
}
|
|
2444
2513
|
|
|
2514
|
+
/**
|
|
2515
|
+
* `Documents` owns two sub-programs: `log` (the source of changes) and
|
|
2516
|
+
* `_index` (a view derived from it, backed by an indexer). `Program` tears
|
|
2517
|
+
* children down concurrently by default, so nothing stopped
|
|
2518
|
+
* `DocumentIndex.close()` -> `indexer.stop()` from completing while a
|
|
2519
|
+
* `Log.joinRecursively()` was still in flight. That join calls `handleChanges`
|
|
2520
|
+
* with an entry it has *already* committed to the log, and `handleChanges`
|
|
2521
|
+
* reads the index (`getLocalIndexedContext`) before it writes - so the read hit
|
|
2522
|
+
* an indexer in state "closed" and threw `NotStartedError` out of a join that
|
|
2523
|
+
* had no business failing.
|
|
2524
|
+
*
|
|
2525
|
+
* Ranking the index behind the log fixes the ordering rather than the symptom:
|
|
2526
|
+
* `SharedLog.close()` drains its in-flight receives and then closes the lower
|
|
2527
|
+
* `Log`, so by the time the index is torn down no further change can be
|
|
2528
|
+
* dispatched, and every change already committed to the log has been applied to
|
|
2529
|
+
* the index. Nothing is dropped.
|
|
2530
|
+
*/
|
|
2531
|
+
protected terminalChildOrder(child: Program): number {
|
|
2532
|
+
return child === (this._index as Program) ? 1 : 0;
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2445
2535
|
private async _resolveEntry(
|
|
2446
2536
|
history: Entry<Operation> | string,
|
|
2447
2537
|
options?: {
|
|
@@ -5369,7 +5459,7 @@ export class Documents<
|
|
|
5369
5459
|
? reference.existing
|
|
5370
5460
|
: this.isNativeMode()
|
|
5371
5461
|
? this.getNativeModeIndexedContext(key) || null
|
|
5372
|
-
: (await this.
|
|
5462
|
+
: (await this.getLocalIndexedContextForChange(key)) || null;
|
|
5373
5463
|
if (!this.strictHistory && existing) {
|
|
5374
5464
|
// if immutable use oldest, else use newest
|
|
5375
5465
|
let shouldIgnoreChange = this.immutable
|
package/src/search.ts
CHANGED
|
@@ -15,12 +15,6 @@ import {
|
|
|
15
15
|
sha256Base64Sync,
|
|
16
16
|
} from "@peerbit/crypto";
|
|
17
17
|
import * as types from "@peerbit/document-interface";
|
|
18
|
-
import {
|
|
19
|
-
type SimpleDocumentFieldExtractionPlan,
|
|
20
|
-
type SimpleDocumentProjectionContext,
|
|
21
|
-
type SimpleDocumentProjectionPlan,
|
|
22
|
-
tryProjectDocumentIndexSimple,
|
|
23
|
-
} from "./native-rust.js";
|
|
24
18
|
import { CachedIndex, type QueryCacheOptions } from "@peerbit/indexer-cache";
|
|
25
19
|
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
26
20
|
import { HashmapIndex } from "@peerbit/indexer-simple";
|
|
@@ -56,6 +50,12 @@ import type { QueryPredictor } from "./most-common-query-predictor.js";
|
|
|
56
50
|
import MostCommonQueryPredictor, {
|
|
57
51
|
idAgnosticQueryKey,
|
|
58
52
|
} from "./most-common-query-predictor.js";
|
|
53
|
+
import {
|
|
54
|
+
type SimpleDocumentFieldExtractionPlan,
|
|
55
|
+
type SimpleDocumentProjectionContext,
|
|
56
|
+
type SimpleDocumentProjectionPlan,
|
|
57
|
+
tryProjectDocumentIndexSimple,
|
|
58
|
+
} from "./native-rust.js";
|
|
59
59
|
import { type Operation, isPutOperation } from "./operation.js";
|
|
60
60
|
import { Prefetch } from "./prefetch.js";
|
|
61
61
|
import type { ExtractArgs } from "./program.js";
|
|
@@ -67,13 +67,13 @@ import {
|
|
|
67
67
|
} from "./result-shape.js";
|
|
68
68
|
import { ResumableIterators } from "./resumable-iterator.js";
|
|
69
69
|
import {
|
|
70
|
+
type DocumentTransformDescriptor,
|
|
71
|
+
type DocumentTransformFacts,
|
|
72
|
+
type DocumentTransformer,
|
|
70
73
|
canPrepareDocumentTransformBeforeAppend,
|
|
71
74
|
canPrepareDocumentTransformWithAppendFacts,
|
|
72
75
|
documentTransformPreservesFieldPath,
|
|
73
76
|
getDocumentTransformDescriptor,
|
|
74
|
-
type DocumentTransformFacts,
|
|
75
|
-
type DocumentTransformDescriptor,
|
|
76
|
-
type DocumentTransformer,
|
|
77
77
|
} from "./transform.js";
|
|
78
78
|
|
|
79
79
|
const WARNING_WHEN_ITERATING_FOR_MORE_THAN = 1e5;
|
|
@@ -1221,10 +1221,9 @@ export class DocumentIndex<
|
|
|
1221
1221
|
} catch {
|
|
1222
1222
|
// A native-backed head may be hollow until read from the block store.
|
|
1223
1223
|
}
|
|
1224
|
-
return Entry.fromMultihash<Operation>(
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
).catch(() => head);
|
|
1224
|
+
return Entry.fromMultihash<Operation>(this._log.log.blocks, hash).catch(
|
|
1225
|
+
() => head,
|
|
1226
|
+
);
|
|
1228
1227
|
}
|
|
1229
1228
|
return Entry.fromMultihash<Operation>(this._log.log.blocks, hash);
|
|
1230
1229
|
}
|
|
@@ -1458,18 +1457,12 @@ export class DocumentIndex<
|
|
|
1458
1457
|
claimedIds = wrapped
|
|
1459
1458
|
.map((result) =>
|
|
1460
1459
|
result instanceof types.ResultValue && result.indexed
|
|
1461
|
-
? indexerTypes.toId(
|
|
1462
|
-
this.indexByResolver(result.indexed),
|
|
1463
|
-
)
|
|
1460
|
+
? indexerTypes.toId(this.indexByResolver(result.indexed))
|
|
1464
1461
|
: result instanceof types.ResultIndexedValue
|
|
1465
|
-
? indexerTypes.toId(
|
|
1466
|
-
this.indexByResolver(result.value),
|
|
1467
|
-
)
|
|
1462
|
+
? indexerTypes.toId(this.indexByResolver(result.value))
|
|
1468
1463
|
: undefined,
|
|
1469
1464
|
)
|
|
1470
|
-
.filter(
|
|
1471
|
-
(id): id is indexerTypes.IdKey => id !== undefined,
|
|
1472
|
-
);
|
|
1465
|
+
.filter((id): id is indexerTypes.IdKey => id !== undefined);
|
|
1473
1466
|
}
|
|
1474
1467
|
}
|
|
1475
1468
|
if (batches.length) {
|
|
@@ -1792,9 +1785,7 @@ export class DocumentIndex<
|
|
|
1792
1785
|
private canPrepareNativeBackboneDocumentIndexCommit(): boolean {
|
|
1793
1786
|
return (
|
|
1794
1787
|
(this.transformerIsIdentity && this.indexedTypeIsDocumentType) ||
|
|
1795
|
-
canPrepareDocumentTransformBeforeAppend(
|
|
1796
|
-
this.nativeTransformDescriptor,
|
|
1797
|
-
)
|
|
1788
|
+
canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)
|
|
1798
1789
|
);
|
|
1799
1790
|
}
|
|
1800
1791
|
|
|
@@ -1802,9 +1793,7 @@ export class DocumentIndex<
|
|
|
1802
1793
|
return (
|
|
1803
1794
|
this.canPrepareNativeBackboneDocumentIndexCommit() ||
|
|
1804
1795
|
!!this.nativeTransformProjectionPlan ||
|
|
1805
|
-
canPrepareDocumentTransformWithAppendFacts(
|
|
1806
|
-
this.nativeTransformDescriptor,
|
|
1807
|
-
)
|
|
1796
|
+
canPrepareDocumentTransformWithAppendFacts(this.nativeTransformDescriptor)
|
|
1808
1797
|
);
|
|
1809
1798
|
}
|
|
1810
1799
|
|
|
@@ -1865,9 +1854,7 @@ export class DocumentIndex<
|
|
|
1865
1854
|
};
|
|
1866
1855
|
}
|
|
1867
1856
|
if (
|
|
1868
|
-
!canPrepareDocumentTransformBeforeAppend(
|
|
1869
|
-
this.nativeTransformDescriptor,
|
|
1870
|
-
)
|
|
1857
|
+
!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)
|
|
1871
1858
|
) {
|
|
1872
1859
|
return;
|
|
1873
1860
|
}
|
|
@@ -1950,9 +1937,7 @@ export class DocumentIndex<
|
|
|
1950
1937
|
!canPrepareDocumentTransformWithAppendFacts(
|
|
1951
1938
|
this.nativeTransformDescriptor,
|
|
1952
1939
|
) &&
|
|
1953
|
-
!canPrepareDocumentTransformBeforeAppend(
|
|
1954
|
-
this.nativeTransformDescriptor,
|
|
1955
|
-
)
|
|
1940
|
+
!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)
|
|
1956
1941
|
) {
|
|
1957
1942
|
return;
|
|
1958
1943
|
}
|
|
@@ -1991,9 +1976,7 @@ export class DocumentIndex<
|
|
|
1991
1976
|
!canPrepareDocumentTransformWithAppendFacts(
|
|
1992
1977
|
this.nativeTransformDescriptor,
|
|
1993
1978
|
) &&
|
|
1994
|
-
!canPrepareDocumentTransformBeforeAppend(
|
|
1995
|
-
this.nativeTransformDescriptor,
|
|
1996
|
-
)
|
|
1979
|
+
!canPrepareDocumentTransformBeforeAppend(this.nativeTransformDescriptor)
|
|
1997
1980
|
) {
|
|
1998
1981
|
return;
|
|
1999
1982
|
}
|
|
@@ -2488,9 +2471,7 @@ export class DocumentIndex<
|
|
|
2488
2471
|
return indexed?.id;
|
|
2489
2472
|
}
|
|
2490
2473
|
|
|
2491
|
-
private getIndexedKeyByHead(
|
|
2492
|
-
head: string,
|
|
2493
|
-
): indexerTypes.IdKey | undefined {
|
|
2474
|
+
private getIndexedKeyByHead(head: string): indexerTypes.IdKey | undefined {
|
|
2494
2475
|
const getIdByHead = (this.index as ContextHeadIndex<I>).getIdByContextHead;
|
|
2495
2476
|
return typeof getIdByHead === "function"
|
|
2496
2477
|
? getIdByHead.call(this.index, head)
|
|
@@ -2507,9 +2488,10 @@ export class DocumentIndex<
|
|
|
2507
2488
|
return heads.map((head) => getIdByHead.call(this.index, head));
|
|
2508
2489
|
}
|
|
2509
2490
|
|
|
2510
|
-
public tryGetIdentityIndexedKeyByHead(
|
|
2511
|
-
|
|
2512
|
-
|
|
2491
|
+
public tryGetIdentityIndexedKeyByHead(head: string): {
|
|
2492
|
+
supported: boolean;
|
|
2493
|
+
key?: indexerTypes.IdKey;
|
|
2494
|
+
} {
|
|
2513
2495
|
const getIdByHead = (this.index as ContextHeadIndex<I>).getIdByContextHead;
|
|
2514
2496
|
if (typeof getIdByHead !== "function") {
|
|
2515
2497
|
return { supported: false };
|
|
@@ -2849,12 +2831,18 @@ export class DocumentIndex<
|
|
|
2849
2831
|
return false;
|
|
2850
2832
|
}
|
|
2851
2833
|
return isPromiseLike(persistResult)
|
|
2852
|
-
? persistResult.then(
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2834
|
+
? persistResult.then(
|
|
2835
|
+
() => true,
|
|
2836
|
+
(error: unknown) => {
|
|
2837
|
+
if (
|
|
2838
|
+
error instanceof indexerTypes.NotStartedError &&
|
|
2839
|
+
this.closed
|
|
2840
|
+
) {
|
|
2841
|
+
return true;
|
|
2842
|
+
}
|
|
2843
|
+
throw error;
|
|
2844
|
+
},
|
|
2845
|
+
)
|
|
2858
2846
|
: true;
|
|
2859
2847
|
} catch (error) {
|
|
2860
2848
|
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
@@ -2974,9 +2962,7 @@ export class DocumentIndex<
|
|
|
2974
2962
|
}
|
|
2975
2963
|
const batchValues: Array<{
|
|
2976
2964
|
id: indexerTypes.IdKey;
|
|
2977
|
-
encodedValueParts: NonNullable<
|
|
2978
|
-
ContextualPutOptions["encodedValueParts"]
|
|
2979
|
-
>;
|
|
2965
|
+
encodedValueParts: NonNullable<ContextualPutOptions["encodedValueParts"]>;
|
|
2980
2966
|
options?: { replace?: boolean };
|
|
2981
2967
|
}> = [];
|
|
2982
2968
|
for (const item of values) {
|
|
@@ -3341,6 +3327,29 @@ export class DocumentIndex<
|
|
|
3341
3327
|
});
|
|
3342
3328
|
}
|
|
3343
3329
|
|
|
3330
|
+
/**
|
|
3331
|
+
* The removal counterpart of `putWithContext`'s guard. Once this index is
|
|
3332
|
+
* closed there is nothing left to remove from, so a `NotStartedError` marks
|
|
3333
|
+
* the teardown window rather than a failure.
|
|
3334
|
+
*
|
|
3335
|
+
* This exists because the guard used to be one-legged: the read leg
|
|
3336
|
+
* (`Documents.getLocalIndexedContextForChange`) tolerated a closed index while
|
|
3337
|
+
* the remove leg did not, so a DELETE-carrying change still threw out of a
|
|
3338
|
+
* join in exactly the window the read guard was written for. A guard that
|
|
3339
|
+
* covers one direction of the same operation is worse than none, because it
|
|
3340
|
+
* reads as covered.
|
|
3341
|
+
*
|
|
3342
|
+
* Narrow in the same way as the read leg: only `NotStartedError`, and only
|
|
3343
|
+
* once this index is actually closed. An indexer that breaks while open still
|
|
3344
|
+
* throws.
|
|
3345
|
+
*/
|
|
3346
|
+
private recoverClosedRemoval(error: unknown): void {
|
|
3347
|
+
if (error instanceof indexerTypes.NotStartedError && this.closed) {
|
|
3348
|
+
return;
|
|
3349
|
+
}
|
|
3350
|
+
throw error;
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3344
3353
|
public async delMany(keys: indexerTypes.IdKey[]): Promise<void> {
|
|
3345
3354
|
if (keys.length === 0) {
|
|
3346
3355
|
return;
|
|
@@ -3348,17 +3357,21 @@ export class DocumentIndex<
|
|
|
3348
3357
|
for (const key of keys) {
|
|
3349
3358
|
this.deleteResolvedCacheForKey(key);
|
|
3350
3359
|
}
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
+
try {
|
|
3361
|
+
const delIdsNoReturn = (this.index as ExactDeleteIndex).delIdsNoReturn;
|
|
3362
|
+
if (delIdsNoReturn) {
|
|
3363
|
+
await delIdsNoReturn.call(this.index, keys);
|
|
3364
|
+
return;
|
|
3365
|
+
}
|
|
3366
|
+
const delIds = (this.index as ExactDeleteIndex).delIds;
|
|
3367
|
+
if (delIds) {
|
|
3368
|
+
await delIds.call(this.index, keys);
|
|
3369
|
+
return;
|
|
3370
|
+
}
|
|
3371
|
+
await Promise.all(keys.map((key) => this.del(key)));
|
|
3372
|
+
} catch (error) {
|
|
3373
|
+
this.recoverClosedRemoval(error);
|
|
3360
3374
|
}
|
|
3361
|
-
await Promise.all(keys.map((key) => this.del(key)));
|
|
3362
3375
|
}
|
|
3363
3376
|
|
|
3364
3377
|
public clearResolvedCacheForKeys(keys: indexerTypes.IdKey[]): void {
|
|
@@ -3374,17 +3387,28 @@ export class DocumentIndex<
|
|
|
3374
3387
|
for (const key of keys) {
|
|
3375
3388
|
this.deleteResolvedCacheForKey(key);
|
|
3376
3389
|
}
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3390
|
+
// The native index answers synchronously and may throw synchronously, so
|
|
3391
|
+
// both shapes need the guard - see recoverClosedRemoval.
|
|
3392
|
+
const guard = (result: MaybePromise<unknown>): MaybePromise<void> =>
|
|
3393
|
+
isPromiseLike(result)
|
|
3394
|
+
? result.then(
|
|
3395
|
+
() => undefined,
|
|
3396
|
+
(error: unknown) => this.recoverClosedRemoval(error),
|
|
3397
|
+
)
|
|
3398
|
+
: undefined;
|
|
3399
|
+
try {
|
|
3400
|
+
const delIdsNoReturn = (this.index as ExactDeleteIndex).delIdsNoReturn;
|
|
3401
|
+
if (delIdsNoReturn) {
|
|
3402
|
+
return guard(delIdsNoReturn.call(this.index, keys));
|
|
3403
|
+
}
|
|
3404
|
+
const delIds = (this.index as ExactDeleteIndex).delIds;
|
|
3405
|
+
if (delIds) {
|
|
3406
|
+
return guard(delIds.call(this.index, keys));
|
|
3407
|
+
}
|
|
3408
|
+
return guard(Promise.all(keys.map((key) => this.del(key))));
|
|
3409
|
+
} catch (error) {
|
|
3410
|
+
return this.recoverClosedRemoval(error);
|
|
3386
3411
|
}
|
|
3387
|
-
return Promise.all(keys.map((key) => this.del(key))).then(() => undefined);
|
|
3388
3412
|
}
|
|
3389
3413
|
|
|
3390
3414
|
public async getDetailed<
|
|
@@ -5457,7 +5481,7 @@ export class DocumentIndex<
|
|
|
5457
5481
|
"Failed to collect sorted results from self. " + e?.message,
|
|
5458
5482
|
);
|
|
5459
5483
|
peerBufferMap.delete(peer);
|
|
5460
|
-
|
|
5484
|
+
}),
|
|
5461
5485
|
);
|
|
5462
5486
|
} else {
|
|
5463
5487
|
// Fetch remotely
|
|
@@ -5823,9 +5847,7 @@ export class DocumentIndex<
|
|
|
5823
5847
|
keepRemoteAlive
|
|
5824
5848
|
? [...peerBufferMap.keys()].filter((peer) => peer !== selfHash)
|
|
5825
5849
|
: [...peerBufferMap.entries()]
|
|
5826
|
-
.filter(
|
|
5827
|
-
([peer, buffer]) => peer !== selfHash && buffer.kept > 0,
|
|
5828
|
-
)
|
|
5850
|
+
.filter(([peer, buffer]) => peer !== selfHash && buffer.kept > 0)
|
|
5829
5851
|
.map(([peer]) => peer),
|
|
5830
5852
|
);
|
|
5831
5853
|
for (const peer of remoteIteratorPeersToClose) {
|
|
@@ -5859,8 +5881,9 @@ export class DocumentIndex<
|
|
|
5859
5881
|
if (activeRemotePeers.has(peer)) {
|
|
5860
5882
|
ids.push(remoteIteratorIds?.get(peer) ?? queryRequestCoerced.id);
|
|
5861
5883
|
}
|
|
5862
|
-
for (const staleRemoteIteratorId of
|
|
5863
|
-
|
|
5884
|
+
for (const staleRemoteIteratorId of staleRemoteIteratorIds.get(
|
|
5885
|
+
peer,
|
|
5886
|
+
) ?? []) {
|
|
5864
5887
|
if (!ids.some((id) => equals(id, staleRemoteIteratorId))) {
|
|
5865
5888
|
ids.push(staleRemoteIteratorId);
|
|
5866
5889
|
}
|