@peerbit/document 13.1.5 → 13.1.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/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 +116 -41
- package/dist/src/search.js.map +1 -1
- package/package.json +13 -13
- package/src/resumable-iterator.ts +68 -20
- package/src/search.ts +165 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peerbit/document",
|
|
3
|
-
"version": "13.1.
|
|
3
|
+
"version": "13.1.6",
|
|
4
4
|
"description": "Document store implementation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -59,19 +59,19 @@
|
|
|
59
59
|
"@multiformats/multiaddr": "^13.0.1",
|
|
60
60
|
"p-defer": "^4.0.0",
|
|
61
61
|
"uint8arrays": "^5.1.0",
|
|
62
|
-
"@peerbit/indexer-cache": "0.2.8",
|
|
63
|
-
"@peerbit/indexer-interface": "3.0.5",
|
|
64
62
|
"@peerbit/cache": "3.1.0",
|
|
65
|
-
"@peerbit/document-interface": "3.2.47",
|
|
66
|
-
"@peerbit/indexer-simple": "1.2.9",
|
|
67
63
|
"@peerbit/crypto": "3.1.2",
|
|
68
|
-
"@peerbit/
|
|
64
|
+
"@peerbit/document-interface": "3.2.48",
|
|
65
|
+
"@peerbit/indexer-interface": "3.0.6",
|
|
66
|
+
"@peerbit/indexer-cache": "0.2.9",
|
|
67
|
+
"@peerbit/indexer-simple": "1.2.10",
|
|
68
|
+
"@peerbit/log": "6.2.5",
|
|
69
|
+
"@peerbit/indexer-sqlite3": "3.0.9",
|
|
69
70
|
"@peerbit/logger": "2.0.1",
|
|
70
|
-
"@peerbit/indexer-sqlite3": "3.0.8",
|
|
71
71
|
"@peerbit/pubsub": "5.3.0",
|
|
72
|
-
"@peerbit/
|
|
73
|
-
"@peerbit/
|
|
74
|
-
"@peerbit/shared-log": "13.2.
|
|
72
|
+
"@peerbit/rpc": "6.1.3",
|
|
73
|
+
"@peerbit/program": "6.0.35",
|
|
74
|
+
"@peerbit/shared-log": "13.2.6",
|
|
75
75
|
"@peerbit/stream-interface": "6.0.11"
|
|
76
76
|
},
|
|
77
77
|
"optionalDependencies": {
|
|
@@ -85,9 +85,9 @@
|
|
|
85
85
|
"uuid": "^10.0.0",
|
|
86
86
|
"@peerbit/log-rust": "1.1.2",
|
|
87
87
|
"@peerbit/native-backbone": "0.1.4",
|
|
88
|
+
"@peerbit/test-utils": "3.1.6",
|
|
88
89
|
"@peerbit/time": "3.0.0",
|
|
89
|
-
"
|
|
90
|
-
"peerbit": "5.3.5"
|
|
90
|
+
"peerbit": "5.3.6"
|
|
91
91
|
},
|
|
92
92
|
"repository": {
|
|
93
93
|
"type": "git",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"clean": "aegir clean",
|
|
103
103
|
"build": "aegir build --no-bundle",
|
|
104
104
|
"test": "aegir test --target node",
|
|
105
|
-
"test:document-rust-core": "npm run build && PEERBIT_SHARED_LOG_RUST_CORE=1 aegir test -t node --grep '^(?!.*(uses the validated local append path|uses the independent native prepared batch path|uses native shared-log planning for replicated target-none puts|uses commit-only local puts when coordinate persistence is deferred
|
|
105
|
+
"test:document-rust-core": "npm run build && PEERBIT_SHARED_LOG_RUST_CORE=1 aegir test -t node --grep '^(?!.*(uses the validated local append path|uses the independent native prepared batch path|uses native shared-log planning for replicated target-none puts|uses commit-only local puts when coordinate persistence is deferred)).*(native conformance guard |operations basic |operations get |operations index |operations search |iterate sort |count approximate |query distribution |returnIndexed |caching |custom index |prefetch )' -- --forbid-pending",
|
|
106
106
|
"lint": "aegir lint",
|
|
107
107
|
"test:cov": "aegir test -t node --cov"
|
|
108
108
|
}
|
|
@@ -11,6 +11,11 @@ import { logger as loggerFn } from "@peerbit/logger";
|
|
|
11
11
|
const iteratorLogger = loggerFn("peerbit:document:index:iterate");
|
|
12
12
|
|
|
13
13
|
export class ResumableIterators<T extends Record<string, any>> {
|
|
14
|
+
private readonly pendingMarks = new Map<
|
|
15
|
+
string,
|
|
16
|
+
Map<string, indexerTypes.IdKey>
|
|
17
|
+
>();
|
|
18
|
+
|
|
14
19
|
constructor(
|
|
15
20
|
readonly index: indexerTypes.Index<T>,
|
|
16
21
|
readonly queues = new Cache<{
|
|
@@ -22,6 +27,36 @@ export class ResumableIterators<T extends Record<string, any>> {
|
|
|
22
27
|
// TODO choose upper limit better
|
|
23
28
|
}
|
|
24
29
|
|
|
30
|
+
private markKey(id: indexerTypes.IdKey) {
|
|
31
|
+
return `${id.key instanceof Uint8Array ? "bytes" : typeof id.key}:${String(id.primitive)}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private retainMarks(id: string, ids: Iterable<indexerTypes.IdKey>) {
|
|
35
|
+
let retained = this.pendingMarks.get(id);
|
|
36
|
+
for (const mark of ids) {
|
|
37
|
+
if (!retained) {
|
|
38
|
+
retained = new Map();
|
|
39
|
+
this.pendingMarks.set(id, retained);
|
|
40
|
+
}
|
|
41
|
+
retained.set(this.markKey(mark), mark);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async applyPendingMarks(
|
|
46
|
+
id: string,
|
|
47
|
+
iterator: indexerTypes.IndexIterator<T, undefined>,
|
|
48
|
+
) {
|
|
49
|
+
while (true) {
|
|
50
|
+
const retained = this.pendingMarks.get(id);
|
|
51
|
+
if (!retained?.size) {
|
|
52
|
+
this.pendingMarks.delete(id);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.pendingMarks.delete(id);
|
|
56
|
+
await iterator.markYielded?.(retained.values());
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
25
60
|
async iterateAndFetch(
|
|
26
61
|
request: SearchRequest | SearchRequestIndexed | IterationRequest,
|
|
27
62
|
options?: { keepAlive?: boolean },
|
|
@@ -31,29 +66,32 @@ export class ResumableIterators<T extends Record<string, any>> {
|
|
|
31
66
|
fetch: request.fetch,
|
|
32
67
|
keepAlive: Boolean(options?.keepAlive),
|
|
33
68
|
});
|
|
34
|
-
const iterator = this.index.iterate(request);
|
|
35
|
-
const firstResult = await iterator.next(request.fetch);
|
|
36
69
|
const keepAlive = options?.keepAlive === true;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
70
|
+
const iterator = this.index.iterate(request);
|
|
71
|
+
this.queues.add(request.idString, { iterator, request, keepAlive });
|
|
72
|
+
try {
|
|
73
|
+
await this.applyPendingMarks(request.idString, iterator);
|
|
74
|
+
const firstResult = await iterator.next(request.fetch);
|
|
75
|
+
if (!keepAlive && iterator.done() === true) {
|
|
76
|
+
this.queues.del(request.idString);
|
|
77
|
+
this.pendingMarks.delete(request.idString);
|
|
78
|
+
}
|
|
79
|
+
iteratorLogger("iterate:queued", {
|
|
80
|
+
id: request.idString,
|
|
41
81
|
keepAlive,
|
|
42
|
-
|
|
43
|
-
|
|
82
|
+
done: iterator.done() === true,
|
|
83
|
+
batch: firstResult.length,
|
|
84
|
+
});
|
|
85
|
+
/* console.debug(
|
|
86
|
+
"[ResumableIterators] iterateAndFetch",
|
|
87
|
+
request.idString,
|
|
88
|
+
{ keepAlive },
|
|
89
|
+
); */
|
|
90
|
+
return firstResult;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
this.clear(request.idString);
|
|
93
|
+
throw error;
|
|
44
94
|
}
|
|
45
|
-
iteratorLogger("iterate:queued", {
|
|
46
|
-
id: request.idString,
|
|
47
|
-
keepAlive,
|
|
48
|
-
done: iterator.done() === true,
|
|
49
|
-
batch: firstResult.length,
|
|
50
|
-
});
|
|
51
|
-
/* console.debug(
|
|
52
|
-
"[ResumableIterators] iterateAndFetch",
|
|
53
|
-
request.idString,
|
|
54
|
-
{ keepAlive },
|
|
55
|
-
); */
|
|
56
|
-
return firstResult;
|
|
57
95
|
}
|
|
58
96
|
|
|
59
97
|
async next(
|
|
@@ -138,6 +176,7 @@ export class ResumableIterators<T extends Record<string, any>> {
|
|
|
138
176
|
}
|
|
139
177
|
}
|
|
140
178
|
this.queues.del(id);
|
|
179
|
+
this.pendingMarks.delete(id);
|
|
141
180
|
}
|
|
142
181
|
|
|
143
182
|
async clearAll() {
|
|
@@ -155,6 +194,7 @@ export class ResumableIterators<T extends Record<string, any>> {
|
|
|
155
194
|
),
|
|
156
195
|
);
|
|
157
196
|
this.queues.clear();
|
|
197
|
+
this.pendingMarks.clear();
|
|
158
198
|
}
|
|
159
199
|
|
|
160
200
|
has(id: string) {
|
|
@@ -179,4 +219,12 @@ export class ResumableIterators<T extends Record<string, any>> {
|
|
|
179
219
|
});
|
|
180
220
|
return pending;
|
|
181
221
|
}
|
|
222
|
+
|
|
223
|
+
async markYielded(id: string, ids: Iterable<indexerTypes.IdKey>) {
|
|
224
|
+
this.retainMarks(id, ids);
|
|
225
|
+
const iterator = this.queues.get(id);
|
|
226
|
+
if (iterator) {
|
|
227
|
+
await this.applyPendingMarks(id, iterator.iterator);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
182
230
|
}
|
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 {
|
|
@@ -1179,26 +1179,56 @@ export class DocumentIndex<
|
|
|
1179
1179
|
}
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
|
-
/**
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1186
|
-
|
|
1187
|
-
private async
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1182
|
+
/**
|
|
1183
|
+
* Resolve documents without bypassing the resolver/program caches. Cache and
|
|
1184
|
+
* identity-index hits are collected first; only the remaining heads cross the
|
|
1185
|
+
* log read boundary, and those reads stay aligned in one batch.
|
|
1186
|
+
*/
|
|
1187
|
+
private async resolveDocumentsWithBatchedHeads(
|
|
1188
|
+
values: Array<{
|
|
1189
|
+
id?: indexerTypes.IdPrimitive;
|
|
1190
|
+
indexed: I;
|
|
1191
|
+
head: string;
|
|
1192
|
+
}>,
|
|
1193
|
+
): Promise<{
|
|
1194
|
+
resolved: Array<{ value: T } | undefined>;
|
|
1195
|
+
heads: Array<Entry<Operation> | undefined>;
|
|
1196
|
+
}> {
|
|
1197
|
+
const resolved: Array<{ value: T } | undefined> = new Array(values.length);
|
|
1198
|
+
const heads: Array<Entry<Operation> | undefined> = new Array(values.length);
|
|
1199
|
+
const unresolvedPositions: number[] = [];
|
|
1200
|
+
|
|
1201
|
+
for (let i = 0; i < values.length; i++) {
|
|
1202
|
+
const value = values[i]!;
|
|
1203
|
+
const cached = await this.resolveDocument({
|
|
1204
|
+
...value,
|
|
1205
|
+
headEntry: null,
|
|
1206
|
+
});
|
|
1207
|
+
if (cached) {
|
|
1208
|
+
resolved[i] = cached;
|
|
1209
|
+
} else {
|
|
1210
|
+
unresolvedPositions.push(i);
|
|
1200
1211
|
}
|
|
1201
1212
|
}
|
|
1213
|
+
|
|
1214
|
+
if (unresolvedPositions.length === 0) {
|
|
1215
|
+
return { resolved, heads };
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
const unresolvedHeads = await this._log.log.getMany(
|
|
1219
|
+
unresolvedPositions.map((position) => values[position]!.head),
|
|
1220
|
+
);
|
|
1221
|
+
for (let i = 0; i < unresolvedPositions.length; i++) {
|
|
1222
|
+
const position = unresolvedPositions[i]!;
|
|
1223
|
+
const head = unresolvedHeads[i];
|
|
1224
|
+
heads[position] = head;
|
|
1225
|
+
resolved[position] = await this.resolveDocument({
|
|
1226
|
+
...values[position]!,
|
|
1227
|
+
headEntry: head ?? null,
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
return { resolved, heads };
|
|
1202
1232
|
}
|
|
1203
1233
|
|
|
1204
1234
|
private async wrapPushResults(
|
|
@@ -1206,8 +1236,41 @@ export class DocumentIndex<
|
|
|
1206
1236
|
resolve: boolean,
|
|
1207
1237
|
): Promise<types.Result[]> {
|
|
1208
1238
|
if (!matches.length) return [];
|
|
1239
|
+
const headsByMatch: Array<Entry<Operation> | undefined> = [];
|
|
1240
|
+
const resolvedByMatch: Array<{ value: T } | undefined> = [];
|
|
1241
|
+
if (!resolve) {
|
|
1242
|
+
headsByMatch.push(
|
|
1243
|
+
...(await this._log.log.getMany(
|
|
1244
|
+
matches.map((match) => match.__context.head),
|
|
1245
|
+
)),
|
|
1246
|
+
);
|
|
1247
|
+
} else {
|
|
1248
|
+
const indexedPositions: number[] = [];
|
|
1249
|
+
for (let i = 0; i < matches.length; i++) {
|
|
1250
|
+
if (!(matches[i] instanceof this.documentType)) {
|
|
1251
|
+
indexedPositions.push(i);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
const indexedBatch = indexedPositions.length
|
|
1255
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
1256
|
+
indexedPositions.map((position) => {
|
|
1257
|
+
const indexed = matches[position] as WithContext<I>;
|
|
1258
|
+
return {
|
|
1259
|
+
indexed,
|
|
1260
|
+
head: indexed.__context.head,
|
|
1261
|
+
};
|
|
1262
|
+
}),
|
|
1263
|
+
)
|
|
1264
|
+
: { resolved: [], heads: [] };
|
|
1265
|
+
for (let i = 0; i < indexedPositions.length; i++) {
|
|
1266
|
+
const position = indexedPositions[i]!;
|
|
1267
|
+
resolvedByMatch[position] = indexedBatch.resolved[i];
|
|
1268
|
+
headsByMatch[position] = indexedBatch.heads[i];
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1209
1271
|
const results: types.Result[] = [];
|
|
1210
|
-
for (
|
|
1272
|
+
for (let i = 0; i < matches.length; i++) {
|
|
1273
|
+
const match = matches[i]!;
|
|
1211
1274
|
if (resolve) {
|
|
1212
1275
|
if (match instanceof this.documentType) {
|
|
1213
1276
|
const doc = match as WithContext<T>;
|
|
@@ -1225,10 +1288,7 @@ export class DocumentIndex<
|
|
|
1225
1288
|
}
|
|
1226
1289
|
|
|
1227
1290
|
const indexed = match as WithContext<I>;
|
|
1228
|
-
const resolved =
|
|
1229
|
-
indexed,
|
|
1230
|
-
head: indexed.__context.head,
|
|
1231
|
-
});
|
|
1291
|
+
const resolved = resolvedByMatch[i];
|
|
1232
1292
|
|
|
1233
1293
|
if (resolved) {
|
|
1234
1294
|
results.push(
|
|
@@ -1242,7 +1302,7 @@ export class DocumentIndex<
|
|
|
1242
1302
|
continue;
|
|
1243
1303
|
}
|
|
1244
1304
|
|
|
1245
|
-
const head =
|
|
1305
|
+
const head = headsByMatch[i];
|
|
1246
1306
|
results.push(
|
|
1247
1307
|
new types.ResultIndexedValue({
|
|
1248
1308
|
context: indexed.__context,
|
|
@@ -1253,7 +1313,7 @@ export class DocumentIndex<
|
|
|
1253
1313
|
);
|
|
1254
1314
|
} else {
|
|
1255
1315
|
const indexed = match as WithContext<I>;
|
|
1256
|
-
const head =
|
|
1316
|
+
const head = headsByMatch[i];
|
|
1257
1317
|
results.push(
|
|
1258
1318
|
new types.ResultIndexedValue({
|
|
1259
1319
|
context: indexed.__context,
|
|
@@ -1275,17 +1335,28 @@ export class DocumentIndex<
|
|
|
1275
1335
|
return [];
|
|
1276
1336
|
}
|
|
1277
1337
|
const drained = queueEntries.splice(0);
|
|
1338
|
+
const resolvedBatch = resolve
|
|
1339
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
1340
|
+
drained.map((entry) => ({
|
|
1341
|
+
indexed: entry.value,
|
|
1342
|
+
head: entry.value.__context.head,
|
|
1343
|
+
})),
|
|
1344
|
+
)
|
|
1345
|
+
: undefined;
|
|
1346
|
+
const heads = resolvedBatch
|
|
1347
|
+
? resolvedBatch.heads
|
|
1348
|
+
: await this._log.log.getMany(
|
|
1349
|
+
drained.map((entry) => entry.value.__context.head),
|
|
1350
|
+
);
|
|
1278
1351
|
const results: types.Result[] = [];
|
|
1279
|
-
for (
|
|
1352
|
+
for (let i = 0; i < drained.length; i++) {
|
|
1353
|
+
const entry = drained[i]!;
|
|
1280
1354
|
const indexedUnwrapped = Object.assign(
|
|
1281
1355
|
Object.create(this.indexedType.prototype),
|
|
1282
1356
|
entry.value,
|
|
1283
1357
|
);
|
|
1284
1358
|
if (resolve) {
|
|
1285
|
-
const value =
|
|
1286
|
-
indexed: entry.value,
|
|
1287
|
-
head: entry.value.__context.head,
|
|
1288
|
-
});
|
|
1359
|
+
const value = resolvedBatch!.resolved[i];
|
|
1289
1360
|
if (value) {
|
|
1290
1361
|
results.push(
|
|
1291
1362
|
new types.ResultValue({
|
|
@@ -1298,7 +1369,7 @@ export class DocumentIndex<
|
|
|
1298
1369
|
continue;
|
|
1299
1370
|
}
|
|
1300
1371
|
|
|
1301
|
-
const head =
|
|
1372
|
+
const head = heads[i];
|
|
1302
1373
|
results.push(
|
|
1303
1374
|
new types.ResultIndexedValue({
|
|
1304
1375
|
context: entry.value.__context,
|
|
@@ -1308,7 +1379,7 @@ export class DocumentIndex<
|
|
|
1308
1379
|
}),
|
|
1309
1380
|
);
|
|
1310
1381
|
} else {
|
|
1311
|
-
const head =
|
|
1382
|
+
const head = heads[i];
|
|
1312
1383
|
results.push(
|
|
1313
1384
|
new types.ResultIndexedValue({
|
|
1314
1385
|
context: entry.value.__context,
|
|
@@ -1358,6 +1429,7 @@ export class DocumentIndex<
|
|
|
1358
1429
|
let pendingAdded = added;
|
|
1359
1430
|
do {
|
|
1360
1431
|
const batches: types.Result[] = [];
|
|
1432
|
+
let claimedIds: indexerTypes.IdKey[] = [];
|
|
1361
1433
|
const queued = await this.drainQueuedResults(
|
|
1362
1434
|
queue.queue,
|
|
1363
1435
|
resolveFlag,
|
|
@@ -1379,6 +1451,21 @@ export class DocumentIndex<
|
|
|
1379
1451
|
const wrapped = await this.wrapPushResults(matches, resolveFlag);
|
|
1380
1452
|
if (wrapped.length) {
|
|
1381
1453
|
batches.push(...wrapped);
|
|
1454
|
+
claimedIds = wrapped
|
|
1455
|
+
.map((result) =>
|
|
1456
|
+
result instanceof types.ResultValue && result.indexed
|
|
1457
|
+
? indexerTypes.toId(
|
|
1458
|
+
this.indexByResolver(result.indexed),
|
|
1459
|
+
)
|
|
1460
|
+
: result instanceof types.ResultIndexedValue
|
|
1461
|
+
? indexerTypes.toId(
|
|
1462
|
+
this.indexByResolver(result.value),
|
|
1463
|
+
)
|
|
1464
|
+
: undefined,
|
|
1465
|
+
)
|
|
1466
|
+
.filter(
|
|
1467
|
+
(id): id is indexerTypes.IdKey => id !== undefined,
|
|
1468
|
+
);
|
|
1382
1469
|
}
|
|
1383
1470
|
}
|
|
1384
1471
|
if (batches.length) {
|
|
@@ -1396,6 +1483,12 @@ export class DocumentIndex<
|
|
|
1396
1483
|
redundancy: 1,
|
|
1397
1484
|
}),
|
|
1398
1485
|
});
|
|
1486
|
+
if (claimedIds.length) {
|
|
1487
|
+
await this._resumableIterators.markYielded(
|
|
1488
|
+
_iteratorId,
|
|
1489
|
+
claimedIds,
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1399
1492
|
}
|
|
1400
1493
|
pendingAdded = queue.pendingAdded ?? [];
|
|
1401
1494
|
queue.pendingAdded = undefined;
|
|
@@ -3474,6 +3567,7 @@ export class DocumentIndex<
|
|
|
3474
3567
|
id?: indexerTypes.IdPrimitive;
|
|
3475
3568
|
indexed: I;
|
|
3476
3569
|
head: string;
|
|
3570
|
+
headEntry?: Entry<Operation> | null;
|
|
3477
3571
|
}): Promise<{ value: T } | undefined> {
|
|
3478
3572
|
const id =
|
|
3479
3573
|
value.id ??
|
|
@@ -3495,7 +3589,10 @@ export class DocumentIndex<
|
|
|
3495
3589
|
return { value: obj as T };
|
|
3496
3590
|
}
|
|
3497
3591
|
|
|
3498
|
-
const head =
|
|
3592
|
+
const head =
|
|
3593
|
+
value.headEntry === undefined
|
|
3594
|
+
? await this._log.log.get(value.head)
|
|
3595
|
+
: (value.headEntry ?? undefined);
|
|
3499
3596
|
if (!head) {
|
|
3500
3597
|
return undefined; // we could end up here if we recently pruned the document and other peers never persisted the entry
|
|
3501
3598
|
// TODO update changes in index before removing entries from log entry storage
|
|
@@ -3633,7 +3730,10 @@ export class DocumentIndex<
|
|
|
3633
3730
|
this._resultQueue.set(query.idString, prevQueued);
|
|
3634
3731
|
}
|
|
3635
3732
|
|
|
3636
|
-
const
|
|
3733
|
+
const candidates: Array<{
|
|
3734
|
+
result: indexerTypes.IndexedResult<WithContext<I>>;
|
|
3735
|
+
indexed: I;
|
|
3736
|
+
}> = [];
|
|
3637
3737
|
const resolveDocumentsFlag = resolvesDocuments(fromQuery);
|
|
3638
3738
|
const replicateIndexFlag = replicatesIndex(fromQuery);
|
|
3639
3739
|
for (const result of toIterate) {
|
|
@@ -3655,11 +3755,29 @@ export class DocumentIndex<
|
|
|
3655
3755
|
) {
|
|
3656
3756
|
continue;
|
|
3657
3757
|
}
|
|
3758
|
+
candidates.push({ result, indexed: indexedUnwrapped });
|
|
3759
|
+
}
|
|
3760
|
+
|
|
3761
|
+
const resolvedBatch = resolveDocumentsFlag
|
|
3762
|
+
? await this.resolveDocumentsWithBatchedHeads(
|
|
3763
|
+
candidates.map(({ result }) => ({
|
|
3764
|
+
indexed: result.value,
|
|
3765
|
+
head: result.value.__context.head,
|
|
3766
|
+
})),
|
|
3767
|
+
)
|
|
3768
|
+
: undefined;
|
|
3769
|
+
const heads = resolvedBatch
|
|
3770
|
+
? resolvedBatch.heads
|
|
3771
|
+
: candidates.length > 0
|
|
3772
|
+
? await this._log.log.getMany(
|
|
3773
|
+
candidates.map(({ result }) => result.value.__context.head),
|
|
3774
|
+
)
|
|
3775
|
+
: [];
|
|
3776
|
+
const filteredResults: types.Result[] = [];
|
|
3777
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
3778
|
+
const { result, indexed: indexedUnwrapped } = candidates[i]!;
|
|
3658
3779
|
if (resolveDocumentsFlag) {
|
|
3659
|
-
const value =
|
|
3660
|
-
indexed: result.value,
|
|
3661
|
-
head: result.value.__context.head,
|
|
3662
|
-
});
|
|
3780
|
+
const value = resolvedBatch!.resolved[i];
|
|
3663
3781
|
|
|
3664
3782
|
if (!value) {
|
|
3665
3783
|
continue;
|
|
@@ -3675,7 +3793,7 @@ export class DocumentIndex<
|
|
|
3675
3793
|
);
|
|
3676
3794
|
} else {
|
|
3677
3795
|
const context = result.value.__context;
|
|
3678
|
-
const head =
|
|
3796
|
+
const head = heads[i];
|
|
3679
3797
|
if (replicateIndexFlag) {
|
|
3680
3798
|
if (!head) {
|
|
3681
3799
|
continue;
|
|
@@ -6144,9 +6262,10 @@ export class DocumentIndex<
|
|
|
6144
6262
|
continue;
|
|
6145
6263
|
}
|
|
6146
6264
|
}
|
|
6147
|
-
const
|
|
6265
|
+
const indexId = indexerTypes.toId(
|
|
6148
6266
|
this.indexByResolver(indexedCandidate),
|
|
6149
|
-
)
|
|
6267
|
+
);
|
|
6268
|
+
const id = indexId.primitive;
|
|
6150
6269
|
const existingIndexed = indexedPlaceholders?.get(id);
|
|
6151
6270
|
if (existingIndexed) {
|
|
6152
6271
|
if (resolve) {
|
|
@@ -6187,6 +6306,10 @@ export class DocumentIndex<
|
|
|
6187
6306
|
if (!resolve) {
|
|
6188
6307
|
ensureIndexedPlaceholders().set(id, placeholder);
|
|
6189
6308
|
}
|
|
6309
|
+
await this._resumableIterators.markYielded(
|
|
6310
|
+
queryRequestCoerced.idString,
|
|
6311
|
+
[indexId],
|
|
6312
|
+
);
|
|
6190
6313
|
hasRelevantChange = true;
|
|
6191
6314
|
}
|
|
6192
6315
|
}
|