@minnowdb/core 0.6.5 → 0.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/block-format/codecs.d.ts +0 -8
- package/dist/block-format/codecs.js +1 -1
- package/dist/engine/artifact-cache.d.ts +2 -1
- package/dist/engine/batch.d.ts +0 -1
- package/dist/engine/batch.js +1 -1
- package/dist/engine/buffered-writer.js +1 -12
- package/dist/engine/byte-estimates.d.ts +11 -0
- package/dist/engine/byte-estimates.js +25 -0
- package/dist/engine/database.js +58 -34
- package/dist/engine/fts.d.ts +0 -1
- package/dist/engine/fts.js +1 -1
- package/dist/engine/group-index.d.ts +2 -0
- package/dist/engine/group-index.js +4 -8
- package/dist/engine/join-index.d.ts +0 -1
- package/dist/engine/join-index.js +1 -15
- package/dist/engine/keyed-live.js +2 -36
- package/dist/engine/live-equal.d.ts +7 -0
- package/dist/engine/live-equal.js +42 -0
- package/dist/engine/optimizer.js +11 -16
- package/dist/engine/point-read.d.ts +1 -1
- package/dist/engine/point-read.js +3 -2
- package/dist/engine/query-cache.js +1 -12
- package/dist/engine/query.d.ts +20 -59
- package/dist/engine/query.js +286 -54
- package/dist/engine/result-wire.d.ts +2 -1
- package/dist/engine/schema.d.ts +15 -11
- package/dist/engine/schema.js +11 -19
- package/dist/engine/sort-keys.d.ts +2 -3
- package/dist/engine/sort-keys.js +1 -1
- package/dist/engine/sql-domains.d.ts +27 -2
- package/dist/engine/sql-domains.js +120 -6
- package/dist/engine/sql-json.d.ts +0 -2
- package/dist/engine/sql-json.js +1 -1
- package/dist/engine/sql-semantics.d.ts +2 -1
- package/dist/engine/typed-live.js +3 -41
- package/dist/engine/vector.d.ts +7 -7
- package/dist/engine/vector.js +11 -30
- package/dist/engine/write-block-planner.d.ts +2 -1
- package/dist/plan/model.d.ts +22 -0
- package/dist/plan/model.js +29 -1
- package/dist/storage/indexeddb.js +13 -23
- package/dist/storage/opfs/leader.d.ts +0 -4
- package/dist/storage/opfs/leader.js +5 -14
- package/dist/storage/opfs/snapshot-ledger.d.ts +3 -2
- package/dist/storage/toolkit/index.d.ts +1 -1
- package/dist/storage/toolkit/record-core.d.ts +0 -1
- package/dist/storage/toolkit/record-core.js +3 -19
- package/dist/storage/types.d.ts +4 -3
- package/dist/storage/types.js +13 -2
- package/dist/testing/block-store-conformance.js +28 -0
- package/dist/testing/opfs-shim.d.ts +2 -1
- package/dist/testing/simulator.js +3 -0
- package/dist/worker-protocol/index.d.ts +0 -32
- package/dist/worker-protocol/index.js +0 -40
- package/package.json +2 -1
- package/postgres-feature-profile.json +8 -3
- package/sql-feature-matrix.json +71 -11
package/dist/plan/model.js
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* A cross join rides the nested-loop inner-join path with a condition every row pair satisfies:
|
|
3
|
+
* 1 = 1 over null literal key expressions. Producers build the shape with crossJoinPlan and
|
|
4
|
+
* consumers recognize it with isCrossJoinPlan, so the encoding lives in exactly one place.
|
|
5
|
+
*/
|
|
6
|
+
export function crossJoinPlan(source) {
|
|
7
|
+
return {
|
|
8
|
+
...source,
|
|
9
|
+
kind: "inner",
|
|
10
|
+
left: { kind: "literal", value: null },
|
|
11
|
+
right: { kind: "literal", value: null },
|
|
12
|
+
on: {
|
|
13
|
+
kind: "condition",
|
|
14
|
+
operator: "=",
|
|
15
|
+
left: { kind: "literal", value: 1 },
|
|
16
|
+
right: { kind: "literal", value: 1 },
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function isCrossJoinPlan(join) {
|
|
21
|
+
const condition = join.on;
|
|
22
|
+
return (join.kind === "inner" &&
|
|
23
|
+
condition?.kind === "condition" &&
|
|
24
|
+
condition.operator === "=" &&
|
|
25
|
+
condition.left.kind === "literal" &&
|
|
26
|
+
condition.left.value === 1 &&
|
|
27
|
+
condition.right.kind === "literal" &&
|
|
28
|
+
condition.right.value === 1);
|
|
29
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompactionJobConflictError, assertCompactionOutputProvenance, compactionOutputSegmentIds, CompactionBacklogError, createManifest, createGarbageCollectionJobRecord, storeNames, advanceGarbageCollectionJobRecord as advanceGarbageCollectionJobRecordUnchecked, BlockReadBatchTooLargeError, activePostingStorageColumnIds, assertTempRunPageBatchLimits, assertStorageBulkReadItems, assertTransactionArtifactBatchLimits, assertTransactionArtifactJournalLimits, boundedMaintenanceBatchItems, canonicalManifestChangedTableIds, catalogRecordRetainedBytes, manifestRecordRetainedReservationBytes, segmentRecordRetainedBytes, collectFtsPostings, ftsPostingQueryMatches, invalidateUncoveredFtsColumns, invalidateUncoveredSecondaryIndexes, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, LeaseOwnerConflictError, MAX_FTS_CANDIDATE_ROW_IDS, MAX_ACTIVE_UNIQUE_KEY_BUILDS, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES_TOTAL, MAX_UNIQUE_KEY_BUILD_CHUNK_BYTES, MAX_UNIQUE_KEY_BUILD_TOKENS_PER_CHUNK, MAX_UNIQUE_KEY_BUILD_TTL_MS, MAX_FTS_BASE_CHUNKS, MAX_FTS_DELTA_CHUNKS, MAX_FTS_POSTINGS_PER_CHUNK, MAX_FTS_POSTING_ROW_IDS_PER_CHUNK, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_FTS_TOKENS_PER_DOCUMENT, MAX_FTS_ORDERED_READ_BYTES, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_MANIFEST_RECORDS, MAX_MANIFEST_RETAINED_BYTES, MAX_BLOCK_READ_BATCH_BYTES, MAX_STORAGE_ID_CHARACTERS, MAX_LEASE_TTL_MS, MAX_ACTIVE_LEASES, MAX_ACTIVE_TRANSACTIONS, MAX_GLOBAL_STAGED_ARTIFACT_BYTES, MAX_GLOBAL_STAGED_BLOCKS, MAX_GLOBAL_STAGED_SEGMENTS, MAX_RETIRED_HISTORY_BYTES, MAX_PINNED_MANIFEST_VERSION_LAG, MAX_PINNED_RETIRED_BLOCKS, MAX_PINNED_RETIRED_BYTES, MAX_TERMINAL_TRANSACTION_RECORDS, MAX_ACTIVE_COMPACTION_JOBS, MAX_ACTIVE_GARBAGE_COLLECTION_JOBS, MAX_TERMINAL_COMPACTION_JOB_RECORDS, MAX_COMPLETED_GARBAGE_COLLECTION_JOB_RECORDS, MAX_CATALOG_RECORDS, MAX_CATALOG_RETAINED_BYTES, MAX_SEGMENT_RECORDS, MAX_SEGMENT_RETAINED_BYTES, MAX_ACTIVE_FTS_BASE_BUILDS, MAX_ACTIVE_SECONDARY_INDEX_BUILDS, MAX_ACCELERATOR_BUILD_STAGED_BYTES_TOTAL, MAX_ACCELERATOR_BUILD_STAGED_ENTRIES_TOTAL, MAX_POSTING_BUILD_TTL_MS, MAX_SNAPSHOT_SESSION_TTL_MS, MAX_SNAPSHOT_FRAME_BATCH_BYTES, MAX_SNAPSHOT_FRAME_BATCH_ITEMS, MAX_SNAPSHOT_METADATA_BATCH_BYTES, MAX_SNAPSHOT_METADATA_FRAME_BYTES, SNAPSHOT_FRAME_KINDS, MAX_LEVEL_ZERO_SEGMENTS, MAX_AUTO_INCREMENT_EXCLUSIVE_END, MAX_ROW_ID, MAX_ROW_ID_EXCLUSIVE_END, StorageCorruptionError, StorageFormatVersionError, IndexedDbSchemaUpgradeBlockedError, StorageResourceLimitError, SnapshotManifestMissingError, SnapshotImportConflictError, PostingBuildConflictError, validateTableForeignKey, TableInUseError, TableRecordConflictError, TempOwnerConflictError, MAX_TEMP_OWNER_TTL_MS, MAX_ACTIVE_TEMP_OWNERS, MAX_TEMP_RUNS_PER_OWNER, MAX_TEMP_PAGES_PER_OWNER, MAX_TEMP_RUNS_TOTAL, MAX_TEMP_PAGES_TOTAL, MAX_TEMP_BYTES_PER_OWNER, MAX_TEMP_BYTES_TOTAL, TransactionRecordConflictError, UniqueKeyConflictError, UniqueKeyBuildConflictError, UniqueIndexCoverageError, SchemaConflictError, normalizeCompactionJobRecord, normalizeGarbageCollectionJobRecord, normalizeSegmentRecord, updateCompactionJobRecord as updateCompactionJobRecordUnchecked, updateGarbageCollectionPlanningRecord, updateTransactionRecord as updateTransactionRecordUnchecked, validateColumnDefault, validateCatalogName, validateCanonicalManifestChangedTableIds, validateEnumValues, validateFtsOrderedReadLimits, validateFtsPostingQueries, validateStorageId, validateStorageDatabaseName, validateTableColumns, validateSecondaryIndexes, validateTableRecordBounds, secondaryIndexColumnIds, secondaryIndexWriteContractChanged, secondaryUniqueKeyNamespace, transactionCommitDeltaRetainedBytes, uniqueKeyBuildChunkRetainedBytes, WriteConflictError, } from "./types.js";
|
|
1
|
+
import { CompactionJobConflictError, assertCompactionOutputProvenance, compactionOutputSegmentIds, CompactionBacklogError, createManifest, createGarbageCollectionJobRecord, storeNames, advanceGarbageCollectionJobRecord as advanceGarbageCollectionJobRecordUnchecked, BlockReadBatchTooLargeError, activePostingStorageColumnIds, assertTempRunPageBatchLimits, assertStorageBulkReadItems, assertTransactionArtifactBatchLimits, assertTransactionArtifactJournalLimits, boundedMaintenanceBatchItems, canonicalManifestChangedTableIds, catalogRecordRetainedBytes, manifestRecordRetainedReservationBytes, segmentRecordRetainedBytes, collectFtsPostings, ftsPostingQueryMatches, invalidateUncoveredFtsColumns, invalidateUncoveredSecondaryIndexes, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, LeaseOwnerConflictError, MAX_FTS_CANDIDATE_ROW_IDS, MAX_ACTIVE_UNIQUE_KEY_BUILDS, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES_TOTAL, MAX_UNIQUE_KEY_BUILD_CHUNK_BYTES, MAX_UNIQUE_KEY_BUILD_TOKENS_PER_CHUNK, MAX_UNIQUE_KEY_BUILD_TTL_MS, MAX_FTS_BASE_CHUNKS, MAX_FTS_DELTA_CHUNKS, MAX_FTS_POSTINGS_PER_CHUNK, MAX_FTS_POSTING_ROW_IDS_PER_CHUNK, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_FTS_TOKENS_PER_DOCUMENT, MAX_FTS_ORDERED_READ_BYTES, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_MANIFEST_RECORDS, MAX_MANIFEST_RETAINED_BYTES, MAX_BLOCK_READ_BATCH_BYTES, MAX_STORAGE_ID_CHARACTERS, MAX_LEASE_TTL_MS, MAX_ACTIVE_LEASES, MAX_ACTIVE_TRANSACTIONS, MAX_GLOBAL_STAGED_ARTIFACT_BYTES, MAX_GLOBAL_STAGED_BLOCKS, MAX_GLOBAL_STAGED_SEGMENTS, MAX_RETIRED_HISTORY_BYTES, MAX_PINNED_MANIFEST_VERSION_LAG, MAX_PINNED_RETIRED_BLOCKS, MAX_PINNED_RETIRED_BYTES, MAX_TERMINAL_TRANSACTION_RECORDS, MAX_ACTIVE_COMPACTION_JOBS, MAX_ACTIVE_GARBAGE_COLLECTION_JOBS, MAX_TERMINAL_COMPACTION_JOB_RECORDS, MAX_COMPLETED_GARBAGE_COLLECTION_JOB_RECORDS, MAX_CATALOG_RECORDS, MAX_CATALOG_RETAINED_BYTES, MAX_SEGMENT_RECORDS, MAX_SEGMENT_RETAINED_BYTES, MAX_ACTIVE_FTS_BASE_BUILDS, MAX_ACTIVE_SECONDARY_INDEX_BUILDS, MAX_ACCELERATOR_BUILD_STAGED_BYTES_TOTAL, MAX_ACCELERATOR_BUILD_STAGED_ENTRIES_TOTAL, MAX_POSTING_BUILD_TTL_MS, MAX_SNAPSHOT_SESSION_TTL_MS, MAX_SNAPSHOT_FRAME_BATCH_BYTES, MAX_SNAPSHOT_FRAME_BATCH_ITEMS, MAX_SNAPSHOT_METADATA_BATCH_BYTES, MAX_SNAPSHOT_METADATA_FRAME_BYTES, SNAPSHOT_FRAME_KINDS, MAX_LEVEL_ZERO_SEGMENTS, MAX_AUTO_INCREMENT_EXCLUSIVE_END, MAX_ROW_ID, MAX_ROW_ID_EXCLUSIVE_END, StorageCorruptionError, StorageFormatVersionError, IndexedDbSchemaUpgradeBlockedError, StorageResourceLimitError, SnapshotManifestMissingError, SnapshotImportConflictError, PostingBuildConflictError, validateTableForeignKey, TableInUseError, TableRecordConflictError, TempOwnerConflictError, MAX_TEMP_OWNER_TTL_MS, MAX_ACTIVE_TEMP_OWNERS, MAX_TEMP_RUNS_PER_OWNER, MAX_TEMP_PAGES_PER_OWNER, MAX_TEMP_RUNS_TOTAL, MAX_TEMP_PAGES_TOTAL, MAX_TEMP_BYTES_PER_OWNER, MAX_TEMP_BYTES_TOTAL, TransactionRecordConflictError, UniqueKeyConflictError, UniqueKeyBuildConflictError, UniqueIndexCoverageError, SchemaConflictError, normalizeCompactionJobRecord, normalizeGarbageCollectionJobRecord, normalizeSegmentRecord, updateCompactionJobRecord as updateCompactionJobRecordUnchecked, updateGarbageCollectionPlanningRecord, updateTransactionRecord as updateTransactionRecordUnchecked, validateColumnDefault, validateCatalogName, validateCanonicalManifestChangedTableIds, validateEnumValues, validateFtsCandidateLimit, validateFtsOrderedReadLimits, validateFtsReadVersion, validateFtsPostingQueries, validateStorageId, validateStorageDatabaseName, validateTableColumns, validateSecondaryIndexes, validateTableRecordBounds, secondaryIndexColumnIds, secondaryIndexWriteContractChanged, secondaryUniqueKeyNamespace, transactionCommitDeltaRetainedBytes, uniqueKeyBuildChunkRetainedBytes, WriteConflictError, } from "./types.js";
|
|
2
2
|
import { crc32, verifyStoredBlock } from "../block-format/index.js";
|
|
3
3
|
import { dateIsoString } from "../date-value.js";
|
|
4
4
|
import { decodeSnapshotMetadataItems, encodeSnapshotMetadataPage, extendSnapshotFrameStreamChecksum, prepareSnapshotFrameStreamHeader, snapshotFrameEnvelopeParts, snapshotFrameStreamHeaderIdentity, } from "./snapshot-stream.js";
|
|
@@ -1769,11 +1769,8 @@ export class IndexedDbBlockStore {
|
|
|
1769
1769
|
validateId(tableId, "Table ID");
|
|
1770
1770
|
validateId(columnId, "Column ID");
|
|
1771
1771
|
validateFtsPostingQueries(terms);
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
maxRowIds > MAX_FTS_CANDIDATE_ROW_IDS) {
|
|
1775
|
-
throw new RangeError(`Full-text candidate limit must be between 1 and ${String(MAX_FTS_CANDIDATE_ROW_IDS)}`);
|
|
1776
|
-
}
|
|
1772
|
+
validateFtsReadVersion(upToVersion);
|
|
1773
|
+
validateFtsCandidateLimit(maxRowIds);
|
|
1777
1774
|
const transaction = this.#transaction("catalog", "readonly");
|
|
1778
1775
|
const store = transaction.objectStore("catalog");
|
|
1779
1776
|
const [rawToc, rawDeltaIndex] = await Promise.all([
|
|
@@ -1870,9 +1867,7 @@ export class IndexedDbBlockStore {
|
|
|
1870
1867
|
async readFtsPostings(tableId, columnId, upToVersion, maxRowIds = MAX_FTS_CANDIDATE_ROW_IDS, maxRetainedBytes = MAX_FTS_ORDERED_READ_BYTES) {
|
|
1871
1868
|
validateId(tableId, "Table ID");
|
|
1872
1869
|
validateId(columnId, "Column ID");
|
|
1873
|
-
|
|
1874
|
-
throw new RangeError("Full-text snapshot version must be a non-negative safe integer");
|
|
1875
|
-
}
|
|
1870
|
+
validateFtsReadVersion(upToVersion);
|
|
1876
1871
|
validateFtsOrderedReadLimits(maxRowIds, maxRetainedBytes);
|
|
1877
1872
|
const transaction = this.#transaction("catalog", "readonly");
|
|
1878
1873
|
const store = transaction.objectStore("catalog");
|
|
@@ -6983,20 +6978,15 @@ function createCurrentIndexedDbSchema(database, upgrade) {
|
|
|
6983
6978
|
for (const storeName of storeNames)
|
|
6984
6979
|
database.createObjectStore(storeName);
|
|
6985
6980
|
database.createObjectStore(SNAPSHOT_HEADER_STORE);
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
upgrade.objectStore("catalog").createIndex(UNIQUE_KEY_BUILD_ACTIVE_INDEX, "activeBuildState");
|
|
6996
|
-
upgrade.objectStore("catalog").createIndex(UNIQUE_KEY_BUILD_EXPIRY_INDEX, "activeExpiry");
|
|
6997
|
-
upgrade.objectStore("catalog").createIndex(MANIFEST_BLOCK_ID_INDEX, "blockId", {
|
|
6998
|
-
unique: true,
|
|
6999
|
-
});
|
|
6981
|
+
// Creation is driven by the same declaration validateCurrentIndexedDbSchema verifies
|
|
6982
|
+
// against, so the two can never disagree about what the current schema is.
|
|
6983
|
+
for (const [storeName, indexes] of Object.entries(indexedDbIndexSchema)) {
|
|
6984
|
+
const store = upgrade.objectStore(storeName);
|
|
6985
|
+
for (const index of indexes) {
|
|
6986
|
+
const keyPath = typeof index.keyPath === "string" ? index.keyPath : [...index.keyPath];
|
|
6987
|
+
store.createIndex(index.name, keyPath, { unique: index.unique ?? false });
|
|
6988
|
+
}
|
|
6989
|
+
}
|
|
7000
6990
|
upgrade.objectStore("gc").add(emptyMaintenanceQuota(), MAINTENANCE_QUOTA_KEY);
|
|
7001
6991
|
upgrade.objectStore("statistics").add(emptyResourceLedger(), RESOURCE_LEDGER_KEY);
|
|
7002
6992
|
upgrade.objectStore("statistics").add(emptyCatalogResourceLedger(), CATALOG_RESOURCE_LEDGER_KEY);
|
|
@@ -4,8 +4,6 @@ import { type Placement } from "../toolkit/extents.js";
|
|
|
4
4
|
/** A failed checkpoint may defer compaction, but the recovery log itself stays bounded. */
|
|
5
5
|
export declare const MAX_OPFS_WAL_BYTES: number;
|
|
6
6
|
export declare const MAX_OPFS_CHECKPOINT_BYTES: number;
|
|
7
|
-
/** Failed physical reclamation cannot permit byte-growing work forever. */
|
|
8
|
-
export declare const MAX_OPFS_CLEANUP_DEBT_BYTES: number;
|
|
9
7
|
interface IdPlacement {
|
|
10
8
|
id: string;
|
|
11
9
|
placement: Placement;
|
|
@@ -459,6 +457,4 @@ export declare class OpfsLeader {
|
|
|
459
457
|
export declare function assertBlockReadBatchByteLimit(placements: ReadonlyArray<{
|
|
460
458
|
length: number;
|
|
461
459
|
} | undefined>): void;
|
|
462
|
-
/** Conservative retained-heap model for one decoded postings chunk and its nested arrays. */
|
|
463
|
-
export declare function modeledFtsChunkBytes(chunk: readonly FtsPosting[]): number;
|
|
464
460
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { activePostingStorageColumnIds, assertStorageBulkReadItems, assertTempRunPageBatchLimits, BlockReadBatchTooLargeError, collectFtsPostingsBounded, ftsPostingQueryMatches, MAX_BLOCK_READ_BATCH_BYTES, MAX_FTS_BASE_CHUNKS, MAX_POSTING_BUILD_TTL_MS, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_STORAGE_ID_CHARACTERS, MAX_TEMP_RUN_PAGE_BYTES, MAX_TEMP_RUN_PAGES_PER_BATCH, MAX_TEMP_RUN_BATCH_BYTES, MAX_TEMP_RUNS_PER_OWNER, MAX_TEMP_PAGES_PER_OWNER, MAX_TEMP_RUNS_TOTAL, MAX_TEMP_PAGES_TOTAL, MAX_TEMP_BYTES_PER_OWNER, MAX_TEMP_BYTES_TOTAL, MAX_ACTIVE_FTS_BASE_BUILDS, MAX_ACTIVE_SECONDARY_INDEX_BUILDS, MAX_ACCELERATOR_BUILD_STAGED_BYTES_TOTAL, MAX_ACCELERATOR_BUILD_STAGED_ENTRIES_TOTAL, MAX_FTS_CANDIDATE_ROW_IDS, MAX_FTS_ORDERED_READ_BYTES, MAX_SNAPSHOT_SESSION_TTL_MS, MAX_SNAPSHOT_FRAME_BATCH_BYTES, MAX_SNAPSHOT_FRAME_BATCH_ITEMS, MAX_SNAPSHOT_METADATA_BATCH_BYTES, SNAPSHOT_FRAME_KINDS, MAX_TRANSACTION_STAGE_BLOCKS, MAX_TRANSACTION_STAGE_SEGMENTS, SnapshotImportConflictError, PostingBuildConflictError, StorageResourceLimitError, StorageCorruptionError, StorageFormatVersionError, validateFtsPostingQueries, validateFtsOrderedReadLimits, uniqueKeyBuildChunkRetainedBytes, } from "../types.js";
|
|
1
|
+
import { activePostingStorageColumnIds, assertStorageBulkReadItems, assertTempRunPageBatchLimits, BlockReadBatchTooLargeError, collectFtsPostingsBounded, ftsPostingQueryMatches, MAX_BLOCK_READ_BATCH_BYTES, MAX_FTS_BASE_CHUNKS, MAX_POSTING_BUILD_TTL_MS, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_STORAGE_ID_CHARACTERS, MAX_TEMP_RUN_PAGE_BYTES, MAX_TEMP_RUN_PAGES_PER_BATCH, MAX_TEMP_RUN_BATCH_BYTES, MAX_TEMP_RUNS_PER_OWNER, MAX_TEMP_PAGES_PER_OWNER, MAX_TEMP_RUNS_TOTAL, MAX_TEMP_PAGES_TOTAL, MAX_TEMP_BYTES_PER_OWNER, MAX_TEMP_BYTES_TOTAL, MAX_ACTIVE_FTS_BASE_BUILDS, MAX_ACTIVE_SECONDARY_INDEX_BUILDS, MAX_ACCELERATOR_BUILD_STAGED_BYTES_TOTAL, MAX_ACCELERATOR_BUILD_STAGED_ENTRIES_TOTAL, MAX_FTS_CANDIDATE_ROW_IDS, MAX_FTS_ORDERED_READ_BYTES, MAX_SNAPSHOT_SESSION_TTL_MS, MAX_SNAPSHOT_FRAME_BATCH_BYTES, MAX_SNAPSHOT_FRAME_BATCH_ITEMS, MAX_SNAPSHOT_METADATA_BATCH_BYTES, SNAPSHOT_FRAME_KINDS, MAX_TRANSACTION_STAGE_BLOCKS, MAX_TRANSACTION_STAGE_SEGMENTS, SnapshotImportConflictError, PostingBuildConflictError, StorageResourceLimitError, StorageCorruptionError, StorageFormatVersionError, validateFtsPostingQueries, validateFtsCandidateLimit, validateFtsOrderedReadLimits, validateFtsReadVersion, uniqueKeyBuildChunkRetainedBytes, } from "../types.js";
|
|
2
2
|
import { dateIsoString } from "../../date-value.js";
|
|
3
3
|
import { decodeSnapshotMetadataItems, encodeSnapshotMetadataPage, extendSnapshotFrameStreamChecksum, prepareSnapshotFrameStreamHeader, snapshotFrameEnvelopeParts, snapshotFrameStreamHeaderIdentity, } from "../snapshot-stream.js";
|
|
4
4
|
import { RecordCore, validateBeginTransactionInput, validateBlockWriteBytes, validateFtsBaseInput, validateFtsPostingChunks, validateId, validateTempRunPage, validateTempRunPageIdentity, } from "../toolkit/record-core.js";
|
|
@@ -17,7 +17,7 @@ const CHECKPOINT_ENTRIES = 1024;
|
|
|
17
17
|
export const MAX_OPFS_WAL_BYTES = 256 * 1024 * 1024;
|
|
18
18
|
export const MAX_OPFS_CHECKPOINT_BYTES = 256 * 1024 * 1024;
|
|
19
19
|
/** Failed physical reclamation cannot permit byte-growing work forever. */
|
|
20
|
-
|
|
20
|
+
const MAX_OPFS_CLEANUP_DEBT_BYTES = 64 * 1024 * 1024;
|
|
21
21
|
/** Decoded full-text base cache: bounded primarily by modeled retained heap, count secondarily. */
|
|
22
22
|
const FTS_CHUNK_CACHE_BYTES = 16 * 1024 * 1024;
|
|
23
23
|
const FTS_CHUNK_CACHE_SIZE = 64;
|
|
@@ -2485,9 +2485,7 @@ export class OpfsLeader {
|
|
|
2485
2485
|
validateId(tableId);
|
|
2486
2486
|
validateId(columnId);
|
|
2487
2487
|
validateFtsPostingQueries(terms);
|
|
2488
|
-
|
|
2489
|
-
throw new RangeError("Full-text query version must be a safe integer at least -1");
|
|
2490
|
-
}
|
|
2488
|
+
validateFtsReadVersion(upToVersion);
|
|
2491
2489
|
validateFtsCandidateLimit(maxRowIds);
|
|
2492
2490
|
return this.#run(async () => {
|
|
2493
2491
|
// Unlike immutable table blocks, derived-index extents are not protected by reader leases:
|
|
@@ -2553,9 +2551,7 @@ export class OpfsLeader {
|
|
|
2553
2551
|
async readFtsPostings(tableId, columnId, upToVersion, maxRowIds = MAX_FTS_CANDIDATE_ROW_IDS, maxRetainedBytes = MAX_FTS_ORDERED_READ_BYTES) {
|
|
2554
2552
|
validateId(tableId);
|
|
2555
2553
|
validateId(columnId);
|
|
2556
|
-
|
|
2557
|
-
throw new RangeError("Full-text query version must be a safe integer at least -1");
|
|
2558
|
-
}
|
|
2554
|
+
validateFtsReadVersion(upToVersion);
|
|
2559
2555
|
validateFtsOrderedReadLimits(maxRowIds, maxRetainedBytes);
|
|
2560
2556
|
return this.#run(async () => {
|
|
2561
2557
|
const key = postingStorageKey(tableId, columnId);
|
|
@@ -4041,11 +4037,6 @@ function requireCoverageVersion(value, label) {
|
|
|
4041
4037
|
if (!Number.isSafeInteger(value) || value < -1)
|
|
4042
4038
|
throw new Error(`Invalid ${label}`);
|
|
4043
4039
|
}
|
|
4044
|
-
function validateFtsCandidateLimit(value) {
|
|
4045
|
-
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_FTS_CANDIDATE_ROW_IDS) {
|
|
4046
|
-
throw new RangeError(`Full-text candidate limit must be between 1 and ${String(MAX_FTS_CANDIDATE_ROW_IDS)}`);
|
|
4047
|
-
}
|
|
4048
|
-
}
|
|
4049
4040
|
function requirePositiveInteger(value, label) {
|
|
4050
4041
|
if (!Number.isSafeInteger(value) || value < 1)
|
|
4051
4042
|
throw new Error(`Invalid ${label}`);
|
|
@@ -5035,7 +5026,7 @@ function samePlacement(left, right) {
|
|
|
5035
5026
|
left.checksum === right.checksum);
|
|
5036
5027
|
}
|
|
5037
5028
|
/** Conservative retained-heap model for one decoded postings chunk and its nested arrays. */
|
|
5038
|
-
|
|
5029
|
+
function modeledFtsChunkBytes(chunk) {
|
|
5039
5030
|
let bytes = 64;
|
|
5040
5031
|
for (const posting of chunk) {
|
|
5041
5032
|
bytes += 64 + posting.term.length * 2 + posting.rowIds.length * 40;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type SnapshotFrame, type SnapshotFrameKind } from "../types.js";
|
|
2
2
|
import { type Placement } from "../toolkit/extents.js";
|
|
3
3
|
import { OpfsTree } from "./files.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type SnapshotLedgerKind = "export" | "import" | "completed";
|
|
5
|
+
interface SnapshotLedgerRecord {
|
|
6
6
|
readonly sequence: number;
|
|
7
7
|
readonly kind: SnapshotFrameKind;
|
|
8
8
|
readonly itemCount: number;
|
|
@@ -38,3 +38,4 @@ export declare class SnapshotFrameLedger {
|
|
|
38
38
|
adoptLength(length: number): void;
|
|
39
39
|
close(): void;
|
|
40
40
|
}
|
|
41
|
+
export {};
|
|
@@ -26,4 +26,4 @@ export { readFully, writeFully, type SyncFileHandle } from "./sync-file.js";
|
|
|
26
26
|
export { RecordCore, type PhysicalBlocks, type RecordCoreState } from "./record-core.js";
|
|
27
27
|
export { MAX_WAL_FRAME_BYTES, WalWriter, iterateWalFrames, replayWalFrames, type ReplayedWalFrame, } from "./wal.js";
|
|
28
28
|
export { ExtentPool, assertValidExtentMeta, assertValidPlacement, extentPath, validPlacement, type ExtentBatchMark, type ExtentFiles, type ExtentMeta, type ExtentPoolOptions, type Placement, } from "./extents.js";
|
|
29
|
-
export { LOG_FORMAT_VERSION, decodeChunk, decodePostingChunk, decodeRecordJson, decodeSyncCheckpoint, encodeChunk, encodePostingChunk, encodeRecordJson, encodeSyncCheckpoint, } from "./wire.js";
|
|
29
|
+
export { LOG_FORMAT_VERSION, decodeChunk, decodePostingChunk, decodeRecordJson, decodeSyncCheckpoint, encodeChunk, encodePostingChunk, encodeRecordJson, encodeSyncCheckpoint, type PostingChunkEntry, } from "./wire.js";
|
|
@@ -373,7 +373,6 @@ export declare function validateFtsPostingChunks(chunks: unknown, label: string)
|
|
|
373
373
|
export declare function validateSegmentRuntimeRecord(value: unknown, label: string): SegmentRecord;
|
|
374
374
|
export declare function validateAutoIncrementReservation(count: number, atLeast: bigint | undefined): void;
|
|
375
375
|
export declare function validateBeginTransactionInput(input: BeginTransactionInput): void;
|
|
376
|
-
export declare function validateLeaseExpiration(expiresAt: string): void;
|
|
377
376
|
export declare function validateTempRunPage(page: TempRunPage): void;
|
|
378
377
|
export declare function validateTempRunPageIdentity(ownerId: string, runId: string, pageIndex: number): void;
|
|
379
378
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompactionBacklogError, CompactionJobConflictError, assertCompactionOutputProvenance, compactionOutputSegmentIds, createManifest, createGarbageCollectionJobRecord, advanceGarbageCollectionJobRecord, collectFtsCandidates, collectFtsPostingsBounded, activePostingStorageColumnIds, invalidateUncoveredFtsColumns, invalidateUncoveredSecondaryIndexes, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, LeaseOwnerConflictError, MAX_LEASE_TTL_MS, MAX_ACTIVE_LEASES, MAX_ACTIVE_TEMP_OWNERS, MAX_ACTIVE_COMPACTION_JOBS, MAX_ACTIVE_UNIQUE_KEY_BUILDS, MAX_ACTIVE_TRANSACTIONS, MAX_TERMINAL_TRANSACTION_RECORDS, MAX_TERMINAL_COMPACTION_JOB_RECORDS, MAX_COMPLETED_GARBAGE_COLLECTION_JOB_RECORDS, MAX_PINNED_MANIFEST_VERSION_LAG, MAX_PINNED_RETIRED_BLOCKS, MAX_PINNED_RETIRED_BYTES, MAX_RETIRED_HISTORY_BYTES, MAX_GLOBAL_STAGED_ARTIFACT_BYTES, MAX_GLOBAL_STAGED_BLOCKS, MAX_GLOBAL_STAGED_SEGMENTS, MAX_TEMP_OWNER_TTL_MS, MAX_ROW_ID, MAX_ROW_ID_EXCLUSIVE_END, MAX_AUTO_INCREMENT_EXCLUSIVE_END, MAX_LEVEL_ZERO_SEGMENTS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_STORAGE_ID_CHARACTERS, MAX_CATALOG_RECORDS, MAX_CATALOG_RETAINED_BYTES, MAX_MANIFEST_RECORDS, MAX_MANIFEST_RETAINED_BYTES, MAX_SEGMENT_RECORDS, MAX_SEGMENT_RETAINED_BYTES, MAX_FTS_CANDIDATE_ROW_IDS, MAX_FTS_POSTINGS_PER_CHUNK, MAX_FTS_POSTING_ROW_IDS_PER_CHUNK, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_FTS_TOKENS_PER_DOCUMENT, MAX_FTS_BASE_CHUNKS, MAX_FTS_DELTA_CHUNKS, SnapshotManifestMissingError, StorageResourceLimitError, TableInUseError, TableRecordConflictError, TempOwnerConflictError, TransactionRecordConflictError, UniqueKeyConflictError, UniqueKeyBuildConflictError, UniqueIndexCoverageError, assertTransactionArtifactBatchLimits, assertTransactionArtifactJournalLimits, assertTempRunPageBatchLimits, assertStorageBulkReadItems, boundedMaintenanceBatchItems, normalizeCompactionJobRecord, normalizeGarbageCollectionJobRecord, normalizeSegmentRecord, updateCompactionJobRecord, updateTransactionRecord, updateGarbageCollectionPlanningRecord, validateTableColumns, validateTableForeignKey, validateSecondaryIndexes, secondaryIndexColumnIds, secondaryIndexWriteContractChanged, secondaryUniqueKeyNamespace, transactionCommitDeltaRetainedBytes, uniqueKeyBuildChunkRetainedBytes, MAX_UNIQUE_KEY_BUILD_TTL_MS, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES_TOTAL, MAX_UNIQUE_KEY_BUILD_TOKENS_PER_CHUNK, validateFtsPostingQueries, validateCanonicalManifestChangedTableIds, catalogRecordRetainedBytes, manifestRecordRetainedReservationBytes, segmentRecordRetainedBytes, snapshotAcceleratorItemRetainedUsage, assertSnapshotImportAcceleratorUsage, SchemaConflictError, WriteConflictError, } from "../types.js";
|
|
1
|
+
import { CompactionBacklogError, CompactionJobConflictError, assertCompactionOutputProvenance, compactionOutputSegmentIds, createManifest, createGarbageCollectionJobRecord, advanceGarbageCollectionJobRecord, collectFtsCandidates, collectFtsPostingsBounded, validateFtsCandidateLimit, validateFtsReadVersion, activePostingStorageColumnIds, invalidateUncoveredFtsColumns, invalidateUncoveredSecondaryIndexes, GarbageCollectionJobConflictError, LeaseConflictError, LeaseExpiredError, LeaseOwnerConflictError, MAX_LEASE_TTL_MS, MAX_ACTIVE_LEASES, MAX_ACTIVE_TEMP_OWNERS, MAX_ACTIVE_COMPACTION_JOBS, MAX_ACTIVE_UNIQUE_KEY_BUILDS, MAX_ACTIVE_TRANSACTIONS, MAX_TERMINAL_TRANSACTION_RECORDS, MAX_TERMINAL_COMPACTION_JOB_RECORDS, MAX_COMPLETED_GARBAGE_COLLECTION_JOB_RECORDS, MAX_PINNED_MANIFEST_VERSION_LAG, MAX_PINNED_RETIRED_BLOCKS, MAX_PINNED_RETIRED_BYTES, MAX_RETIRED_HISTORY_BYTES, MAX_GLOBAL_STAGED_ARTIFACT_BYTES, MAX_GLOBAL_STAGED_BLOCKS, MAX_GLOBAL_STAGED_SEGMENTS, MAX_TEMP_OWNER_TTL_MS, MAX_ROW_ID, MAX_ROW_ID_EXCLUSIVE_END, MAX_AUTO_INCREMENT_EXCLUSIVE_END, MAX_LEVEL_ZERO_SEGMENTS, MAX_MANIFEST_BLOCK_PRESENCE_IDS, MAX_STORAGE_ID_CHARACTERS, MAX_CATALOG_RECORDS, MAX_CATALOG_RETAINED_BYTES, MAX_MANIFEST_RECORDS, MAX_MANIFEST_RETAINED_BYTES, MAX_SEGMENT_RECORDS, MAX_SEGMENT_RETAINED_BYTES, MAX_FTS_CANDIDATE_ROW_IDS, MAX_FTS_POSTINGS_PER_CHUNK, MAX_FTS_POSTING_ROW_IDS_PER_CHUNK, MAX_FTS_POSTING_TERM_CHARACTERS, MAX_FTS_TOKENS_PER_DOCUMENT, MAX_FTS_BASE_CHUNKS, MAX_FTS_DELTA_CHUNKS, SnapshotManifestMissingError, StorageResourceLimitError, TableInUseError, TableRecordConflictError, TempOwnerConflictError, TransactionRecordConflictError, UniqueKeyConflictError, UniqueKeyBuildConflictError, UniqueIndexCoverageError, assertTransactionArtifactBatchLimits, assertTransactionArtifactJournalLimits, assertTempRunPageBatchLimits, assertStorageBulkReadItems, boundedMaintenanceBatchItems, normalizeCompactionJobRecord, normalizeGarbageCollectionJobRecord, normalizeSegmentRecord, updateCompactionJobRecord, updateTransactionRecord, updateGarbageCollectionPlanningRecord, validateTableColumns, validateTableForeignKey, validateSecondaryIndexes, secondaryIndexColumnIds, secondaryIndexWriteContractChanged, secondaryUniqueKeyNamespace, transactionCommitDeltaRetainedBytes, uniqueKeyBuildChunkRetainedBytes, MAX_UNIQUE_KEY_BUILD_TTL_MS, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES, MAX_UNIQUE_KEY_BUILD_STAGED_BYTES_TOTAL, MAX_UNIQUE_KEY_BUILD_TOKENS_PER_CHUNK, validateFtsPostingQueries, validateCanonicalManifestChangedTableIds, catalogRecordRetainedBytes, manifestRecordRetainedReservationBytes, segmentRecordRetainedBytes, snapshotAcceleratorItemRetainedUsage, assertSnapshotImportAcceleratorUsage, SchemaConflictError, WriteConflictError, } from "../types.js";
|
|
2
2
|
import { dateIsoString } from "../../date-value.js";
|
|
3
3
|
import { assertWellFormedString, crc32, MAX_STORED_BLOCK_BYTE_LENGTH, } from "../../block-format/index.js";
|
|
4
4
|
/**
|
|
@@ -1729,9 +1729,7 @@ export class RecordCore {
|
|
|
1729
1729
|
validateId(tableId);
|
|
1730
1730
|
validateId(columnId);
|
|
1731
1731
|
validateFtsPostingQueries(terms);
|
|
1732
|
-
|
|
1733
|
-
throw new RangeError("Full-text query version must be a safe integer at least -1");
|
|
1734
|
-
}
|
|
1732
|
+
validateFtsReadVersion(upToVersion);
|
|
1735
1733
|
validateFtsCandidateLimit(maxRowIds);
|
|
1736
1734
|
const key = `${tableId}/${columnId}`;
|
|
1737
1735
|
const base = this.#ftsBases.get(key);
|
|
@@ -1834,9 +1832,7 @@ export class RecordCore {
|
|
|
1834
1832
|
readFtsPostings(tableId, columnId, upToVersion, maxRowIds = MAX_FTS_CANDIDATE_ROW_IDS, maxRetainedBytes) {
|
|
1835
1833
|
validateId(tableId);
|
|
1836
1834
|
validateId(columnId);
|
|
1837
|
-
|
|
1838
|
-
throw new RangeError("Full-text query version must be a safe integer at least -1");
|
|
1839
|
-
}
|
|
1835
|
+
validateFtsReadVersion(upToVersion);
|
|
1840
1836
|
const base = this.#ftsBases.get(`${tableId}/${columnId}`);
|
|
1841
1837
|
const coversVersion = base?.coversVersion ?? -1;
|
|
1842
1838
|
const delta = this.readFtsDeltas(tableId, columnId, coversVersion, upToVersion);
|
|
@@ -6382,13 +6378,6 @@ function validateTempOwnerRecord(record) {
|
|
|
6382
6378
|
throw new RangeError("Temp owner record must be created at revision zero");
|
|
6383
6379
|
}
|
|
6384
6380
|
}
|
|
6385
|
-
export function validateLeaseExpiration(expiresAt) {
|
|
6386
|
-
if (typeof expiresAt !== "string" ||
|
|
6387
|
-
expiresAt.length === 0 ||
|
|
6388
|
-
!Number.isFinite(Date.parse(expiresAt))) {
|
|
6389
|
-
throw new TypeError("Lease expiration must be valid");
|
|
6390
|
-
}
|
|
6391
|
-
}
|
|
6392
6381
|
function isCanonicalTimestamp(value) {
|
|
6393
6382
|
const timestamp = Date.parse(value);
|
|
6394
6383
|
return Number.isFinite(timestamp) && dateIsoString(new Date(timestamp)) === value;
|
|
@@ -6496,11 +6485,6 @@ function sortedVersionInInterval(versions, addedVersion, removedVersion) {
|
|
|
6496
6485
|
const version = versions[low];
|
|
6497
6486
|
return version !== undefined && (removedVersion === null || version < removedVersion);
|
|
6498
6487
|
}
|
|
6499
|
-
function validateFtsCandidateLimit(value) {
|
|
6500
|
-
if (!Number.isSafeInteger(value) || value < 1 || value > MAX_FTS_CANDIDATE_ROW_IDS) {
|
|
6501
|
-
throw new RangeError(`Full-text candidate limit must be between 1 and ${String(MAX_FTS_CANDIDATE_ROW_IDS)}`);
|
|
6502
|
-
}
|
|
6503
|
-
}
|
|
6504
6488
|
function varuintByteLength(value) {
|
|
6505
6489
|
let length = 1;
|
|
6506
6490
|
while (value >= 0x80n) {
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -534,8 +534,6 @@ export interface CompactionJobCursor {
|
|
|
534
534
|
sourceSegmentIndex: number;
|
|
535
535
|
sourceBlockIndex: number;
|
|
536
536
|
}
|
|
537
|
-
export declare const compactionRewritePlanKinds: readonly ["copy-v1", "rechunk-v1", "merge-v1"];
|
|
538
|
-
export type CompactionRewritePlanKind = (typeof compactionRewritePlanKinds)[number];
|
|
539
537
|
export interface CopyCompactionRewritePlan {
|
|
540
538
|
readonly kind: "copy-v1";
|
|
541
539
|
}
|
|
@@ -1669,6 +1667,10 @@ export declare function ftsPostingQueryMatches(term: string, query: FtsPostingQu
|
|
|
1669
1667
|
* never drift between backends — pruning would silently differ per store.
|
|
1670
1668
|
*/
|
|
1671
1669
|
export declare function collectFtsCandidates(chunkLists: Iterable<readonly FtsPosting[]>, terms: readonly FtsPostingQuery[], maxRowIds?: number): FtsCandidates;
|
|
1670
|
+
/** Validates the snapshot bound of one full-text read; -1 selects the base view alone. */
|
|
1671
|
+
export declare function validateFtsReadVersion(upToVersion: number): void;
|
|
1672
|
+
/** Validates the candidate row-ID ceiling accepted by one full-text candidate read. */
|
|
1673
|
+
export declare function validateFtsCandidateLimit(maxRowIds: number): void;
|
|
1672
1674
|
/** Validates the fixed memory ceilings accepted by one ordered postings read. */
|
|
1673
1675
|
export declare function validateFtsOrderedReadLimits(maxRowIds?: number, maxRetainedBytes?: number): void;
|
|
1674
1676
|
/**
|
|
@@ -2422,7 +2424,6 @@ export declare function createManifest(input: CreateManifestInput): Manifest;
|
|
|
2422
2424
|
export declare function normalizeSegmentRecord(record: SegmentRecord): SegmentRecord;
|
|
2423
2425
|
export declare function updateTransactionRecord(record: TransactionRecord, update: TransactionRecordUpdate): TransactionRecord;
|
|
2424
2426
|
export declare function createGarbageCollectionJobRecord(input: CreateGarbageCollectionJobInput): GarbageCollectionJobRecord;
|
|
2425
|
-
export declare function normalizeGarbageCollectionDiscovery(discovery: GarbageCollectionDiscovery): GarbageCollectionDiscovery;
|
|
2426
2427
|
export declare function updateGarbageCollectionPlanningRecord(record: GarbageCollectionJobRecord, input: UpdateGarbageCollectionPlanningInput): GarbageCollectionJobRecord;
|
|
2427
2428
|
export declare function normalizeGarbageCollectionJobRecord(record: GarbageCollectionJobRecord): GarbageCollectionJobRecord;
|
|
2428
2429
|
export declare function advanceGarbageCollectionJobRecord(record: GarbageCollectionJobRecord, accounting: GarbageCollectionStepAccounting): GarbageCollectionJobRecord;
|
package/dist/storage/types.js
CHANGED
|
@@ -726,7 +726,6 @@ export const compactionJobStates = [
|
|
|
726
726
|
"cancelled",
|
|
727
727
|
"aborted",
|
|
728
728
|
];
|
|
729
|
-
export const compactionRewritePlanKinds = ["copy-v1", "rechunk-v1", "merge-v1"];
|
|
730
729
|
export const compactionOutputCompressions = ["raw", "gzip"];
|
|
731
730
|
/** Every segment ID owned by a compaction job, including merge partition outputs. */
|
|
732
731
|
export function compactionOutputSegmentIds(job) {
|
|
@@ -1427,6 +1426,18 @@ export function collectFtsCandidates(chunkLists, terms, maxRowIds = MAX_FTS_CAND
|
|
|
1427
1426
|
overflow: false,
|
|
1428
1427
|
};
|
|
1429
1428
|
}
|
|
1429
|
+
/** Validates the snapshot bound of one full-text read; -1 selects the base view alone. */
|
|
1430
|
+
export function validateFtsReadVersion(upToVersion) {
|
|
1431
|
+
if (!Number.isSafeInteger(upToVersion) || upToVersion < -1) {
|
|
1432
|
+
throw new RangeError("Full-text query version must be a safe integer at least -1");
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
/** Validates the candidate row-ID ceiling accepted by one full-text candidate read. */
|
|
1436
|
+
export function validateFtsCandidateLimit(maxRowIds) {
|
|
1437
|
+
if (!Number.isSafeInteger(maxRowIds) || maxRowIds < 1 || maxRowIds > MAX_FTS_CANDIDATE_ROW_IDS) {
|
|
1438
|
+
throw new RangeError(`Full-text candidate limit must be between 1 and ${String(MAX_FTS_CANDIDATE_ROW_IDS)}`);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1430
1441
|
/** Validates the fixed memory ceilings accepted by one ordered postings read. */
|
|
1431
1442
|
export function validateFtsOrderedReadLimits(maxRowIds = MAX_FTS_CANDIDATE_ROW_IDS, maxRetainedBytes = MAX_FTS_ORDERED_READ_BYTES) {
|
|
1432
1443
|
if (!Number.isSafeInteger(maxRowIds) || maxRowIds < 1 || maxRowIds > MAX_FTS_CANDIDATE_ROW_IDS) {
|
|
@@ -1940,7 +1951,7 @@ export function createGarbageCollectionJobRecord(input) {
|
|
|
1940
1951
|
...(discovery === undefined ? {} : { discovery }),
|
|
1941
1952
|
};
|
|
1942
1953
|
}
|
|
1943
|
-
|
|
1954
|
+
function normalizeGarbageCollectionDiscovery(discovery) {
|
|
1944
1955
|
const runtime = discovery;
|
|
1945
1956
|
if (typeof runtime !== "object" || runtime === null) {
|
|
1946
1957
|
throw new TypeError("Garbage collection discovery must be an object");
|
|
@@ -1008,6 +1008,34 @@ export function blockStoreConformanceCases() {
|
|
|
1008
1008
|
{ term: "minnows", rowIds: [2n], tf: [1] },
|
|
1009
1009
|
{ term: "shark", rowIds: [4n], tf: [1] },
|
|
1010
1010
|
], "ordered postings must merge into canonical term and row-ID order");
|
|
1011
|
+
// The read-argument contract is uniform across adapters: -1 selects the base view
|
|
1012
|
+
// alone, anything below it (or non-integral) is refused, and the candidate limit is
|
|
1013
|
+
// validated on every read path.
|
|
1014
|
+
const baseOnly = await store.readFtsPostings("table-t", "col-v", -1);
|
|
1015
|
+
check(baseOnly.hasBase && baseOnly.postings.length === 3, "an upToVersion of -1 must serve the base view alone");
|
|
1016
|
+
for (const version of [-2, Number.NaN, 1.5]) {
|
|
1017
|
+
try {
|
|
1018
|
+
await store.readFtsCandidates("table-t", "col-v", [{ term: "minnow", prefix: false }], version);
|
|
1019
|
+
throw new Error(`candidate read accepted invalid version ${String(version)}`);
|
|
1020
|
+
}
|
|
1021
|
+
catch (error) {
|
|
1022
|
+
check(error instanceof RangeError, "invalid candidate versions must throw RangeError");
|
|
1023
|
+
}
|
|
1024
|
+
try {
|
|
1025
|
+
await store.readFtsPostings("table-t", "col-v", version);
|
|
1026
|
+
throw new Error(`postings read accepted invalid version ${String(version)}`);
|
|
1027
|
+
}
|
|
1028
|
+
catch (error) {
|
|
1029
|
+
check(error instanceof RangeError, "invalid postings versions must throw RangeError");
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
try {
|
|
1033
|
+
await store.readFtsCandidates("table-t", "col-v", [{ term: "minnow", prefix: false }], 10, 0);
|
|
1034
|
+
throw new Error("candidate read accepted a zero row-ID limit");
|
|
1035
|
+
}
|
|
1036
|
+
catch (error) {
|
|
1037
|
+
check(error instanceof RangeError, "invalid candidate limits must throw RangeError");
|
|
1038
|
+
}
|
|
1011
1039
|
store.close();
|
|
1012
1040
|
},
|
|
1013
1041
|
},
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* toolkit's `SyncFileHandle` surface, in plain vitest, with crashes and quota failures on tap.
|
|
22
22
|
*/
|
|
23
23
|
export type WriteFault = (path: string, phase: "create" | "write" | "flush") => void;
|
|
24
|
-
|
|
24
|
+
type DeleteFault = (path: string) => void;
|
|
25
25
|
export type TransferLimit = (path: string, operation: "read" | "write", requestedBytes: number, at: number) => number | undefined;
|
|
26
26
|
export declare class MemoryOpfs {
|
|
27
27
|
#private;
|
|
@@ -43,3 +43,4 @@ export declare class MemoryOpfs {
|
|
|
43
43
|
/** Test-side in-place corruption: existing sync handles observe the changed byte. */
|
|
44
44
|
corruptFileByte(path: string, offset: number): void;
|
|
45
45
|
}
|
|
46
|
+
export {};
|
|
@@ -572,6 +572,9 @@ function summarizeCollection(result) {
|
|
|
572
572
|
retainedTransactions: result.retainedTransactionCount,
|
|
573
573
|
};
|
|
574
574
|
}
|
|
575
|
+
// Stream-identical copy of `mulberry32` in ./seeds.ts. This module ships in the tarball and
|
|
576
|
+
// seeds.ts does not (it reads MINNOW_SEED and the unpublished regression-seeds.json), so the
|
|
577
|
+
// published simulator cannot import the canonical copy.
|
|
575
578
|
function mulberry32(seed) {
|
|
576
579
|
let state = seed >>> 0;
|
|
577
580
|
return () => {
|
|
@@ -1,38 +1,6 @@
|
|
|
1
1
|
export declare const protocolVersion: 3;
|
|
2
2
|
/** Outstanding request/response pairs retained by either side of one database RPC connection. */
|
|
3
3
|
export declare const MAX_DATABASE_RPC_IN_FLIGHT = 256;
|
|
4
|
-
export type WorkerOperation = "benchmark" | "cancelBenchmark" | "memorySample" | "datasetList" | "datasetCreate" | "datasetDelete" | "runQuery" | "suiteReference" | "suiteWrite" | "suiteFeatureMatrix" | "suiteLive";
|
|
5
|
-
export interface WorkerRequest<T = unknown> {
|
|
6
|
-
version: typeof protocolVersion;
|
|
7
|
-
requestId: string;
|
|
8
|
-
operation: WorkerOperation;
|
|
9
|
-
payload: T;
|
|
10
|
-
}
|
|
11
|
-
export interface SuccessResponse<T = unknown> {
|
|
12
|
-
version: typeof protocolVersion;
|
|
13
|
-
requestId: string;
|
|
14
|
-
kind: "success";
|
|
15
|
-
result: T;
|
|
16
|
-
}
|
|
17
|
-
export interface FailureResponse {
|
|
18
|
-
version: typeof protocolVersion;
|
|
19
|
-
requestId: string;
|
|
20
|
-
kind: "failure";
|
|
21
|
-
error: {
|
|
22
|
-
name: string;
|
|
23
|
-
message: string;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
export interface ProgressResponse<T = unknown> {
|
|
27
|
-
version: typeof protocolVersion;
|
|
28
|
-
requestId: string;
|
|
29
|
-
kind: "progress";
|
|
30
|
-
progress: T;
|
|
31
|
-
}
|
|
32
|
-
export type WorkerResponse<T = unknown> = SuccessResponse<T> | FailureResponse | ProgressResponse;
|
|
33
|
-
export declare function parseRequest(value: unknown): WorkerRequest;
|
|
34
|
-
export declare function success<T>(requestId: string, result: T): SuccessResponse<T>;
|
|
35
|
-
export declare function failure(requestId: string, error: unknown): FailureResponse;
|
|
36
4
|
export type RpcRequest = {
|
|
37
5
|
version: typeof protocolVersion;
|
|
38
6
|
requestId: string;
|
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
export const protocolVersion = 3;
|
|
2
2
|
/** Outstanding request/response pairs retained by either side of one database RPC connection. */
|
|
3
3
|
export const MAX_DATABASE_RPC_IN_FLIGHT = 256;
|
|
4
|
-
export function parseRequest(value) {
|
|
5
|
-
if (typeof value !== "object" || value === null)
|
|
6
|
-
throw new TypeError("Request must be an object");
|
|
7
|
-
const candidate = value;
|
|
8
|
-
if (candidate.version !== protocolVersion)
|
|
9
|
-
throw new Error("Unsupported protocol version");
|
|
10
|
-
if (typeof candidate.requestId !== "string" || candidate.requestId.length === 0) {
|
|
11
|
-
throw new TypeError("Request ID must be a non-empty string");
|
|
12
|
-
}
|
|
13
|
-
if (!isOperation(candidate.operation))
|
|
14
|
-
throw new Error("Unsupported worker operation");
|
|
15
|
-
return candidate;
|
|
16
|
-
}
|
|
17
|
-
export function success(requestId, result) {
|
|
18
|
-
return { version: protocolVersion, requestId, kind: "success", result };
|
|
19
|
-
}
|
|
20
|
-
export function failure(requestId, error) {
|
|
21
|
-
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
22
|
-
return {
|
|
23
|
-
version: protocolVersion,
|
|
24
|
-
requestId,
|
|
25
|
-
kind: "failure",
|
|
26
|
-
error: { name: normalized.name, message: normalized.message },
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
4
|
export function serializeError(error) {
|
|
30
5
|
if (!(error instanceof Error)) {
|
|
31
6
|
return { name: "Error", message: String(error) };
|
|
@@ -101,18 +76,3 @@ export function parseRpcResponse(value) {
|
|
|
101
76
|
throw new Error("Unsupported protocol version");
|
|
102
77
|
return candidate;
|
|
103
78
|
}
|
|
104
|
-
function isOperation(value) {
|
|
105
|
-
return [
|
|
106
|
-
"benchmark",
|
|
107
|
-
"cancelBenchmark",
|
|
108
|
-
"memorySample",
|
|
109
|
-
"datasetList",
|
|
110
|
-
"datasetCreate",
|
|
111
|
-
"datasetDelete",
|
|
112
|
-
"runQuery",
|
|
113
|
-
"suiteReference",
|
|
114
|
-
"suiteWrite",
|
|
115
|
-
"suiteFeatureMatrix",
|
|
116
|
-
"suiteLive",
|
|
117
|
-
].includes(String(value));
|
|
118
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@minnowdb/core",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.7",
|
|
4
4
|
"description": "A columnar SQL database for the browser: PostgreSQL-style SQL over durable IndexedDB or OPFS data, with no server or WebAssembly module.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Wilhite",
|
|
@@ -125,6 +125,7 @@
|
|
|
125
125
|
"!dist/storage/fixture-shape.*",
|
|
126
126
|
"!dist/engine/storage-test-helpers.*",
|
|
127
127
|
"!dist/testing/seeds.*",
|
|
128
|
+
"!dist/testing/oracle.*",
|
|
128
129
|
"!dist/*.tsbuildinfo",
|
|
129
130
|
"sql-feature-matrix.json",
|
|
130
131
|
"postgres-feature-profile.json"
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
{
|
|
112
112
|
"id": "function.string-extended",
|
|
113
113
|
"classification": "different",
|
|
114
|
-
"reason": "The bundled form includes INSTR; PostgreSQL spells
|
|
114
|
+
"reason": "The bundled form includes INSTR; PostgreSQL has no INSTR and spells the same (string, substring) lookup STRPOS, with the arguments in the same order."
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"id": "function.trim-multi-character",
|
|
@@ -134,10 +134,15 @@
|
|
|
134
134
|
"classification": "different",
|
|
135
135
|
"reason": "Both engines accept the correlated JSON aggregate and agree on its JSON value, but Minnow returns JSON text while PostgreSQL returns a native JSON value."
|
|
136
136
|
},
|
|
137
|
+
{
|
|
138
|
+
"id": "literal.scientific",
|
|
139
|
+
"classification": "different",
|
|
140
|
+
"reason": "PostgreSQL types every scientific-notation constant NUMERIC and renders it as text. Minnow evaluates it exactly but returns a number whenever the value reads back identically from one, keeping ordinary constants number-typed at the JavaScript boundary; a constant that stays exact renders fully expanded, as PostgreSQL renders it."
|
|
141
|
+
},
|
|
137
142
|
{
|
|
138
143
|
"id": "type.exact-numeric",
|
|
139
144
|
"classification": "different",
|
|
140
|
-
"reason": "Minnow preserves exact decimals at the JavaScript boundary as strings
|
|
145
|
+
"reason": "Minnow preserves exact decimals at the JavaScript boundary as strings, as PGlite's default decoder also does. A declared scale renders at exactly that scale as PostgreSQL does; a bare NUMERIC column, a derived arithmetic result, and a value cast or concatenated to text render canonically, without the trailing fractional zeros PostgreSQL preserves. Division and AVG select their result scale the way PostgreSQL does, so quotient digits agree — including AVG over a column whose declared scale exceeds the selection. The canonical encoding does drop a stored value's display scale, so an explicit arithmetic quotient (such as SUM(v) / COUNT(v)) over a column declared with more than about twenty fractional digits can carry fewer digits than PostgreSQL, which floors the selection at the operand's display scale. An arithmetic or comparison expression mixing a float column with a constant Float64 cannot represent stays exact, where PostgreSQL casts the constant to float8 and rounds it before evaluating."
|
|
141
146
|
},
|
|
142
147
|
{
|
|
143
148
|
"id": "type.json-jsonb",
|
|
@@ -182,7 +187,7 @@
|
|
|
182
187
|
{
|
|
183
188
|
"id": "json.array",
|
|
184
189
|
"classification": "different",
|
|
185
|
-
"reason": "
|
|
190
|
+
"reason": "Minnow defaults JSON_ARRAY to NULL ON NULL, so a NULL argument becomes a JSON null where PostgreSQL's ABSENT ON NULL default drops it; Minnow also returns compact JSON text while PostgreSQL's rendering includes spaces."
|
|
186
191
|
},
|
|
187
192
|
{
|
|
188
193
|
"id": "trigger.create-after",
|