@delali/narsil 0.3.1-next.72 → 0.3.1-next.73
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/README.md +2 -2
- package/dist/adapters/filesystem.mjs +1 -1
- package/dist/adapters/indexeddb.mjs +1 -1
- package/dist/{capabilities-D6gjjQyA.d.ts → capabilities-CYeAWYxQ.d.ts} +19 -4
- package/dist/{chunk-Y52WZWAU.mjs → chunk-2WLD2NFW.mjs} +4 -4
- package/dist/{chunk-QR4OKRVY.mjs → chunk-3YKWSO54.mjs} +8 -3
- package/dist/{chunk-KZTI25D3.mjs → chunk-4MQ5F4IL.mjs} +1 -1
- package/dist/{chunk-CVPA5Q7R.mjs → chunk-AFKH4ZK3.mjs} +9 -6
- package/dist/{chunk-M6XF5HDE.mjs → chunk-AK3BLGCI.mjs} +141 -11
- package/dist/{chunk-7QMTA7AA.mjs → chunk-CVFAFZSN.mjs} +7771 -4271
- package/dist/{chunk-RV77FR2F.mjs → chunk-I64LXKO3.mjs} +0 -1
- package/dist/{chunk-EDMCZLSJ.mjs → chunk-LPBWCHBE.mjs} +193 -13
- package/dist/{chunk-P2ZZN32C.mjs → chunk-PU43WDY4.mjs} +4 -2
- package/dist/{chunk-HVJYTKK7.mjs → chunk-THMSFOJO.mjs} +365 -774
- package/dist/{chunk-LCCL6EEH.mjs → chunk-WVDFG45M.mjs} +92 -94
- package/dist/{chunk-3HQPUCCT.mjs → chunk-XW25X6AU.mjs} +66 -237
- package/dist/{chunk-2X2ZQOAB.mjs → chunk-ZULSEZCE.mjs} +3 -4
- package/dist/{client-C2TiW29y.d.ts → client-D698E5ge.d.ts} +76 -25
- package/dist/client.d.ts +7 -7
- package/dist/client.mjs +44 -22
- package/dist/{config-BLguB-om.d.ts → config-Bv8etwUZ.d.ts} +10 -3
- package/dist/{config-C7Ip8Ife.d.ts → config-QXU3HMpq.d.ts} +10 -1
- package/dist/direct-executor-5SRDFZAS.mjs +13 -0
- package/dist/distribution/coordinator/etcd.d.ts +27 -14
- package/dist/distribution/coordinator/etcd.mjs +162 -75
- package/dist/distribution/transport/grpc.d.ts +2 -2
- package/dist/distribution/transport/grpc.mjs +22 -2
- package/dist/distribution/transport/in-memory.d.ts +2 -2
- package/dist/distribution/transport/in-memory.mjs +6 -3
- package/dist/distribution/transport/tcp.d.ts +2 -2
- package/dist/distribution/transport/tcp.mjs +40 -16
- package/dist/distribution.d.ts +6 -6
- package/dist/distribution.mjs +637 -366
- package/dist/embeddings/openai.mjs +1 -1
- package/dist/{engine-Dm4446j1.d.ts → engine-D_OzKZ-6.d.ts} +96 -187
- package/dist/index.browser.mjs +7179 -4031
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +11 -14
- package/dist/{memory-CKHTU1CL.d.ts → memory-B4jMmygw.d.ts} +213 -2
- package/dist/pattern.mjs +1 -1
- package/dist/persistence/durability/checkpoint-worker.d.ts +24 -16
- package/dist/persistence/durability/checkpoint-worker.mjs +22 -16
- package/dist/react.d.ts +6 -6
- package/dist/react.mjs +0 -1
- package/dist/server.d.ts +9 -9
- package/dist/server.mjs +210 -32
- package/dist/{tasks-BECd0b__.d.ts → tasks-DpgCpW1x.d.ts} +3 -3
- package/dist/{thread-IBSIZZ6W.mjs → thread-3LNVA43V.mjs} +79 -21
- package/dist/{types-BQDlIvfS.d.ts → types-B3b68nfF.d.ts} +1 -1
- package/dist/{types-D5OwhtsQ.d.ts → types-Cb9kiY5P.d.ts} +1 -1
- package/dist/vector/search-worker.mjs +3 -3
- package/dist/workers/entry.mjs +4 -4
- package/package.json +7 -7
- package/dist/chunk-3L4U6EJQ.mjs +0 -49
- package/dist/chunk-IFBKLBGB.mjs +0 -7
- package/dist/chunk-XZ4PAREY.mjs +0 -25
- package/dist/direct-executor-SVCHXR74.mjs +0 -14
- package/dist/serialization/crc32-worker.d.ts +0 -20
- package/dist/serialization/crc32-worker.mjs +0 -62
package/dist/distribution.mjs
CHANGED
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
import { MAX_MESSAGE_SIZE_BYTES } from './chunk-UNEEFTEU.mjs';
|
|
2
|
-
import { validateIndexName, indexConfigKey, indexSettingsOf, putIndexMetadata,
|
|
3
|
-
import { requireKnownConfig, resolveRunnableConfig, createEngineCore, startEngineCore, createNarsilFromCore, runEngineQueryStats, runEngineListDocuments, runEngineSuggest, runEnginePreflight, runEngineQuery, createEngineIndex, applyIndexEntry, applyDeleteEntry, validateEntryBatchPayload, createAckMessage, validateEntryPayload, validateForwardBatchPayload, createForwardBatchResultMessage, createForwardBatchMessage, validateForwardBatchResultPayload, createForwardMessage, validateReplicationEntry, computeEntryChecksum, createEntryMessage, createEntryBatchMessage, createInsyncConfirmMessage, validateAckPayload, createInsyncRemoveMessage, validateInsyncConfirmPayload, createInsyncAddMessage } from './chunk-
|
|
4
|
-
import { now, listBindingOf, queryBindingOf, hitsKeptPerGroup, clampLimit, resolveHybridFusion, dedupePinnedEntries, foldGroupReducer } from './chunk-2X2ZQOAB.mjs';
|
|
2
|
+
import { validateIndexName, indexConfigKey, withPartitionCount, indexSettingsOf, putIndexMetadata, getIndexMetadata, getClusterIndexConfig } from './chunk-2WLD2NFW.mjs';
|
|
3
|
+
import { requireKnownConfig, resolveRunnableConfig, createEngineCore, startEngineCore, createNarsilFromCore, runEngineQueryStats, runEngineListDocuments, runEngineSuggest, runEnginePreflight, runEngineQuery, createEngineIndex, buildArchiveFromMemory, indexMetadataOf, encodeIndexConfiguration, archiveStream, applyIndexEntry, applyDeleteEntry, requireConfigurationWithinSizeLimit, validateEntryBatchPayload, createAckMessage, validateEntryPayload, validateForwardBatchPayload, createForwardBatchResultMessage, memoryCheckpointStore, readSnapshotArchive, createByteReader, openChecksummedEnvelope, loadPartitionSegments, readListedFile, createForwardBatchMessage, validateForwardBatchResultPayload, createForwardMessage, validateReplicationEntry, crc32Init, crc32Final, crc32Update, computeEntryChecksum, createEntryMessage, createEntryBatchMessage, createInsyncConfirmMessage, validateAckPayload, createInsyncRemoveMessage, validateInsyncConfirmPayload, createInsyncAddMessage } from './chunk-CVFAFZSN.mjs';
|
|
5
4
|
import { ReplicationMessageTypes, TransportErrorCodes, ClusterMessageTypes, QueryMessageTypes, TransportError } from './chunk-GCM3JFVA.mjs';
|
|
6
|
-
import { providedDocId, MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR, WIRE_BATCH_BUDGET } from './chunk-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { validateSchema, DEFAULT_PAGE_SIZE, MAX_SORT_FIELDS, MAX_CURSOR_LENGTH, MAX_TOLERANCE, MAX_PREFIX_LENGTH, RESULT_WINDOW, MIN_POLYGON_POINTS, isLatitude, MAX_LATITUDE_DEGREES, isLongitude, MAX_LONGITUDE_DEGREES, MAX_NESTING_DEPTH } from './chunk-
|
|
5
|
+
import { providedDocId, MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR, WIRE_BATCH_BUDGET } from './chunk-AFKH4ZK3.mjs';
|
|
6
|
+
import { generateId, decodeVectorFilePayload, bytesToVectors, isDead, FILTER_EXPRESSION_KEYS, FIELD_FILTER_OPERATORS } from './chunk-THMSFOJO.mjs';
|
|
7
|
+
import { getLanguage } from './chunk-4MQ5F4IL.mjs';
|
|
8
|
+
import { now, listBindingOf, queryBindingOf, hitsKeptPerGroup, clampLimit, resolveHybridFusion, dedupePinnedEntries, foldGroupReducer } from './chunk-ZULSEZCE.mjs';
|
|
9
|
+
import { oversampledShardSize, resolveProjection, clampRowCount, sortSignatureOf, requireMatchingCursor, decodePageCursor, normalizeSort, sortModesOf, encodePageCursor, applyProjection, readSortValues, requireWithinResultWindow, fnv1a, sortSignatureEntry, MAX_FILTER_DEPTH, filterTestCount, MAX_FILTER_TESTS, fnv1aUint32s, mergePartitionStats, MAX_FILTER_ARRAY_SIZE } from './chunk-3YKWSO54.mjs';
|
|
10
|
+
import { DEFAULT_SUGGEST_LIMIT, MAX_SUGGEST_LIMIT, validateSchema, requireCreatableSchema, DEFAULT_PAGE_SIZE, encodeDocument, MAX_SUGGEST_SCATTER_LIMIT, MAX_INDEX_NAME_LENGTH, MAX_SORT_FIELDS, MAX_DOC_ID_LENGTH, MAX_CURSOR_LENGTH, MAX_TOLERANCE, SUGGEST_OVERSAMPLE_FACTOR, SUGGEST_OVERSAMPLE_PADDING, INDEX_NAME_PATTERN, MAX_PREFIX_LENGTH, RESULT_WINDOW, MAX_STORED_VECTOR_DIMENSION, MIN_POLYGON_POINTS, isLatitude, MAX_LATITUDE_DEGREES, isLongitude, MAX_LONGITUDE_DEGREES, MAX_NESTING_DEPTH } from './chunk-AK3BLGCI.mjs';
|
|
12
11
|
import './chunk-TGP5M5R7.mjs';
|
|
13
|
-
import './chunk-
|
|
12
|
+
import './chunk-WVDFG45M.mjs';
|
|
14
13
|
import { MIN_OVERSAMPLE } from './chunk-ZJ4CSAB2.mjs';
|
|
15
|
-
import './chunk-
|
|
16
|
-
import
|
|
17
|
-
import './chunk-IFBKLBGB.mjs';
|
|
18
|
-
import './chunk-3HQPUCCT.mjs';
|
|
14
|
+
import './chunk-PU43WDY4.mjs';
|
|
15
|
+
import './chunk-XW25X6AU.mjs';
|
|
19
16
|
import './chunk-ZKRV5M2P.mjs';
|
|
20
17
|
import './chunk-U2BKYEC7.mjs';
|
|
21
18
|
import { compareCodePoints, toComparableSortValue, compareComparableKeys, isSortMode, SORT_MODES, exceedsCodePoints, compareSortValues } from './chunk-LJYTW7GT.mjs';
|
|
22
19
|
import './chunk-POWOTUKJ.mjs';
|
|
23
|
-
import { ErrorCodes, NarsilError, describeError } from './chunk-
|
|
20
|
+
import { ErrorCodes, NarsilError, describeError } from './chunk-I64LXKO3.mjs';
|
|
24
21
|
import { encode, decode } from '@msgpack/msgpack';
|
|
22
|
+
import { randomUUID } from 'crypto';
|
|
23
|
+
import { openSync, writeSync, closeSync, rmSync, readSync } from 'fs';
|
|
24
|
+
import { mkdtemp, rm, mkdir } from 'fs/promises';
|
|
25
|
+
import { tmpdir } from 'os';
|
|
26
|
+
import { join } from 'path';
|
|
25
27
|
|
|
26
28
|
// src/distribution/cluster/constants.ts
|
|
27
29
|
var LEADERSHIP_IMBALANCE_THRESHOLD = 2;
|
|
@@ -1251,7 +1253,6 @@ var REPLICATION_ENTRY_FIXED_OVERHEAD_BYTES = 40;
|
|
|
1251
1253
|
var DEFAULT_LOG_RETENTION_BYTES = 268435456;
|
|
1252
1254
|
var INSYNC_CAS_ATTEMPTS = 5;
|
|
1253
1255
|
var SNAPSHOT_CHUNK_SIZE = 65536;
|
|
1254
|
-
var MAX_SNAPSHOT_SIZE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
1255
1256
|
|
|
1256
1257
|
// src/distribution/replication/insync.ts
|
|
1257
1258
|
var REFUSE = { outcome: "refuse" };
|
|
@@ -2516,6 +2517,119 @@ function createDataNodeLifecycle(config) {
|
|
|
2516
2517
|
};
|
|
2517
2518
|
return handle;
|
|
2518
2519
|
}
|
|
2520
|
+
var SPOOL_FILE_PREFIX = "narsil-snapshot-";
|
|
2521
|
+
var DURABLE_SPOOL_DIRECTORY = ".snapshot-transfer";
|
|
2522
|
+
var TEMPORARY_SPOOL_DIRECTORY_PREFIX = "narsil-snapshot-transfer-";
|
|
2523
|
+
var OWNER_ONLY_FILE_MODE = 384;
|
|
2524
|
+
var OWNER_ONLY_DIRECTORY_MODE = 448;
|
|
2525
|
+
function defaultSpoolDirectory() {
|
|
2526
|
+
return tmpdir();
|
|
2527
|
+
}
|
|
2528
|
+
function spoolFilePath(directory) {
|
|
2529
|
+
return join(directory, `${SPOOL_FILE_PREFIX}${randomUUID()}`);
|
|
2530
|
+
}
|
|
2531
|
+
async function* readSpoolFile(path) {
|
|
2532
|
+
const descriptor = openSync(path, "r");
|
|
2533
|
+
try {
|
|
2534
|
+
for (; ; ) {
|
|
2535
|
+
const buffer = new Uint8Array(SNAPSHOT_CHUNK_SIZE);
|
|
2536
|
+
const bytesRead = readSync(descriptor, buffer, 0, buffer.byteLength, null);
|
|
2537
|
+
if (bytesRead === 0) return;
|
|
2538
|
+
yield bytesRead === buffer.byteLength ? buffer : buffer.subarray(0, bytesRead);
|
|
2539
|
+
}
|
|
2540
|
+
} finally {
|
|
2541
|
+
closeSync(descriptor);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
function spooledFile(path, totalBytes, checksum) {
|
|
2545
|
+
let discarded = false;
|
|
2546
|
+
return {
|
|
2547
|
+
totalBytes,
|
|
2548
|
+
checksum,
|
|
2549
|
+
read: () => readSpoolFile(path),
|
|
2550
|
+
async discard() {
|
|
2551
|
+
if (discarded) return;
|
|
2552
|
+
discarded = true;
|
|
2553
|
+
removeQuietly(path);
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
function openSnapshotSpoolWriter(directory) {
|
|
2558
|
+
const path = spoolFilePath(directory);
|
|
2559
|
+
let descriptor = openSync(path, "wx", OWNER_ONLY_FILE_MODE);
|
|
2560
|
+
let checksumState = crc32Init();
|
|
2561
|
+
let totalBytes = 0;
|
|
2562
|
+
const close = () => {
|
|
2563
|
+
if (descriptor === null) return;
|
|
2564
|
+
const closing = descriptor;
|
|
2565
|
+
descriptor = null;
|
|
2566
|
+
closeSync(closing);
|
|
2567
|
+
};
|
|
2568
|
+
return {
|
|
2569
|
+
write(bytes) {
|
|
2570
|
+
if (descriptor === null) {
|
|
2571
|
+
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "The snapshot spool file is already closed", {
|
|
2572
|
+
path
|
|
2573
|
+
});
|
|
2574
|
+
}
|
|
2575
|
+
let offset = 0;
|
|
2576
|
+
while (offset < bytes.byteLength) {
|
|
2577
|
+
offset += writeSync(descriptor, bytes, offset, bytes.byteLength - offset);
|
|
2578
|
+
}
|
|
2579
|
+
checksumState = crc32Update(checksumState, bytes);
|
|
2580
|
+
totalBytes += bytes.byteLength;
|
|
2581
|
+
},
|
|
2582
|
+
checksum() {
|
|
2583
|
+
return crc32Final(checksumState);
|
|
2584
|
+
},
|
|
2585
|
+
finish() {
|
|
2586
|
+
close();
|
|
2587
|
+
return spooledFile(path, totalBytes, crc32Final(checksumState));
|
|
2588
|
+
},
|
|
2589
|
+
discard() {
|
|
2590
|
+
try {
|
|
2591
|
+
close();
|
|
2592
|
+
} finally {
|
|
2593
|
+
removeQuietly(path);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
function removeQuietly(path) {
|
|
2599
|
+
try {
|
|
2600
|
+
rmSync(path, { force: true });
|
|
2601
|
+
} catch (_) {
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
async function spoolSnapshotStream(directory, stream) {
|
|
2605
|
+
const reader = stream.getReader();
|
|
2606
|
+
let writer = null;
|
|
2607
|
+
try {
|
|
2608
|
+
writer = openSnapshotSpoolWriter(directory);
|
|
2609
|
+
for (; ; ) {
|
|
2610
|
+
const step = await reader.read();
|
|
2611
|
+
if (step.done) break;
|
|
2612
|
+
if (step.value.byteLength > 0) writer.write(step.value);
|
|
2613
|
+
}
|
|
2614
|
+
const spooled = writer.finish();
|
|
2615
|
+
writer = null;
|
|
2616
|
+
return spooled;
|
|
2617
|
+
} catch (err) {
|
|
2618
|
+
writer?.discard();
|
|
2619
|
+
await reader.cancel().catch(() => void 0);
|
|
2620
|
+
throw err;
|
|
2621
|
+
} finally {
|
|
2622
|
+
reader.releaseLock();
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
async function openSnapshotSpoolDirectory(durabilityDirectory) {
|
|
2626
|
+
const path = durabilityDirectory === void 0 ? await mkdtemp(join(tmpdir(), TEMPORARY_SPOOL_DIRECTORY_PREFIX)) : join(durabilityDirectory, DURABLE_SPOOL_DIRECTORY);
|
|
2627
|
+
if (durabilityDirectory !== void 0) {
|
|
2628
|
+
await rm(path, { recursive: true, force: true });
|
|
2629
|
+
await mkdir(path, { recursive: true, mode: OWNER_ONLY_DIRECTORY_MODE });
|
|
2630
|
+
}
|
|
2631
|
+
return { path, dispose: () => rm(path, { recursive: true, force: true }) };
|
|
2632
|
+
}
|
|
2519
2633
|
|
|
2520
2634
|
// src/distribution/cluster-node/local-index-gone.ts
|
|
2521
2635
|
function localIndexIsGone(err) {
|
|
@@ -2583,6 +2697,19 @@ function fail(state, code, message, details = {}) {
|
|
|
2583
2697
|
return;
|
|
2584
2698
|
}
|
|
2585
2699
|
state.failure = { ok: false, code, message, details };
|
|
2700
|
+
releaseSpool(state);
|
|
2701
|
+
}
|
|
2702
|
+
function releaseSpool(state) {
|
|
2703
|
+
const spool = state.spool;
|
|
2704
|
+
if (spool === null) return;
|
|
2705
|
+
state.spool = null;
|
|
2706
|
+
spool.discard();
|
|
2707
|
+
}
|
|
2708
|
+
function spoolFailure(state, err) {
|
|
2709
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
2710
|
+
fail(state, ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, `the snapshot could not be written to local storage: ${cause}`, {
|
|
2711
|
+
cause
|
|
2712
|
+
});
|
|
2586
2713
|
}
|
|
2587
2714
|
function applyErrorEnvelope(state, record) {
|
|
2588
2715
|
const code = typeof record.code === "string" && record.code.length > 0 ? record.code : "UNKNOWN_ERROR";
|
|
@@ -2633,19 +2760,17 @@ function applyStartPayload(state, record) {
|
|
|
2633
2760
|
fail(state, ErrorCodes.SNAPSHOT_SYNC_HEADER_INVALID, "totalBytes must be a non-negative integer");
|
|
2634
2761
|
return;
|
|
2635
2762
|
}
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
});
|
|
2763
|
+
try {
|
|
2764
|
+
state.spool = openSnapshotSpoolWriter(state.expectation.spoolDirectory);
|
|
2765
|
+
} catch (err) {
|
|
2766
|
+
spoolFailure(state, err);
|
|
2641
2767
|
return;
|
|
2642
2768
|
}
|
|
2643
2769
|
state.header = header;
|
|
2644
2770
|
state.totalBytes = start.totalBytes;
|
|
2645
|
-
state.assembled = new Uint8Array(start.totalBytes);
|
|
2646
2771
|
}
|
|
2647
2772
|
function applyChunkPayload(state, payload) {
|
|
2648
|
-
if (state.totalBytes === null || state.
|
|
2773
|
+
if (state.totalBytes === null || state.header === null) {
|
|
2649
2774
|
fail(state, ErrorCodes.SNAPSHOT_SYNC_FRAME_INVALID, "received chunk before SNAPSHOT_START");
|
|
2650
2775
|
return;
|
|
2651
2776
|
}
|
|
@@ -2699,7 +2824,16 @@ function applyChunkPayload(state, payload) {
|
|
|
2699
2824
|
});
|
|
2700
2825
|
return;
|
|
2701
2826
|
}
|
|
2702
|
-
state.
|
|
2827
|
+
if (state.spool === null) {
|
|
2828
|
+
fail(state, ErrorCodes.SNAPSHOT_SYNC_FRAME_INVALID, "received chunk after the snapshot stream closed");
|
|
2829
|
+
return;
|
|
2830
|
+
}
|
|
2831
|
+
try {
|
|
2832
|
+
state.spool.write(payload.data);
|
|
2833
|
+
} catch (err) {
|
|
2834
|
+
spoolFailure(state, err);
|
|
2835
|
+
return;
|
|
2836
|
+
}
|
|
2703
2837
|
state.accumulatedBytes = nextBytes;
|
|
2704
2838
|
state.expectedNextOffset = payload.offset + payload.data.byteLength;
|
|
2705
2839
|
}
|
|
@@ -2777,7 +2911,7 @@ function createSnapshotStreamState(expectation) {
|
|
|
2777
2911
|
expectation,
|
|
2778
2912
|
header: null,
|
|
2779
2913
|
totalBytes: null,
|
|
2780
|
-
|
|
2914
|
+
spool: null,
|
|
2781
2915
|
accumulatedBytes: 0,
|
|
2782
2916
|
expectedNextOffset: 0,
|
|
2783
2917
|
endPayload: null,
|
|
@@ -2832,11 +2966,20 @@ function handleIncomingSnapshotRecord(state, record) {
|
|
|
2832
2966
|
}
|
|
2833
2967
|
fail(state, ErrorCodes.SNAPSHOT_SYNC_FRAME_INVALID, "unrecognised snapshot frame shape");
|
|
2834
2968
|
}
|
|
2969
|
+
function abandonSnapshotStream(state) {
|
|
2970
|
+
fail(state, ErrorCodes.SNAPSHOT_SYNC_ABORTED, "the snapshot stream was abandoned before it finished");
|
|
2971
|
+
releaseSpool(state);
|
|
2972
|
+
}
|
|
2835
2973
|
function finalizeSnapshotStream(state) {
|
|
2974
|
+
const result = settleSnapshotStream(state);
|
|
2975
|
+
if (!result.ok) releaseSpool(state);
|
|
2976
|
+
return result;
|
|
2977
|
+
}
|
|
2978
|
+
function settleSnapshotStream(state) {
|
|
2836
2979
|
if (state.failure !== null) {
|
|
2837
2980
|
return state.failure;
|
|
2838
2981
|
}
|
|
2839
|
-
if (state.header === null || state.totalBytes === null
|
|
2982
|
+
if (state.header === null || state.totalBytes === null) {
|
|
2840
2983
|
return {
|
|
2841
2984
|
ok: false,
|
|
2842
2985
|
code: ErrorCodes.SNAPSHOT_SYNC_CHUNK_MISSING,
|
|
@@ -2868,9 +3011,28 @@ function finalizeSnapshotStream(state) {
|
|
|
2868
3011
|
}
|
|
2869
3012
|
};
|
|
2870
3013
|
}
|
|
3014
|
+
const spool = state.spool;
|
|
3015
|
+
if (spool === null) {
|
|
3016
|
+
return {
|
|
3017
|
+
ok: false,
|
|
3018
|
+
code: ErrorCodes.SNAPSHOT_SYNC_FRAME_INVALID,
|
|
3019
|
+
message: "the snapshot stream was already settled",
|
|
3020
|
+
details: { indexName: state.expectation.indexName }
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
const computed = spool.checksum();
|
|
3024
|
+
if (computed !== state.header.checksum) {
|
|
3025
|
+
return {
|
|
3026
|
+
ok: false,
|
|
3027
|
+
code: ErrorCodes.SNAPSHOT_SYNC_CHECKSUM_MISMATCH,
|
|
3028
|
+
message: "computed checksum does not match header checksum",
|
|
3029
|
+
details: { computed, header: state.header.checksum }
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
state.spool = null;
|
|
2871
3033
|
return {
|
|
2872
3034
|
ok: true,
|
|
2873
|
-
|
|
3035
|
+
snapshot: spool.finish(),
|
|
2874
3036
|
header: state.header,
|
|
2875
3037
|
end: state.endPayload
|
|
2876
3038
|
};
|
|
@@ -3081,7 +3243,11 @@ async function fetchSnapshotFromTarget(indexName, partitionId, target, deadline,
|
|
|
3081
3243
|
requestId: generateId(),
|
|
3082
3244
|
payload: encode(requestPayload)
|
|
3083
3245
|
};
|
|
3084
|
-
const streamState = createSnapshotStreamState({
|
|
3246
|
+
const streamState = createSnapshotStreamState({
|
|
3247
|
+
indexName,
|
|
3248
|
+
partitionId: null,
|
|
3249
|
+
spoolDirectory: deps.spoolDirectory ?? defaultSpoolDirectory()
|
|
3250
|
+
});
|
|
3085
3251
|
const remainingMs = deadline - Date.now();
|
|
3086
3252
|
if (remainingMs <= 0) {
|
|
3087
3253
|
return {
|
|
@@ -3097,6 +3263,7 @@ async function fetchSnapshotFromTarget(indexName, partitionId, target, deadline,
|
|
|
3097
3263
|
});
|
|
3098
3264
|
await withDeadline(streamWork, remainingMs, indexName, "stream");
|
|
3099
3265
|
} catch (err) {
|
|
3266
|
+
abandonSnapshotStream(streamState);
|
|
3100
3267
|
if (err instanceof NarsilError && err.code === ErrorCodes.SNAPSHOT_SYNC_TIMEOUT) {
|
|
3101
3268
|
return toStreamFailure(err, ErrorCodes.SNAPSHOT_SYNC_TIMEOUT, "snapshot stream deadline exceeded");
|
|
3102
3269
|
}
|
|
@@ -3105,20 +3272,7 @@ async function fetchSnapshotFromTarget(indexName, partitionId, target, deadline,
|
|
|
3105
3272
|
}
|
|
3106
3273
|
return toStreamFailure(err, ErrorCodes.SNAPSHOT_SYNC_PRIMARY_ERROR, "snapshot fetch raised non-transport error");
|
|
3107
3274
|
}
|
|
3108
|
-
|
|
3109
|
-
if (!result.ok) {
|
|
3110
|
-
return result;
|
|
3111
|
-
}
|
|
3112
|
-
const computedChecksum = crc32(result.bytes);
|
|
3113
|
-
if (computedChecksum !== result.header.checksum) {
|
|
3114
|
-
return {
|
|
3115
|
-
ok: false,
|
|
3116
|
-
code: ErrorCodes.SNAPSHOT_SYNC_CHECKSUM_MISMATCH,
|
|
3117
|
-
message: "computed checksum does not match header checksum",
|
|
3118
|
-
details: { computed: computedChecksum, header: result.header.checksum }
|
|
3119
|
-
};
|
|
3120
|
-
}
|
|
3121
|
-
return result;
|
|
3275
|
+
return finalizeSnapshotStream(streamState);
|
|
3122
3276
|
}
|
|
3123
3277
|
async function withDeadline(work, ms, indexName, phase) {
|
|
3124
3278
|
let timer = null;
|
|
@@ -3267,9 +3421,9 @@ function surfaceAborted(deps, indexName, primaryNodeId) {
|
|
|
3267
3421
|
})
|
|
3268
3422
|
);
|
|
3269
3423
|
}
|
|
3270
|
-
async function executeEngineRestore(engine, indexName, primaryNodeId,
|
|
3424
|
+
async function executeEngineRestore(engine, indexName, primaryNodeId, source, remainingMs) {
|
|
3271
3425
|
try {
|
|
3272
|
-
await withDeadline(engine.restore(indexName,
|
|
3426
|
+
await withDeadline(engine.restore(indexName, source), remainingMs, indexName, "restore");
|
|
3273
3427
|
return null;
|
|
3274
3428
|
} catch (err) {
|
|
3275
3429
|
if (err instanceof NarsilError && err.code === ErrorCodes.SNAPSHOT_SYNC_TIMEOUT) {
|
|
@@ -3555,9 +3709,9 @@ function validateSyncEntryForApply(entry, indexName, partitionId, expectedSeqNo,
|
|
|
3555
3709
|
}
|
|
3556
3710
|
return null;
|
|
3557
3711
|
}
|
|
3558
|
-
function createLiveSyncFrameState(indexName, partitionId) {
|
|
3712
|
+
function createLiveSyncFrameState(indexName, partitionId, spoolDirectory) {
|
|
3559
3713
|
return {
|
|
3560
|
-
snapshotState: createSnapshotStreamState({ indexName, partitionId }),
|
|
3714
|
+
snapshotState: createSnapshotStreamState({ indexName, partitionId, spoolDirectory }),
|
|
3561
3715
|
syncEntries: [],
|
|
3562
3716
|
sawSnapshotFrame: false,
|
|
3563
3717
|
error: null
|
|
@@ -3659,35 +3813,25 @@ async function applyLiveIncrementalSync(indexName, partitionId, target, entriesP
|
|
|
3659
3813
|
async function applyLiveSnapshotSync(state, entry, indexName, partitionId, target, frameState, coordinatorConfig, partitionCount, deadline, deps) {
|
|
3660
3814
|
const finalized = finalizeSnapshotStream(frameState.snapshotState);
|
|
3661
3815
|
if (!finalized.ok) {
|
|
3662
|
-
return { ok: false, error: streamFailureToError(finalized) };
|
|
3816
|
+
return { ok: false, error: streamFailureToError({ ...finalized, details: { ...finalized.details, target } }) };
|
|
3663
3817
|
}
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3818
|
+
let restoreError;
|
|
3819
|
+
try {
|
|
3820
|
+
restoreError = await restoreLiveSnapshotPartition(
|
|
3821
|
+
state,
|
|
3822
|
+
entry,
|
|
3823
|
+
indexName,
|
|
3824
|
+
partitionId,
|
|
3825
|
+
target,
|
|
3826
|
+
finalized.snapshot.read(),
|
|
3827
|
+
coordinatorConfig,
|
|
3828
|
+
partitionCount,
|
|
3829
|
+
deadline,
|
|
3830
|
+
deps
|
|
3831
|
+
);
|
|
3832
|
+
} finally {
|
|
3833
|
+
await finalized.snapshot.discard();
|
|
3678
3834
|
}
|
|
3679
|
-
const restoreError = await restoreLiveSnapshotPartition(
|
|
3680
|
-
state,
|
|
3681
|
-
entry,
|
|
3682
|
-
indexName,
|
|
3683
|
-
partitionId,
|
|
3684
|
-
target,
|
|
3685
|
-
finalized.bytes,
|
|
3686
|
-
coordinatorConfig,
|
|
3687
|
-
partitionCount,
|
|
3688
|
-
deadline,
|
|
3689
|
-
deps
|
|
3690
|
-
);
|
|
3691
3835
|
if (restoreError !== null) {
|
|
3692
3836
|
return { ok: false, error: restoreError };
|
|
3693
3837
|
}
|
|
@@ -3711,7 +3855,7 @@ async function applyLiveSnapshotSync(state, entry, indexName, partitionId, targe
|
|
|
3711
3855
|
snapshotHeader: finalized.header
|
|
3712
3856
|
};
|
|
3713
3857
|
}
|
|
3714
|
-
async function restoreLiveSnapshotPartition(state, entry, indexName, partitionId, primaryNodeId,
|
|
3858
|
+
async function restoreLiveSnapshotPartition(state, entry, indexName, partitionId, primaryNodeId, source, coordinatorConfig, partitionCount, deadline, deps) {
|
|
3715
3859
|
const remainingMs = deadline - Date.now();
|
|
3716
3860
|
if (remainingMs <= 0) {
|
|
3717
3861
|
return new NarsilError(
|
|
@@ -3735,7 +3879,7 @@ async function restoreLiveSnapshotPartition(state, entry, indexName, partitionId
|
|
|
3735
3879
|
}
|
|
3736
3880
|
try {
|
|
3737
3881
|
await withDeadline(
|
|
3738
|
-
deps.restoreReplicationPartition(indexName, partitionId,
|
|
3882
|
+
deps.restoreReplicationPartition(indexName, partitionId, source, coordinatorConfig, partitionCount),
|
|
3739
3883
|
remainingMs,
|
|
3740
3884
|
indexName,
|
|
3741
3885
|
"partition-restore"
|
|
@@ -3927,6 +4071,27 @@ async function syncFromAnyTarget(state, entry, indexName, partitionId, primaryNo
|
|
|
3927
4071
|
return { ok: false, error: lastError };
|
|
3928
4072
|
}
|
|
3929
4073
|
async function syncFromTarget(state, entry, indexName, partitionId, target, coordinatorConfig, partitionCount, deadline, deps, abortCheck) {
|
|
4074
|
+
const spoolDirectory = deps.snapshotSpoolDirectory ?? defaultSpoolDirectory();
|
|
4075
|
+
const frameState = createLiveSyncFrameState(indexName, partitionId, spoolDirectory);
|
|
4076
|
+
try {
|
|
4077
|
+
return await syncFrameStateFromTarget(
|
|
4078
|
+
state,
|
|
4079
|
+
entry,
|
|
4080
|
+
indexName,
|
|
4081
|
+
partitionId,
|
|
4082
|
+
target,
|
|
4083
|
+
coordinatorConfig,
|
|
4084
|
+
partitionCount,
|
|
4085
|
+
deadline,
|
|
4086
|
+
deps,
|
|
4087
|
+
abortCheck,
|
|
4088
|
+
frameState
|
|
4089
|
+
);
|
|
4090
|
+
} finally {
|
|
4091
|
+
abandonSnapshotStream(frameState.snapshotState);
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
async function syncFrameStateFromTarget(state, entry, indexName, partitionId, target, coordinatorConfig, partitionCount, deadline, deps, abortCheck, frameState) {
|
|
3930
4095
|
const logState = readLocalLogState(indexName, partitionId, deps);
|
|
3931
4096
|
const requestPayload = {
|
|
3932
4097
|
indexName,
|
|
@@ -3940,7 +4105,6 @@ async function syncFromTarget(state, entry, indexName, partitionId, target, coor
|
|
|
3940
4105
|
requestId: generateId(),
|
|
3941
4106
|
payload: encode(requestPayload)
|
|
3942
4107
|
};
|
|
3943
|
-
const frameState = createLiveSyncFrameState(indexName, partitionId);
|
|
3944
4108
|
const remainingMs = deadline - Date.now();
|
|
3945
4109
|
if (remainingMs <= 0) {
|
|
3946
4110
|
return {
|
|
@@ -4172,7 +4336,7 @@ async function fetchSchemaAndPrepare(entry, indexName, primaryNodeId, deps) {
|
|
|
4172
4336
|
}
|
|
4173
4337
|
return configResult.config.schema;
|
|
4174
4338
|
}
|
|
4175
|
-
async function applyRestore(state, entry, indexName, primaryNodeId,
|
|
4339
|
+
async function applyRestore(state, entry, indexName, primaryNodeId, source, coordinatorSchema, deadline, deps) {
|
|
4176
4340
|
const remainingMs = deadline - Date.now();
|
|
4177
4341
|
if (remainingMs <= 0) {
|
|
4178
4342
|
surfaceError(
|
|
@@ -4191,7 +4355,7 @@ async function applyRestore(state, entry, indexName, primaryNodeId, bytes, coord
|
|
|
4191
4355
|
surfaceAborted(deps, indexName, primaryNodeId);
|
|
4192
4356
|
return false;
|
|
4193
4357
|
}
|
|
4194
|
-
const restoreError = await executeEngineRestore(deps.engine, indexName, primaryNodeId,
|
|
4358
|
+
const restoreError = await executeEngineRestore(deps.engine, indexName, primaryNodeId, source, remainingMs);
|
|
4195
4359
|
if (restoreError !== null) {
|
|
4196
4360
|
surfaceError(deps, indexName, primaryNodeId, restoreError);
|
|
4197
4361
|
return false;
|
|
@@ -4312,7 +4476,11 @@ async function executeBootstrapSync(state, entry, indexName, partitionId, primar
|
|
|
4312
4476
|
surfaceError(deps, indexName, primaryNodeId, targetsResult);
|
|
4313
4477
|
return false;
|
|
4314
4478
|
}
|
|
4315
|
-
const fetchDeps = {
|
|
4479
|
+
const fetchDeps = {
|
|
4480
|
+
transport: deps.transport,
|
|
4481
|
+
sourceNodeId: deps.sourceNodeId,
|
|
4482
|
+
spoolDirectory: deps.snapshotSpoolDirectory
|
|
4483
|
+
};
|
|
4316
4484
|
const fetchResult = await fetchSnapshotFromAnyTarget(
|
|
4317
4485
|
indexName,
|
|
4318
4486
|
primaryNodeId,
|
|
@@ -4339,20 +4507,25 @@ async function executeBootstrapSync(state, entry, indexName, partitionId, primar
|
|
|
4339
4507
|
);
|
|
4340
4508
|
return false;
|
|
4341
4509
|
}
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4510
|
+
let restoreSucceeded;
|
|
4511
|
+
try {
|
|
4512
|
+
if (abortCheck()) {
|
|
4513
|
+
surfaceAborted(deps, indexName, primaryNodeId);
|
|
4514
|
+
return false;
|
|
4515
|
+
}
|
|
4516
|
+
restoreSucceeded = await applyRestore(
|
|
4517
|
+
state,
|
|
4518
|
+
entry,
|
|
4519
|
+
indexName,
|
|
4520
|
+
primaryNodeId,
|
|
4521
|
+
fetchResult.snapshot.read(),
|
|
4522
|
+
schemaResult,
|
|
4523
|
+
deadline,
|
|
4524
|
+
deps
|
|
4525
|
+
);
|
|
4526
|
+
} finally {
|
|
4527
|
+
await fetchResult.snapshot.discard();
|
|
4345
4528
|
}
|
|
4346
|
-
const restoreSucceeded = await applyRestore(
|
|
4347
|
-
state,
|
|
4348
|
-
entry,
|
|
4349
|
-
indexName,
|
|
4350
|
-
primaryNodeId,
|
|
4351
|
-
fetchResult.bytes,
|
|
4352
|
-
schemaResult,
|
|
4353
|
-
deadline,
|
|
4354
|
-
deps
|
|
4355
|
-
);
|
|
4356
4529
|
if (!restoreSucceeded) {
|
|
4357
4530
|
return false;
|
|
4358
4531
|
}
|
|
@@ -5216,173 +5389,40 @@ async function applyLocalReplicationEntry(core, entry) {
|
|
|
5216
5389
|
}
|
|
5217
5390
|
}
|
|
5218
5391
|
|
|
5219
|
-
// src/distribution/cluster-node/
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
const runnableConfig = await resolveRunnableConfig(config);
|
|
5223
|
-
const core = createEngineCore(runnableConfig, hooks, "partition");
|
|
5224
|
-
await startEngineCore(core, runnableConfig);
|
|
5225
|
-
core.orchestrator.shareMainThread();
|
|
5226
|
-
const engine = createNarsilFromCore(core, runnableConfig);
|
|
5227
|
-
const heldPartitions = createHeldPartitionRecord(core);
|
|
5228
|
-
return Object.assign(engine, {
|
|
5229
|
-
createIndex: (name, indexConfig) => createEngineIndex(core, runnableConfig, name, indexConfig, { adapterBinding: "deferred" }),
|
|
5230
|
-
createIndexWithUuid: (name, indexConfig, indexUuid) => createEngineIndex(core, runnableConfig, name, indexConfig, { indexUuid }),
|
|
5231
|
-
acquireIndexForReplication: (indexName) => core.indexState.acquire(indexName, false),
|
|
5232
|
-
indexUuidOf: (indexName) => core.indexRegistry.get(indexName)?.indexUuid,
|
|
5233
|
-
stampIndexUuid: (indexName, indexUuid) => stampIndexUuid(core, indexName, indexUuid),
|
|
5234
|
-
highestPersistedSeqNoOf: (indexName, partitionId) => core.durability?.manager.highestPersistedSeqNo(indexName, partitionId) ?? 0,
|
|
5235
|
-
heldPartitionsOf: (indexName) => heldPartitions.held(indexName),
|
|
5236
|
-
recordHeldPartition: (indexName, partitionId) => heldPartitions.record(indexName, partitionId),
|
|
5237
|
-
forgetHeldPartition: (indexName, partitionId) => heldPartitions.forget(indexName, partitionId),
|
|
5238
|
-
applyReplicationEntry: (entry) => applyLocalReplicationEntry(core, entry),
|
|
5239
|
-
serializeReplicationPartition: (indexName, partitionId) => serializeReplicationPartition(core, indexName, partitionId),
|
|
5240
|
-
restoreReplicationPartition: (indexName, partitionId, bytes, indexConfig, partitionCount) => restoreReplicationPartition(core, engine, indexName, partitionId, bytes, indexConfig, partitionCount),
|
|
5241
|
-
queryPartitions: (indexName, params, partitionIds, globalStats) => runEngineQuery(core, indexName, params, { partitionIds, globalStats }),
|
|
5242
|
-
preflightPartitions: (indexName, params, partitionIds) => runEnginePreflight(core, indexName, params, { partitionIds }),
|
|
5243
|
-
suggestPartitions: (indexName, params, partitionIds) => runEngineSuggest(core, indexName, params, partitionIds),
|
|
5244
|
-
listPartitions: (indexName, params, partitionIds) => runEngineListDocuments(core, indexName, params, partitionIds),
|
|
5245
|
-
collectQueryStats: (indexName, terms, partitionIds) => runEngineQueryStats(core, indexName, terms, partitionIds),
|
|
5246
|
-
partitionStatsForRead: async (indexName) => {
|
|
5247
|
-
const release = await core.indexState.acquire(indexName);
|
|
5248
|
-
try {
|
|
5249
|
-
return core.requireManager(indexName).getPartitionStats();
|
|
5250
|
-
} finally {
|
|
5251
|
-
release();
|
|
5252
|
-
}
|
|
5253
|
-
}
|
|
5254
|
-
});
|
|
5255
|
-
}
|
|
5256
|
-
async function stampIndexUuid(core, indexName, indexUuid) {
|
|
5257
|
-
const entry = core.indexRegistry.get(indexName);
|
|
5258
|
-
if (entry === void 0 || entry.indexUuid === indexUuid) {
|
|
5259
|
-
return;
|
|
5260
|
-
}
|
|
5261
|
-
core.indexRegistry.set(indexName, { ...entry, indexUuid });
|
|
5262
|
-
if (core.durability !== null) {
|
|
5263
|
-
await core.durability.manager.persistMetadata(indexName);
|
|
5264
|
-
}
|
|
5265
|
-
}
|
|
5266
|
-
async function serializeReplicationPartition(core, indexName, partitionId) {
|
|
5267
|
-
core.guardShutdown();
|
|
5268
|
-
const release = await core.indexState.acquire(indexName, false);
|
|
5269
|
-
try {
|
|
5270
|
-
return core.requireManager(indexName).serializePartitionToBytes(partitionId);
|
|
5271
|
-
} finally {
|
|
5272
|
-
release();
|
|
5273
|
-
}
|
|
5392
|
+
// src/distribution/cluster-node/replication-index.ts
|
|
5393
|
+
function isNestedSchema(value) {
|
|
5394
|
+
return typeof value === "object" && value !== null;
|
|
5274
5395
|
}
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
partition = deserializePayloadV2(bytes);
|
|
5282
|
-
} catch (err) {
|
|
5283
|
-
const cause = err instanceof Error ? err.message : String(err);
|
|
5284
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, `partition snapshot decode failed: ${cause}`, {
|
|
5285
|
-
indexName,
|
|
5286
|
-
partitionId,
|
|
5287
|
-
cause
|
|
5288
|
-
});
|
|
5289
|
-
}
|
|
5290
|
-
validatePartitionSnapshotPayload(indexName, partitionId, partitionCount, schema, partition);
|
|
5291
|
-
const trackPositions = core.indexRegistry.get(indexName)?.config.trackPositions ?? true;
|
|
5292
|
-
createPartitionIndex(partitionId, trackPositions).deserialize(partition, schema);
|
|
5293
|
-
let release = core.indexRegistry.has(indexName) ? await core.indexState.acquire(indexName, false) : null;
|
|
5294
|
-
try {
|
|
5295
|
-
const restoreIndex = await ensureReplicationIndex(
|
|
5296
|
-
core,
|
|
5297
|
-
engine,
|
|
5298
|
-
indexName,
|
|
5299
|
-
indexConfig,
|
|
5300
|
-
partition.language,
|
|
5301
|
-
partitionCount
|
|
5302
|
-
);
|
|
5303
|
-
if (release === null) release = await core.indexState.acquire(indexName, false);
|
|
5304
|
-
if (restoreIndex.created) {
|
|
5305
|
-
await core.orchestrator.replicateToWorkers({
|
|
5306
|
-
type: "createIndex",
|
|
5307
|
-
indexName,
|
|
5308
|
-
config: restoreIndex.config,
|
|
5309
|
-
requestId: `replicate-partition-index-${indexName}`
|
|
5310
|
-
});
|
|
5396
|
+
function flattenSchemaInto(schema, prefix, flat) {
|
|
5397
|
+
for (const [field, value] of Object.entries(schema)) {
|
|
5398
|
+
const path = prefix.length === 0 ? field : `${prefix}.${field}`;
|
|
5399
|
+
if (isNestedSchema(value)) {
|
|
5400
|
+
flattenSchemaInto(value, path, flat);
|
|
5401
|
+
continue;
|
|
5311
5402
|
}
|
|
5312
|
-
|
|
5313
|
-
manager.deserializePartition(partitionId, partition);
|
|
5314
|
-
await core.orchestrator.replicateToWorkers({
|
|
5315
|
-
type: "deserialize",
|
|
5316
|
-
indexName,
|
|
5317
|
-
partitionId,
|
|
5318
|
-
data: partition,
|
|
5319
|
-
requestId: `replicate-partition-restore-${indexName}-${partitionId}`
|
|
5320
|
-
});
|
|
5321
|
-
} finally {
|
|
5322
|
-
release?.();
|
|
5403
|
+
flat[path] = value;
|
|
5323
5404
|
}
|
|
5324
5405
|
}
|
|
5325
|
-
function
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
partitionId
|
|
5330
|
-
});
|
|
5331
|
-
}
|
|
5332
|
-
if (!Number.isInteger(partitionCount) || partitionCount <= 0 || partitionCount > MAX_PARTITION_COUNT) {
|
|
5333
|
-
throw new NarsilError(
|
|
5334
|
-
ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED,
|
|
5335
|
-
`partitionCount must be an integer between 1 and ${MAX_PARTITION_COUNT}`,
|
|
5336
|
-
{ indexName, partitionCount }
|
|
5337
|
-
);
|
|
5338
|
-
}
|
|
5339
|
-
if (partitionId >= partitionCount) {
|
|
5340
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "partitionId is outside partitionCount", {
|
|
5341
|
-
indexName,
|
|
5342
|
-
partitionId,
|
|
5343
|
-
partitionCount
|
|
5344
|
-
});
|
|
5345
|
-
}
|
|
5406
|
+
function flattenSchema(schema) {
|
|
5407
|
+
const flat = {};
|
|
5408
|
+
flattenSchemaInto(schema, "", flat);
|
|
5409
|
+
return flat;
|
|
5346
5410
|
}
|
|
5347
|
-
function
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
receivedIndexName: partition.indexName
|
|
5352
|
-
});
|
|
5353
|
-
}
|
|
5354
|
-
if (partition.partitionId !== partitionId) {
|
|
5355
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "partition snapshot partitionId mismatch", {
|
|
5356
|
-
indexName,
|
|
5357
|
-
expectedPartitionId: partitionId,
|
|
5358
|
-
receivedPartitionId: partition.partitionId
|
|
5359
|
-
});
|
|
5360
|
-
}
|
|
5361
|
-
if (partition.totalPartitions !== partitionCount) {
|
|
5362
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "partition snapshot partition count mismatch", {
|
|
5363
|
-
indexName,
|
|
5364
|
-
partitionId,
|
|
5365
|
-
expectedPartitionCount: partitionCount,
|
|
5366
|
-
receivedPartitionCount: partition.totalPartitions
|
|
5367
|
-
});
|
|
5368
|
-
}
|
|
5369
|
-
const expectedSchema = flattenSchema(schema);
|
|
5370
|
-
for (const [field, expectedType] of Object.entries(expectedSchema)) {
|
|
5371
|
-
if (partition.schema[field] !== expectedType) {
|
|
5372
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "partition snapshot schema mismatch", {
|
|
5411
|
+
function requireSameFlatSchema(indexName, expected, actual, what) {
|
|
5412
|
+
for (const [field, expectedType] of Object.entries(expected)) {
|
|
5413
|
+
if (actual[field] !== expectedType) {
|
|
5414
|
+
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, `${what} schema mismatch`, {
|
|
5373
5415
|
indexName,
|
|
5374
|
-
partitionId,
|
|
5375
5416
|
field,
|
|
5376
5417
|
expected: expectedType,
|
|
5377
|
-
received:
|
|
5418
|
+
received: actual[field] ?? "(absent)"
|
|
5378
5419
|
});
|
|
5379
5420
|
}
|
|
5380
5421
|
}
|
|
5381
|
-
for (const field of Object.keys(
|
|
5382
|
-
if (!(field in
|
|
5383
|
-
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED,
|
|
5422
|
+
for (const field of Object.keys(actual)) {
|
|
5423
|
+
if (!(field in expected)) {
|
|
5424
|
+
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, `${what} schema contains extra field`, {
|
|
5384
5425
|
indexName,
|
|
5385
|
-
partitionId,
|
|
5386
5426
|
field
|
|
5387
5427
|
});
|
|
5388
5428
|
}
|
|
@@ -5414,7 +5454,12 @@ async function ensureReplicationIndex(core, engine, indexName, coordinatorConfig
|
|
|
5414
5454
|
receivedLanguage: language.name
|
|
5415
5455
|
});
|
|
5416
5456
|
}
|
|
5417
|
-
|
|
5457
|
+
requireSameFlatSchema(
|
|
5458
|
+
indexName,
|
|
5459
|
+
flattenSchema(coordinatorConfig.schema),
|
|
5460
|
+
flattenSchema(entry.config.schema),
|
|
5461
|
+
"local index"
|
|
5462
|
+
);
|
|
5418
5463
|
const manager = core.requireManager(indexName);
|
|
5419
5464
|
if (manager.partitionCount > partitionCount) {
|
|
5420
5465
|
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, "local index has more partitions than allocation", {
|
|
@@ -5433,45 +5478,222 @@ async function ensureReplicationIndex(core, engine, indexName, coordinatorConfig
|
|
|
5433
5478
|
}
|
|
5434
5479
|
return { config: entry.config, created };
|
|
5435
5480
|
}
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5481
|
+
|
|
5482
|
+
// src/distribution/cluster-node/partition-archive.ts
|
|
5483
|
+
var VECTOR_FILE_ENVELOPE_VERSION = 2;
|
|
5484
|
+
async function archiveReplicationPartition(core, indexName, partitionId, lastSeqNo) {
|
|
5485
|
+
core.guardShutdown();
|
|
5486
|
+
const release = await core.indexState.acquire(indexName, false);
|
|
5487
|
+
try {
|
|
5488
|
+
const entry = core.requireIndex(indexName);
|
|
5489
|
+
const manager = core.requireManager(indexName);
|
|
5490
|
+
let captured = 0;
|
|
5491
|
+
const checkpoint = await buildArchiveFromMemory({
|
|
5492
|
+
indexName,
|
|
5493
|
+
metadata: indexMetadataOf(indexName, entry, manager.partitionCount),
|
|
5494
|
+
manager,
|
|
5495
|
+
vectorIndexes: manager.getVectorIndexes(),
|
|
5496
|
+
appliedSeqNo: () => {
|
|
5497
|
+
captured = lastSeqNo();
|
|
5498
|
+
return captured;
|
|
5499
|
+
},
|
|
5500
|
+
partitionId
|
|
5501
|
+
});
|
|
5502
|
+
const config = await encodeIndexConfiguration(entry);
|
|
5503
|
+
return { stream: archiveStream({ ...checkpoint, config, sourceIndexName: indexName }), lastSeqNo: captured };
|
|
5504
|
+
} finally {
|
|
5505
|
+
release();
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
function restoreFailed(message, details) {
|
|
5509
|
+
throw new NarsilError(ErrorCodes.SNAPSHOT_SYNC_RESTORE_FAILED, message, details);
|
|
5510
|
+
}
|
|
5511
|
+
function requireRestoreTarget(indexName, partitionId, partitionCount) {
|
|
5512
|
+
if (!Number.isInteger(partitionId) || partitionId < 0) {
|
|
5513
|
+
restoreFailed("partitionId must be a non-negative integer", { indexName, partitionId });
|
|
5514
|
+
}
|
|
5515
|
+
if (!Number.isInteger(partitionCount) || partitionCount <= 0 || partitionCount > MAX_PARTITION_COUNT) {
|
|
5516
|
+
restoreFailed(`partitionCount must be an integer between 1 and ${MAX_PARTITION_COUNT}`, {
|
|
5517
|
+
indexName,
|
|
5518
|
+
partitionCount
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5521
|
+
if (partitionId >= partitionCount) {
|
|
5522
|
+
restoreFailed("partitionId is outside partitionCount", { indexName, partitionId, partitionCount });
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5525
|
+
async function receiveArchive(indexName, partitionId, source, schema) {
|
|
5526
|
+
const store = memoryCheckpointStore();
|
|
5527
|
+
let language = "";
|
|
5528
|
+
let received = null;
|
|
5529
|
+
await readSnapshotArchive(createByteReader(source), {
|
|
5530
|
+
config: async (bytes) => {
|
|
5531
|
+
const { payload } = await openChecksummedEnvelope(bytes, {
|
|
5532
|
+
envelopeFormatVersion: 5,
|
|
5533
|
+
what: "index configuration",
|
|
5534
|
+
allowsCompression: true
|
|
5446
5535
|
});
|
|
5536
|
+
const raw = decode(payload);
|
|
5537
|
+
if (typeof raw.language !== "string") restoreFailed("partition archive names no language", { indexName });
|
|
5538
|
+
language = raw.language;
|
|
5539
|
+
},
|
|
5540
|
+
manifest: async (manifest, sourceName) => {
|
|
5541
|
+
const listed = manifest.partitions.map((partition) => partition.partitionId);
|
|
5542
|
+
if (listed.length !== 1 || listed[0] !== partitionId) {
|
|
5543
|
+
restoreFailed("partition archive lists other partitions", { indexName, partitionId, listed });
|
|
5544
|
+
}
|
|
5545
|
+
if (manifest.vectors.some((field) => field.graphParts.length > 0)) {
|
|
5546
|
+
restoreFailed("partition archive holds a graph", { indexName, partitionId });
|
|
5547
|
+
}
|
|
5548
|
+
requireSameFlatSchema(indexName, schema, manifest.schema, "partition snapshot");
|
|
5549
|
+
const rename = (key) => `${indexName}/${key.slice(sourceName.length + 1)}`;
|
|
5550
|
+
received = {
|
|
5551
|
+
...manifest,
|
|
5552
|
+
partitions: manifest.partitions.map((partition) => ({
|
|
5553
|
+
...partition,
|
|
5554
|
+
segments: partition.segments.map((segment) => ({ ...segment, key: rename(segment.key) }))
|
|
5555
|
+
})),
|
|
5556
|
+
vectors: manifest.vectors.map((field) => ({
|
|
5557
|
+
...field,
|
|
5558
|
+
files: field.files.map((file) => ({ ...file, key: rename(file.key) }))
|
|
5559
|
+
}))
|
|
5560
|
+
};
|
|
5561
|
+
},
|
|
5562
|
+
file: async (name, _ref, bytes) => store.write(`${indexName}/${name}`, [bytes])
|
|
5563
|
+
});
|
|
5564
|
+
if (received === null) restoreFailed("partition archive holds no manifest", { indexName, partitionId });
|
|
5565
|
+
return { language, manifest: received, store };
|
|
5566
|
+
}
|
|
5567
|
+
function emptyPartition(manager, partitionId) {
|
|
5568
|
+
return {
|
|
5569
|
+
indexName: manager.indexName,
|
|
5570
|
+
partitionId,
|
|
5571
|
+
totalPartitions: manager.partitionCount,
|
|
5572
|
+
language: manager.language.name,
|
|
5573
|
+
schema: {},
|
|
5574
|
+
docCount: 0,
|
|
5575
|
+
avgDocLength: 0,
|
|
5576
|
+
documents: {},
|
|
5577
|
+
invertedIndex: {},
|
|
5578
|
+
fieldIndexes: { numeric: {}, boolean: {}, enum: {}, geopoint: {} },
|
|
5579
|
+
statistics: { totalDocuments: 0, totalFieldLengths: {}, averageFieldLengths: {}, docFrequencies: {} }
|
|
5580
|
+
};
|
|
5581
|
+
}
|
|
5582
|
+
async function replacePartition(manager, partitionId, archive) {
|
|
5583
|
+
const vectorIndexes = manager.getVectorIndexes();
|
|
5584
|
+
const held = [...manager.getPartition(partitionId).docIds()];
|
|
5585
|
+
for (const vectorIndex of vectorIndexes.values()) {
|
|
5586
|
+
for (const docId of held) if (vectorIndex.has(docId)) vectorIndex.remove(docId);
|
|
5587
|
+
}
|
|
5588
|
+
manager.deserializePartition(partitionId, emptyPartition(manager, partitionId));
|
|
5589
|
+
const entry = archive.manifest.partitions[0];
|
|
5590
|
+
if (entry !== void 0) {
|
|
5591
|
+
await loadPartitionSegments(archive.store, entry, manager, {
|
|
5592
|
+
schema: archive.manifest.schema,
|
|
5593
|
+
decodesEveryDocument: true
|
|
5594
|
+
});
|
|
5595
|
+
}
|
|
5596
|
+
for (const field of archive.manifest.vectors) {
|
|
5597
|
+
const vectorIndex = vectorIndexes.get(field.fieldPath);
|
|
5598
|
+
if (vectorIndex === void 0) continue;
|
|
5599
|
+
for (const file of field.files) {
|
|
5600
|
+
const bytes = await readListedFile(archive.store, file.key, { bytes: file.bytes, what: "vector file" });
|
|
5601
|
+
const { payload } = await openChecksummedEnvelope(bytes, {
|
|
5602
|
+
envelopeFormatVersion: VECTOR_FILE_ENVELOPE_VERSION,
|
|
5603
|
+
what: `vector file "${file.key}"`,
|
|
5604
|
+
allowsCompression: false
|
|
5605
|
+
});
|
|
5606
|
+
const decoded = decodeVectorFilePayload(decode(payload));
|
|
5607
|
+
const vectors = bytesToVectors(decoded.vectors);
|
|
5608
|
+
for (let i = 0; i < decoded.docIds.length; i++) {
|
|
5609
|
+
if (isDead(file.dead, i)) continue;
|
|
5610
|
+
const vector = vectors.slice(i * decoded.dimension, (i + 1) * decoded.dimension);
|
|
5611
|
+
vectorIndex.insert(decoded.docIds[i], vector, partitionId);
|
|
5612
|
+
}
|
|
5447
5613
|
}
|
|
5614
|
+
vectorIndex.scheduleBuild();
|
|
5448
5615
|
}
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5616
|
+
}
|
|
5617
|
+
async function restoreReplicationPartition(core, engine, indexName, partitionId, source, indexConfig, partitionCount) {
|
|
5618
|
+
core.guardShutdown();
|
|
5619
|
+
requireRestoreTarget(indexName, partitionId, partitionCount);
|
|
5620
|
+
const archive = await receiveArchive(indexName, partitionId, source, flattenSchema(indexConfig.schema));
|
|
5621
|
+
let release = core.indexRegistry.has(indexName) ? await core.indexState.acquire(indexName, false) : null;
|
|
5622
|
+
try {
|
|
5623
|
+
const restoreIndex = await ensureReplicationIndex(
|
|
5624
|
+
core,
|
|
5625
|
+
engine,
|
|
5626
|
+
indexName,
|
|
5627
|
+
indexConfig,
|
|
5628
|
+
archive.language,
|
|
5629
|
+
partitionCount
|
|
5630
|
+
);
|
|
5631
|
+
if (release === null) release = await core.indexState.acquire(indexName, false);
|
|
5632
|
+
if (restoreIndex.created) {
|
|
5633
|
+
await core.orchestrator.replicateToWorkers({
|
|
5634
|
+
type: "createIndex",
|
|
5452
5635
|
indexName,
|
|
5453
|
-
|
|
5636
|
+
config: restoreIndex.config,
|
|
5637
|
+
requestId: `replicate-partition-index-${indexName}`
|
|
5454
5638
|
});
|
|
5455
5639
|
}
|
|
5640
|
+
const wasScaledOut = core.orchestrator.desyncIndex(indexName);
|
|
5641
|
+
try {
|
|
5642
|
+
await replacePartition(core.requireManager(indexName), partitionId, archive);
|
|
5643
|
+
} finally {
|
|
5644
|
+
await core.orchestrator.resyncIndex(indexName, wasScaledOut);
|
|
5645
|
+
}
|
|
5646
|
+
} finally {
|
|
5647
|
+
release?.();
|
|
5456
5648
|
}
|
|
5457
5649
|
}
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5650
|
+
|
|
5651
|
+
// src/distribution/cluster-node/local-engine.ts
|
|
5652
|
+
async function createClusterLocalEngine(config, hooks) {
|
|
5653
|
+
requireKnownConfig(config);
|
|
5654
|
+
const runnableConfig = await resolveRunnableConfig(config);
|
|
5655
|
+
const core = createEngineCore(runnableConfig, hooks, "partition");
|
|
5656
|
+
await startEngineCore(core, runnableConfig);
|
|
5657
|
+
core.orchestrator.shareMainThread();
|
|
5658
|
+
const engine = createNarsilFromCore(core, runnableConfig);
|
|
5659
|
+
const heldPartitions = createHeldPartitionRecord(core);
|
|
5660
|
+
return Object.assign(engine, {
|
|
5661
|
+
createIndex: (name, indexConfig) => createEngineIndex(core, runnableConfig, name, indexConfig, { adapterBinding: "deferred" }),
|
|
5662
|
+
createIndexWithUuid: (name, indexConfig, indexUuid) => createEngineIndex(core, runnableConfig, name, indexConfig, { indexUuid }),
|
|
5663
|
+
acquireIndexForReplication: (indexName) => core.indexState.acquire(indexName, false),
|
|
5664
|
+
indexUuidOf: (indexName) => core.indexRegistry.get(indexName)?.indexUuid,
|
|
5665
|
+
stampIndexUuid: (indexName, indexUuid) => stampIndexUuid(core, indexName, indexUuid),
|
|
5666
|
+
highestPersistedSeqNoOf: (indexName, partitionId) => core.durability?.manager.highestPersistedSeqNo(indexName, partitionId) ?? 0,
|
|
5667
|
+
heldPartitionsOf: (indexName) => heldPartitions.held(indexName),
|
|
5668
|
+
recordHeldPartition: (indexName, partitionId) => heldPartitions.record(indexName, partitionId),
|
|
5669
|
+
forgetHeldPartition: (indexName, partitionId) => heldPartitions.forget(indexName, partitionId),
|
|
5670
|
+
applyReplicationEntry: (entry) => applyLocalReplicationEntry(core, entry),
|
|
5671
|
+
archiveReplicationPartition: (indexName, partitionId, lastSeqNo) => archiveReplicationPartition(core, indexName, partitionId, lastSeqNo),
|
|
5672
|
+
restoreReplicationPartition: (indexName, partitionId, source, indexConfig, partitionCount) => restoreReplicationPartition(core, engine, indexName, partitionId, source, indexConfig, partitionCount),
|
|
5673
|
+
queryPartitions: (indexName, params, partitionIds, globalStats) => runEngineQuery(core, indexName, params, { partitionIds, globalStats }),
|
|
5674
|
+
preflightPartitions: (indexName, params, partitionIds) => runEnginePreflight(core, indexName, params, { partitionIds }),
|
|
5675
|
+
suggestPartitions: (indexName, params, partitionIds) => runEngineSuggest(core, indexName, params, partitionIds),
|
|
5676
|
+
listPartitions: (indexName, params, partitionIds) => runEngineListDocuments(core, indexName, params, partitionIds),
|
|
5677
|
+
collectQueryStats: (indexName, terms, partitionIds) => runEngineQueryStats(core, indexName, terms, partitionIds),
|
|
5678
|
+
partitionStatsForRead: async (indexName) => {
|
|
5679
|
+
const release = await core.indexState.acquire(indexName);
|
|
5680
|
+
try {
|
|
5681
|
+
return core.requireManager(indexName).getPartitionStats();
|
|
5682
|
+
} finally {
|
|
5683
|
+
release();
|
|
5684
|
+
}
|
|
5469
5685
|
}
|
|
5470
|
-
|
|
5471
|
-
}
|
|
5686
|
+
});
|
|
5472
5687
|
}
|
|
5473
|
-
function
|
|
5474
|
-
|
|
5688
|
+
async function stampIndexUuid(core, indexName, indexUuid) {
|
|
5689
|
+
const entry = core.indexRegistry.get(indexName);
|
|
5690
|
+
if (entry === void 0 || entry.indexUuid === indexUuid) {
|
|
5691
|
+
return;
|
|
5692
|
+
}
|
|
5693
|
+
core.indexRegistry.set(indexName, { ...entry, indexUuid });
|
|
5694
|
+
if (core.durability !== null) {
|
|
5695
|
+
await core.durability.manager.persistMetadata(indexName);
|
|
5696
|
+
}
|
|
5475
5697
|
}
|
|
5476
5698
|
|
|
5477
5699
|
// src/distribution/cluster-node/local-index-reconcile.ts
|
|
@@ -5584,6 +5806,25 @@ async function authorizeSnapshotRequest(coordinator, indexName, sourceId) {
|
|
|
5584
5806
|
}
|
|
5585
5807
|
|
|
5586
5808
|
// src/distribution/cluster-node/snapshot-cache.ts
|
|
5809
|
+
function soleSnapshotLease(build) {
|
|
5810
|
+
return { build, release: () => build.discard() };
|
|
5811
|
+
}
|
|
5812
|
+
function sharedLease(entry, build) {
|
|
5813
|
+
let released = false;
|
|
5814
|
+
return {
|
|
5815
|
+
build,
|
|
5816
|
+
async release() {
|
|
5817
|
+
if (released) return;
|
|
5818
|
+
released = true;
|
|
5819
|
+
entry.holders -= 1;
|
|
5820
|
+
if (entry.holders === 0) await build.discard();
|
|
5821
|
+
}
|
|
5822
|
+
};
|
|
5823
|
+
}
|
|
5824
|
+
async function joinSnapshotBuild(entry) {
|
|
5825
|
+
entry.holders += 1;
|
|
5826
|
+
return sharedLease(entry, await entry.promise);
|
|
5827
|
+
}
|
|
5587
5828
|
function createSnapshotCacheState(maxConcurrent = DEFAULT_MAX_CONCURRENT_SNAPSHOTS, maxPerSource = DEFAULT_MAX_PER_SOURCE_SNAPSHOTS, maxStreamsPerIndex = DEFAULT_MAX_STREAMS_PER_INDEX) {
|
|
5588
5829
|
if (!Number.isInteger(maxConcurrent) || maxConcurrent <= 0) {
|
|
5589
5830
|
throw new NarsilError(ErrorCodes.CONFIG_INVALID, "maxConcurrent must be a positive integer", {
|
|
@@ -5671,7 +5912,7 @@ function releaseStreamSlot(state, handle) {
|
|
|
5671
5912
|
async function acquireSnapshotBuild(state, indexName, builder) {
|
|
5672
5913
|
const existing = state.cache.get(indexName);
|
|
5673
5914
|
if (existing !== void 0) {
|
|
5674
|
-
return existing
|
|
5915
|
+
return joinSnapshotBuild(existing);
|
|
5675
5916
|
}
|
|
5676
5917
|
if (state.active >= state.maxConcurrent) {
|
|
5677
5918
|
throw new NarsilError(
|
|
@@ -5694,7 +5935,7 @@ async function acquireSnapshotBuild(state, indexName, builder) {
|
|
|
5694
5935
|
state.active = Math.max(0, state.active - 1);
|
|
5695
5936
|
};
|
|
5696
5937
|
const rawBuild = (async () => builder())();
|
|
5697
|
-
const entry = { promise: rawBuild };
|
|
5938
|
+
const entry = { promise: rawBuild, holders: 0 };
|
|
5698
5939
|
entry.promise = rawBuild.then(
|
|
5699
5940
|
(result) => {
|
|
5700
5941
|
clearEntry(entry);
|
|
@@ -5706,7 +5947,7 @@ async function acquireSnapshotBuild(state, indexName, builder) {
|
|
|
5706
5947
|
}
|
|
5707
5948
|
);
|
|
5708
5949
|
state.cache.set(indexName, entry);
|
|
5709
|
-
return entry
|
|
5950
|
+
return joinSnapshotBuild(entry);
|
|
5710
5951
|
}
|
|
5711
5952
|
var SNAPSHOT_SYNC_ERROR_TYPE = `${ReplicationMessageTypes.SNAPSHOT_SYNC_REQUEST}.error`;
|
|
5712
5953
|
function createSingleResponseSink(respond) {
|
|
@@ -5720,8 +5961,7 @@ function createSingleResponseSink(respond) {
|
|
|
5720
5961
|
return sink;
|
|
5721
5962
|
}
|
|
5722
5963
|
async function streamSnapshotToReplica(sink, nodeId, requestId, indexName, build, metadata, options = {}) {
|
|
5723
|
-
const
|
|
5724
|
-
const totalBytes = snapshotBytes.byteLength;
|
|
5964
|
+
const totalBytes = build.totalBytes;
|
|
5725
5965
|
const checksum = build.checksum;
|
|
5726
5966
|
const header = {
|
|
5727
5967
|
lastSeqNo: metadata.lastSeqNo,
|
|
@@ -5737,22 +5977,23 @@ async function streamSnapshotToReplica(sink, nodeId, requestId, indexName, build
|
|
|
5737
5977
|
await yieldToEventLoop();
|
|
5738
5978
|
let offset = 0;
|
|
5739
5979
|
let lastYieldAt = now2();
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5980
|
+
for await (const source of build.read()) {
|
|
5981
|
+
for (let from = 0; from < source.byteLength; from += SNAPSHOT_CHUNK_SIZE) {
|
|
5982
|
+
const chunk = source.subarray(from, Math.min(from + SNAPSHOT_CHUNK_SIZE, source.byteLength));
|
|
5983
|
+
const chunkPayload = {
|
|
5984
|
+
partitionId: metadata.partitionId,
|
|
5985
|
+
indexName,
|
|
5986
|
+
offset,
|
|
5987
|
+
data: chunk
|
|
5988
|
+
};
|
|
5989
|
+
const chunkBytes = encode(chunkPayload);
|
|
5990
|
+
assertMessageWithinLimit(chunkBytes, "SNAPSHOT_CHUNK");
|
|
5991
|
+
await respondMessage(sink, ReplicationMessageTypes.SNAPSHOT_CHUNK, nodeId, requestId, chunkBytes);
|
|
5992
|
+
offset += chunk.byteLength;
|
|
5993
|
+
if (offset < totalBytes && now2() - lastYieldAt >= SNAPSHOT_CHUNK_YIELD_INTERVAL_MS) {
|
|
5994
|
+
await yieldToEventLoop();
|
|
5995
|
+
lastYieldAt = now2();
|
|
5996
|
+
}
|
|
5756
5997
|
}
|
|
5757
5998
|
}
|
|
5758
5999
|
await yieldToEventLoop();
|
|
@@ -5833,6 +6074,26 @@ async function defaultSnapshotHeaderMetadataProvider(coordinator, indexName) {
|
|
|
5833
6074
|
lastSeqNo: SNAPSHOT_HEADER_SENTINEL_SEQNO
|
|
5834
6075
|
};
|
|
5835
6076
|
}
|
|
6077
|
+
async function nodeSnapshotHeaderMetadata(deps, indexName, partitionId) {
|
|
6078
|
+
const fallback = await defaultSnapshotHeaderMetadataProvider(deps.coordinator, indexName);
|
|
6079
|
+
if (partitionId === null) {
|
|
6080
|
+
return fallback;
|
|
6081
|
+
}
|
|
6082
|
+
const localIndex = deps.engine.listIndexes().find((index) => index.name === indexName);
|
|
6083
|
+
const release = localIndex !== void 0 ? await deps.engine.acquireIndexForReplication(indexName) : null;
|
|
6084
|
+
try {
|
|
6085
|
+
const allocation = await deps.coordinator.getAllocation(indexName);
|
|
6086
|
+
const assignment = allocation?.assignments.get(partitionId);
|
|
6087
|
+
const log = deps.getReplicationLog(indexName, partitionId);
|
|
6088
|
+
return {
|
|
6089
|
+
partitionId,
|
|
6090
|
+
primaryTerm: assignment?.primaryTerm ?? fallback.primaryTerm,
|
|
6091
|
+
lastSeqNo: log.newestSeqNo ?? 0
|
|
6092
|
+
};
|
|
6093
|
+
} finally {
|
|
6094
|
+
release?.();
|
|
6095
|
+
}
|
|
6096
|
+
}
|
|
5836
6097
|
async function resolveHeaderMetadata(deps, indexName, partitionId) {
|
|
5837
6098
|
const provider = deps.resolveHeaderMetadata;
|
|
5838
6099
|
if (provider === void 0) {
|
|
@@ -5862,55 +6123,56 @@ async function acquireAndStream(message, sink, request, deps, options) {
|
|
|
5862
6123
|
return;
|
|
5863
6124
|
}
|
|
5864
6125
|
try {
|
|
5865
|
-
let
|
|
6126
|
+
let lease;
|
|
5866
6127
|
try {
|
|
5867
6128
|
const buildForRequest = async () => buildSnapshotForRequest(deps, indexName, options);
|
|
5868
|
-
|
|
6129
|
+
lease = options.disableBuildCache === true ? soleSnapshotLease(await buildForRequest()) : await acquireSnapshotBuild(deps.state, indexName, buildForRequest);
|
|
5869
6130
|
} catch (err) {
|
|
5870
6131
|
const code = err instanceof NarsilError ? err.code : ErrorCodes.SNAPSHOT_SYNC_SNAPSHOT_FAILED;
|
|
5871
6132
|
const errMessage = err instanceof Error ? err.message : String(err);
|
|
5872
6133
|
await respondError(sink, deps.nodeId, message.requestId, code, errMessage);
|
|
5873
6134
|
return;
|
|
5874
6135
|
}
|
|
5875
|
-
if (build.bytes.byteLength > MAX_SNAPSHOT_SIZE_BYTES) {
|
|
5876
|
-
await respondError(
|
|
5877
|
-
sink,
|
|
5878
|
-
deps.nodeId,
|
|
5879
|
-
message.requestId,
|
|
5880
|
-
ErrorCodes.SNAPSHOT_SYNC_TOO_LARGE,
|
|
5881
|
-
`Snapshot size ${build.bytes.byteLength} exceeds the ${MAX_SNAPSHOT_SIZE_BYTES} byte limit`
|
|
5882
|
-
);
|
|
5883
|
-
return;
|
|
5884
|
-
}
|
|
5885
|
-
let streamHandle;
|
|
5886
|
-
try {
|
|
5887
|
-
streamHandle = acquireStreamSlot(deps.state, indexName);
|
|
5888
|
-
} catch (err) {
|
|
5889
|
-
const code = err instanceof NarsilError ? err.code : ErrorCodes.SNAPSHOT_SYNC_CAPACITY_EXHAUSTED;
|
|
5890
|
-
const errMessage = err instanceof Error ? err.message : String(err);
|
|
5891
|
-
await respondError(sink, deps.nodeId, message.requestId, code, errMessage);
|
|
5892
|
-
return;
|
|
5893
|
-
}
|
|
5894
6136
|
try {
|
|
5895
|
-
|
|
5896
|
-
await streamSnapshotToReplica(sink, deps.nodeId, message.requestId, indexName, build, metadata, {
|
|
5897
|
-
closeOnEnd: options.closeOnEnd
|
|
5898
|
-
});
|
|
5899
|
-
await options.afterSnapshot?.(sink);
|
|
5900
|
-
if (options.closeOnEnd === false) {
|
|
5901
|
-
sink.closed = true;
|
|
5902
|
-
}
|
|
6137
|
+
await streamLeasedSnapshot(message, sink, request, deps, options, lease.build);
|
|
5903
6138
|
} finally {
|
|
5904
|
-
|
|
6139
|
+
await lease.release();
|
|
5905
6140
|
}
|
|
5906
6141
|
} finally {
|
|
5907
6142
|
releaseSourceSlot(deps.state, sourceHandle);
|
|
5908
6143
|
}
|
|
5909
6144
|
}
|
|
6145
|
+
async function streamLeasedSnapshot(message, sink, request, deps, options, build) {
|
|
6146
|
+
const { indexName } = request;
|
|
6147
|
+
let streamHandle;
|
|
6148
|
+
try {
|
|
6149
|
+
streamHandle = acquireStreamSlot(deps.state, indexName);
|
|
6150
|
+
} catch (err) {
|
|
6151
|
+
const code = err instanceof NarsilError ? err.code : ErrorCodes.SNAPSHOT_SYNC_CAPACITY_EXHAUSTED;
|
|
6152
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
6153
|
+
await respondError(sink, deps.nodeId, message.requestId, code, errMessage);
|
|
6154
|
+
return;
|
|
6155
|
+
}
|
|
6156
|
+
try {
|
|
6157
|
+
const resolved = options.metadata ?? await resolveHeaderMetadata(deps, indexName, request.partitionId ?? null);
|
|
6158
|
+
const metadata = build.lastSeqNo === void 0 ? resolved : { ...resolved, lastSeqNo: build.lastSeqNo };
|
|
6159
|
+
await streamSnapshotToReplica(sink, deps.nodeId, message.requestId, indexName, build, metadata, {
|
|
6160
|
+
closeOnEnd: options.closeOnEnd
|
|
6161
|
+
});
|
|
6162
|
+
await options.afterSnapshot?.(sink, build);
|
|
6163
|
+
if (options.closeOnEnd === false) {
|
|
6164
|
+
sink.closed = true;
|
|
6165
|
+
}
|
|
6166
|
+
} finally {
|
|
6167
|
+
releaseStreamSlot(deps.state, streamHandle);
|
|
6168
|
+
}
|
|
6169
|
+
}
|
|
5910
6170
|
async function buildSnapshot(deps, indexName) {
|
|
5911
|
-
let bytes;
|
|
5912
6171
|
try {
|
|
5913
|
-
|
|
6172
|
+
return await spoolSnapshotStream(
|
|
6173
|
+
deps.spoolDirectory ?? defaultSpoolDirectory(),
|
|
6174
|
+
await deps.engine.snapshot(indexName)
|
|
6175
|
+
);
|
|
5914
6176
|
} catch (err) {
|
|
5915
6177
|
if (err instanceof NarsilError) {
|
|
5916
6178
|
throw err;
|
|
@@ -5921,8 +6183,6 @@ async function buildSnapshot(deps, indexName) {
|
|
|
5921
6183
|
cause: errMessage
|
|
5922
6184
|
});
|
|
5923
6185
|
}
|
|
5924
|
-
const checksum = bytes.byteLength <= MAX_SNAPSHOT_SIZE_BYTES ? crc32(bytes) : 0;
|
|
5925
|
-
return { bytes, checksum };
|
|
5926
6186
|
}
|
|
5927
6187
|
function buildSnapshotForRequest(deps, indexName, options) {
|
|
5928
6188
|
if (options.buildSnapshot !== void 0) {
|
|
@@ -6131,7 +6391,6 @@ var MAX_FACET_VALUE_LENGTH = 1024;
|
|
|
6131
6391
|
var MAX_GROUPS_PER_RESPONSE = 65536;
|
|
6132
6392
|
var MAX_FACET_SIZE = 1e3;
|
|
6133
6393
|
var DEFAULT_MAX_FACET_BUCKETS = 100;
|
|
6134
|
-
var MAX_VECTOR_DIMENSION = 8192;
|
|
6135
6394
|
var MAX_VECTOR_TEXT_LENGTH = 16384;
|
|
6136
6395
|
|
|
6137
6396
|
// src/distribution/query/validators/common.ts
|
|
@@ -6867,11 +7126,11 @@ function validateVectorParams(value) {
|
|
|
6867
7126
|
);
|
|
6868
7127
|
}
|
|
6869
7128
|
const dims = value.value.length;
|
|
6870
|
-
if (dims === 0 || dims >
|
|
7129
|
+
if (dims === 0 || dims > MAX_STORED_VECTOR_DIMENSION) {
|
|
6871
7130
|
throwInvalid(
|
|
6872
7131
|
CONFIG_INVALID,
|
|
6873
|
-
`Invalid SearchPayload: "params.vector.value" length must be between 1 and ${
|
|
6874
|
-
{ length: dims, limit:
|
|
7132
|
+
`Invalid SearchPayload: "params.vector.value" length must be between 1 and ${MAX_STORED_VECTOR_DIMENSION}`,
|
|
7133
|
+
{ length: dims, limit: MAX_STORED_VECTOR_DIMENSION }
|
|
6875
7134
|
);
|
|
6876
7135
|
}
|
|
6877
7136
|
for (let i = 0; i < dims; i++) {
|
|
@@ -8073,6 +8332,8 @@ function toWireSortValue2(value) {
|
|
|
8073
8332
|
if (typeof value === "boolean") return value;
|
|
8074
8333
|
return null;
|
|
8075
8334
|
}
|
|
8335
|
+
|
|
8336
|
+
// src/distribution/replication/sync-primary.ts
|
|
8076
8337
|
function decideSyncTier(log, replicaLastSeqNo) {
|
|
8077
8338
|
const oldest = log.oldestSeqNo;
|
|
8078
8339
|
if (oldest === void 0) {
|
|
@@ -8194,7 +8455,8 @@ async function handleSyncRequestMessage(message, respond, deps) {
|
|
|
8194
8455
|
engine: deps.engine,
|
|
8195
8456
|
coordinator: deps.coordinator,
|
|
8196
8457
|
state: deps.snapshotSyncState,
|
|
8197
|
-
resolveHeaderMetadata: deps.resolveHeaderMetadata
|
|
8458
|
+
resolveHeaderMetadata: deps.resolveHeaderMetadata,
|
|
8459
|
+
spoolDirectory: deps.snapshotSpoolDirectory
|
|
8198
8460
|
},
|
|
8199
8461
|
{
|
|
8200
8462
|
metadata: {
|
|
@@ -8205,11 +8467,16 @@ async function handleSyncRequestMessage(message, respond, deps) {
|
|
|
8205
8467
|
closeOnEnd: false,
|
|
8206
8468
|
disableBuildCache: true,
|
|
8207
8469
|
buildSnapshot: async () => {
|
|
8208
|
-
const
|
|
8209
|
-
|
|
8470
|
+
const archive = await deps.engine.archiveReplicationPartition(
|
|
8471
|
+
request.indexName,
|
|
8472
|
+
request.partitionId,
|
|
8473
|
+
() => log.localLogEnd
|
|
8474
|
+
);
|
|
8475
|
+
const directory = deps.snapshotSpoolDirectory ?? defaultSpoolDirectory();
|
|
8476
|
+
return { ...await spoolSnapshotStream(directory, archive.stream), lastSeqNo: archive.lastSeqNo };
|
|
8210
8477
|
},
|
|
8211
|
-
afterSnapshot: async (trailingSink) => {
|
|
8212
|
-
const entries = log.getEntriesFrom(snapshotSeqNo + 1);
|
|
8478
|
+
afterSnapshot: async (trailingSink, build) => {
|
|
8479
|
+
const entries = log.getEntriesFrom((build.lastSeqNo ?? snapshotSeqNo) + 1);
|
|
8213
8480
|
await sendSyncEntriesResponse(message, trailingSink, deps, entries);
|
|
8214
8481
|
}
|
|
8215
8482
|
}
|
|
@@ -8325,7 +8592,7 @@ async function forwardInsertToRemote(indexName, document, docId, primaryNodeId,
|
|
|
8325
8592
|
indexName,
|
|
8326
8593
|
documentId: docId,
|
|
8327
8594
|
operation: "insert",
|
|
8328
|
-
document:
|
|
8595
|
+
document: encodeDocument(document),
|
|
8329
8596
|
updateFields: null
|
|
8330
8597
|
};
|
|
8331
8598
|
const message = createForwardMessage(payload, deps.nodeId);
|
|
@@ -8345,7 +8612,7 @@ async function forwardUpdateToRemote(indexName, document, docId, primaryNodeId,
|
|
|
8345
8612
|
indexName,
|
|
8346
8613
|
documentId: docId,
|
|
8347
8614
|
operation: "update",
|
|
8348
|
-
document:
|
|
8615
|
+
document: encodeDocument(document),
|
|
8349
8616
|
updateFields: null
|
|
8350
8617
|
};
|
|
8351
8618
|
const message = createForwardMessage(payload, deps.nodeId);
|
|
@@ -8371,6 +8638,8 @@ async function sendToNode(nodeId, message, deps) {
|
|
|
8371
8638
|
details: { targetNodeId: nodeId }
|
|
8372
8639
|
});
|
|
8373
8640
|
}
|
|
8641
|
+
|
|
8642
|
+
// src/distribution/cluster-node/write-routing/replication.ts
|
|
8374
8643
|
async function assertPrimaryWriteAuthority(entry, deps) {
|
|
8375
8644
|
const table = await deps.coordinator.getAllocation(entry.indexName);
|
|
8376
8645
|
const currentAssignment = table?.assignments.get(entry.partitionId);
|
|
@@ -8400,7 +8669,7 @@ function appendIndexReplicationEntry(indexName, partitionId, assignment, documen
|
|
|
8400
8669
|
partitionId,
|
|
8401
8670
|
indexName,
|
|
8402
8671
|
documentId,
|
|
8403
|
-
document:
|
|
8672
|
+
document: encodeDocument(document)
|
|
8404
8673
|
});
|
|
8405
8674
|
}
|
|
8406
8675
|
function appendDeleteReplicationEntry(indexName, partitionId, assignment, documentId, deps) {
|
|
@@ -8884,7 +9153,7 @@ function toWireOperation(item) {
|
|
|
8884
9153
|
return {
|
|
8885
9154
|
documentId: item.documentId,
|
|
8886
9155
|
operation: item.operation,
|
|
8887
|
-
document: item.document === null ? null :
|
|
9156
|
+
document: item.document === null ? null : encodeDocument(item.document),
|
|
8888
9157
|
updateFields: null
|
|
8889
9158
|
};
|
|
8890
9159
|
}
|
|
@@ -9291,9 +9560,14 @@ function validateCreateIndexOptions(partitionCount, replicationFactor) {
|
|
|
9291
9560
|
async function routeCreateIndex(name, requestedConfig, options, coordinator, engine) {
|
|
9292
9561
|
validateIndexName(name);
|
|
9293
9562
|
const config = { ...requestedConfig, schema: validateSchema(requestedConfig.schema) };
|
|
9563
|
+
requireCreatableSchema(config.schema);
|
|
9294
9564
|
const partitionCount = options?.partitionCount ?? DEFAULT_PARTITION_COUNT;
|
|
9295
9565
|
const replicationFactor = options?.replicationFactor ?? DEFAULT_REPLICATION_FACTOR;
|
|
9296
9566
|
validateCreateIndexOptions(partitionCount, replicationFactor);
|
|
9567
|
+
requireConfigurationWithinSizeLimit(
|
|
9568
|
+
withPartitionCount(config, partitionCount),
|
|
9569
|
+
getLanguage(config.language ?? "english")
|
|
9570
|
+
);
|
|
9297
9571
|
const constraints = {
|
|
9298
9572
|
zoneAwareness: false,
|
|
9299
9573
|
zoneAttribute: "zone",
|
|
@@ -9574,7 +9848,8 @@ function createDataNodeHandler(deps) {
|
|
|
9574
9848
|
engine: deps.engine,
|
|
9575
9849
|
coordinator: deps.coordinator,
|
|
9576
9850
|
state: deps.snapshotSyncState,
|
|
9577
|
-
resolveHeaderMetadata: deps.resolveHeaderMetadata
|
|
9851
|
+
resolveHeaderMetadata: deps.resolveHeaderMetadata,
|
|
9852
|
+
spoolDirectory: deps.snapshotSpoolDirectory
|
|
9578
9853
|
});
|
|
9579
9854
|
return;
|
|
9580
9855
|
}
|
|
@@ -11529,6 +11804,10 @@ async function createClusterNode(config) {
|
|
|
11529
11804
|
onIndexClose: (indexName) => deleteIndexReplicationLogs(replicationLogs, indexName)
|
|
11530
11805
|
});
|
|
11531
11806
|
localEngine = engine;
|
|
11807
|
+
const snapshotSpool = await openSnapshotSpoolDirectory(config.engine?.durability?.directory).catch(async (err) => {
|
|
11808
|
+
await engine.shutdown();
|
|
11809
|
+
throw err;
|
|
11810
|
+
});
|
|
11532
11811
|
function replicationLogKey2(indexName, partitionId) {
|
|
11533
11812
|
return replicationLogKey(indexName, partitionId);
|
|
11534
11813
|
}
|
|
@@ -11588,7 +11867,8 @@ async function createClusterNode(config) {
|
|
|
11588
11867
|
resetReplicationLog: seedReplicationLog2,
|
|
11589
11868
|
applyReplicationEntry: engine.applyReplicationEntry,
|
|
11590
11869
|
restoreReplicationPartition: engine.restoreReplicationPartition,
|
|
11591
|
-
onError: forwardOnError
|
|
11870
|
+
onError: forwardOnError,
|
|
11871
|
+
snapshotSpoolDirectory: snapshotSpool.path
|
|
11592
11872
|
};
|
|
11593
11873
|
const primaryPartitionDeps = {
|
|
11594
11874
|
engine,
|
|
@@ -11720,6 +12000,7 @@ async function createClusterNode(config) {
|
|
|
11720
12000
|
coordinator: config.coordinator,
|
|
11721
12001
|
writeDeps,
|
|
11722
12002
|
snapshotSyncState: snapshotSyncHandlerState,
|
|
12003
|
+
snapshotSpoolDirectory: snapshotSpool.path,
|
|
11723
12004
|
resolveHeaderMetadata: resolveSnapshotHeaderMetadata,
|
|
11724
12005
|
isBootstrapSynced: (indexName, partitionId) => hasCompletedBootstrapSync(bootstrapSyncState, indexName, partitionId)
|
|
11725
12006
|
});
|
|
@@ -11751,28 +12032,16 @@ async function createClusterNode(config) {
|
|
|
11751
12032
|
}
|
|
11752
12033
|
await Promise.all([...heldPartitionWrites]);
|
|
11753
12034
|
await engine.shutdown();
|
|
12035
|
+
await snapshotSpool.dispose();
|
|
11754
12036
|
}
|
|
11755
12037
|
};
|
|
11756
12038
|
return node;
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
const release = localIndex !== void 0 ? await engine.acquireIndexForReplication(indexName) : null;
|
|
11764
|
-
try {
|
|
11765
|
-
const allocation = await config.coordinator.getAllocation(indexName);
|
|
11766
|
-
const assignment = allocation?.assignments.get(partitionId);
|
|
11767
|
-
const log = getReplicationLog2(indexName, partitionId);
|
|
11768
|
-
return {
|
|
11769
|
-
partitionId,
|
|
11770
|
-
primaryTerm: assignment?.primaryTerm ?? fallback.primaryTerm,
|
|
11771
|
-
lastSeqNo: log.newestSeqNo ?? 0
|
|
11772
|
-
};
|
|
11773
|
-
} finally {
|
|
11774
|
-
release?.();
|
|
11775
|
-
}
|
|
12039
|
+
function resolveSnapshotHeaderMetadata(indexName, partitionId) {
|
|
12040
|
+
return nodeSnapshotHeaderMetadata(
|
|
12041
|
+
{ coordinator: config.coordinator, engine, getReplicationLog: getReplicationLog2 },
|
|
12042
|
+
indexName,
|
|
12043
|
+
partitionId
|
|
12044
|
+
);
|
|
11776
12045
|
}
|
|
11777
12046
|
}
|
|
11778
12047
|
|
|
@@ -11875,6 +12144,8 @@ function clusterNodeEngine(node, options) {
|
|
|
11875
12144
|
rebuildAnalysis: () => unsupported("rebuildAnalysis"),
|
|
11876
12145
|
snapshot: () => unsupported("snapshot"),
|
|
11877
12146
|
restore: () => unsupported("restore"),
|
|
12147
|
+
exportDocuments: () => unsupported("exportDocuments"),
|
|
12148
|
+
importDocumentExport: () => unsupported("importDocumentExport"),
|
|
11878
12149
|
rebalance: () => unsupported("rebalance"),
|
|
11879
12150
|
updatePartitionConfig: () => unsupported("updatePartitionConfig"),
|
|
11880
12151
|
compactVectors: () => unsupported("compactVectors"),
|