@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.2
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/out/shared/src/custom-key-map.d.ts +4 -4
- package/out/shared/src/custom-key-map.d.ts.map +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/iterables.d.ts +6 -8
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +13 -7
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/options.d.ts +1 -0
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +5 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/zero-cache-dev.js +7 -3
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +10 -1
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +27 -7
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/observability/events.d.ts.map +1 -1
- package/out/zero-cache/src/observability/events.js +15 -5
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +10 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +22 -4
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +0 -4
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -10
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +8 -2
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -14
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js +8 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +5 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +16 -5
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config.yml +1 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +9 -24
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +1 -2
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +51 -12
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +4 -3
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -2
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +36 -31
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +6 -4
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -8
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -11
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -10
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -2
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +40 -42
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +0 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +0 -2
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +2 -5
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +1 -4
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-client/src/client/context.js +1 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +2 -4
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +7 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +9 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +1 -0
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +41 -2
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +9 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.js +1 -0
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/mutate/mutator.js +4 -4
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -5
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-registry.js +4 -4
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/package.json +3 -3
- package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
- package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
- package/out/zero-cache/src/types/schema-versions.js +0 -28
- package/out/zero-cache/src/types/schema-versions.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-store.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"sourcesContent":["import {trace} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {MaybeRow, PendingQuery} from 'postgres';\nimport {startAsyncSpan} from '../../../../otel/src/span.ts';\nimport {version} from '../../../../otel/src/version.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {CustomKeyMap} from '../../../../shared/src/custom-key-map.ts';\nimport {CustomKeySet} from '../../../../shared/src/custom-key-set.ts';\nimport {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {sleep} from '../../../../shared/src/sleep.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../zero-protocol/src/ast.ts';\nimport {clientSchemaSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {InspectQueryRow} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {clampTTL, DEFAULT_TTL_MS} from '../../../../zql/src/query/ttl.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {TransactionPool} from '../../db/transaction-pool.ts';\nimport {recordRowsSynced} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {rowIDString} from '../../types/row-key.ts';\nimport {cvrSchema, type ShardID, upstreamSchema} from '../../types/shards.ts';\nimport type {Patch, PatchToVersion} from './client-handler.ts';\nimport type {CVR, CVRSnapshot} from './cvr.ts';\nimport {RowRecordCache} from './row-record-cache.ts';\nimport {\n type ClientsRow,\n type DesiresRow,\n type InstancesRow,\n type QueriesRow,\n type RowsRow,\n} from './schema/cvr.ts';\nimport {\n type ClientQueryRecord,\n type ClientRecord,\n cmpVersions,\n type CustomQueryRecord,\n type CVRVersion,\n EMPTY_CVR_VERSION,\n type InternalQueryRecord,\n type NullableCVRVersion,\n type QueryPatch,\n type QueryRecord,\n queryRecordToQueryRow,\n type RowID,\n type RowRecord,\n versionFromString,\n versionString,\n} from './schema/types.ts';\nimport {\n type TTLClock,\n ttlClockAsNumber,\n ttlClockFromNumber,\n} from './ttl-clock.ts';\n\nexport type CVRFlushStats = {\n instances: number;\n queries: number;\n desires: number;\n clients: number;\n rows: number;\n rowsDeferred: number;\n statements: number;\n};\n\nconst tracer = trace.getTracer('cvr-store', version);\n\nfunction asQuery(row: QueriesRow): QueryRecord {\n const maybeVersion = (s: string | null) =>\n s === null ? undefined : versionFromString(s);\n\n if (row.clientAST === null) {\n // custom query\n assert(\n row.queryName !== null && row.queryArgs !== null,\n 'queryName and queryArgs must be set for custom queries',\n );\n return {\n type: 'custom',\n id: row.queryHash,\n name: row.queryName,\n args: row.queryArgs,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies CustomQueryRecord;\n }\n\n const ast = astSchema.parse(row.clientAST);\n return row.internal\n ? ({\n type: 'internal',\n id: row.queryHash,\n ast,\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies InternalQueryRecord)\n : ({\n type: 'client',\n id: row.queryHash,\n ast,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies ClientQueryRecord);\n}\n\n// The time to wait between load attempts.\nconst LOAD_ATTEMPT_INTERVAL_MS = 500;\n// The maximum number of load() attempts if the rowsVersion is behind.\n// This currently results in a maximum catchup time of ~5 seconds, after\n// which we give up and consider the CVR invalid.\n//\n// TODO: Make this configurable with something like --max-catchup-wait-ms,\n// as it is technically application specific.\nconst MAX_LOAD_ATTEMPTS = 10;\n\nexport class CVRStore {\n readonly #schema: string;\n readonly #taskID: string;\n readonly #id: string;\n readonly #failService: (e: unknown) => void;\n readonly #db: PostgresDB;\n readonly #upstreamDb: PostgresDB | undefined;\n readonly #writes: Set<{\n stats: Partial<CVRFlushStats>;\n write: (\n tx: PostgresTransaction,\n lastConnectTime: number,\n ) => PendingQuery<MaybeRow[]>;\n }> = new Set();\n readonly #upstreamWrites: ((\n tx: PostgresTransaction,\n ) => PendingQuery<MaybeRow[]>)[] = [];\n readonly #pendingRowRecordUpdates = new CustomKeyMap<RowID, RowRecord | null>(\n rowIDString,\n );\n readonly #forceUpdates = new CustomKeySet<RowID>(rowIDString);\n readonly #rowCache: RowRecordCache;\n readonly #loadAttemptIntervalMs: number;\n readonly #maxLoadAttempts: number;\n readonly #upstreamSchemaName: string;\n #rowCount: number = 0;\n\n constructor(\n lc: LogContext,\n cvrDb: PostgresDB,\n // Optionally undefined to deal with custom upstreams.\n // This is temporary until we have a more principled protocol to deal with\n // custom upstreams and clearing their custom mutator responses.\n // An implementor could simply clear them after N minutes for the time being.\n upstreamDb: PostgresDB | undefined,\n shard: ShardID,\n taskID: string,\n cvrID: string,\n failService: (e: unknown) => void,\n loadAttemptIntervalMs = LOAD_ATTEMPT_INTERVAL_MS,\n maxLoadAttempts = MAX_LOAD_ATTEMPTS,\n deferredRowFlushThreshold = 100, // somewhat arbitrary\n setTimeoutFn = setTimeout,\n ) {\n this.#failService = failService;\n this.#db = cvrDb;\n this.#upstreamDb = upstreamDb;\n this.#schema = cvrSchema(shard);\n this.#taskID = taskID;\n this.#id = cvrID;\n this.#rowCache = new RowRecordCache(\n lc,\n cvrDb,\n shard,\n cvrID,\n failService,\n deferredRowFlushThreshold,\n setTimeoutFn,\n );\n this.#loadAttemptIntervalMs = loadAttemptIntervalMs;\n this.#maxLoadAttempts = maxLoadAttempts;\n this.#upstreamSchemaName = upstreamSchema(shard);\n }\n\n #cvr(table: string) {\n return this.#db(`${this.#schema}.${table}`);\n }\n\n load(lc: LogContext, lastConnectTime: number): Promise<CVR> {\n return startAsyncSpan(tracer, 'cvr.load', async () => {\n let err: RowsVersionBehindError | undefined;\n for (let i = 0; i < this.#maxLoadAttempts; i++) {\n if (i > 0) {\n await sleep(this.#loadAttemptIntervalMs);\n }\n const result = await this.#load(lc, lastConnectTime);\n if (result instanceof RowsVersionBehindError) {\n lc.info?.(`attempt ${i + 1}: ${String(result)}`);\n err = result;\n continue;\n }\n return result;\n }\n assert(err);\n throw new ClientNotFoundError(\n `max attempts exceeded waiting for CVR@${err.cvrVersion} to catch up from ${err.rowsVersion}`,\n );\n });\n }\n\n async #load(\n lc: LogContext,\n lastConnectTime: number,\n ): Promise<CVR | RowsVersionBehindError> {\n const start = Date.now();\n\n const id = this.#id;\n const cvr: CVR = {\n id,\n version: EMPTY_CVR_VERSION,\n lastActive: 0,\n ttlClock: ttlClockFromNumber(0), // TTL clock starts at 0, not Date.now()\n replicaVersion: null,\n clients: {},\n queries: {},\n clientSchema: null,\n profileID: null,\n };\n\n const [instance, clientsRows, queryRows, desiresRows] =\n await this.#db.begin(Mode.READONLY, tx => [\n tx<\n (Omit<InstancesRow, 'clientGroupID'> & {\n profileID: string | null;\n deleted: boolean;\n rowsVersion: string | null;\n })[]\n >`SELECT cvr.\"version\", \n \"lastActive\",\n \"ttlClock\",\n \"replicaVersion\", \n \"owner\", \n \"grantedAt\",\n \"clientSchema\", \n \"profileID\",\n \"deleted\",\n rows.\"version\" as \"rowsVersion\"\n FROM ${this.#cvr('instances')} AS cvr\n LEFT JOIN ${this.#cvr('rowsVersion')} AS rows \n ON cvr.\"clientGroupID\" = rows.\"clientGroupID\"\n WHERE cvr.\"clientGroupID\" = ${id}`,\n tx<Pick<ClientsRow, 'clientID'>[]>`SELECT \"clientID\" FROM ${this.#cvr(\n 'clients',\n )}\n WHERE \"clientGroupID\" = ${id}`,\n tx<QueriesRow[]>`SELECT * FROM ${this.#cvr('queries')} \n WHERE \"clientGroupID\" = ${id} AND deleted IS DISTINCT FROM true`,\n tx<DesiresRow[]>`SELECT \n \"clientGroupID\",\n \"clientID\",\n \"queryHash\",\n \"patchVersion\",\n \"deleted\",\n \"ttlMs\" AS \"ttl\",\n \"inactivatedAtMs\" AS \"inactivatedAt\"\n FROM ${this.#cvr('desires')}\n WHERE \"clientGroupID\" = ${id}`,\n ]);\n\n if (instance.length === 0) {\n // This is the first time we see this CVR.\n this.putInstance({\n version: cvr.version,\n lastActive: 0,\n ttlClock: ttlClockFromNumber(0), // TTL clock starts at 0 for new instances\n replicaVersion: null,\n clientSchema: null,\n profileID: null,\n });\n } else {\n assert(instance.length === 1);\n const {\n version,\n lastActive,\n ttlClock,\n replicaVersion,\n owner,\n grantedAt,\n rowsVersion,\n clientSchema,\n profileID,\n deleted,\n } = instance[0];\n\n if (deleted) {\n throw new ClientNotFoundError(\n 'Client has been purged due to inactivity',\n );\n }\n\n if (owner !== this.#taskID) {\n if ((grantedAt ?? 0) > lastConnectTime) {\n throw new OwnershipError(owner, grantedAt, lastConnectTime);\n } else {\n // Fire-and-forget an ownership change to signal the current owner.\n // Note that the query is structured such that it only succeeds in the\n // correct conditions (i.e. gated on `grantedAt`).\n void this.#db`\n UPDATE ${this.#cvr('instances')} \n SET \"owner\" = ${this.#taskID}, \n \"grantedAt\" = ${lastConnectTime}\n WHERE \"clientGroupID\" = ${this.#id} AND\n (\"grantedAt\" IS NULL OR\n \"grantedAt\" <= to_timestamp(${lastConnectTime / 1000}))\n `\n .execute()\n .catch(this.#failService);\n }\n }\n\n if (version !== (rowsVersion ?? EMPTY_CVR_VERSION.stateVersion)) {\n // This will cause the load() method to wait for row catchup and retry.\n // Assuming the ownership signal succeeds, the current owner will stop\n // modifying the CVR and flush its pending row changes.\n return new RowsVersionBehindError(version, rowsVersion);\n }\n\n cvr.version = versionFromString(version);\n cvr.lastActive = lastActive;\n cvr.ttlClock = ttlClock;\n cvr.replicaVersion = replicaVersion;\n cvr.profileID = profileID;\n\n try {\n cvr.clientSchema =\n clientSchema === null\n ? null\n : v.parse(clientSchema, clientSchemaSchema);\n } catch (e) {\n throw new InvalidClientSchemaError(e);\n }\n }\n\n for (const row of clientsRows) {\n cvr.clients[row.clientID] = {\n id: row.clientID,\n desiredQueryIDs: [],\n };\n }\n\n for (const row of queryRows) {\n const query = asQuery(row);\n cvr.queries[row.queryHash] = query;\n }\n\n for (const row of desiresRows) {\n const client = cvr.clients[row.clientID];\n // Note: row.inactivatedAt is mapped from inactivatedAtMs in the SQL query\n if (client) {\n if (!row.deleted && row.inactivatedAt === null) {\n client.desiredQueryIDs.push(row.queryHash);\n }\n } else {\n // This can happen if the client was deleted but the queries are still alive.\n lc.debug?.(`Client ${row.clientID} not found`);\n }\n\n const query = cvr.queries[row.queryHash];\n if (\n query &&\n query.type !== 'internal' &&\n (!row.deleted || row.inactivatedAt !== null)\n ) {\n query.clientState[row.clientID] = {\n inactivatedAt: row.inactivatedAt ?? undefined,\n ttl: clampTTL(row.ttl ?? DEFAULT_TTL_MS),\n version: versionFromString(row.patchVersion),\n };\n }\n }\n lc.debug?.(\n `loaded cvr@${versionString(cvr.version)} (${Date.now() - start} ms)`,\n );\n\n // why do we not sort `desiredQueryIDs` here?\n\n return cvr;\n }\n\n getRowRecords(): Promise<ReadonlyMap<RowID, RowRecord>> {\n return this.#rowCache.getRowRecords();\n }\n\n putRowRecord(row: RowRecord): void {\n this.#pendingRowRecordUpdates.set(row.id, row);\n }\n\n /**\n * Note: Removing a row from the CVR should be represented by a\n * {@link putRowRecord()} with `refCounts: null` in order to properly\n * produce the appropriate delete patch when catching up old clients.\n *\n * This `delRowRecord()` method, on the other hand, is only used for\n * \"canceling\" the put of a row that was not in the CVR in the first place.\n */\n delRowRecord(id: RowID): void {\n this.#pendingRowRecordUpdates.set(id, null);\n }\n\n /**\n * Overrides the default logic that removes no-op writes and forces\n * the updates for the given row `ids`. This has no effect if there\n * are no corresponding puts or dels for the associated row records.\n */\n forceUpdates(...ids: RowID[]) {\n for (const id of ids) {\n this.#forceUpdates.add(id);\n }\n }\n\n /**\n * Updates the `ttlClock` of the CVR instance. The ttlClock starts at 0 when\n * the CVR instance is first created and increments based on elapsed time\n * since the base time established by the ViewSyncerService.\n */\n async updateTTLClock(ttlClock: TTLClock, lastActive: number): Promise<void> {\n await this.#db`UPDATE ${this.#cvr('instances')}\n SET \"lastActive\" = ${lastActive},\n \"ttlClock\" = ${ttlClock}\n WHERE \"clientGroupID\" = ${this.#id}`.execute();\n }\n\n /**\n * @returns This returns the current `ttlClock` of the CVR instance. The ttlClock\n * represents elapsed time since the instance was created (starting from 0).\n * If the CVR has never been initialized for this client group, it returns\n * `undefined`.\n */\n async getTTLClock(): Promise<TTLClock | undefined> {\n const result = await this.#db<Pick<InstancesRow, 'ttlClock'>[]>`\n SELECT \"ttlClock\" FROM ${this.#cvr('instances')}\n WHERE \"clientGroupID\" = ${this.#id}`.values();\n if (result.length === 0) {\n // This can happen if the CVR has not been initialized yet.\n return undefined;\n }\n assert(result.length === 1);\n return result[0][0];\n }\n\n putInstance({\n version,\n replicaVersion,\n lastActive,\n clientSchema,\n profileID,\n ttlClock,\n }: Pick<\n CVRSnapshot,\n | 'version'\n | 'replicaVersion'\n | 'lastActive'\n | 'clientSchema'\n | 'profileID'\n | 'ttlClock'\n >): void {\n this.#writes.add({\n stats: {instances: 1},\n write: (tx, lastConnectTime) => {\n const change: InstancesRow = {\n clientGroupID: this.#id,\n version: versionString(version),\n lastActive,\n ttlClock,\n replicaVersion,\n owner: this.#taskID,\n grantedAt: lastConnectTime,\n clientSchema,\n profileID,\n };\n return tx`\n INSERT INTO ${this.#cvr('instances')} ${tx(change)} \n ON CONFLICT (\"clientGroupID\") DO UPDATE SET ${tx(change)}`;\n },\n });\n }\n\n markQueryAsDeleted(version: CVRVersion, queryPatch: QueryPatch): void {\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`UPDATE ${this.#cvr('queries')} SET ${tx({\n patchVersion: versionString(version),\n deleted: true,\n transformationHash: null,\n transformationVersion: null,\n })}\n WHERE \"clientGroupID\" = ${this.#id} AND \"queryHash\" = ${queryPatch.id}`,\n });\n }\n\n putQuery(query: QueryRecord): void {\n const change: QueriesRow = queryRecordToQueryRow(this.#id, query);\n // ${JSON.stringify(change.queryArgs)}::text::json is used because postgres.js\n // gets confused if the input is `[boolean]` and throws an error saying a bool\n // cannot be converted to json.\n // https://github.com/porsager/postgres/issues/386\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`INSERT INTO ${this.#cvr('queries')} (\n \"clientGroupID\",\n \"queryHash\",\n \"clientAST\",\n \"queryName\",\n \"queryArgs\",\n \"patchVersion\",\n \"transformationHash\",\n \"transformationVersion\",\n \"internal\",\n \"deleted\"\n ) VALUES (\n ${change.clientGroupID},\n ${change.queryHash},\n ${change.clientAST},\n ${change.queryName},\n ${change.queryArgs === undefined ? null : JSON.stringify(change.queryArgs)}::text::json,\n ${change.patchVersion},\n ${change.transformationHash ?? null},\n ${change.transformationVersion ?? null},\n ${change.internal},\n ${change.deleted ?? false}\n )\n ON CONFLICT (\"clientGroupID\", \"queryHash\")\n DO UPDATE SET \n \"clientAST\" = ${change.clientAST},\n \"queryName\" = ${change.queryName},\n \"queryArgs\" = ${change.queryArgs === undefined ? null : JSON.stringify(change.queryArgs)}::text::json,\n \"patchVersion\" = ${change.patchVersion},\n \"transformationHash\" = ${change.transformationHash ?? null},\n \"transformationVersion\" = ${change.transformationVersion ?? null},\n \"internal\" = ${change.internal},\n \"deleted\" = ${change.deleted ?? false}`,\n });\n }\n\n updateQuery(query: QueryRecord) {\n const maybeVersionString = (v: CVRVersion | undefined) =>\n v ? versionString(v) : null;\n\n const change: Pick<\n QueriesRow,\n | 'patchVersion'\n | 'transformationHash'\n | 'transformationVersion'\n | 'deleted'\n > = {\n patchVersion:\n query.type === 'internal'\n ? null\n : maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n deleted: false,\n };\n\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`UPDATE ${this.#cvr('queries')} SET ${tx(change)}\n WHERE \"clientGroupID\" = ${this.#id} AND \"queryHash\" = ${query.id}`,\n });\n }\n\n insertClient(client: ClientRecord): void {\n const change: ClientsRow = {\n clientGroupID: this.#id,\n clientID: client.id,\n };\n\n this.#writes.add({\n stats: {clients: 1},\n write: tx => tx`INSERT INTO ${this.#cvr('clients')} ${tx(change)}`,\n });\n }\n\n deleteClient(clientID: string) {\n this.#writes.add({\n stats: {clients: 1},\n write: sql =>\n sql`DELETE FROM ${this.#cvr('clients')} \n WHERE \"clientGroupID\" = ${this.#id} \n AND \"clientID\" = ${clientID}`,\n });\n this.#upstreamWrites.push(\n sql =>\n sql`DELETE FROM ${sql(this.#upstreamSchemaName)}.\"mutations\" \n WHERE \"clientGroupID\" = ${this.#id} \n AND \"clientID\" = ${clientID}`,\n );\n }\n\n putDesiredQuery(\n newVersion: CVRVersion,\n query: {id: string},\n client: {id: string},\n deleted: boolean,\n inactivatedAt: TTLClock | undefined,\n ttl: number,\n ): void {\n const change: DesiresRow = {\n clientGroupID: this.#id,\n clientID: client.id,\n deleted,\n inactivatedAt: inactivatedAt ?? null,\n patchVersion: versionString(newVersion),\n queryHash: query.id,\n\n // ttl is in ms in JavaScript\n ttl: ttl < 0 ? null : ttl,\n };\n\n // For backward compatibility during rollout, write to both old and new columns:\n // Old columns: inactivatedAt (TIMESTAMPTZ), ttl (INTERVAL) - need conversion ms->seconds\n // New columns: inactivatedAtMs (DOUBLE PRECISION), ttlMs (DOUBLE PRECISION) - store ms directly (1:1 with JS)\n const inactivatedAtTimestamp =\n inactivatedAt === undefined\n ? null\n : ttlClockFromNumber(ttlClockAsNumber(inactivatedAt) / 1000);\n const inactivatedAtMs = inactivatedAt ?? null;\n const ttlInterval = ttl < 0 ? null : ttl / 1000; // INTERVAL needs seconds\n const ttlMs = ttl < 0 ? null : ttl; // New column stores ms directly\n\n this.#writes.add({\n stats: {desires: 1},\n write: tx => tx`\n INSERT INTO ${this.#cvr('desires')} (\n \"clientGroupID\", \"clientID\", \"queryHash\", \"patchVersion\", \"deleted\",\n \"ttl\", \"ttlMs\", \"inactivatedAt\", \"inactivatedAtMs\"\n ) VALUES (\n ${change.clientGroupID}, ${change.clientID}, ${change.queryHash}, \n ${change.patchVersion}, ${change.deleted}, ${ttlInterval}, ${ttlMs},\n ${inactivatedAtTimestamp}, ${inactivatedAtMs}\n )\n ON CONFLICT (\"clientGroupID\", \"clientID\", \"queryHash\")\n DO UPDATE SET\n \"patchVersion\" = ${change.patchVersion},\n \"deleted\" = ${change.deleted},\n \"ttl\" = ${ttlInterval},\n \"ttlMs\" = ${ttlMs},\n \"inactivatedAt\" = ${inactivatedAtTimestamp},\n \"inactivatedAtMs\" = ${inactivatedAtMs}\n `,\n });\n }\n\n catchupRowPatches(\n lc: LogContext,\n afterVersion: NullableCVRVersion,\n upToCVR: CVRSnapshot,\n current: CVRVersion,\n excludeQueryHashes: string[] = [],\n ): AsyncGenerator<RowsRow[], void, undefined> {\n return this.#rowCache.catchupRowPatches(\n lc,\n afterVersion,\n upToCVR,\n current,\n excludeQueryHashes,\n );\n }\n\n async catchupConfigPatches(\n lc: LogContext,\n afterVersion: NullableCVRVersion,\n upToCVR: CVRSnapshot,\n current: CVRVersion,\n ): Promise<PatchToVersion[]> {\n if (cmpVersions(afterVersion, upToCVR.version) >= 0) {\n return [];\n }\n\n const startMs = Date.now();\n const start = afterVersion ? versionString(afterVersion) : '';\n const end = versionString(upToCVR.version);\n lc.debug?.(`scanning config patches for clients from ${start}`);\n\n const reader = new TransactionPool(lc, Mode.READONLY).run(this.#db);\n try {\n // Verify that we are reading the right version of the CVR.\n await reader.processReadTask(tx =>\n checkVersion(tx, this.#schema, this.#id, current),\n );\n\n const [allDesires, queryRows] = await reader.processReadTask(tx =>\n Promise.all([\n tx<DesiresRow[]>`\n SELECT * FROM ${this.#cvr('desires')}\n WHERE \"clientGroupID\" = ${this.#id}\n AND \"patchVersion\" > ${start}\n AND \"patchVersion\" <= ${end}`,\n tx<Pick<QueriesRow, 'deleted' | 'queryHash' | 'patchVersion'>[]>`\n SELECT deleted, \"queryHash\", \"patchVersion\" FROM ${this.#cvr('queries')}\n WHERE \"clientGroupID\" = ${this.#id}\n AND \"patchVersion\" > ${start}\n AND \"patchVersion\" <= ${end}`,\n ]),\n );\n\n const patches: PatchToVersion[] = [];\n for (const row of queryRows) {\n const {queryHash: id} = row;\n const patch: Patch = row.deleted\n ? {type: 'query', op: 'del', id}\n : {type: 'query', op: 'put', id};\n const v = row.patchVersion;\n assert(v);\n patches.push({patch, toVersion: versionFromString(v)});\n }\n for (const row of allDesires) {\n const {clientID, queryHash: id} = row;\n const patch: Patch = row.deleted\n ? {type: 'query', op: 'del', id, clientID}\n : {type: 'query', op: 'put', id, clientID};\n patches.push({patch, toVersion: versionFromString(row.patchVersion)});\n }\n\n lc.debug?.(\n `${patches.length} config patches (${Date.now() - startMs} ms)`,\n );\n return patches;\n } finally {\n reader.setDone();\n }\n }\n\n async #checkVersionAndOwnership(\n tx: PostgresTransaction,\n expectedCurrentVersion: CVRVersion,\n lastConnectTime: number,\n ): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<\n Pick<InstancesRow, 'version' | 'owner' | 'grantedAt'>[]\n >`SELECT \"version\", \"owner\", \"grantedAt\" FROM ${this.#cvr('instances')}\n WHERE \"clientGroupID\" = ${this.#id}\n FOR UPDATE`.execute(); // Note: execute() immediately to send the query before others.\n const {version, owner, grantedAt} =\n result.length > 0\n ? result[0]\n : {\n version: EMPTY_CVR_VERSION.stateVersion,\n owner: null,\n grantedAt: null,\n };\n if (owner !== this.#taskID && (grantedAt ?? 0) > lastConnectTime) {\n throw new OwnershipError(owner, grantedAt, lastConnectTime);\n }\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n }\n\n async #flush(\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const stats: CVRFlushStats = {\n instances: 0,\n queries: 0,\n desires: 0,\n clients: 0,\n rows: 0,\n rowsDeferred: 0,\n statements: 0,\n };\n if (this.#pendingRowRecordUpdates.size) {\n const existingRowRecords = await this.getRowRecords();\n this.#rowCount = existingRowRecords.size;\n for (const [id, row] of this.#pendingRowRecordUpdates.entries()) {\n if (this.#forceUpdates.has(id)) {\n continue;\n }\n const existing = existingRowRecords.get(id);\n if (\n // Don't delete or add an unreferenced row if it's not in the CVR.\n (existing === undefined && !row?.refCounts) ||\n // Don't write a row record that exactly matches what's in the CVR.\n deepEqual(\n (row ?? undefined) as ReadonlyJSONValue | undefined,\n existing as ReadonlyJSONValue | undefined,\n )\n ) {\n this.#pendingRowRecordUpdates.delete(id);\n }\n }\n }\n if (this.#pendingRowRecordUpdates.size === 0 && this.#writes.size === 0) {\n return null;\n }\n // Note: The CVR instance itself is only updated if there are material\n // changes (i.e. changes to the CVR contents) to flush.\n this.putInstance(cvr);\n\n const rowsFlushed = await this.#db.begin(Mode.READ_COMMITTED, async tx => {\n const pipelined: Promise<unknown>[] = [\n // #checkVersionAndOwnership() executes a `SELECT ... FOR UPDATE`\n // query to acquire a row-level lock so that version-updating\n // transactions are effectively serialized per cvr.instance.\n //\n // Note that `rowsVersion` updates, on the other hand, are not subject\n // to this lock and can thus commit / be-committed independently of\n // cvr.instances.\n this.#checkVersionAndOwnership(\n tx,\n expectedCurrentVersion,\n lastConnectTime,\n ),\n ];\n\n for (const write of this.#writes) {\n stats.instances += write.stats.instances ?? 0;\n stats.queries += write.stats.queries ?? 0;\n stats.desires += write.stats.desires ?? 0;\n stats.clients += write.stats.clients ?? 0;\n stats.rows += write.stats.rows ?? 0;\n\n pipelined.push(write.write(tx, lastConnectTime).execute());\n stats.statements++;\n }\n\n const rowUpdates = this.#rowCache.executeRowUpdates(\n tx,\n cvr.version,\n this.#pendingRowRecordUpdates,\n 'allow-defer',\n );\n pipelined.push(...rowUpdates);\n stats.statements += rowUpdates.length;\n\n // Make sure Errors thrown by pipelined statements\n // are propagated up the stack.\n await Promise.all(pipelined);\n\n if (rowUpdates.length === 0) {\n stats.rowsDeferred = this.#pendingRowRecordUpdates.size;\n return false;\n }\n stats.rows += this.#pendingRowRecordUpdates.size;\n return true;\n });\n\n this.#rowCount = await this.#rowCache.apply(\n this.#pendingRowRecordUpdates,\n cvr.version,\n rowsFlushed,\n );\n recordRowsSynced(this.#rowCount);\n\n if (this.#upstreamDb) {\n await this.#upstreamDb.begin(Mode.READ_COMMITTED, async tx => {\n await Promise.all(this.#upstreamWrites.map(write => write(tx)));\n });\n }\n\n return stats;\n }\n\n get rowCount(): number {\n return this.#rowCount;\n }\n\n async flush(\n lc: LogContext,\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const start = performance.now();\n try {\n const stats = await this.#flush(\n expectedCurrentVersion,\n cvr,\n lastConnectTime,\n );\n if (stats) {\n const elapsed = performance.now() - start;\n lc.debug?.(\n `flushed cvr@${versionString(cvr.version)} ` +\n `${JSON.stringify(stats)} in (${elapsed} ms)`,\n );\n this.#rowCache.recordSyncFlushStats(stats, elapsed);\n }\n return stats;\n } catch (e) {\n // Clear cached state if an error (e.g. ConcurrentModificationException) is encountered.\n this.#rowCache.clear();\n throw e;\n } finally {\n this.#writes.clear();\n this.#upstreamWrites.length = 0;\n this.#pendingRowRecordUpdates.clear();\n this.#forceUpdates.clear();\n }\n }\n\n hasPendingUpdates(): boolean {\n return this.#rowCache.hasPendingUpdates();\n }\n\n /** Resolves when all pending updates are flushed. */\n flushed(lc: LogContext): Promise<void> {\n return this.#rowCache.flushed(lc);\n }\n\n async inspectQueries(\n lc: LogContext,\n ttlClock: TTLClock,\n clientID?: string,\n ): Promise<InspectQueryRow[]> {\n const db = this.#db;\n const clientGroupID = this.#id;\n\n const reader = new TransactionPool(lc, Mode.READONLY).run(db);\n try {\n return await reader.processReadTask(\n tx => tx<InspectQueryRow[]>`\n SELECT DISTINCT ON (d.\"clientID\", d.\"queryHash\")\n d.\"clientID\",\n d.\"queryHash\" AS \"queryID\",\n COALESCE(d.\"ttlMs\", ${DEFAULT_TTL_MS}) AS \"ttl\",\n d.\"inactivatedAtMs\" AS \"inactivatedAt\",\n (SELECT COUNT(*)::INT FROM ${this.#cvr('rows')} r \n WHERE r.\"clientGroupID\" = d.\"clientGroupID\" \n AND r.\"refCounts\" ? d.\"queryHash\") AS \"rowCount\",\n q.\"clientAST\" AS \"ast\",\n (q.\"patchVersion\" IS NOT NULL) AS \"got\",\n COALESCE(d.\"deleted\", FALSE) AS \"deleted\",\n q.\"queryName\" AS \"name\",\n q.\"queryArgs\" AS \"args\"\n FROM ${this.#cvr('desires')} d\n LEFT JOIN ${this.#cvr('queries')} q\n ON q.\"clientGroupID\" = d.\"clientGroupID\"\n AND q.\"queryHash\" = d.\"queryHash\"\n WHERE d.\"clientGroupID\" = ${clientGroupID}\n ${clientID ? tx`AND d.\"clientID\" = ${clientID}` : tx``}\n AND NOT (\n d.\"inactivatedAtMs\" IS NOT NULL \n AND d.\"ttlMs\" IS NOT NULL \n AND (d.\"inactivatedAtMs\" + d.\"ttlMs\") <= ${ttlClockAsNumber(ttlClock)}\n )\n ORDER BY d.\"clientID\", d.\"queryHash\"`,\n );\n } finally {\n reader.setDone();\n }\n }\n}\n\n/**\n * This is similar to {@link CVRStore.#checkVersionAndOwnership} except\n * that it only checks the version and is suitable for snapshot reads\n * (i.e. by doing a plain `SELECT` rather than a `SELECT ... FOR UPDATE`).\n */\nexport async function checkVersion(\n tx: PostgresTransaction,\n schema: string,\n clientGroupID: string,\n expectedCurrentVersion: CVRVersion,\n): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<Pick<InstancesRow, 'version'>[]>`\n SELECT version FROM ${tx(schema)}.instances \n WHERE \"clientGroupID\" = ${clientGroupID}`;\n const {version} =\n result.length > 0 ? result[0] : {version: EMPTY_CVR_VERSION.stateVersion};\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n}\n\nexport class ClientNotFoundError extends ProtocolErrorWithLevel {\n constructor(message: string) {\n super({\n kind: ErrorKind.ClientNotFound,\n message,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n}\n\nexport class ConcurrentModificationException extends ProtocolErrorWithLevel {\n readonly name = 'ConcurrentModificationException';\n\n constructor(expectedVersion: string, actualVersion: string) {\n super(\n {\n kind: ErrorKind.Internal,\n message: `CVR has been concurrently modified. Expected ${expectedVersion}, got ${actualVersion}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n}\n\nexport class OwnershipError extends ProtocolErrorWithLevel {\n readonly name = 'OwnershipError';\n\n constructor(\n owner: string | null,\n grantedAt: number | null,\n lastConnectTime: number,\n ) {\n super(\n {\n kind: ErrorKind.Rehome,\n message:\n `CVR ownership was transferred to ${owner} at ` +\n `${new Date(grantedAt ?? 0).toISOString()} ` +\n `(last connect time: ${new Date(lastConnectTime).toISOString()})`,\n maxBackoffMs: 0,\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n }\n}\n\nexport class InvalidClientSchemaError extends ProtocolErrorWithLevel {\n readonly name = 'InvalidClientSchemaError';\n\n constructor(cause: unknown) {\n super(\n {\n kind: ErrorKind.SchemaVersionNotSupported,\n message: `Could not parse clientSchema stored in CVR: ${String(cause)}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n {cause},\n );\n }\n}\n\nexport class RowsVersionBehindError extends Error {\n readonly name = 'RowsVersionBehindError';\n readonly cvrVersion: string;\n readonly rowsVersion: string | null;\n\n constructor(cvrVersion: string, rowsVersion: string | null) {\n super(`rowsVersion (${rowsVersion}) is behind CVR ${cvrVersion}`);\n this.cvrVersion = cvrVersion;\n this.rowsVersion = rowsVersion;\n }\n}\n"],"names":["Mode.READONLY","version","v.parse","v","Mode.READ_COMMITTED","ErrorKind.ClientNotFound","ErrorOrigin.ZeroCache","ErrorKind.Internal","ErrorKind.Rehome","ErrorKind.SchemaVersionNotSupported"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cvr-store.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"sourcesContent":["import {trace} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {MaybeRow, PendingQuery} from 'postgres';\nimport {startAsyncSpan} from '../../../../otel/src/span.ts';\nimport {version} from '../../../../otel/src/version.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {CustomKeyMap} from '../../../../shared/src/custom-key-map.ts';\nimport {CustomKeySet} from '../../../../shared/src/custom-key-set.ts';\nimport {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {sleep} from '../../../../shared/src/sleep.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../zero-protocol/src/ast.ts';\nimport {clientSchemaSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {InspectQueryRow} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {clampTTL, DEFAULT_TTL_MS} from '../../../../zql/src/query/ttl.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {TransactionPool} from '../../db/transaction-pool.ts';\nimport {recordRowsSynced} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {rowIDString} from '../../types/row-key.ts';\nimport {cvrSchema, type ShardID, upstreamSchema} from '../../types/shards.ts';\nimport type {Patch, PatchToVersion} from './client-handler.ts';\nimport type {CVR, CVRSnapshot} from './cvr.ts';\nimport {RowRecordCache} from './row-record-cache.ts';\nimport {\n type ClientsRow,\n type DesiresRow,\n type InstancesRow,\n type QueriesRow,\n type RowsRow,\n} from './schema/cvr.ts';\nimport {\n type ClientQueryRecord,\n type ClientRecord,\n cmpVersions,\n type CustomQueryRecord,\n type CVRVersion,\n EMPTY_CVR_VERSION,\n type InternalQueryRecord,\n type NullableCVRVersion,\n type QueryPatch,\n type QueryRecord,\n queryRecordToQueryRow,\n type RowID,\n type RowRecord,\n versionFromString,\n versionString,\n} from './schema/types.ts';\nimport {\n type TTLClock,\n ttlClockAsNumber,\n ttlClockFromNumber,\n} from './ttl-clock.ts';\n\nexport type CVRFlushStats = {\n instances: number;\n queries: number;\n desires: number;\n clients: number;\n rows: number;\n rowsDeferred: number;\n statements: number;\n};\n\nconst tracer = trace.getTracer('cvr-store', version);\n\nfunction asQuery(row: QueriesRow): QueryRecord {\n const maybeVersion = (s: string | null) =>\n s === null ? undefined : versionFromString(s);\n\n if (row.clientAST === null) {\n // custom query\n assert(\n row.queryName !== null && row.queryArgs !== null,\n 'queryName and queryArgs must be set for custom queries',\n );\n return {\n type: 'custom',\n id: row.queryHash,\n name: row.queryName,\n args: row.queryArgs,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies CustomQueryRecord;\n }\n\n const ast = astSchema.parse(row.clientAST);\n return row.internal\n ? ({\n type: 'internal',\n id: row.queryHash,\n ast,\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies InternalQueryRecord)\n : ({\n type: 'client',\n id: row.queryHash,\n ast,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies ClientQueryRecord);\n}\n\n// The time to wait between load attempts.\nconst LOAD_ATTEMPT_INTERVAL_MS = 500;\n// The maximum number of load() attempts if the rowsVersion is behind.\n// This currently results in a maximum catchup time of ~5 seconds, after\n// which we give up and consider the CVR invalid.\n//\n// TODO: Make this configurable with something like --max-catchup-wait-ms,\n// as it is technically application specific.\nconst MAX_LOAD_ATTEMPTS = 10;\n\nexport class CVRStore {\n readonly #schema: string;\n readonly #taskID: string;\n readonly #id: string;\n readonly #failService: (e: unknown) => void;\n readonly #db: PostgresDB;\n readonly #upstreamDb: PostgresDB | undefined;\n readonly #writes: Set<{\n stats: Partial<CVRFlushStats>;\n write: (\n tx: PostgresTransaction,\n lastConnectTime: number,\n ) => PendingQuery<MaybeRow[]>;\n }> = new Set();\n readonly #upstreamWrites: ((\n tx: PostgresTransaction,\n ) => PendingQuery<MaybeRow[]>)[] = [];\n readonly #pendingRowRecordUpdates = new CustomKeyMap<RowID, RowRecord | null>(\n rowIDString,\n );\n readonly #forceUpdates = new CustomKeySet<RowID>(rowIDString);\n readonly #rowCache: RowRecordCache;\n readonly #loadAttemptIntervalMs: number;\n readonly #maxLoadAttempts: number;\n readonly #upstreamSchemaName: string;\n #rowCount: number = 0;\n\n constructor(\n lc: LogContext,\n cvrDb: PostgresDB,\n // Optionally undefined to deal with custom upstreams.\n // This is temporary until we have a more principled protocol to deal with\n // custom upstreams and clearing their custom mutator responses.\n // An implementor could simply clear them after N minutes for the time being.\n upstreamDb: PostgresDB | undefined,\n shard: ShardID,\n taskID: string,\n cvrID: string,\n failService: (e: unknown) => void,\n loadAttemptIntervalMs = LOAD_ATTEMPT_INTERVAL_MS,\n maxLoadAttempts = MAX_LOAD_ATTEMPTS,\n deferredRowFlushThreshold = 100, // somewhat arbitrary\n setTimeoutFn = setTimeout,\n ) {\n this.#failService = failService;\n this.#db = cvrDb;\n this.#upstreamDb = upstreamDb;\n this.#schema = cvrSchema(shard);\n this.#taskID = taskID;\n this.#id = cvrID;\n this.#rowCache = new RowRecordCache(\n lc,\n cvrDb,\n shard,\n cvrID,\n failService,\n deferredRowFlushThreshold,\n setTimeoutFn,\n );\n this.#loadAttemptIntervalMs = loadAttemptIntervalMs;\n this.#maxLoadAttempts = maxLoadAttempts;\n this.#upstreamSchemaName = upstreamSchema(shard);\n }\n\n #cvr(table: string) {\n return this.#db(`${this.#schema}.${table}`);\n }\n\n load(lc: LogContext, lastConnectTime: number): Promise<CVR> {\n return startAsyncSpan(tracer, 'cvr.load', async () => {\n let err: RowsVersionBehindError | undefined;\n for (let i = 0; i < this.#maxLoadAttempts; i++) {\n if (i > 0) {\n await sleep(this.#loadAttemptIntervalMs);\n }\n const result = await this.#load(lc, lastConnectTime);\n if (result instanceof RowsVersionBehindError) {\n lc.info?.(`attempt ${i + 1}: ${String(result)}`);\n err = result;\n continue;\n }\n return result;\n }\n assert(err);\n throw new ClientNotFoundError(\n `max attempts exceeded waiting for CVR@${err.cvrVersion} to catch up from ${err.rowsVersion}`,\n );\n });\n }\n\n async #load(\n lc: LogContext,\n lastConnectTime: number,\n ): Promise<CVR | RowsVersionBehindError> {\n const start = Date.now();\n\n const id = this.#id;\n const cvr: CVR = {\n id,\n version: EMPTY_CVR_VERSION,\n lastActive: 0,\n ttlClock: ttlClockFromNumber(0), // TTL clock starts at 0, not Date.now()\n replicaVersion: null,\n clients: {},\n queries: {},\n clientSchema: null,\n profileID: null,\n };\n\n const [instance, clientsRows, queryRows, desiresRows] =\n await this.#db.begin(Mode.READONLY, tx => [\n tx<\n (Omit<InstancesRow, 'clientGroupID'> & {\n profileID: string | null;\n deleted: boolean;\n rowsVersion: string | null;\n })[]\n >`SELECT cvr.\"version\", \n \"lastActive\",\n \"ttlClock\",\n \"replicaVersion\", \n \"owner\", \n \"grantedAt\",\n \"clientSchema\", \n \"profileID\",\n \"deleted\",\n rows.\"version\" as \"rowsVersion\"\n FROM ${this.#cvr('instances')} AS cvr\n LEFT JOIN ${this.#cvr('rowsVersion')} AS rows \n ON cvr.\"clientGroupID\" = rows.\"clientGroupID\"\n WHERE cvr.\"clientGroupID\" = ${id}`,\n tx<Pick<ClientsRow, 'clientID'>[]>`SELECT \"clientID\" FROM ${this.#cvr(\n 'clients',\n )}\n WHERE \"clientGroupID\" = ${id}`,\n tx<QueriesRow[]>`SELECT * FROM ${this.#cvr('queries')} \n WHERE \"clientGroupID\" = ${id} AND deleted IS DISTINCT FROM true`,\n tx<DesiresRow[]>`SELECT \n \"clientGroupID\",\n \"clientID\",\n \"queryHash\",\n \"patchVersion\",\n \"deleted\",\n \"ttlMs\" AS \"ttl\",\n \"inactivatedAtMs\" AS \"inactivatedAt\"\n FROM ${this.#cvr('desires')}\n WHERE \"clientGroupID\" = ${id}`,\n ]);\n\n if (instance.length === 0) {\n // This is the first time we see this CVR.\n this.putInstance({\n version: cvr.version,\n lastActive: 0,\n ttlClock: ttlClockFromNumber(0), // TTL clock starts at 0 for new instances\n replicaVersion: null,\n clientSchema: null,\n profileID: null,\n });\n } else {\n assert(instance.length === 1);\n const {\n version,\n lastActive,\n ttlClock,\n replicaVersion,\n owner,\n grantedAt,\n rowsVersion,\n clientSchema,\n profileID,\n deleted,\n } = instance[0];\n\n if (deleted) {\n throw new ClientNotFoundError(\n 'Client has been purged due to inactivity',\n );\n }\n\n if (owner !== this.#taskID) {\n if ((grantedAt ?? 0) > lastConnectTime) {\n throw new OwnershipError(owner, grantedAt, lastConnectTime);\n } else {\n // Fire-and-forget an ownership change to signal the current owner.\n // Note that the query is structured such that it only succeeds in the\n // correct conditions (i.e. gated on `grantedAt`).\n void this.#db`\n UPDATE ${this.#cvr('instances')} \n SET \"owner\" = ${this.#taskID}, \n \"grantedAt\" = ${lastConnectTime}\n WHERE \"clientGroupID\" = ${this.#id} AND\n (\"grantedAt\" IS NULL OR\n \"grantedAt\" <= to_timestamp(${lastConnectTime / 1000}))\n `\n .execute()\n .catch(this.#failService);\n }\n }\n\n if (version !== (rowsVersion ?? EMPTY_CVR_VERSION.stateVersion)) {\n // This will cause the load() method to wait for row catchup and retry.\n // Assuming the ownership signal succeeds, the current owner will stop\n // modifying the CVR and flush its pending row changes.\n return new RowsVersionBehindError(version, rowsVersion);\n }\n\n cvr.version = versionFromString(version);\n cvr.lastActive = lastActive;\n cvr.ttlClock = ttlClock;\n cvr.replicaVersion = replicaVersion;\n cvr.profileID = profileID;\n\n try {\n cvr.clientSchema =\n clientSchema === null\n ? null\n : v.parse(clientSchema, clientSchemaSchema);\n } catch (e) {\n throw new InvalidClientSchemaError(e);\n }\n }\n\n for (const row of clientsRows) {\n cvr.clients[row.clientID] = {\n id: row.clientID,\n desiredQueryIDs: [],\n };\n }\n\n for (const row of queryRows) {\n const query = asQuery(row);\n cvr.queries[row.queryHash] = query;\n }\n\n for (const row of desiresRows) {\n const client = cvr.clients[row.clientID];\n // Note: row.inactivatedAt is mapped from inactivatedAtMs in the SQL query\n if (!row.deleted && row.inactivatedAt === null) {\n if (client) {\n client.desiredQueryIDs.push(row.queryHash);\n } else {\n // This can happen if the client was deleted but the queries are still alive.\n lc.debug?.(\n `Not adding to desiredQueryIDs for client ${row.clientID} because it has been deleted.`,\n );\n }\n }\n\n const query = cvr.queries[row.queryHash];\n if (\n query &&\n query.type !== 'internal' &&\n (!row.deleted || row.inactivatedAt !== null)\n ) {\n query.clientState[row.clientID] = {\n inactivatedAt: row.inactivatedAt ?? undefined,\n ttl: clampTTL(row.ttl ?? DEFAULT_TTL_MS),\n version: versionFromString(row.patchVersion),\n };\n }\n }\n\n lc.debug?.(\n `loaded cvr@${versionString(cvr.version)} (${Date.now() - start} ms)`,\n );\n\n // why do we not sort `desiredQueryIDs` here?\n\n return cvr;\n }\n\n getRowRecords(): Promise<ReadonlyMap<RowID, RowRecord>> {\n return this.#rowCache.getRowRecords();\n }\n\n putRowRecord(row: RowRecord): void {\n this.#pendingRowRecordUpdates.set(row.id, row);\n }\n\n /**\n * Note: Removing a row from the CVR should be represented by a\n * {@link putRowRecord()} with `refCounts: null` in order to properly\n * produce the appropriate delete patch when catching up old clients.\n *\n * This `delRowRecord()` method, on the other hand, is only used for\n * \"canceling\" the put of a row that was not in the CVR in the first place.\n */\n delRowRecord(id: RowID): void {\n this.#pendingRowRecordUpdates.set(id, null);\n }\n\n /**\n * Overrides the default logic that removes no-op writes and forces\n * the updates for the given row `ids`. This has no effect if there\n * are no corresponding puts or dels for the associated row records.\n */\n forceUpdates(...ids: RowID[]) {\n for (const id of ids) {\n this.#forceUpdates.add(id);\n }\n }\n\n /**\n * Updates the `ttlClock` of the CVR instance. The ttlClock starts at 0 when\n * the CVR instance is first created and increments based on elapsed time\n * since the base time established by the ViewSyncerService.\n */\n async updateTTLClock(ttlClock: TTLClock, lastActive: number): Promise<void> {\n await this.#db`UPDATE ${this.#cvr('instances')}\n SET \"lastActive\" = ${lastActive},\n \"ttlClock\" = ${ttlClock}\n WHERE \"clientGroupID\" = ${this.#id}`.execute();\n }\n\n /**\n * @returns This returns the current `ttlClock` of the CVR instance. The ttlClock\n * represents elapsed time since the instance was created (starting from 0).\n * If the CVR has never been initialized for this client group, it returns\n * `undefined`.\n */\n async getTTLClock(): Promise<TTLClock | undefined> {\n const result = await this.#db<Pick<InstancesRow, 'ttlClock'>[]>`\n SELECT \"ttlClock\" FROM ${this.#cvr('instances')}\n WHERE \"clientGroupID\" = ${this.#id}`.values();\n if (result.length === 0) {\n // This can happen if the CVR has not been initialized yet.\n return undefined;\n }\n assert(result.length === 1);\n return result[0][0];\n }\n\n putInstance({\n version,\n replicaVersion,\n lastActive,\n clientSchema,\n profileID,\n ttlClock,\n }: Pick<\n CVRSnapshot,\n | 'version'\n | 'replicaVersion'\n | 'lastActive'\n | 'clientSchema'\n | 'profileID'\n | 'ttlClock'\n >): void {\n this.#writes.add({\n stats: {instances: 1},\n write: (tx, lastConnectTime) => {\n const change: InstancesRow = {\n clientGroupID: this.#id,\n version: versionString(version),\n lastActive,\n ttlClock,\n replicaVersion,\n owner: this.#taskID,\n grantedAt: lastConnectTime,\n clientSchema,\n profileID,\n };\n return tx`\n INSERT INTO ${this.#cvr('instances')} ${tx(change)} \n ON CONFLICT (\"clientGroupID\") DO UPDATE SET ${tx(change)}`;\n },\n });\n }\n\n markQueryAsDeleted(version: CVRVersion, queryPatch: QueryPatch): void {\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`UPDATE ${this.#cvr('queries')} SET ${tx({\n patchVersion: versionString(version),\n deleted: true,\n transformationHash: null,\n transformationVersion: null,\n })}\n WHERE \"clientGroupID\" = ${this.#id} AND \"queryHash\" = ${queryPatch.id}`,\n });\n }\n\n putQuery(query: QueryRecord): void {\n const change: QueriesRow = queryRecordToQueryRow(this.#id, query);\n // ${JSON.stringify(change.queryArgs)}::text::json is used because postgres.js\n // gets confused if the input is `[boolean]` and throws an error saying a bool\n // cannot be converted to json.\n // https://github.com/porsager/postgres/issues/386\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`INSERT INTO ${this.#cvr('queries')} (\n \"clientGroupID\",\n \"queryHash\",\n \"clientAST\",\n \"queryName\",\n \"queryArgs\",\n \"patchVersion\",\n \"transformationHash\",\n \"transformationVersion\",\n \"internal\",\n \"deleted\"\n ) VALUES (\n ${change.clientGroupID},\n ${change.queryHash},\n ${change.clientAST},\n ${change.queryName},\n ${change.queryArgs === undefined ? null : JSON.stringify(change.queryArgs)}::text::json,\n ${change.patchVersion},\n ${change.transformationHash ?? null},\n ${change.transformationVersion ?? null},\n ${change.internal},\n ${change.deleted ?? false}\n )\n ON CONFLICT (\"clientGroupID\", \"queryHash\")\n DO UPDATE SET \n \"clientAST\" = ${change.clientAST},\n \"queryName\" = ${change.queryName},\n \"queryArgs\" = ${change.queryArgs === undefined ? null : JSON.stringify(change.queryArgs)}::text::json,\n \"patchVersion\" = ${change.patchVersion},\n \"transformationHash\" = ${change.transformationHash ?? null},\n \"transformationVersion\" = ${change.transformationVersion ?? null},\n \"internal\" = ${change.internal},\n \"deleted\" = ${change.deleted ?? false}`,\n });\n }\n\n updateQuery(query: QueryRecord) {\n const maybeVersionString = (v: CVRVersion | undefined) =>\n v ? versionString(v) : null;\n\n const change: Pick<\n QueriesRow,\n | 'patchVersion'\n | 'transformationHash'\n | 'transformationVersion'\n | 'deleted'\n > = {\n patchVersion:\n query.type === 'internal'\n ? null\n : maybeVersionString(query.patchVersion),\n transformationHash: query.transformationHash ?? null,\n transformationVersion: maybeVersionString(query.transformationVersion),\n deleted: false,\n };\n\n this.#writes.add({\n stats: {queries: 1},\n write: tx => tx`UPDATE ${this.#cvr('queries')} SET ${tx(change)}\n WHERE \"clientGroupID\" = ${this.#id} AND \"queryHash\" = ${query.id}`,\n });\n }\n\n insertClient(client: ClientRecord): void {\n const change: ClientsRow = {\n clientGroupID: this.#id,\n clientID: client.id,\n };\n\n this.#writes.add({\n stats: {clients: 1},\n write: tx => tx`INSERT INTO ${this.#cvr('clients')} ${tx(change)}`,\n });\n }\n\n deleteClient(clientID: string) {\n this.#writes.add({\n stats: {clients: 1},\n write: sql =>\n sql`DELETE FROM ${this.#cvr('clients')} \n WHERE \"clientGroupID\" = ${this.#id} \n AND \"clientID\" = ${clientID}`,\n });\n this.#upstreamWrites.push(\n sql =>\n sql`DELETE FROM ${sql(this.#upstreamSchemaName)}.\"mutations\" \n WHERE \"clientGroupID\" = ${this.#id} \n AND \"clientID\" = ${clientID}`,\n );\n }\n\n putDesiredQuery(\n newVersion: CVRVersion,\n query: {id: string},\n client: {id: string},\n deleted: boolean,\n inactivatedAt: TTLClock | undefined,\n ttl: number,\n ): void {\n const change: DesiresRow = {\n clientGroupID: this.#id,\n clientID: client.id,\n deleted,\n inactivatedAt: inactivatedAt ?? null,\n patchVersion: versionString(newVersion),\n queryHash: query.id,\n\n // ttl is in ms in JavaScript\n ttl: ttl < 0 ? null : ttl,\n };\n\n // For backward compatibility during rollout, write to both old and new columns:\n // Old columns: inactivatedAt (TIMESTAMPTZ), ttl (INTERVAL) - need conversion ms->seconds\n // New columns: inactivatedAtMs (DOUBLE PRECISION), ttlMs (DOUBLE PRECISION) - store ms directly (1:1 with JS)\n const inactivatedAtTimestamp =\n inactivatedAt === undefined\n ? null\n : ttlClockFromNumber(ttlClockAsNumber(inactivatedAt) / 1000);\n const inactivatedAtMs = inactivatedAt ?? null;\n const ttlInterval = ttl < 0 ? null : ttl / 1000; // INTERVAL needs seconds\n const ttlMs = ttl < 0 ? null : ttl; // New column stores ms directly\n\n this.#writes.add({\n stats: {desires: 1},\n write: tx => tx`\n INSERT INTO ${this.#cvr('desires')} (\n \"clientGroupID\", \"clientID\", \"queryHash\", \"patchVersion\", \"deleted\",\n \"ttl\", \"ttlMs\", \"inactivatedAt\", \"inactivatedAtMs\"\n ) VALUES (\n ${change.clientGroupID}, ${change.clientID}, ${change.queryHash}, \n ${change.patchVersion}, ${change.deleted}, ${ttlInterval}, ${ttlMs},\n ${inactivatedAtTimestamp}, ${inactivatedAtMs}\n )\n ON CONFLICT (\"clientGroupID\", \"clientID\", \"queryHash\")\n DO UPDATE SET\n \"patchVersion\" = ${change.patchVersion},\n \"deleted\" = ${change.deleted},\n \"ttl\" = ${ttlInterval},\n \"ttlMs\" = ${ttlMs},\n \"inactivatedAt\" = ${inactivatedAtTimestamp},\n \"inactivatedAtMs\" = ${inactivatedAtMs}\n `,\n });\n }\n\n catchupRowPatches(\n lc: LogContext,\n afterVersion: NullableCVRVersion,\n upToCVR: CVRSnapshot,\n current: CVRVersion,\n excludeQueryHashes: string[] = [],\n ): AsyncGenerator<RowsRow[], void, undefined> {\n return this.#rowCache.catchupRowPatches(\n lc,\n afterVersion,\n upToCVR,\n current,\n excludeQueryHashes,\n );\n }\n\n async catchupConfigPatches(\n lc: LogContext,\n afterVersion: NullableCVRVersion,\n upToCVR: CVRSnapshot,\n current: CVRVersion,\n ): Promise<PatchToVersion[]> {\n if (cmpVersions(afterVersion, upToCVR.version) >= 0) {\n return [];\n }\n\n const startMs = Date.now();\n const start = afterVersion ? versionString(afterVersion) : '';\n const end = versionString(upToCVR.version);\n lc.debug?.(`scanning config patches for clients from ${start}`);\n\n const reader = new TransactionPool(lc, Mode.READONLY).run(this.#db);\n try {\n // Verify that we are reading the right version of the CVR.\n await reader.processReadTask(tx =>\n checkVersion(tx, this.#schema, this.#id, current),\n );\n\n const [allDesires, queryRows] = await reader.processReadTask(tx =>\n Promise.all([\n tx<DesiresRow[]>`\n SELECT * FROM ${this.#cvr('desires')}\n WHERE \"clientGroupID\" = ${this.#id}\n AND \"patchVersion\" > ${start}\n AND \"patchVersion\" <= ${end}`,\n tx<Pick<QueriesRow, 'deleted' | 'queryHash' | 'patchVersion'>[]>`\n SELECT deleted, \"queryHash\", \"patchVersion\" FROM ${this.#cvr('queries')}\n WHERE \"clientGroupID\" = ${this.#id}\n AND \"patchVersion\" > ${start}\n AND \"patchVersion\" <= ${end}`,\n ]),\n );\n\n const patches: PatchToVersion[] = [];\n for (const row of queryRows) {\n const {queryHash: id} = row;\n const patch: Patch = row.deleted\n ? {type: 'query', op: 'del', id}\n : {type: 'query', op: 'put', id};\n const v = row.patchVersion;\n assert(v);\n patches.push({patch, toVersion: versionFromString(v)});\n }\n for (const row of allDesires) {\n const {clientID, queryHash: id} = row;\n const patch: Patch = row.deleted\n ? {type: 'query', op: 'del', id, clientID}\n : {type: 'query', op: 'put', id, clientID};\n patches.push({patch, toVersion: versionFromString(row.patchVersion)});\n }\n\n lc.debug?.(\n `${patches.length} config patches (${Date.now() - startMs} ms)`,\n );\n return patches;\n } finally {\n reader.setDone();\n }\n }\n\n async #checkVersionAndOwnership(\n tx: PostgresTransaction,\n expectedCurrentVersion: CVRVersion,\n lastConnectTime: number,\n ): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<\n Pick<InstancesRow, 'version' | 'owner' | 'grantedAt'>[]\n >`SELECT \"version\", \"owner\", \"grantedAt\" FROM ${this.#cvr('instances')}\n WHERE \"clientGroupID\" = ${this.#id}\n FOR UPDATE`.execute(); // Note: execute() immediately to send the query before others.\n const {version, owner, grantedAt} =\n result.length > 0\n ? result[0]\n : {\n version: EMPTY_CVR_VERSION.stateVersion,\n owner: null,\n grantedAt: null,\n };\n if (owner !== this.#taskID && (grantedAt ?? 0) > lastConnectTime) {\n throw new OwnershipError(owner, grantedAt, lastConnectTime);\n }\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n }\n\n async #flush(\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const stats: CVRFlushStats = {\n instances: 0,\n queries: 0,\n desires: 0,\n clients: 0,\n rows: 0,\n rowsDeferred: 0,\n statements: 0,\n };\n if (this.#pendingRowRecordUpdates.size) {\n const existingRowRecords = await this.getRowRecords();\n this.#rowCount = existingRowRecords.size;\n for (const [id, row] of this.#pendingRowRecordUpdates.entries()) {\n if (this.#forceUpdates.has(id)) {\n continue;\n }\n const existing = existingRowRecords.get(id);\n if (\n // Don't delete or add an unreferenced row if it's not in the CVR.\n (existing === undefined && !row?.refCounts) ||\n // Don't write a row record that exactly matches what's in the CVR.\n deepEqual(\n (row ?? undefined) as ReadonlyJSONValue | undefined,\n existing as ReadonlyJSONValue | undefined,\n )\n ) {\n this.#pendingRowRecordUpdates.delete(id);\n }\n }\n }\n if (this.#pendingRowRecordUpdates.size === 0 && this.#writes.size === 0) {\n return null;\n }\n // Note: The CVR instance itself is only updated if there are material\n // changes (i.e. changes to the CVR contents) to flush.\n this.putInstance(cvr);\n\n const rowsFlushed = await this.#db.begin(Mode.READ_COMMITTED, async tx => {\n const pipelined: Promise<unknown>[] = [\n // #checkVersionAndOwnership() executes a `SELECT ... FOR UPDATE`\n // query to acquire a row-level lock so that version-updating\n // transactions are effectively serialized per cvr.instance.\n //\n // Note that `rowsVersion` updates, on the other hand, are not subject\n // to this lock and can thus commit / be-committed independently of\n // cvr.instances.\n this.#checkVersionAndOwnership(\n tx,\n expectedCurrentVersion,\n lastConnectTime,\n ),\n ];\n\n for (const write of this.#writes) {\n stats.instances += write.stats.instances ?? 0;\n stats.queries += write.stats.queries ?? 0;\n stats.desires += write.stats.desires ?? 0;\n stats.clients += write.stats.clients ?? 0;\n stats.rows += write.stats.rows ?? 0;\n\n pipelined.push(write.write(tx, lastConnectTime).execute());\n stats.statements++;\n }\n\n const rowUpdates = this.#rowCache.executeRowUpdates(\n tx,\n cvr.version,\n this.#pendingRowRecordUpdates,\n 'allow-defer',\n );\n pipelined.push(...rowUpdates);\n stats.statements += rowUpdates.length;\n\n // Make sure Errors thrown by pipelined statements\n // are propagated up the stack.\n await Promise.all(pipelined);\n\n if (rowUpdates.length === 0) {\n stats.rowsDeferred = this.#pendingRowRecordUpdates.size;\n return false;\n }\n stats.rows += this.#pendingRowRecordUpdates.size;\n return true;\n });\n\n this.#rowCount = await this.#rowCache.apply(\n this.#pendingRowRecordUpdates,\n cvr.version,\n rowsFlushed,\n );\n recordRowsSynced(this.#rowCount);\n\n if (this.#upstreamDb) {\n await this.#upstreamDb.begin(Mode.READ_COMMITTED, async tx => {\n await Promise.all(this.#upstreamWrites.map(write => write(tx)));\n });\n }\n\n return stats;\n }\n\n get rowCount(): number {\n return this.#rowCount;\n }\n\n async flush(\n lc: LogContext,\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const start = performance.now();\n try {\n const stats = await this.#flush(\n expectedCurrentVersion,\n cvr,\n lastConnectTime,\n );\n if (stats) {\n const elapsed = performance.now() - start;\n lc.debug?.(\n `flushed cvr@${versionString(cvr.version)} ` +\n `${JSON.stringify(stats)} in (${elapsed} ms)`,\n );\n this.#rowCache.recordSyncFlushStats(stats, elapsed);\n }\n return stats;\n } catch (e) {\n // Clear cached state if an error (e.g. ConcurrentModificationException) is encountered.\n this.#rowCache.clear();\n throw e;\n } finally {\n this.#writes.clear();\n this.#upstreamWrites.length = 0;\n this.#pendingRowRecordUpdates.clear();\n this.#forceUpdates.clear();\n }\n }\n\n hasPendingUpdates(): boolean {\n return this.#rowCache.hasPendingUpdates();\n }\n\n /** Resolves when all pending updates are flushed. */\n flushed(lc: LogContext): Promise<void> {\n return this.#rowCache.flushed(lc);\n }\n\n async inspectQueries(\n lc: LogContext,\n ttlClock: TTLClock,\n clientID?: string,\n ): Promise<InspectQueryRow[]> {\n const db = this.#db;\n const clientGroupID = this.#id;\n\n const reader = new TransactionPool(lc, Mode.READONLY).run(db);\n try {\n return await reader.processReadTask(\n tx => tx<InspectQueryRow[]>`\n SELECT DISTINCT ON (d.\"clientID\", d.\"queryHash\")\n d.\"clientID\",\n d.\"queryHash\" AS \"queryID\",\n COALESCE(d.\"ttlMs\", ${DEFAULT_TTL_MS}) AS \"ttl\",\n d.\"inactivatedAtMs\" AS \"inactivatedAt\",\n (SELECT COUNT(*)::INT FROM ${this.#cvr('rows')} r \n WHERE r.\"clientGroupID\" = d.\"clientGroupID\" \n AND r.\"refCounts\" ? d.\"queryHash\") AS \"rowCount\",\n q.\"clientAST\" AS \"ast\",\n (q.\"patchVersion\" IS NOT NULL) AS \"got\",\n COALESCE(d.\"deleted\", FALSE) AS \"deleted\",\n q.\"queryName\" AS \"name\",\n q.\"queryArgs\" AS \"args\"\n FROM ${this.#cvr('desires')} d\n LEFT JOIN ${this.#cvr('queries')} q\n ON q.\"clientGroupID\" = d.\"clientGroupID\"\n AND q.\"queryHash\" = d.\"queryHash\"\n WHERE d.\"clientGroupID\" = ${clientGroupID}\n ${clientID ? tx`AND d.\"clientID\" = ${clientID}` : tx``}\n AND NOT (\n d.\"inactivatedAtMs\" IS NOT NULL \n AND d.\"ttlMs\" IS NOT NULL \n AND (d.\"inactivatedAtMs\" + d.\"ttlMs\") <= ${ttlClockAsNumber(ttlClock)}\n )\n ORDER BY d.\"clientID\", d.\"queryHash\"`,\n );\n } finally {\n reader.setDone();\n }\n }\n}\n\n/**\n * This is similar to {@link CVRStore.#checkVersionAndOwnership} except\n * that it only checks the version and is suitable for snapshot reads\n * (i.e. by doing a plain `SELECT` rather than a `SELECT ... FOR UPDATE`).\n */\nexport async function checkVersion(\n tx: PostgresTransaction,\n schema: string,\n clientGroupID: string,\n expectedCurrentVersion: CVRVersion,\n): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<Pick<InstancesRow, 'version'>[]>`\n SELECT version FROM ${tx(schema)}.instances \n WHERE \"clientGroupID\" = ${clientGroupID}`;\n const {version} =\n result.length > 0 ? result[0] : {version: EMPTY_CVR_VERSION.stateVersion};\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n}\n\nexport class ClientNotFoundError extends ProtocolErrorWithLevel {\n constructor(message: string) {\n super({\n kind: ErrorKind.ClientNotFound,\n message,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n}\n\nexport class ConcurrentModificationException extends ProtocolErrorWithLevel {\n readonly name = 'ConcurrentModificationException';\n\n constructor(expectedVersion: string, actualVersion: string) {\n super(\n {\n kind: ErrorKind.Internal,\n message: `CVR has been concurrently modified. Expected ${expectedVersion}, got ${actualVersion}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n}\n\nexport class OwnershipError extends ProtocolErrorWithLevel {\n readonly name = 'OwnershipError';\n\n constructor(\n owner: string | null,\n grantedAt: number | null,\n lastConnectTime: number,\n ) {\n super(\n {\n kind: ErrorKind.Rehome,\n message:\n `CVR ownership was transferred to ${owner} at ` +\n `${new Date(grantedAt ?? 0).toISOString()} ` +\n `(last connect time: ${new Date(lastConnectTime).toISOString()})`,\n maxBackoffMs: 0,\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n }\n}\n\nexport class InvalidClientSchemaError extends ProtocolErrorWithLevel {\n readonly name = 'InvalidClientSchemaError';\n\n constructor(cause: unknown) {\n super(\n {\n kind: ErrorKind.SchemaVersionNotSupported,\n message: `Could not parse clientSchema stored in CVR: ${String(cause)}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n {cause},\n );\n }\n}\n\nexport class RowsVersionBehindError extends Error {\n readonly name = 'RowsVersionBehindError';\n readonly cvrVersion: string;\n readonly rowsVersion: string | null;\n\n constructor(cvrVersion: string, rowsVersion: string | null) {\n super(`rowsVersion (${rowsVersion}) is behind CVR ${cvrVersion}`);\n this.cvrVersion = cvrVersion;\n this.rowsVersion = rowsVersion;\n }\n}\n"],"names":["Mode.READONLY","version","v.parse","v","Mode.READ_COMMITTED","ErrorKind.ClientNotFound","ErrorOrigin.ZeroCache","ErrorKind.Internal","ErrorKind.Rehome","ErrorKind.SchemaVersionNotSupported"],"mappings":"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"}
|
|
@@ -9,7 +9,6 @@ import { type LoadedPermissions } from '../../auth/load-permissions.ts';
|
|
|
9
9
|
import type { LogConfig } from '../../config/zero-config.ts';
|
|
10
10
|
import type { InspectorDelegate } from '../../server/inspector-delegate.ts';
|
|
11
11
|
import { type RowKey } from '../../types/row-key.ts';
|
|
12
|
-
import type { SchemaVersions } from '../../types/schema-versions.ts';
|
|
13
12
|
import { type ShardID } from '../../types/shards.ts';
|
|
14
13
|
import type { Snapshotter } from './snapshotter.ts';
|
|
15
14
|
export type RowAdd = {
|
|
@@ -43,7 +42,7 @@ export type Timer = {
|
|
|
43
42
|
*/
|
|
44
43
|
export declare class PipelineDriver {
|
|
45
44
|
#private;
|
|
46
|
-
constructor(lc: LogContext, logConfig: LogConfig, snapshotter: Snapshotter, shardID: ShardID, storage: ClientGroupStorage, clientGroupID: string, inspectorDelegate: InspectorDelegate, yieldThresholdMs: number, enablePlanner?: boolean);
|
|
45
|
+
constructor(lc: LogContext, logConfig: LogConfig, snapshotter: Snapshotter, shardID: ShardID, storage: ClientGroupStorage, clientGroupID: string, inspectorDelegate: InspectorDelegate, yieldThresholdMs: () => number, enablePlanner?: boolean);
|
|
47
46
|
/**
|
|
48
47
|
* Initializes the PipelineDriver to the current head of the database.
|
|
49
48
|
* Queries can then be added (i.e. hydrated) with {@link addQuery()}.
|
|
@@ -69,12 +68,6 @@ export declare class PipelineDriver {
|
|
|
69
68
|
* iteration has begun.
|
|
70
69
|
*/
|
|
71
70
|
currentVersion(): string;
|
|
72
|
-
/**
|
|
73
|
-
* Returns the current supported schema version range of the database. This
|
|
74
|
-
* will reflect changes to supported schema version range when calling
|
|
75
|
-
* {@link advance()} once the iteration has begun.
|
|
76
|
-
*/
|
|
77
|
-
currentSchemaVersions(): SchemaVersions;
|
|
78
71
|
/**
|
|
79
72
|
* Returns the current upstream {app}.permissions, or `null` if none are defined.
|
|
80
73
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-driver.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAIjD,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,sCAAsC,CAAC;AAC9D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gDAAgD,CAAC;AACjF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,uCAAuC,CAAC;AAC/D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,8CAA8C,CAAC;AAQ7E,OAAO,EAAC,KAAK,KAAK,EAAe,MAAM,qCAAqC,CAAC;AAS7E,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,4CAA4C,CAAC;AAInF,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,6BAA6B,CAAC;AAO3D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,
|
|
1
|
+
{"version":3,"file":"pipeline-driver.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -121,15 +121,6 @@ class PipelineDriver {
|
|
|
121
121
|
assert(this.initialized(), "Not yet initialized");
|
|
122
122
|
return this.#snapshotter.current().version;
|
|
123
123
|
}
|
|
124
|
-
/**
|
|
125
|
-
* Returns the current supported schema version range of the database. This
|
|
126
|
-
* will reflect changes to supported schema version range when calling
|
|
127
|
-
* {@link advance()} once the iteration has begun.
|
|
128
|
-
*/
|
|
129
|
-
currentSchemaVersions() {
|
|
130
|
-
assert(this.initialized(), "Not yet initialized");
|
|
131
|
-
return this.#snapshotter.current().schemaVersions;
|
|
132
|
-
}
|
|
133
124
|
/**
|
|
134
125
|
* Returns the current upstream {app}.permissions, or `null` if none are defined.
|
|
135
126
|
*/
|
|
@@ -436,7 +427,7 @@ class PipelineDriver {
|
|
|
436
427
|
}
|
|
437
428
|
#shouldYield() {
|
|
438
429
|
if (this.#hydrateContext) {
|
|
439
|
-
return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs;
|
|
430
|
+
return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs();
|
|
440
431
|
}
|
|
441
432
|
if (this.#advanceContext) {
|
|
442
433
|
return this.#shouldAdvanceYieldMaybeAbortAdvance();
|
|
@@ -469,7 +460,7 @@ class PipelineDriver {
|
|
|
469
460
|
`Advancement exceeded timeout at ${pos} of ${numChanges} changes after ${elapsed} ms. Advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms.`
|
|
470
461
|
);
|
|
471
462
|
}
|
|
472
|
-
return advanceTimer.elapsedLap() > this.#yieldThresholdMs;
|
|
463
|
+
return advanceTimer.elapsedLap() > this.#yieldThresholdMs();
|
|
473
464
|
}
|
|
474
465
|
/** Implements `BuilderDelegate.createStorage()` */
|
|
475
466
|
#createStorage() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport {type Input, type Storage} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport type {SchemaVersions} from '../../types/schema-versions.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {getSubscriptionState} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly originalHash: string;\n readonly transformedAst: AST; // Optional, only set after hydration\n readonly transformationHash: string; // The hash of the transformed AST\n};\n\ntype AdvanceContext = {\n readonly timer: Timer;\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n pos: number;\n};\n\ntype HydrateContext = {\n readonly timer: Timer;\n};\n\nexport type Timer = {\n elapsedLap: () => number;\n totalElapsed: () => number;\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 50;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // We probs need the original query hash\n // so we can decide not to re-transform a custom query\n // that is already hydrated.\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n readonly #yieldThresholdMs: number;\n #streamer: Streamer | null = null;\n #hydrateContext: HydrateContext | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n yieldThresholdMs: number,\n enablePlanner?: boolean,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n this.#yieldThresholdMs = yieldThresholdMs;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const {input} of this.#pipelines.values()) {\n input.destroy();\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(this.#lc, db.db, this.#tableSpecs, fullTables);\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current supported schema version range of the database. This\n * will reflect changes to supported schema version range when calling\n * {@link advance()} once the iteration has begun.\n */\n currentSchemaVersions(): SchemaVersions {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().schemaVersions;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return The Set of query hashes for all added queries. */\n addedQueries(): [\n transformationHashes: Set<string>,\n byOriginalHash: Map<\n string,\n {\n transformationHash: string;\n transformedAst: AST;\n }[]\n >,\n ] {\n const byOriginalHash = new Map<\n string,\n {transformationHash: string; transformedAst: AST}[]\n >();\n for (const pipeline of this.#pipelines.values()) {\n const {originalHash, transformedAst, transformationHash} = pipeline;\n\n if (!byOriginalHash.has(originalHash)) {\n byOriginalHash.set(originalHash, []);\n }\n byOriginalHash.get(originalHash)!.push({\n transformationHash,\n transformedAst,\n });\n }\n return [new Set(this.#pipelines.keys()), byOriginalHash];\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with an identical hash has already been added, this method is a\n * no-op and no RowChanges are generated.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: Timer,\n ): Iterable<RowChange | 'yield'> {\n assert(this.initialized());\n this.#inspectorDelegate.addQuery(transformationHash, queryID, query);\n if (this.#pipelines.has(transformationHash)) {\n this.#lc.info?.(`query ${transformationHash} already added`, query);\n return;\n }\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n const input = buildPipeline(\n query,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n transformationHash,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n streamer.accumulate(transformationHash, schema, [change]);\n return [];\n },\n });\n\n assert(this.#advanceContext === null);\n this.#hydrateContext = {\n timer,\n };\n try {\n yield* hydrateInternal(\n input,\n transformationHash,\n must(this.#primaryKeys),\n );\n } finally {\n this.#hydrateContext = null;\n }\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('hash', transformationHash)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(transformationHash, {\n input,\n hydrationTimeMs,\n originalHash: queryID,\n transformedAst: query,\n transformationHash,\n });\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(hash: string) {\n const pipeline = this.#pipelines.get(hash);\n if (pipeline) {\n this.#pipelines.delete(hash);\n pipeline.input.destroy();\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: Timer): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange | 'yield'>;\n } {\n assert(this.initialized());\n const diff = this.#snapshotter.advance(this.#tableSpecs);\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: Timer,\n numChanges: number,\n ): Iterable<RowChange | 'yield'> {\n assert(this.#hydrateContext === null);\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n // Advance progress is checked each time a row is fetched\n // from a TableSource during push processing, but some pushes\n // don't read any rows. Check progress here before processing\n // the next change.\n if (this.#shouldAdvanceYieldMaybeAbortAdvance()) {\n yield 'yield';\n }\n const start = performance.now();\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = performance.now() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n () => this.#shouldYield(),\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n #shouldYield(): boolean {\n if (this.#hydrateContext) {\n return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs;\n }\n if (this.#advanceContext) {\n return this.#shouldAdvanceYieldMaybeAbortAdvance();\n }\n throw new Error('shouldYield called outside of hydration or advancement');\n }\n\n /**\n * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if\n * it has taken longer than half the total hydration time to make it through\n * half of the advancement, or if processing time exceeds total hydration\n * time. This serves as both a circuit breaker for very large transactions,\n * as well as a bound on the amount of time the previous connection locks\n * the inactive WAL file (as the lock prevents WAL2 from switching to the\n * free WAL when the current one is over the size limit, which can make\n * the WAL grow continuously and compound slowness).\n * This is checked:\n * 1. before starting to process each change in an advancement is processed\n * 2. whenever a row is fetched from a TableSource during push processing\n */\n #shouldAdvanceYieldMaybeAbortAdvance(): boolean {\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = must(this.#advanceContext);\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes ` +\n `after ${elapsed} ms. Advancement time limited based on total ` +\n `hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n return advanceTimer.elapsedLap() > this.#yieldThresholdMs;\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(\n source: TableSource,\n change: SourceChange,\n ): Iterable<RowChange | 'yield'> {\n this.#startAccumulating();\n try {\n for (const val of source.genPush(change)) {\n if (val === 'yield') {\n yield 'yield';\n }\n for (const changeOrYield of this.#stopAccumulating().stream()) {\n yield changeOrYield;\n }\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null);\n this.#streamer = new Streamer(must(this.#primaryKeys));\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer);\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n\n constructor(primaryKeys: Map<string, PrimaryKey>) {\n this.#primaryKeys = primaryKeys;\n }\n\n readonly #changes: [\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ][] = [];\n\n accumulate(\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): this {\n this.#changes.push([hash, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange | 'yield'> {\n for (const [hash, schema, changes] of this.#changes) {\n yield* this.#streamChanges(hash, schema, changes);\n }\n }\n\n *#streamChanges(\n queryHash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n if (change === 'yield') {\n yield change;\n continue;\n }\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryHash, schema, type, () => [\n change.node,\n ]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryHash, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryHash, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryHash: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const {relationships, row} = node;\n const rowKey = getRowKey(primaryKey, row);\n\n yield {\n type: op,\n queryHash,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryHash, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node | 'yield'>): Iterable<Change | 'yield'> {\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n"],"names":["input"],"mappings":";;;;;;;;;;;;;;;;;AAsGA,MAAM,gCAAgC;AAK/B,MAAM,eAAe;AAAA,EACjB,8BAAc,IAAA;AAAA;AAAA;AAAA;AAAA,EAId,iCAAiB,IAAA;AAAA,EAEjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kCAAkB,IAAA;AAAA,EAClB;AAAA,EACA;AAAA,EACT,YAA6B;AAAA,EAC7B,kBAAyC;AAAA,EACzC,kBAAyC;AAAA,EACzC,kBAAiC;AAAA,EACjC,eAA+C;AAAA,EAC/C,eAAyC;AAAA,EAEhC,eAAe,qBAAqB,QAAQ,oBAAoB;AAAA,IACvE,aACE;AAAA,IACF,MAAM;AAAA,EAAA,CACP;AAAA,EAEQ,uBAAuB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGO;AAAA,EAET,YACE,IACA,WACA,aACA,SACA,SACA,eACA,mBACA,kBACA,eACA;AACA,SAAK,MAAM,GAAG,YAAY,iBAAiB,aAAa;AACxD,SAAK,eAAe;AACpB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,aAAa;AAClB,SAAK,qBAAqB;AAC1B,SAAK,cAAc,gBAAgB,oBAAI,QAAA,IAAY;AACnD,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,cAA4B;AAC/B,WAAO,CAAC,KAAK,aAAa,YAAA,GAAe,qBAAqB;AAC9D,SAAK,aAAa,KAAA;AAClB,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,aAAa,YAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAA4B;AAChC,eAAW,EAAC,MAAA,KAAU,KAAK,WAAW,UAAU;AAC9C,YAAM,QAAA;AAAA,IACR;AACA,SAAK,WAAW,MAAA;AAChB,SAAK,QAAQ,MAAA;AACb,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA,EAEA,oBAAoB,cAA4B;AAC9C,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,UAAM,iCAAiB,IAAA;AACvB,oBAAgB,KAAK,KAAK,GAAG,IAAI,KAAK,aAAa,UAAU;AAC7D;AAAA,MACE,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IAAA;AAEF,UAAM,cAAc,KAAK,gBAAgB,oBAAI,IAAA;AAC7C,SAAK,eAAe;AACpB,gBAAY,MAAA;AACZ,eAAW,CAAC,OAAO,IAAI,KAAK,KAAK,YAAY,WAAW;AACtD,UAAI,MAAM,WAAW,eAAe,KAAK,QAAQ,CAAC,GAAG;AACnD,oBAAY,IAAI,OAAO,KAAK,UAAU,UAAU;AAAA,MAClD;AAAA,IACF;AACA,qBAAiB,cAAc,WAAW;AAC1C,UAAM,EAAC,eAAA,IAAkB,qBAAqB,EAAE;AAChD,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,KAAK,iBAAiB,qBAAqB;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAyB;AACvB,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,WAAO,KAAK,aAAa,QAAA,EAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAwC;AACtC,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,WAAO,KAAK,aAAa,QAAA,EAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA+C;AAC7C,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,MAAM;AAAA,MACV,KAAK;AAAA,MACL,KAAK,aAAa,QAAA,EAAU;AAAA,MAC5B,KAAK,SAAS;AAAA,MACd,KAAK;AAAA,IAAA;AAEP,QAAI,IAAI,SAAS;AACf,WAAK,eAAe,IAAI;AACxB,WAAK,IAAI;AAAA,QACP;AAAA,QACA,KAAK,UAAU,KAAK,YAAY;AAAA,MAAA;AAAA,IAEpC;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAA6B;AAC3B,UAAM,EAAC,IAAI,QAAA,IAAW,KAAK,aAAa,qBAAqB;AAC7D,eAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,YAAM,MAAM,GAAG,EAAE;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gCAAgC,IAAc;AAC5C,QAAI,WAAW,KAAK,aAAa,IAAI,EAAE;AACvC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa;AACpB,YAAM,YAAY,sBAAsB,IAAI,KAAK,WAAW;AAC5D,WAAK,YAAY,IAAI,IAAI,SAAS;AAClC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU;AACR,SAAK,SAAS,QAAA;AACd,SAAK,aAAa,QAAA;AAAA,EACpB;AAAA;AAAA,EAGA,eASE;AACA,UAAM,qCAAqB,IAAA;AAI3B,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,YAAM,EAAC,cAAc,gBAAgB,mBAAA,IAAsB;AAE3D,UAAI,CAAC,eAAe,IAAI,YAAY,GAAG;AACrC,uBAAe,IAAI,cAAc,EAAE;AAAA,MACrC;AACA,qBAAe,IAAI,YAAY,EAAG,KAAK;AAAA,QACrC;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IACH;AACA,WAAO,CAAC,IAAI,IAAI,KAAK,WAAW,KAAA,CAAM,GAAG,cAAc;AAAA,EACzD;AAAA,EAEA,uBAA+B;AAC7B,QAAI,QAAQ;AACZ,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,eAAS,SAAS;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,CAAC,SACC,oBACA,SACA,OACA,OAC+B;AAC/B,WAAO,KAAK,aAAa;AACzB,SAAK,mBAAmB,SAAS,oBAAoB,SAAS,KAAK;AACnE,QAAI,KAAK,WAAW,IAAI,kBAAkB,GAAG;AAC3C,WAAK,IAAI,OAAO,SAAS,kBAAkB,kBAAkB,KAAK;AAClE;AAAA,IACF;AACA,UAAM,gBAAgB,kBAAkB,kBACpC,IAAI,UACJ;AAEJ,UAAM,YAAY,KAAK;AAAA,MACrB,KAAK,aAAa,QAAA,EAAU,GAAG;AAAA,IAAA;AAGjC,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,iBAAiB;AAAA;AAAA,QACjB,WAAW,CAAA,SAAQ,KAAK,WAAW,IAAI;AAAA,QACvC,eAAe,MAAM,KAAK,eAAA;AAAA,QAC1B,qBAAqB,CAACA,QAAoB,aACxC,IAAI;AAAA,UACFA;AAAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL;AAAA,QAAA;AAAA,QAEJ,eAAe,CAAAA,WAASA;AAAAA,QACxB,UAAU;AAAA,QAAC;AAAA,QACX,qBAAqB,CAAAA,WAASA;AAAAA,MAAA;AAAA,MAEhC;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,SAAS,MAAM,UAAA;AACrB,UAAM,UAAU;AAAA,MACd,MAAM,CAAA,WAAU;AACd,cAAM,WAAW,KAAK;AACtB,eAAO,UAAU,kDAAkD;AACnE,iBAAS,WAAW,oBAAoB,QAAQ,CAAC,MAAM,CAAC;AACxD,eAAO,CAAA;AAAA,MACT;AAAA,IAAA,CACD;AAED,WAAO,KAAK,oBAAoB,IAAI;AACpC,SAAK,kBAAkB;AAAA,MACrB;AAAA,IAAA;AAEF,QAAI;AACF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,KAAK,KAAK,YAAY;AAAA,MAAA;AAAA,IAE1B,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAEA,UAAM,kBAAkB,MAAM,aAAA;AAC9B,QAAI,kBAAkB,sBAAsB;AAC1C,UAAI,kBAAkB,KAAK,WAAW,sBAAsB;AAC1D,YAAI,sBAAsB;AAC1B,cAAM,KAAK,KAAK,IACb,YAAY,QAAQ,kBAAkB,EACtC,YAAY,mBAAmB,eAAe;AACjD,mBAAW,aAAa,KAAK,QAAQ,KAAA,GAAQ;AAC3C,gBAAM,UAAU,OAAO;AAAA,YACrB,eAAe,qBAAqB,SAAS,KAAK,CAAA;AAAA,UAAC;AAErD,iCAAuB,QAAQ;AAAA,YAC7B,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,YAC7B;AAAA,UAAA;AAEF,aAAG,OAAO,YAAY,aAAa,OAAO;AAAA,QAC5C;AACA,WAAG,OAAO,0BAA0B,mBAAmB,EAAE;AAAA,MAC3D;AAAA,IACF;AACA,mBAAe,MAAA;AAKf,SAAK,WAAW,IAAI,oBAAoB;AAAA,MACtC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB;AAAA,IAAA,CACD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAc;AACxB,UAAM,WAAW,KAAK,WAAW,IAAI,IAAI;AACzC,QAAI,UAAU;AACZ,WAAK,WAAW,OAAO,IAAI;AAC3B,eAAS,MAAM,QAAA;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,OAAe,IAA6B;AACjD,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC;AAC3C,WAAO,OAAO,OAAO,EAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,QAAQ,OAIN;AACA,WAAO,KAAK,aAAa;AACzB,UAAM,OAAO,KAAK,aAAa,QAAQ,KAAK,WAAW;AACvD,UAAM,EAAC,MAAM,MAAM,QAAA,IAAW;AAC9B,SAAK,IAAI;AAAA,MACP,WAAW,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,IAAA;AAGxD,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,SAAS,KAAK,SAAS,MAAM,OAAO,OAAO;AAAA,IAAA;AAAA,EAE/C;AAAA,EAEA,CAAC,SACC,MACA,OACA,YAC+B;AAC/B,WAAO,KAAK,oBAAoB,IAAI;AACpC,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,sBAAsB,KAAK,qBAAA;AAAA,MAC3B;AAAA,MACA,KAAK;AAAA,IAAA;AAEP,QAAI;AACF,iBAAW,EAAC,OAAO,YAAY,UAAA,KAAc,MAAM;AAKjD,YAAI,KAAK,wCAAwC;AAC/C,gBAAM;AAAA,QACR;AACA,cAAM,QAAQ,YAAY,IAAA;AAC1B,YAAI;AACJ,YAAI;AACF,gBAAM,cAAc,KAAK,QAAQ,IAAI,KAAK;AAC1C,cAAI,CAAC,aAAa;AAEhB;AAAA,UACF;AACA,gBAAM,aAAa,kBAAkB,KAAK,cAAc,KAAK;AAC7D,cAAI,aAA8B;AAClC,qBAAW,aAAa,YAAY;AAClC,gBACE,aACA;AAAA,cACE,UAAU,YAAY,SAAgB;AAAA,cACtC,UAAU,YAAY,SAAgB;AAAA,YAAA,GAExC;AACA,2BAAa;AAAA,YACf,OAAO;AACL,kBAAI,WAAW;AACb,qBAAK,qBAAqB,IAAI,CAAC;AAAA,cACjC;AACA,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AACA,cAAI,WAAW;AACb,gBAAI,YAAY;AACd,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,QAAQ;AAAA,cAAA,CACT;AAAA,YACH,OAAO;AACL,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AAAA,QACF,UAAA;AACE,eAAK,gBAAgB;AAAA,QACvB;AAEA,cAAM,UAAU,YAAY,IAAA,IAAQ;AACpC,aAAK,aAAa,OAAO,UAAU,KAAM;AAAA,UACvC;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MACH;AAGA,YAAM,EAAC,SAAQ;AACf,iBAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,cAAM,MAAM,KAAK,GAAG,EAAE;AAAA,MACxB;AACA,WAAK,gCAAgC,KAAK,GAAG,EAAE;AAC/C,WAAK,IAAI,QAAQ,eAAe,KAAK,OAAO,EAAE;AAAA,IAChD,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,WAA2B;AACpC,QAAI,SAAS,KAAK,QAAQ,IAAI,SAAS;AACvC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,iBAAiB,KAAK,aAAa,SAAS;AAC9D,UAAM,aAAa,kBAAkB,KAAK,cAAc,SAAS;AAEjE,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,aAAS,IAAI;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,MAAM,KAAK,aAAA;AAAA,IAAa;AAE1B,SAAK,QAAQ,IAAI,WAAW,MAAM;AAClC,SAAK,IAAI,QAAQ,2BAA2B,SAAS,EAAE;AACvD,WAAO;AAAA,EACT;AAAA,EAEA,eAAwB;AACtB,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,gBAAgB,MAAM,WAAA,IAAe,KAAK;AAAA,IACxD;AACA,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,qCAAA;AAAA,IACd;AACA,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,uCAAgD;AAC9C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IAAA,IACE,KAAK,KAAK,eAAe;AAC7B,UAAM,UAAU,aAAa,aAAA;AAC7B,QACE,UAAU,kCACT,UAAU,wBACR,UAAU,uBAAuB,KAAK,OAAO,aAAa,IAC7D;AACA,YAAM,IAAI;AAAA,QACR,mCAAmC,GAAG,OAAO,UAAU,kBAC5C,OAAO,kEACK,oBAAoB;AAAA,MAAA;AAAA,IAE/C;AACA,WAAO,aAAa,eAAe,KAAK;AAAA,EAC1C;AAAA;AAAA,EAGA,iBAA0B;AACxB,WAAO,KAAK,SAAS,cAAA;AAAA,EACvB;AAAA,EAEA,CAAC,MACC,QACA,QAC+B;AAC/B,SAAK,mBAAA;AACL,QAAI;AACF,iBAAW,OAAO,OAAO,QAAQ,MAAM,GAAG;AACxC,YAAI,QAAQ,SAAS;AACnB,gBAAM;AAAA,QACR;AACA,mBAAW,iBAAiB,KAAK,kBAAA,EAAoB,UAAU;AAC7D,gBAAM;AAAA,QACR;AACA,aAAK,mBAAA;AAAA,MACP;AAAA,IACF,UAAA;AACE,UAAI,KAAK,cAAc,MAAM;AAC3B,aAAK,kBAAA;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAEA,qBAAqB;AACnB,WAAO,KAAK,cAAc,IAAI;AAC9B,SAAK,YAAY,IAAI,SAAS,KAAK,KAAK,YAAY,CAAC;AAAA,EACvD;AAAA,EAEA,oBAA8B;AAC5B,UAAM,WAAW,KAAK;AACtB,WAAO,QAAQ;AACf,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AACF;AAEA,MAAM,SAAS;AAAA,EACJ;AAAA,EAET,YAAY,aAAsC;AAChD,SAAK,eAAe;AAAA,EACtB;AAAA,EAES,WAIH,CAAA;AAAA,EAEN,WACE,MACA,QACA,SACM;AACN,SAAK,SAAS,KAAK,CAAC,MAAM,QAAQ,OAAO,CAAC;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,CAAC,SAAwC;AACvC,eAAW,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,UAAU;AACnD,aAAO,KAAK,eAAe,MAAM,QAAQ,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,CAAC,eACC,WACA,QACA,SAC+B;AAG/B,QAAI,OAAO,WAAW,eAAe;AACnC;AAAA,IACF;AAEA,eAAW,UAAU,SAAS;AAC5B,UAAI,WAAW,SAAS;AACtB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,SAAQ;AAEf,cAAQ,MAAA;AAAA,QACN,KAAK;AAAA,QACL,KAAK,UAAU;AACb,iBAAO,KAAK,aAAa,WAAW,QAAQ,MAAM,MAAM;AAAA,YACtD,OAAO;AAAA,UAAA,CACR;AACD;AAAA,QACF;AAAA,QACA,KAAK,SAAS;AACZ,gBAAM,EAAC,UAAS;AAChB,gBAAM,cAAc;AAAA,YAClB,OAAO,cAAc,MAAM,gBAAgB;AAAA,UAAA;AAG7C,iBAAO,KAAK,eAAe,WAAW,aAAa,CAAC,MAAM,MAAM,CAAC;AACjE;AAAA,QACF;AAAA,QACA,KAAK;AACH,iBAAO,KAAK,aAAa,WAAW,QAAQ,MAAM,MAAM;AAAA,YACtD,EAAC,KAAK,OAAO,KAAK,KAAK,eAAe,CAAA,EAAC;AAAA,UAAC,CACzC;AACD;AAAA,QACF;AACE,sBAAgB;AAAA,MAAA;AAAA,IAEtB;AAAA,EACF;AAAA,EAEA,CAAC,aACC,WACA,QACA,IACA,OAC+B;AAC/B,UAAM,EAAC,WAAW,OAAO,OAAA,IAAU;AAEnC,UAAM,aAAa,KAAK,KAAK,aAAa,IAAI,KAAK,CAAC;AAIpD,QAAI,WAAW,eAAe;AAC5B;AAAA,IACF;AAEA,eAAW,QAAQ,SAAS;AAC1B,UAAI,SAAS,SAAS;AACpB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,eAAe,IAAA,IAAO;AAC7B,YAAM,SAAS,UAAU,YAAY,GAAG;AAExC,YAAM;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,OAAO,WAAW,SAAY;AAAA,MAAA;AAGrC,iBAAW,CAAC,cAAc,QAAQ,KAAK,OAAO,QAAQ,aAAa,GAAG;AACpE,cAAM,cAAc,KAAK,OAAO,cAAc,YAAY,CAAC;AAC3D,eAAO,KAAK,aAAa,WAAW,aAAa,IAAI,QAAQ;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;AAEA,UAAU,OAAO,OAA6D;AAC5E,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,SAAS;AACpB,YAAM;AACN;AAAA,IACF;AACA,UAAM,EAAC,MAAM,OAAO,KAAA;AAAA,EACtB;AACF;AAEA,SAAS,UAAU,MAAkB,KAAkB;AACrD,SAAO,OAAO,YAAY,KAAK,IAAI,CAAA,QAAO,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE;AAOO,UAAU,QACf,OACA,MACA,cAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,iBAAiB,YAAY,CAAC,EAAE;AAAA,IAC5D;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEO,UAAU,gBACf,OACA,MACA,aAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,WAAW,EAAE;AAAA,IACzC;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEA,SAAS,iBACP,cACA,cAAuC,oBAAI,OAC3C;AACA,aAAW,CAAC,WAAW,EAAC,WAAA,CAAW,KAAK,OAAO,QAAQ,aAAa,MAAM,GAAG;AAC3E,gBAAY,IAAI,WAAW,UAAmC;AAAA,EAChE;AACA,SAAO;AACT;AAEA,SAAS,kBACP,aACA,OACY;AACZ,QAAM,QAAQ,KAAK,aAAa,iCAAiC;AAEjE,SAAO;AAAA,IACL,MAAM,IAAI,KAAK;AAAA,IACf,UAAU,KAAK,oBAAoB,CAAC,GAAG,MAAM,KAAA,CAAM,EAAE,KAAA,CAAM;AAAA,EAAA;AAG/D;"}
|
|
1
|
+
{"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport {type Input, type Storage} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {getSubscriptionState} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly originalHash: string;\n readonly transformedAst: AST; // Optional, only set after hydration\n readonly transformationHash: string; // The hash of the transformed AST\n};\n\ntype AdvanceContext = {\n readonly timer: Timer;\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n pos: number;\n};\n\ntype HydrateContext = {\n readonly timer: Timer;\n};\n\nexport type Timer = {\n elapsedLap: () => number;\n totalElapsed: () => number;\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 50;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // We probs need the original query hash\n // so we can decide not to re-transform a custom query\n // that is already hydrated.\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n readonly #yieldThresholdMs: () => number;\n #streamer: Streamer | null = null;\n #hydrateContext: HydrateContext | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n yieldThresholdMs: () => number,\n enablePlanner?: boolean,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n this.#yieldThresholdMs = yieldThresholdMs;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const {input} of this.#pipelines.values()) {\n input.destroy();\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(this.#lc, db.db, this.#tableSpecs, fullTables);\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return The Set of query hashes for all added queries. */\n addedQueries(): [\n transformationHashes: Set<string>,\n byOriginalHash: Map<\n string,\n {\n transformationHash: string;\n transformedAst: AST;\n }[]\n >,\n ] {\n const byOriginalHash = new Map<\n string,\n {transformationHash: string; transformedAst: AST}[]\n >();\n for (const pipeline of this.#pipelines.values()) {\n const {originalHash, transformedAst, transformationHash} = pipeline;\n\n if (!byOriginalHash.has(originalHash)) {\n byOriginalHash.set(originalHash, []);\n }\n byOriginalHash.get(originalHash)!.push({\n transformationHash,\n transformedAst,\n });\n }\n return [new Set(this.#pipelines.keys()), byOriginalHash];\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with an identical hash has already been added, this method is a\n * no-op and no RowChanges are generated.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: Timer,\n ): Iterable<RowChange | 'yield'> {\n assert(this.initialized());\n this.#inspectorDelegate.addQuery(transformationHash, queryID, query);\n if (this.#pipelines.has(transformationHash)) {\n this.#lc.info?.(`query ${transformationHash} already added`, query);\n return;\n }\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n const input = buildPipeline(\n query,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n transformationHash,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n streamer.accumulate(transformationHash, schema, [change]);\n return [];\n },\n });\n\n assert(this.#advanceContext === null);\n this.#hydrateContext = {\n timer,\n };\n try {\n yield* hydrateInternal(\n input,\n transformationHash,\n must(this.#primaryKeys),\n );\n } finally {\n this.#hydrateContext = null;\n }\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('hash', transformationHash)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(transformationHash, {\n input,\n hydrationTimeMs,\n originalHash: queryID,\n transformedAst: query,\n transformationHash,\n });\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(hash: string) {\n const pipeline = this.#pipelines.get(hash);\n if (pipeline) {\n this.#pipelines.delete(hash);\n pipeline.input.destroy();\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: Timer): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange | 'yield'>;\n } {\n assert(this.initialized());\n const diff = this.#snapshotter.advance(this.#tableSpecs);\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: Timer,\n numChanges: number,\n ): Iterable<RowChange | 'yield'> {\n assert(this.#hydrateContext === null);\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n // Advance progress is checked each time a row is fetched\n // from a TableSource during push processing, but some pushes\n // don't read any rows. Check progress here before processing\n // the next change.\n if (this.#shouldAdvanceYieldMaybeAbortAdvance()) {\n yield 'yield';\n }\n const start = performance.now();\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = performance.now() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n () => this.#shouldYield(),\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n #shouldYield(): boolean {\n if (this.#hydrateContext) {\n return this.#hydrateContext.timer.elapsedLap() > this.#yieldThresholdMs();\n }\n if (this.#advanceContext) {\n return this.#shouldAdvanceYieldMaybeAbortAdvance();\n }\n throw new Error('shouldYield called outside of hydration or advancement');\n }\n\n /**\n * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if\n * it has taken longer than half the total hydration time to make it through\n * half of the advancement, or if processing time exceeds total hydration\n * time. This serves as both a circuit breaker for very large transactions,\n * as well as a bound on the amount of time the previous connection locks\n * the inactive WAL file (as the lock prevents WAL2 from switching to the\n * free WAL when the current one is over the size limit, which can make\n * the WAL grow continuously and compound slowness).\n * This is checked:\n * 1. before starting to process each change in an advancement is processed\n * 2. whenever a row is fetched from a TableSource during push processing\n */\n #shouldAdvanceYieldMaybeAbortAdvance(): boolean {\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = must(this.#advanceContext);\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes ` +\n `after ${elapsed} ms. Advancement time limited based on total ` +\n `hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n return advanceTimer.elapsedLap() > this.#yieldThresholdMs();\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(\n source: TableSource,\n change: SourceChange,\n ): Iterable<RowChange | 'yield'> {\n this.#startAccumulating();\n try {\n for (const val of source.genPush(change)) {\n if (val === 'yield') {\n yield 'yield';\n }\n for (const changeOrYield of this.#stopAccumulating().stream()) {\n yield changeOrYield;\n }\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null);\n this.#streamer = new Streamer(must(this.#primaryKeys));\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer);\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n\n constructor(primaryKeys: Map<string, PrimaryKey>) {\n this.#primaryKeys = primaryKeys;\n }\n\n readonly #changes: [\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ][] = [];\n\n accumulate(\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): this {\n this.#changes.push([hash, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange | 'yield'> {\n for (const [hash, schema, changes] of this.#changes) {\n yield* this.#streamChanges(hash, schema, changes);\n }\n }\n\n *#streamChanges(\n queryHash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n if (change === 'yield') {\n yield change;\n continue;\n }\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryHash, schema, type, () => [\n change.node,\n ]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryHash, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryHash, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryHash: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const {relationships, row} = node;\n const rowKey = getRowKey(primaryKey, row);\n\n yield {\n type: op,\n queryHash,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryHash, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node | 'yield'>): Iterable<Change | 'yield'> {\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n"],"names":["input"],"mappings":";;;;;;;;;;;;;;;;;AAqGA,MAAM,gCAAgC;AAK/B,MAAM,eAAe;AAAA,EACjB,8BAAc,IAAA;AAAA;AAAA;AAAA;AAAA,EAId,iCAAiB,IAAA;AAAA,EAEjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,kCAAkB,IAAA;AAAA,EAClB;AAAA,EACA;AAAA,EACT,YAA6B;AAAA,EAC7B,kBAAyC;AAAA,EACzC,kBAAyC;AAAA,EACzC,kBAAiC;AAAA,EACjC,eAA+C;AAAA,EAC/C,eAAyC;AAAA,EAEhC,eAAe,qBAAqB,QAAQ,oBAAoB;AAAA,IACvE,aACE;AAAA,IACF,MAAM;AAAA,EAAA,CACP;AAAA,EAEQ,uBAAuB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAAA,EAGO;AAAA,EAET,YACE,IACA,WACA,aACA,SACA,SACA,eACA,mBACA,kBACA,eACA;AACA,SAAK,MAAM,GAAG,YAAY,iBAAiB,aAAa;AACxD,SAAK,eAAe;AACpB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,aAAa;AAClB,SAAK,qBAAqB;AAC1B,SAAK,cAAc,gBAAgB,oBAAI,QAAA,IAAY;AACnD,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,cAA4B;AAC/B,WAAO,CAAC,KAAK,aAAa,YAAA,GAAe,qBAAqB;AAC9D,SAAK,aAAa,KAAA;AAClB,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,aAAa,YAAA;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAA4B;AAChC,eAAW,EAAC,MAAA,KAAU,KAAK,WAAW,UAAU;AAC9C,YAAM,QAAA;AAAA,IACR;AACA,SAAK,WAAW,MAAA;AAChB,SAAK,QAAQ,MAAA;AACb,SAAK,oBAAoB,YAAY;AAAA,EACvC;AAAA,EAEA,oBAAoB,cAA4B;AAC9C,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,UAAM,iCAAiB,IAAA;AACvB,oBAAgB,KAAK,KAAK,GAAG,IAAI,KAAK,aAAa,UAAU;AAC7D;AAAA,MACE,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IAAA;AAEF,UAAM,cAAc,KAAK,gBAAgB,oBAAI,IAAA;AAC7C,SAAK,eAAe;AACpB,gBAAY,MAAA;AACZ,eAAW,CAAC,OAAO,IAAI,KAAK,KAAK,YAAY,WAAW;AACtD,UAAI,MAAM,WAAW,eAAe,KAAK,QAAQ,CAAC,GAAG;AACnD,oBAAY,IAAI,OAAO,KAAK,UAAU,UAAU;AAAA,MAClD;AAAA,IACF;AACA,qBAAiB,cAAc,WAAW;AAC1C,UAAM,EAAC,eAAA,IAAkB,qBAAqB,EAAE;AAChD,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAGA,IAAI,iBAAyB;AAC3B,WAAO,KAAK,KAAK,iBAAiB,qBAAqB;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAyB;AACvB,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,WAAO,KAAK,aAAa,QAAA,EAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA+C;AAC7C,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,MAAM;AAAA,MACV,KAAK;AAAA,MACL,KAAK,aAAa,QAAA,EAAU;AAAA,MAC5B,KAAK,SAAS;AAAA,MACd,KAAK;AAAA,IAAA;AAEP,QAAI,IAAI,SAAS;AACf,WAAK,eAAe,IAAI;AACxB,WAAK,IAAI;AAAA,QACP;AAAA,QACA,KAAK,UAAU,KAAK,YAAY;AAAA,MAAA;AAAA,IAEpC;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAA6B;AAC3B,UAAM,EAAC,IAAI,QAAA,IAAW,KAAK,aAAa,qBAAqB;AAC7D,eAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,YAAM,MAAM,GAAG,EAAE;AAAA,IACnB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gCAAgC,IAAc;AAC5C,QAAI,WAAW,KAAK,aAAa,IAAI,EAAE;AACvC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AACA,QAAI,KAAK,aAAa;AACpB,YAAM,YAAY,sBAAsB,IAAI,KAAK,WAAW;AAC5D,WAAK,YAAY,IAAI,IAAI,SAAS;AAClC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU;AACR,SAAK,SAAS,QAAA;AACd,SAAK,aAAa,QAAA;AAAA,EACpB;AAAA;AAAA,EAGA,eASE;AACA,UAAM,qCAAqB,IAAA;AAI3B,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,YAAM,EAAC,cAAc,gBAAgB,mBAAA,IAAsB;AAE3D,UAAI,CAAC,eAAe,IAAI,YAAY,GAAG;AACrC,uBAAe,IAAI,cAAc,EAAE;AAAA,MACrC;AACA,qBAAe,IAAI,YAAY,EAAG,KAAK;AAAA,QACrC;AAAA,QACA;AAAA,MAAA,CACD;AAAA,IACH;AACA,WAAO,CAAC,IAAI,IAAI,KAAK,WAAW,KAAA,CAAM,GAAG,cAAc;AAAA,EACzD;AAAA,EAEA,uBAA+B;AAC7B,QAAI,QAAQ;AACZ,eAAW,YAAY,KAAK,WAAW,OAAA,GAAU;AAC/C,eAAS,SAAS;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,CAAC,SACC,oBACA,SACA,OACA,OAC+B;AAC/B,WAAO,KAAK,aAAa;AACzB,SAAK,mBAAmB,SAAS,oBAAoB,SAAS,KAAK;AACnE,QAAI,KAAK,WAAW,IAAI,kBAAkB,GAAG;AAC3C,WAAK,IAAI,OAAO,SAAS,kBAAkB,kBAAkB,KAAK;AAClE;AAAA,IACF;AACA,UAAM,gBAAgB,kBAAkB,kBACpC,IAAI,UACJ;AAEJ,UAAM,YAAY,KAAK;AAAA,MACrB,KAAK,aAAa,QAAA,EAAU,GAAG;AAAA,IAAA;AAGjC,UAAM,QAAQ;AAAA,MACZ;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,iBAAiB;AAAA;AAAA,QACjB,WAAW,CAAA,SAAQ,KAAK,WAAW,IAAI;AAAA,QACvC,eAAe,MAAM,KAAK,eAAA;AAAA,QAC1B,qBAAqB,CAACA,QAAoB,aACxC,IAAI;AAAA,UACFA;AAAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL;AAAA,QAAA;AAAA,QAEJ,eAAe,CAAAA,WAASA;AAAAA,QACxB,UAAU;AAAA,QAAC;AAAA,QACX,qBAAqB,CAAAA,WAASA;AAAAA,MAAA;AAAA,MAEhC;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,SAAS,MAAM,UAAA;AACrB,UAAM,UAAU;AAAA,MACd,MAAM,CAAA,WAAU;AACd,cAAM,WAAW,KAAK;AACtB,eAAO,UAAU,kDAAkD;AACnE,iBAAS,WAAW,oBAAoB,QAAQ,CAAC,MAAM,CAAC;AACxD,eAAO,CAAA;AAAA,MACT;AAAA,IAAA,CACD;AAED,WAAO,KAAK,oBAAoB,IAAI;AACpC,SAAK,kBAAkB;AAAA,MACrB;AAAA,IAAA;AAEF,QAAI;AACF,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,KAAK,KAAK,YAAY;AAAA,MAAA;AAAA,IAE1B,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAEA,UAAM,kBAAkB,MAAM,aAAA;AAC9B,QAAI,kBAAkB,sBAAsB;AAC1C,UAAI,kBAAkB,KAAK,WAAW,sBAAsB;AAC1D,YAAI,sBAAsB;AAC1B,cAAM,KAAK,KAAK,IACb,YAAY,QAAQ,kBAAkB,EACtC,YAAY,mBAAmB,eAAe;AACjD,mBAAW,aAAa,KAAK,QAAQ,KAAA,GAAQ;AAC3C,gBAAM,UAAU,OAAO;AAAA,YACrB,eAAe,qBAAqB,SAAS,KAAK,CAAA;AAAA,UAAC;AAErD,iCAAuB,QAAQ;AAAA,YAC7B,CAAC,KAAK,UAAU,MAAM,MAAM,CAAC;AAAA,YAC7B;AAAA,UAAA;AAEF,aAAG,OAAO,YAAY,aAAa,OAAO;AAAA,QAC5C;AACA,WAAG,OAAO,0BAA0B,mBAAmB,EAAE;AAAA,MAC3D;AAAA,IACF;AACA,mBAAe,MAAA;AAKf,SAAK,WAAW,IAAI,oBAAoB;AAAA,MACtC;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB;AAAA,IAAA,CACD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAc;AACxB,UAAM,WAAW,KAAK,WAAW,IAAI,IAAI;AACzC,QAAI,UAAU;AACZ,WAAK,WAAW,OAAO,IAAI;AAC3B,eAAS,MAAM,QAAA;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,OAAe,IAA6B;AACjD,WAAO,KAAK,YAAA,GAAe,qBAAqB;AAChD,UAAM,SAAS,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC;AAC3C,WAAO,OAAO,OAAO,EAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,QAAQ,OAIN;AACA,WAAO,KAAK,aAAa;AACzB,UAAM,OAAO,KAAK,aAAa,QAAQ,KAAK,WAAW;AACvD,UAAM,EAAC,MAAM,MAAM,QAAA,IAAW;AAC9B,SAAK,IAAI;AAAA,MACP,WAAW,KAAK,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO;AAAA,IAAA;AAGxD,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,YAAY;AAAA,MACZ,SAAS,KAAK,SAAS,MAAM,OAAO,OAAO;AAAA,IAAA;AAAA,EAE/C;AAAA,EAEA,CAAC,SACC,MACA,OACA,YAC+B;AAC/B,WAAO,KAAK,oBAAoB,IAAI;AACpC,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,sBAAsB,KAAK,qBAAA;AAAA,MAC3B;AAAA,MACA,KAAK;AAAA,IAAA;AAEP,QAAI;AACF,iBAAW,EAAC,OAAO,YAAY,UAAA,KAAc,MAAM;AAKjD,YAAI,KAAK,wCAAwC;AAC/C,gBAAM;AAAA,QACR;AACA,cAAM,QAAQ,YAAY,IAAA;AAC1B,YAAI;AACJ,YAAI;AACF,gBAAM,cAAc,KAAK,QAAQ,IAAI,KAAK;AAC1C,cAAI,CAAC,aAAa;AAEhB;AAAA,UACF;AACA,gBAAM,aAAa,kBAAkB,KAAK,cAAc,KAAK;AAC7D,cAAI,aAA8B;AAClC,qBAAW,aAAa,YAAY;AAClC,gBACE,aACA;AAAA,cACE,UAAU,YAAY,SAAgB;AAAA,cACtC,UAAU,YAAY,SAAgB;AAAA,YAAA,GAExC;AACA,2BAAa;AAAA,YACf,OAAO;AACL,kBAAI,WAAW;AACb,qBAAK,qBAAqB,IAAI,CAAC;AAAA,cACjC;AACA,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AACA,cAAI,WAAW;AACb,gBAAI,YAAY;AACd,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,QAAQ;AAAA,cAAA,CACT;AAAA,YACH,OAAO;AACL,qBAAO,KAAK,MAAM,aAAa;AAAA,gBAC7B,MAAM;AAAA,gBACN,KAAK;AAAA,cAAA,CACN;AAAA,YACH;AAAA,UACF;AAAA,QACF,UAAA;AACE,eAAK,gBAAgB;AAAA,QACvB;AAEA,cAAM,UAAU,YAAY,IAAA,IAAQ;AACpC,aAAK,aAAa,OAAO,UAAU,KAAM;AAAA,UACvC;AAAA,UACA;AAAA,QAAA,CACD;AAAA,MACH;AAGA,YAAM,EAAC,SAAQ;AACf,iBAAW,SAAS,KAAK,QAAQ,OAAA,GAAU;AACzC,cAAM,MAAM,KAAK,GAAG,EAAE;AAAA,MACxB;AACA,WAAK,gCAAgC,KAAK,GAAG,EAAE;AAC/C,WAAK,IAAI,QAAQ,eAAe,KAAK,OAAO,EAAE;AAAA,IAChD,UAAA;AACE,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,WAAW,WAA2B;AACpC,QAAI,SAAS,KAAK,QAAQ,IAAI,SAAS;AACvC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,iBAAiB,KAAK,aAAa,SAAS;AAC9D,UAAM,aAAa,kBAAkB,KAAK,cAAc,SAAS;AAEjE,UAAM,EAAC,GAAA,IAAM,KAAK,aAAa,QAAA;AAC/B,aAAS,IAAI;AAAA,MACX,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,UAAU;AAAA,MACV;AAAA,MACA,MAAM,KAAK,aAAA;AAAA,IAAa;AAE1B,SAAK,QAAQ,IAAI,WAAW,MAAM;AAClC,SAAK,IAAI,QAAQ,2BAA2B,SAAS,EAAE;AACvD,WAAO;AAAA,EACT;AAAA,EAEA,eAAwB;AACtB,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,gBAAgB,MAAM,WAAA,IAAe,KAAK,kBAAA;AAAA,IACxD;AACA,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,qCAAA;AAAA,IACd;AACA,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,uCAAgD;AAC9C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IAAA,IACE,KAAK,KAAK,eAAe;AAC7B,UAAM,UAAU,aAAa,aAAA;AAC7B,QACE,UAAU,kCACT,UAAU,wBACR,UAAU,uBAAuB,KAAK,OAAO,aAAa,IAC7D;AACA,YAAM,IAAI;AAAA,QACR,mCAAmC,GAAG,OAAO,UAAU,kBAC5C,OAAO,kEACK,oBAAoB;AAAA,MAAA;AAAA,IAE/C;AACA,WAAO,aAAa,eAAe,KAAK,kBAAA;AAAA,EAC1C;AAAA;AAAA,EAGA,iBAA0B;AACxB,WAAO,KAAK,SAAS,cAAA;AAAA,EACvB;AAAA,EAEA,CAAC,MACC,QACA,QAC+B;AAC/B,SAAK,mBAAA;AACL,QAAI;AACF,iBAAW,OAAO,OAAO,QAAQ,MAAM,GAAG;AACxC,YAAI,QAAQ,SAAS;AACnB,gBAAM;AAAA,QACR;AACA,mBAAW,iBAAiB,KAAK,kBAAA,EAAoB,UAAU;AAC7D,gBAAM;AAAA,QACR;AACA,aAAK,mBAAA;AAAA,MACP;AAAA,IACF,UAAA;AACE,UAAI,KAAK,cAAc,MAAM;AAC3B,aAAK,kBAAA;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA,EAEA,qBAAqB;AACnB,WAAO,KAAK,cAAc,IAAI;AAC9B,SAAK,YAAY,IAAI,SAAS,KAAK,KAAK,YAAY,CAAC;AAAA,EACvD;AAAA,EAEA,oBAA8B;AAC5B,UAAM,WAAW,KAAK;AACtB,WAAO,QAAQ;AACf,SAAK,YAAY;AACjB,WAAO;AAAA,EACT;AACF;AAEA,MAAM,SAAS;AAAA,EACJ;AAAA,EAET,YAAY,aAAsC;AAChD,SAAK,eAAe;AAAA,EACtB;AAAA,EAES,WAIH,CAAA;AAAA,EAEN,WACE,MACA,QACA,SACM;AACN,SAAK,SAAS,KAAK,CAAC,MAAM,QAAQ,OAAO,CAAC;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,CAAC,SAAwC;AACvC,eAAW,CAAC,MAAM,QAAQ,OAAO,KAAK,KAAK,UAAU;AACnD,aAAO,KAAK,eAAe,MAAM,QAAQ,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,CAAC,eACC,WACA,QACA,SAC+B;AAG/B,QAAI,OAAO,WAAW,eAAe;AACnC;AAAA,IACF;AAEA,eAAW,UAAU,SAAS;AAC5B,UAAI,WAAW,SAAS;AACtB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,SAAQ;AAEf,cAAQ,MAAA;AAAA,QACN,KAAK;AAAA,QACL,KAAK,UAAU;AACb,iBAAO,KAAK,aAAa,WAAW,QAAQ,MAAM,MAAM;AAAA,YACtD,OAAO;AAAA,UAAA,CACR;AACD;AAAA,QACF;AAAA,QACA,KAAK,SAAS;AACZ,gBAAM,EAAC,UAAS;AAChB,gBAAM,cAAc;AAAA,YAClB,OAAO,cAAc,MAAM,gBAAgB;AAAA,UAAA;AAG7C,iBAAO,KAAK,eAAe,WAAW,aAAa,CAAC,MAAM,MAAM,CAAC;AACjE;AAAA,QACF;AAAA,QACA,KAAK;AACH,iBAAO,KAAK,aAAa,WAAW,QAAQ,MAAM,MAAM;AAAA,YACtD,EAAC,KAAK,OAAO,KAAK,KAAK,eAAe,CAAA,EAAC;AAAA,UAAC,CACzC;AACD;AAAA,QACF;AACE,sBAAgB;AAAA,MAAA;AAAA,IAEtB;AAAA,EACF;AAAA,EAEA,CAAC,aACC,WACA,QACA,IACA,OAC+B;AAC/B,UAAM,EAAC,WAAW,OAAO,OAAA,IAAU;AAEnC,UAAM,aAAa,KAAK,KAAK,aAAa,IAAI,KAAK,CAAC;AAIpD,QAAI,WAAW,eAAe;AAC5B;AAAA,IACF;AAEA,eAAW,QAAQ,SAAS;AAC1B,UAAI,SAAS,SAAS;AACpB,cAAM;AACN;AAAA,MACF;AACA,YAAM,EAAC,eAAe,IAAA,IAAO;AAC7B,YAAM,SAAS,UAAU,YAAY,GAAG;AAExC,YAAM;AAAA,QACJ,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK,OAAO,WAAW,SAAY;AAAA,MAAA;AAGrC,iBAAW,CAAC,cAAc,QAAQ,KAAK,OAAO,QAAQ,aAAa,GAAG;AACpE,cAAM,cAAc,KAAK,OAAO,cAAc,YAAY,CAAC;AAC3D,eAAO,KAAK,aAAa,WAAW,aAAa,IAAI,QAAQ;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AACF;AAEA,UAAU,OAAO,OAA6D;AAC5E,aAAW,QAAQ,OAAO;AACxB,QAAI,SAAS,SAAS;AACpB,YAAM;AACN;AAAA,IACF;AACA,UAAM,EAAC,MAAM,OAAO,KAAA;AAAA,EACtB;AACF;AAEA,SAAS,UAAU,MAAkB,KAAkB;AACrD,SAAO,OAAO,YAAY,KAAK,IAAI,CAAA,QAAO,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;AAClE;AAOO,UAAU,QACf,OACA,MACA,cAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,iBAAiB,YAAY,CAAC,EAAE;AAAA,IAC5D;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEO,UAAU,gBACf,OACA,MACA,aAC+B;AAC/B,QAAM,MAAM,MAAM,MAAM,EAAE;AAC1B,QAAM,WAAW,IAAI,SAAS,WAAW,EAAE;AAAA,IACzC;AAAA,IACA,MAAM,UAAA;AAAA,IACN,OAAO,GAAG;AAAA,EAAA;AAEZ,SAAO,SAAS,OAAA;AAClB;AAEA,SAAS,iBACP,cACA,cAAuC,oBAAI,OAC3C;AACA,aAAW,CAAC,WAAW,EAAC,WAAA,CAAW,KAAK,OAAO,QAAQ,aAAa,MAAM,GAAG;AAC3E,gBAAY,IAAI,WAAW,UAAmC;AAAA,EAChE;AACA,SAAO;AACT;AAEA,SAAS,kBACP,aACA,OACY;AACZ,QAAM,QAAQ,KAAK,aAAa,iCAAiC;AAEjE,SAAO;AAAA,IACL,MAAM,IAAI,KAAK;AAAA,IACf,UAAU,KAAK,oBAAoB,CAAC,GAAG,MAAM,KAAA,CAAM,EAAE,KAAA,CAAM;AAAA,EAAA;AAG/D;"}
|
|
@@ -5,7 +5,6 @@ import type { PrimaryKey } from '../../../../zero-types/src/schema.ts';
|
|
|
5
5
|
import type { LiteAndZqlSpec, LiteTableSpecWithKeys } from '../../db/specs.ts';
|
|
6
6
|
import { StatementRunner } from '../../db/statements.ts';
|
|
7
7
|
import { type RowKey, type RowValue } from '../../types/row-key.ts';
|
|
8
|
-
import { type SchemaVersions } from '../../types/schema-versions.ts';
|
|
9
8
|
import type { AppID } from '../../types/shards.ts';
|
|
10
9
|
/**
|
|
11
10
|
* A `Snapshotter` manages the progression of database snapshots for a
|
|
@@ -181,7 +180,6 @@ declare class Snapshot {
|
|
|
181
180
|
static create(lc: LogContext, dbFile: string, appID: string, pageCacheSizeKib: number | undefined): Snapshot;
|
|
182
181
|
readonly db: StatementRunner;
|
|
183
182
|
readonly version: string;
|
|
184
|
-
readonly schemaVersions: SchemaVersions;
|
|
185
183
|
constructor(db: StatementRunner, appID: string);
|
|
186
184
|
numChangesSince(prevVersion: string): any;
|
|
187
185
|
changesSince(prevVersion: string): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAY,KAAK,SAAS,EAAC,MAAM,uCAAuC,CAAC;AAGhF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,uCAAuC,CAAC;AAC/D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sCAAsC,CAAC;AAGrE,OAAO,KAAK,EAAC,cAAc,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,QAAQ,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,
|
|
1
|
+
{"version":3,"file":"snapshotter.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/snapshotter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,EAAY,KAAK,SAAS,EAAC,MAAM,uCAAuC,CAAC;AAGhF,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,uCAAuC,CAAC;AAC/D,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,sCAAsC,CAAC;AAGrE,OAAO,KAAK,EAAC,cAAc,EAAE,qBAAqB,EAAC,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAEL,KAAK,MAAM,EACX,KAAK,QAAQ,EACd,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,uBAAuB,CAAC;AAajD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,qBAAa,WAAW;;gBASpB,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,EACd,EAAC,KAAK,EAAC,EAAE,KAAK,EACd,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS;IAQvC;;;;OAIG;IACH,IAAI,IAAI,IAAI;IAYZ,WAAW,IAAI,OAAO;IAItB,+EAA+E;IAC/E,OAAO,IAAI,QAAQ;IAKnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoCG;IACH,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,YAAY;IAK1D,kBAAkB;;;;IAelB;;;OAGG;IACH,OAAO;CAKR;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAAC,MAAM,CAAC;IACpD,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,0BAA0B;gBAE3B,GAAG,EAAE,MAAM;CAGxB;AAED,cAAM,QAAQ;;IACZ,MAAM,CAAC,MAAM,CACX,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,gBAAgB,EAAE,MAAM,GAAG,SAAS;IAsBtC,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;IAE7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM;IAY9C,eAAe,CAAC,WAAW,EAAE,MAAM;IAQnC,YAAY,CAAC,WAAW,EAAE,MAAM;;;;IAUhC,MAAM,CAAC,KAAK,EAAE,qBAAqB,EAAE,MAAM,EAAE,SAAS;IAkBtD,OAAO,CAAC,KAAK,EAAE,qBAAqB,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,QAAQ;IAmBvE,WAAW,IAAI,QAAQ;CAIxB;AAmKD,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,GAAG,EAAE,MAAM;CAGxB"}
|