@rocicorp/zero 0.25.10-canary.19 → 0.25.10-canary.21
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/zero/package.json.js +1 -1
- package/out/zero-cache/src/custom/fetch.d.ts +3 -3
- package/out/zero-cache/src/custom/fetch.d.ts.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +116 -76
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +0 -1
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +1 -0
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +2 -2
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +1 -3
- package/out/zero-cache/src/services/mutagen/pusher.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 +8 -5
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- 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 +21 -17
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/error-with-level.d.ts +1 -1
- package/out/zero-cache/src/types/error-with-level.d.ts.map +1 -1
- package/out/zero-cache/src/types/error-with-level.js +1 -1
- package/out/zero-cache/src/types/error-with-level.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +5 -1
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js +3 -3
- package/out/zero-client/src/client/error.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 +1 -1
- 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/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspector-delegate.js","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport
|
|
1
|
+
{"version":3,"file":"inspector-delegate.js","sources":["../../../../../zero-cache/src/server/inspector-delegate.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {mapValues} from '../../../shared/src/objects.ts';\nimport {TDigest} from '../../../shared/src/tdigest.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {ServerMetrics as ServerMetricsJSON} from '../../../zero-protocol/src/inspect-down.ts';\nimport {hashOfNameAndArgs} from '../../../zero-protocol/src/query-hash.ts';\nimport {\n isServerMetric,\n type MetricMap,\n type MetricsDelegate,\n} from '../../../zql/src/query/metrics-delegate.ts';\nimport {isDevelopmentMode} from '../config/normalize.ts';\nimport type {CustomQueryTransformer} from '../custom-queries/transform-query.ts';\nimport type {HeaderOptions} from '../custom/fetch.ts';\nimport type {CustomQueryRecord} from '../services/view-syncer/schema/types.ts';\nimport {ProtocolErrorWithLevel} from '../types/error-with-level.ts';\n\n/**\n * Server-side metrics collected for queries during materialization and update.\n * These metrics are reported via the inspector and complement client-side metrics.\n */\nexport type ServerMetrics = {\n 'query-materialization-server': TDigest;\n 'query-update-server': TDigest;\n};\n\ntype ClientGroupID = string;\n\n/**\n * Set of authenticated client group IDs. We keep this outside of the class to\n * share this state across all instances of the InspectorDelegate.\n */\nconst authenticatedClientGroupIDs = new Set<ClientGroupID>();\n\nexport class InspectorDelegate implements MetricsDelegate {\n readonly #globalMetrics: ServerMetrics = newMetrics();\n readonly #perQueryServerMetrics = new Map<string, ServerMetrics>();\n readonly #hashToIDs = new Map<string, Set<string>>();\n readonly #queryIDToTransformationHash = new Map<string, string>();\n readonly #transformationASTs: Map<string, AST> = new Map();\n readonly #customQueryTransformer: CustomQueryTransformer | undefined;\n\n constructor(customQueryTransformer: CustomQueryTransformer | undefined) {\n this.#customQueryTransformer = customQueryTransformer;\n }\n\n addMetric<K extends keyof MetricMap>(\n metric: K,\n value: number,\n ...args: MetricMap[K]\n ): void {\n assert(isServerMetric(metric), `Invalid server metric: ${metric}`);\n const transformationHash = args[0];\n\n for (const queryID of this.#hashToIDs.get(transformationHash) ?? []) {\n let serverMetrics = this.#perQueryServerMetrics.get(queryID);\n if (!serverMetrics) {\n serverMetrics = newMetrics();\n this.#perQueryServerMetrics.set(queryID, serverMetrics);\n }\n serverMetrics[metric].add(value);\n }\n this.#globalMetrics[metric].add(value);\n }\n\n getMetricsJSONForQuery(queryID: string): ServerMetricsJSON | null {\n const serverMetrics = this.#perQueryServerMetrics.get(queryID);\n return serverMetrics ? mapValues(serverMetrics, v => v.toJSON()) : null;\n }\n\n getMetricsJSON() {\n return mapValues(this.#globalMetrics, v => v.toJSON());\n }\n\n getASTForQuery(queryID: string): AST | undefined {\n const transformationHash = this.#queryIDToTransformationHash.get(queryID);\n return transformationHash\n ? this.#transformationASTs.get(transformationHash)\n : undefined;\n }\n\n removeQuery(queryID: string): void {\n this.#perQueryServerMetrics.delete(queryID);\n this.#queryIDToTransformationHash.delete(queryID);\n // Remove queryID from all hash-to-ID mappings\n for (const [transformationHash, idSet] of this.#hashToIDs.entries()) {\n idSet.delete(queryID);\n if (idSet.size === 0) {\n this.#hashToIDs.delete(transformationHash);\n this.#transformationASTs.delete(transformationHash);\n }\n }\n }\n\n addQuery(transformationHash: string, queryID: string, ast: AST): void {\n const existing = this.#hashToIDs.get(transformationHash);\n if (existing === undefined) {\n this.#hashToIDs.set(transformationHash, new Set([queryID]));\n } else {\n existing.add(queryID);\n }\n this.#queryIDToTransformationHash.set(queryID, transformationHash);\n this.#transformationASTs.set(transformationHash, ast);\n }\n\n /**\n * Check if the client is authenticated. We only require authentication once\n * per \"worker\".\n */\n isAuthenticated(clientGroupID: ClientGroupID): boolean {\n return (\n isDevelopmentMode() || authenticatedClientGroupIDs.has(clientGroupID)\n );\n }\n\n setAuthenticated(clientGroupID: ClientGroupID): void {\n authenticatedClientGroupIDs.add(clientGroupID);\n }\n\n clearAuthenticated(clientGroupID: ClientGroupID) {\n authenticatedClientGroupIDs.delete(clientGroupID);\n }\n\n /**\n * Transforms a single custom query by name and args using the configured\n * CustomQueryTransformer. This is primarily used by the inspector to transform\n * queries for analysis.\n */\n async transformCustomQuery(\n name: string,\n args: readonly ReadonlyJSONValue[],\n headerOptions: HeaderOptions,\n userQueryURL: string | undefined,\n ): Promise<AST> {\n assert(\n this.#customQueryTransformer,\n 'Custom query transformation requested but no CustomQueryTransformer is configured',\n );\n\n // Create a fake CustomQueryRecord for the single query\n const queryID = hashOfNameAndArgs(name, args);\n const queries: CustomQueryRecord[] = [\n {\n id: queryID,\n type: 'custom',\n name,\n args,\n clientState: {},\n },\n ];\n\n const results = await this.#customQueryTransformer.transform(\n headerOptions,\n queries,\n userQueryURL,\n );\n\n if ('kind' in results) {\n throw new ProtocolErrorWithLevel(results, 'warn');\n }\n\n const result = results[0];\n if (!result) {\n throw new Error('No transformation result returned');\n }\n\n if ('error' in result) {\n const message =\n result.message ?? 'Unknown application error from custom query';\n throw new Error(\n `Error transforming custom query ${name} (${result.error}): ${message} ${JSON.stringify(result.details)}`,\n );\n }\n\n return result.transformedAst;\n }\n}\n\nfunction newMetrics(): ServerMetrics {\n return {\n 'query-materialization-server': new TDigest(),\n 'query-update-server': new TDigest(),\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"pusher.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"names":[],"mappings":"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"}
|
|
@@ -299,7 +299,6 @@ class PushWorker {
|
|
|
299
299
|
"push",
|
|
300
300
|
this.#lc,
|
|
301
301
|
url,
|
|
302
|
-
url === this.#userPushURL,
|
|
303
302
|
this.#pushURLPatterns,
|
|
304
303
|
{
|
|
305
304
|
appID: this.#config.app.id,
|
|
@@ -330,8 +329,7 @@ class PushWorker {
|
|
|
330
329
|
}
|
|
331
330
|
}
|
|
332
331
|
#failDownstream(downstream, errorBody) {
|
|
333
|
-
|
|
334
|
-
downstream.fail(new ProtocolErrorWithLevel(errorBody, logLevel));
|
|
332
|
+
downstream.fail(new ProtocolErrorWithLevel(errorBody, "warn"));
|
|
335
333
|
}
|
|
336
334
|
}
|
|
337
335
|
function combinePushes(entries) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pusher.js","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {groupBy} from '../../../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {getErrorMessage} from '../../../../shared/src/error.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {Queue} from '../../../../shared/src/queue.ts';\nimport type {Downstream} from '../../../../zero-protocol/src/down.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../../zero-protocol/src/error-reason.ts';\nimport {\n isProtocolError,\n type PushFailedBody,\n} from '../../../../zero-protocol/src/error.ts';\nimport {\n pushResponseSchema,\n type MutationID,\n type PushBody,\n type PushResponse,\n} from '../../../../zero-protocol/src/push.ts';\nimport {type ZeroConfig} from '../../config/zero-config.ts';\nimport {compileUrlPattern, fetchFromAPIServer} from '../../custom/fetch.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport {recordMutation} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB} from '../../types/pg.ts';\nimport {upstreamSchema} from '../../types/shards.ts';\nimport type {Source} from '../../types/streams.ts';\nimport {Subscription} from '../../types/subscription.ts';\nimport type {HandlerResult, StreamResult} from '../../workers/connection.ts';\nimport type {RefCountedService, Service} from '../service.ts';\n\nexport interface Pusher extends RefCountedService {\n readonly pushURL: string | undefined;\n\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ): Source<Downstream>;\n enqueuePush(\n clientID: string,\n push: PushBody,\n auth: string | undefined,\n httpCookie: string | undefined,\n ): HandlerResult;\n ackMutationResponses(upToID: MutationID): Promise<void>;\n}\n\ntype Config = Pick<ZeroConfig, 'app' | 'shard'>;\n\n/**\n * Receives push messages from zero-client and forwards\n * them the the user's API server.\n *\n * If the user's API server is taking too long to process\n * the push, the PusherService will add the push to a queue\n * and send pushes in bulk the next time the user's API server\n * is available.\n *\n * - One PusherService exists per client group.\n * - Mutations for a given client are always sent in-order\n * - Mutations for different clients in the same group may be interleaved\n */\nexport class PusherService implements Service, Pusher {\n readonly id: string;\n readonly #pusher: PushWorker;\n readonly #queue: Queue<PusherEntryOrStop>;\n readonly #pushConfig: ZeroConfig['push'] & {url: string[]};\n readonly #upstream: PostgresDB;\n readonly #config: Config;\n #stopped: Promise<void> | undefined;\n #refCount = 0;\n #isStopped = false;\n\n constructor(\n upstream: PostgresDB,\n appConfig: Config,\n pushConfig: ZeroConfig['push'] & {url: string[]},\n lc: LogContext,\n clientGroupID: string,\n ) {\n this.#config = appConfig;\n this.#upstream = upstream;\n this.#queue = new Queue();\n this.#pusher = new PushWorker(\n appConfig,\n lc,\n pushConfig.url,\n pushConfig.apiKey,\n this.#queue,\n );\n this.id = clientGroupID;\n this.#pushConfig = pushConfig;\n }\n\n get pushURL(): string | undefined {\n return this.#pusher.pushURL[0];\n }\n\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ) {\n return this.#pusher.initConnection(\n clientID,\n wsID,\n userPushURL,\n userPushHeaders,\n );\n }\n\n enqueuePush(\n clientID: string,\n push: PushBody,\n auth: string | undefined,\n httpCookie: string | undefined,\n ): Exclude<HandlerResult, StreamResult> {\n if (!this.#pushConfig.forwardCookies) {\n httpCookie = undefined; // remove cookies if not forwarded\n }\n this.#queue.enqueue({push, auth, clientID, httpCookie});\n\n return {\n type: 'ok',\n };\n }\n\n async ackMutationResponses(upToID: MutationID) {\n // delete the relevant rows from the `mutations` table\n const sql = this.#upstream;\n await sql`DELETE FROM ${sql(\n upstreamSchema({\n appID: this.#config.app.id,\n shardNum: this.#config.shard.num,\n }),\n )}.mutations WHERE \"clientGroupID\" = ${this.id} AND \"clientID\" = ${upToID.clientID} AND \"mutationID\" <= ${upToID.id}`;\n }\n\n ref() {\n assert(!this.#isStopped, 'PusherService is already stopped');\n ++this.#refCount;\n }\n\n unref() {\n assert(!this.#isStopped, 'PusherService is already stopped');\n --this.#refCount;\n if (this.#refCount <= 0) {\n void this.stop();\n }\n }\n\n hasRefs(): boolean {\n return this.#refCount > 0;\n }\n\n run(): Promise<void> {\n this.#stopped = this.#pusher.run();\n return this.#stopped;\n }\n\n stop(): Promise<void> {\n if (this.#isStopped) {\n return must(this.#stopped, 'Stop was called before `run`');\n }\n this.#isStopped = true;\n this.#queue.enqueue('stop');\n return must(this.#stopped, 'Stop was called before `run`');\n }\n}\n\ntype PusherEntry = {\n push: PushBody;\n auth: string | undefined;\n httpCookie: string | undefined;\n clientID: string;\n};\ntype PusherEntryOrStop = PusherEntry | 'stop';\n\n/**\n * Awaits items in the queue then drains and sends them all\n * to the user's API server.\n */\nclass PushWorker {\n readonly #pushURLs: string[];\n readonly #pushURLPatterns: URLPattern[];\n readonly #apiKey: string | undefined;\n readonly #queue: Queue<PusherEntryOrStop>;\n readonly #lc: LogContext;\n readonly #config: Config;\n readonly #clients: Map<\n string,\n {\n wsID: string;\n downstream: Subscription<Downstream>;\n }\n >;\n #userPushURL?: string | undefined;\n #userPushHeaders?: Record<string, string> | undefined;\n\n readonly #customMutations = getOrCreateCounter(\n 'mutation',\n 'custom',\n 'Number of custom mutations processed',\n );\n readonly #pushes = getOrCreateCounter(\n 'mutation',\n 'pushes',\n 'Number of pushes processed by the pusher',\n );\n\n constructor(\n config: Config,\n lc: LogContext,\n pushURL: string[],\n apiKey: string | undefined,\n queue: Queue<PusherEntryOrStop>,\n ) {\n this.#pushURLs = pushURL;\n this.#lc = lc.withContext('component', 'pusher');\n this.#pushURLPatterns = pushURL.map(compileUrlPattern);\n this.#apiKey = apiKey;\n this.#queue = queue;\n this.#config = config;\n this.#clients = new Map();\n }\n\n get pushURL() {\n return this.#pushURLs;\n }\n\n /**\n * Returns a new downstream stream if the clientID,wsID pair has not been seen before.\n * If a clientID already exists with a different wsID, that client's downstream is cancelled.\n */\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ) {\n const existing = this.#clients.get(clientID);\n if (existing && existing.wsID === wsID) {\n // already initialized for this socket\n throw new Error('Connection was already initialized');\n }\n\n // client is back on a new connection\n if (existing) {\n existing.downstream.cancel();\n }\n\n // Handle client group level URL parameters\n if (this.#userPushURL === undefined) {\n // First client in the group - store its URL and headers\n this.#userPushURL = userPushURL;\n this.#userPushHeaders = userPushHeaders;\n } else {\n // Validate that subsequent clients have compatible parameters\n if (this.#userPushURL !== userPushURL) {\n this.#lc.warn?.(\n 'Client provided different mutate parameters than client group',\n {\n clientID,\n clientURL: userPushURL,\n clientGroupURL: this.#userPushURL,\n },\n );\n }\n }\n\n const downstream = Subscription.create<Downstream>({\n cleanup: () => {\n this.#clients.delete(clientID);\n },\n });\n this.#clients.set(clientID, {wsID, downstream});\n return downstream;\n }\n\n async run() {\n for (;;) {\n const task = await this.#queue.dequeue();\n const rest = this.#queue.drain();\n const [pushes, terminate] = combinePushes([task, ...rest]);\n for (const push of pushes) {\n const response = await this.#processPush(push);\n await this.#fanOutResponses(response);\n }\n\n if (terminate) {\n break;\n }\n }\n }\n\n /**\n * 1. If the entire `push` fails, we send the error to relevant clients.\n * 2. If the push succeeds, we look for any mutation failure that should cause the connection to terminate\n * and terminate the connection for those clients.\n */\n #fanOutResponses(response: PushResponse) {\n const connectionTerminations: (() => void)[] = [];\n\n // if the entire push failed, send that to the client.\n if ('kind' in response || 'error' in response) {\n this.#lc.warn?.(\n 'The server behind ZERO_MUTATE_URL returned a push error.',\n response,\n );\n const groupedMutationIDs = groupBy(\n response.mutationIDs ?? [],\n m => m.clientID,\n );\n for (const [clientID, mutationIDs] of groupedMutationIDs) {\n const client = this.#clients.get(clientID);\n if (!client) {\n continue;\n }\n\n // We do not resolve mutations on the client if the push fails\n // as those mutations will be retried.\n if ('error' in response) {\n // This error code path will eventually be removed when we\n // no longer support the legacy push error format.\n const pushFailedBody: PushFailedBody =\n response.error === 'http'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview: response.details,\n mutationIDs,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n }\n : response.error === 'unsupportedPushVersion'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version`,\n }\n : {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Internal,\n mutationIDs,\n message:\n response.error === 'zeroPusher'\n ? response.details\n : response.error === 'unsupportedSchemaVersion'\n ? 'Unsupported schema version'\n : 'An unknown error occurred while pushing to the API server',\n };\n\n this.#failDownstream(client.downstream, pushFailedBody);\n } else if ('kind' in response) {\n this.#failDownstream(client.downstream, response);\n } else {\n unreachable(response);\n }\n }\n } else {\n // Look for mutations results that should cause us to terminate the connection\n const groupedMutations = groupBy(response.mutations, m => m.id.clientID);\n for (const [clientID, mutations] of groupedMutations) {\n const client = this.#clients.get(clientID);\n if (!client) {\n continue;\n }\n\n let failure: PushFailedBody | undefined;\n let i = 0;\n for (; i < mutations.length; i++) {\n const m = mutations[i];\n if ('error' in m.result) {\n this.#lc.warn?.(\n 'The server behind ZERO_MUTATE_URL returned a mutation error.',\n m.result,\n );\n }\n // This error code path will eventually be removed,\n // keeping this for backwards compatibility, but the server\n // should now return a PushFailedBody with the mutationIDs\n if ('error' in m.result && m.result.error === 'oooMutation') {\n failure = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.OutOfOrderMutation,\n message: 'mutation was out of order',\n details: m.result.details,\n mutationIDs: mutations.map(m => ({\n clientID: m.id.clientID,\n id: m.id.id,\n })),\n };\n break;\n }\n }\n\n if (failure && i < mutations.length - 1) {\n this.#lc.warn?.(\n 'push-response contains mutations after a mutation which should fatal the connection',\n );\n }\n\n if (failure) {\n connectionTerminations.push(() =>\n this.#failDownstream(client.downstream, failure),\n );\n }\n }\n }\n\n connectionTerminations.forEach(cb => cb());\n }\n\n async #processPush(entry: PusherEntry): Promise<PushResponse> {\n this.#customMutations.add(entry.push.mutations.length, {\n clientGroupID: entry.push.clientGroupID,\n });\n this.#pushes.add(1, {\n clientGroupID: entry.push.clientGroupID,\n });\n\n // Record custom mutations for telemetry\n recordMutation('custom', entry.push.mutations.length);\n\n const url =\n this.#userPushURL ??\n must(this.#pushURLs[0], 'ZERO_MUTATE_URL is not set');\n\n this.#lc.debug?.(\n 'pushing to',\n url,\n 'with',\n entry.push.mutations.length,\n 'mutations',\n );\n\n let mutationIDs: MutationID[] = [];\n\n try {\n mutationIDs = entry.push.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n\n return await fetchFromAPIServer(\n pushResponseSchema,\n 'push',\n this.#lc,\n url,\n url === this.#userPushURL,\n this.#pushURLPatterns,\n {\n appID: this.#config.app.id,\n shardNum: this.#config.shard.num,\n },\n {\n apiKey: this.#apiKey,\n customHeaders: this.#userPushHeaders,\n token: entry.auth,\n cookie: entry.httpCookie,\n },\n entry.push,\n );\n } catch (e) {\n if (isProtocolError(e) && e.errorBody.kind === ErrorKind.PushFailed) {\n return {\n ...e.errorBody,\n mutationIDs,\n } as const satisfies PushFailedBody;\n }\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Failed to push: ${getErrorMessage(e)}`,\n mutationIDs,\n } as const satisfies PushFailedBody;\n }\n }\n\n #failDownstream(\n downstream: Subscription<Downstream>,\n errorBody: PushFailedBody,\n ): void {\n const logLevel = errorBody.origin === ErrorOrigin.Server ? 'warn' : 'error';\n downstream.fail(new ProtocolErrorWithLevel(errorBody, logLevel));\n }\n}\n\n/**\n * Pushes for different clientIDs could theoretically be interleaved.\n *\n * In order to do efficient batching to the user's API server,\n * we collect all pushes for the same clientID into a single push.\n */\nexport function combinePushes(\n entries: readonly (PusherEntryOrStop | undefined)[],\n): [PusherEntry[], boolean] {\n const pushesByClientID = new Map<string, PusherEntry[]>();\n\n function collect() {\n const ret: PusherEntry[] = [];\n for (const entries of pushesByClientID.values()) {\n const composite: PusherEntry = {\n ...entries[0],\n push: {\n ...entries[0].push,\n mutations: [],\n },\n };\n ret.push(composite);\n for (const entry of entries) {\n assertAreCompatiblePushes(composite, entry);\n composite.push.mutations.push(...entry.push.mutations);\n }\n }\n return ret;\n }\n\n for (const entry of entries) {\n if (entry === 'stop' || entry === undefined) {\n return [collect(), true];\n }\n\n const {clientID} = entry;\n const existing = pushesByClientID.get(clientID);\n if (existing) {\n existing.push(entry);\n } else {\n pushesByClientID.set(clientID, [entry]);\n }\n }\n\n return [collect(), false] as const;\n}\n\n// These invariants should always be true for a given clientID.\n// If they are not, we have a bug in the code somewhere.\nfunction assertAreCompatiblePushes(left: PusherEntry, right: PusherEntry) {\n assert(\n left.clientID === right.clientID,\n 'clientID must be the same for all pushes',\n );\n assert(\n left.auth === right.auth,\n 'auth must be the same for all pushes with the same clientID',\n );\n assert(\n left.push.schemaVersion === right.push.schemaVersion,\n 'schemaVersion must be the same for all pushes with the same clientID',\n );\n assert(\n left.push.pushVersion === right.push.pushVersion,\n 'pushVersion must be the same for all pushes with the same clientID',\n );\n assert(\n left.httpCookie === right.httpCookie,\n 'httpCookie must be the same for all pushes with the same clientID',\n );\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.ZeroCache","ErrorReason.HTTP","ErrorOrigin.Server","ErrorReason.UnsupportedPushVersion","ErrorReason.Internal","ErrorReason.OutOfOrderMutation","m","entries"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pusher.js","sources":["../../../../../../zero-cache/src/services/mutagen/pusher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {groupBy} from '../../../../shared/src/arrays.ts';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {getErrorMessage} from '../../../../shared/src/error.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport {Queue} from '../../../../shared/src/queue.ts';\nimport type {Downstream} from '../../../../zero-protocol/src/down.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport {ErrorReason} from '../../../../zero-protocol/src/error-reason.ts';\nimport {\n isProtocolError,\n type PushFailedBody,\n} from '../../../../zero-protocol/src/error.ts';\nimport {\n pushResponseSchema,\n type MutationID,\n type PushBody,\n type PushResponse,\n} from '../../../../zero-protocol/src/push.ts';\nimport {type ZeroConfig} from '../../config/zero-config.ts';\nimport {compileUrlPattern, fetchFromAPIServer} from '../../custom/fetch.ts';\nimport {getOrCreateCounter} from '../../observability/metrics.ts';\nimport {recordMutation} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB} from '../../types/pg.ts';\nimport {upstreamSchema} from '../../types/shards.ts';\nimport type {Source} from '../../types/streams.ts';\nimport {Subscription} from '../../types/subscription.ts';\nimport type {HandlerResult, StreamResult} from '../../workers/connection.ts';\nimport type {RefCountedService, Service} from '../service.ts';\n\nexport interface Pusher extends RefCountedService {\n readonly pushURL: string | undefined;\n\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ): Source<Downstream>;\n enqueuePush(\n clientID: string,\n push: PushBody,\n auth: string | undefined,\n httpCookie: string | undefined,\n ): HandlerResult;\n ackMutationResponses(upToID: MutationID): Promise<void>;\n}\n\ntype Config = Pick<ZeroConfig, 'app' | 'shard'>;\n\n/**\n * Receives push messages from zero-client and forwards\n * them the the user's API server.\n *\n * If the user's API server is taking too long to process\n * the push, the PusherService will add the push to a queue\n * and send pushes in bulk the next time the user's API server\n * is available.\n *\n * - One PusherService exists per client group.\n * - Mutations for a given client are always sent in-order\n * - Mutations for different clients in the same group may be interleaved\n */\nexport class PusherService implements Service, Pusher {\n readonly id: string;\n readonly #pusher: PushWorker;\n readonly #queue: Queue<PusherEntryOrStop>;\n readonly #pushConfig: ZeroConfig['push'] & {url: string[]};\n readonly #upstream: PostgresDB;\n readonly #config: Config;\n #stopped: Promise<void> | undefined;\n #refCount = 0;\n #isStopped = false;\n\n constructor(\n upstream: PostgresDB,\n appConfig: Config,\n pushConfig: ZeroConfig['push'] & {url: string[]},\n lc: LogContext,\n clientGroupID: string,\n ) {\n this.#config = appConfig;\n this.#upstream = upstream;\n this.#queue = new Queue();\n this.#pusher = new PushWorker(\n appConfig,\n lc,\n pushConfig.url,\n pushConfig.apiKey,\n this.#queue,\n );\n this.id = clientGroupID;\n this.#pushConfig = pushConfig;\n }\n\n get pushURL(): string | undefined {\n return this.#pusher.pushURL[0];\n }\n\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ) {\n return this.#pusher.initConnection(\n clientID,\n wsID,\n userPushURL,\n userPushHeaders,\n );\n }\n\n enqueuePush(\n clientID: string,\n push: PushBody,\n auth: string | undefined,\n httpCookie: string | undefined,\n ): Exclude<HandlerResult, StreamResult> {\n if (!this.#pushConfig.forwardCookies) {\n httpCookie = undefined; // remove cookies if not forwarded\n }\n this.#queue.enqueue({push, auth, clientID, httpCookie});\n\n return {\n type: 'ok',\n };\n }\n\n async ackMutationResponses(upToID: MutationID) {\n // delete the relevant rows from the `mutations` table\n const sql = this.#upstream;\n await sql`DELETE FROM ${sql(\n upstreamSchema({\n appID: this.#config.app.id,\n shardNum: this.#config.shard.num,\n }),\n )}.mutations WHERE \"clientGroupID\" = ${this.id} AND \"clientID\" = ${upToID.clientID} AND \"mutationID\" <= ${upToID.id}`;\n }\n\n ref() {\n assert(!this.#isStopped, 'PusherService is already stopped');\n ++this.#refCount;\n }\n\n unref() {\n assert(!this.#isStopped, 'PusherService is already stopped');\n --this.#refCount;\n if (this.#refCount <= 0) {\n void this.stop();\n }\n }\n\n hasRefs(): boolean {\n return this.#refCount > 0;\n }\n\n run(): Promise<void> {\n this.#stopped = this.#pusher.run();\n return this.#stopped;\n }\n\n stop(): Promise<void> {\n if (this.#isStopped) {\n return must(this.#stopped, 'Stop was called before `run`');\n }\n this.#isStopped = true;\n this.#queue.enqueue('stop');\n return must(this.#stopped, 'Stop was called before `run`');\n }\n}\n\ntype PusherEntry = {\n push: PushBody;\n auth: string | undefined;\n httpCookie: string | undefined;\n clientID: string;\n};\ntype PusherEntryOrStop = PusherEntry | 'stop';\n\n/**\n * Awaits items in the queue then drains and sends them all\n * to the user's API server.\n */\nclass PushWorker {\n readonly #pushURLs: string[];\n readonly #pushURLPatterns: URLPattern[];\n readonly #apiKey: string | undefined;\n readonly #queue: Queue<PusherEntryOrStop>;\n readonly #lc: LogContext;\n readonly #config: Config;\n readonly #clients: Map<\n string,\n {\n wsID: string;\n downstream: Subscription<Downstream>;\n }\n >;\n #userPushURL?: string | undefined;\n #userPushHeaders?: Record<string, string> | undefined;\n\n readonly #customMutations = getOrCreateCounter(\n 'mutation',\n 'custom',\n 'Number of custom mutations processed',\n );\n readonly #pushes = getOrCreateCounter(\n 'mutation',\n 'pushes',\n 'Number of pushes processed by the pusher',\n );\n\n constructor(\n config: Config,\n lc: LogContext,\n pushURL: string[],\n apiKey: string | undefined,\n queue: Queue<PusherEntryOrStop>,\n ) {\n this.#pushURLs = pushURL;\n this.#lc = lc.withContext('component', 'pusher');\n this.#pushURLPatterns = pushURL.map(compileUrlPattern);\n this.#apiKey = apiKey;\n this.#queue = queue;\n this.#config = config;\n this.#clients = new Map();\n }\n\n get pushURL() {\n return this.#pushURLs;\n }\n\n /**\n * Returns a new downstream stream if the clientID,wsID pair has not been seen before.\n * If a clientID already exists with a different wsID, that client's downstream is cancelled.\n */\n initConnection(\n clientID: string,\n wsID: string,\n userPushURL: string | undefined,\n userPushHeaders: Record<string, string> | undefined,\n ) {\n const existing = this.#clients.get(clientID);\n if (existing && existing.wsID === wsID) {\n // already initialized for this socket\n throw new Error('Connection was already initialized');\n }\n\n // client is back on a new connection\n if (existing) {\n existing.downstream.cancel();\n }\n\n // Handle client group level URL parameters\n if (this.#userPushURL === undefined) {\n // First client in the group - store its URL and headers\n this.#userPushURL = userPushURL;\n this.#userPushHeaders = userPushHeaders;\n } else {\n // Validate that subsequent clients have compatible parameters\n if (this.#userPushURL !== userPushURL) {\n this.#lc.warn?.(\n 'Client provided different mutate parameters than client group',\n {\n clientID,\n clientURL: userPushURL,\n clientGroupURL: this.#userPushURL,\n },\n );\n }\n }\n\n const downstream = Subscription.create<Downstream>({\n cleanup: () => {\n this.#clients.delete(clientID);\n },\n });\n this.#clients.set(clientID, {wsID, downstream});\n return downstream;\n }\n\n async run() {\n for (;;) {\n const task = await this.#queue.dequeue();\n const rest = this.#queue.drain();\n const [pushes, terminate] = combinePushes([task, ...rest]);\n for (const push of pushes) {\n const response = await this.#processPush(push);\n await this.#fanOutResponses(response);\n }\n\n if (terminate) {\n break;\n }\n }\n }\n\n /**\n * 1. If the entire `push` fails, we send the error to relevant clients.\n * 2. If the push succeeds, we look for any mutation failure that should cause the connection to terminate\n * and terminate the connection for those clients.\n */\n #fanOutResponses(response: PushResponse) {\n const connectionTerminations: (() => void)[] = [];\n\n // if the entire push failed, send that to the client.\n if ('kind' in response || 'error' in response) {\n this.#lc.warn?.(\n 'The server behind ZERO_MUTATE_URL returned a push error.',\n response,\n );\n const groupedMutationIDs = groupBy(\n response.mutationIDs ?? [],\n m => m.clientID,\n );\n for (const [clientID, mutationIDs] of groupedMutationIDs) {\n const client = this.#clients.get(clientID);\n if (!client) {\n continue;\n }\n\n // We do not resolve mutations on the client if the push fails\n // as those mutations will be retried.\n if ('error' in response) {\n // This error code path will eventually be removed when we\n // no longer support the legacy push error format.\n const pushFailedBody: PushFailedBody =\n response.error === 'http'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.HTTP,\n status: response.status,\n bodyPreview: response.details,\n mutationIDs,\n message: `Fetch from API server returned non-OK status ${response.status}`,\n }\n : response.error === 'unsupportedPushVersion'\n ? {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.UnsupportedPushVersion,\n mutationIDs,\n message: `Unsupported push version`,\n }\n : {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.Internal,\n mutationIDs,\n message:\n response.error === 'zeroPusher'\n ? response.details\n : response.error === 'unsupportedSchemaVersion'\n ? 'Unsupported schema version'\n : 'An unknown error occurred while pushing to the API server',\n };\n\n this.#failDownstream(client.downstream, pushFailedBody);\n } else if ('kind' in response) {\n this.#failDownstream(client.downstream, response);\n } else {\n unreachable(response);\n }\n }\n } else {\n // Look for mutations results that should cause us to terminate the connection\n const groupedMutations = groupBy(response.mutations, m => m.id.clientID);\n for (const [clientID, mutations] of groupedMutations) {\n const client = this.#clients.get(clientID);\n if (!client) {\n continue;\n }\n\n let failure: PushFailedBody | undefined;\n let i = 0;\n for (; i < mutations.length; i++) {\n const m = mutations[i];\n if ('error' in m.result) {\n this.#lc.warn?.(\n 'The server behind ZERO_MUTATE_URL returned a mutation error.',\n m.result,\n );\n }\n // This error code path will eventually be removed,\n // keeping this for backwards compatibility, but the server\n // should now return a PushFailedBody with the mutationIDs\n if ('error' in m.result && m.result.error === 'oooMutation') {\n failure = {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.Server,\n reason: ErrorReason.OutOfOrderMutation,\n message: 'mutation was out of order',\n details: m.result.details,\n mutationIDs: mutations.map(m => ({\n clientID: m.id.clientID,\n id: m.id.id,\n })),\n };\n break;\n }\n }\n\n if (failure && i < mutations.length - 1) {\n this.#lc.warn?.(\n 'push-response contains mutations after a mutation which should fatal the connection',\n );\n }\n\n if (failure) {\n connectionTerminations.push(() =>\n this.#failDownstream(client.downstream, failure),\n );\n }\n }\n }\n\n connectionTerminations.forEach(cb => cb());\n }\n\n async #processPush(entry: PusherEntry): Promise<PushResponse> {\n this.#customMutations.add(entry.push.mutations.length, {\n clientGroupID: entry.push.clientGroupID,\n });\n this.#pushes.add(1, {\n clientGroupID: entry.push.clientGroupID,\n });\n\n // Record custom mutations for telemetry\n recordMutation('custom', entry.push.mutations.length);\n\n const url =\n this.#userPushURL ??\n must(this.#pushURLs[0], 'ZERO_MUTATE_URL is not set');\n\n this.#lc.debug?.(\n 'pushing to',\n url,\n 'with',\n entry.push.mutations.length,\n 'mutations',\n );\n\n let mutationIDs: MutationID[] = [];\n\n try {\n mutationIDs = entry.push.mutations.map(m => ({\n id: m.id,\n clientID: m.clientID,\n }));\n\n return await fetchFromAPIServer(\n pushResponseSchema,\n 'push',\n this.#lc,\n url,\n this.#pushURLPatterns,\n {\n appID: this.#config.app.id,\n shardNum: this.#config.shard.num,\n },\n {\n apiKey: this.#apiKey,\n customHeaders: this.#userPushHeaders,\n token: entry.auth,\n cookie: entry.httpCookie,\n },\n entry.push,\n );\n } catch (e) {\n if (isProtocolError(e) && e.errorBody.kind === ErrorKind.PushFailed) {\n return {\n ...e.errorBody,\n mutationIDs,\n } as const satisfies PushFailedBody;\n }\n\n return {\n kind: ErrorKind.PushFailed,\n origin: ErrorOrigin.ZeroCache,\n reason: ErrorReason.Internal,\n message: `Failed to push: ${getErrorMessage(e)}`,\n mutationIDs,\n } as const satisfies PushFailedBody;\n }\n }\n\n #failDownstream(\n downstream: Subscription<Downstream>,\n errorBody: PushFailedBody,\n ): void {\n downstream.fail(new ProtocolErrorWithLevel(errorBody, 'warn'));\n }\n}\n\n/**\n * Pushes for different clientIDs could theoretically be interleaved.\n *\n * In order to do efficient batching to the user's API server,\n * we collect all pushes for the same clientID into a single push.\n */\nexport function combinePushes(\n entries: readonly (PusherEntryOrStop | undefined)[],\n): [PusherEntry[], boolean] {\n const pushesByClientID = new Map<string, PusherEntry[]>();\n\n function collect() {\n const ret: PusherEntry[] = [];\n for (const entries of pushesByClientID.values()) {\n const composite: PusherEntry = {\n ...entries[0],\n push: {\n ...entries[0].push,\n mutations: [],\n },\n };\n ret.push(composite);\n for (const entry of entries) {\n assertAreCompatiblePushes(composite, entry);\n composite.push.mutations.push(...entry.push.mutations);\n }\n }\n return ret;\n }\n\n for (const entry of entries) {\n if (entry === 'stop' || entry === undefined) {\n return [collect(), true];\n }\n\n const {clientID} = entry;\n const existing = pushesByClientID.get(clientID);\n if (existing) {\n existing.push(entry);\n } else {\n pushesByClientID.set(clientID, [entry]);\n }\n }\n\n return [collect(), false] as const;\n}\n\n// These invariants should always be true for a given clientID.\n// If they are not, we have a bug in the code somewhere.\nfunction assertAreCompatiblePushes(left: PusherEntry, right: PusherEntry) {\n assert(\n left.clientID === right.clientID,\n 'clientID must be the same for all pushes',\n );\n assert(\n left.auth === right.auth,\n 'auth must be the same for all pushes with the same clientID',\n );\n assert(\n left.push.schemaVersion === right.push.schemaVersion,\n 'schemaVersion must be the same for all pushes with the same clientID',\n );\n assert(\n left.push.pushVersion === right.push.pushVersion,\n 'pushVersion must be the same for all pushes with the same clientID',\n );\n assert(\n left.httpCookie === right.httpCookie,\n 'httpCookie must be the same for all pushes with the same clientID',\n );\n}\n"],"names":["ErrorKind.PushFailed","ErrorOrigin.ZeroCache","ErrorReason.HTTP","ErrorOrigin.Server","ErrorReason.UnsupportedPushVersion","ErrorReason.Internal","ErrorReason.OutOfOrderMutation","m","entries"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAiBjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+CAA+C,CAAC;AAKnF,OAAO,EAAC,sBAAsB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAY,KAAK,OAAO,EAAiB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAQ,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAC,GAAG,EAAE,WAAW,EAAC,MAAM,UAAU,CAAC;AAE/C,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,KAAK,YAAY,EAGjB,KAAK,UAAU,EAGf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,KAAK,EACV,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,QAAQ,EAGd,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AA0DF,qBAAa,QAAQ;;gBA4BjB,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,UAAU,EAKjB,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EACjC,qBAAqB,SAA2B,EAChD,eAAe,SAAoB,EACnC,yBAAyB,SAAM,EAAE,qBAAqB;IACtD,YAAY,oBAAa;IA0B3B,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAgN3D,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAIvD,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI;IAIlC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI;IAI7B;;;;OAIG;IACH,YAAY,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE;IAM5B;;;;OAIG;IACG,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3E;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAYlD,WAAW,CAAC,EACV,OAAO,EACP,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,QAAQ,GACT,EAAE,IAAI,CACL,WAAW,EACT,SAAS,GACT,gBAAgB,GAChB,YAAY,GACZ,cAAc,GACd,WAAW,GACX,UAAU,CACb,GAAG,IAAI;IAsBR,kBAAkB,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;IAarE,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IA4ClC,WAAW,CAAC,KAAK,EAAE,WAAW;IA2B9B,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAYxC,YAAY,CAAC,QAAQ,EAAE,MAAM;IAgB7B,eAAe,CACb,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,EACnB,MAAM,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,EACpB,OAAO,EAAE,OAAO,EAChB,aAAa,EAAE,QAAQ,GAAG,SAAS,EACnC,GAAG,EAAE,MAAM,GACV,IAAI;IA+CP,iBAAiB,CACf,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,kBAAkB,EAChC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,UAAU,EACnB,kBAAkB,GAAE,MAAM,EAAO,GAChC,cAAc,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC;IAUvC,oBAAoB,CACxB,EAAE,EAAE,UAAU,EACd,YAAY,EAAE,kBAAkB,EAChC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,UAAU,GAClB,OAAO,CAAC,cAAc,EAAE,CAAC;IA6N5B,IAAI,QAAQ,IAAI,MAAM,CAErB;IAEK,KAAK,CACT,EAAE,EAAE,UAAU,EACd,sBAAsB,EAAE,UAAU,EAClC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA+BhC,iBAAiB,IAAI,OAAO;IAI5B,qDAAqD;IACrD,OAAO,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC,cAAc,CAClB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,QAAQ,EAClB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,EAAE,CAAC;CAsC9B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,mBAAmB,EACvB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,sBAAsB,EAAE,UAAU,GACjC,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,qBAAa,mBAAoB,SAAQ,sBAAsB;gBACjD,OAAO,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -746,11 +746,14 @@ async function checkVersion(tx, schema, clientGroupID, expectedCurrentVersion) {
|
|
|
746
746
|
}
|
|
747
747
|
class ClientNotFoundError extends ProtocolErrorWithLevel {
|
|
748
748
|
constructor(message) {
|
|
749
|
-
super(
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
749
|
+
super(
|
|
750
|
+
{
|
|
751
|
+
kind: ClientNotFound,
|
|
752
|
+
message,
|
|
753
|
+
origin: ZeroCache
|
|
754
|
+
},
|
|
755
|
+
"warn"
|
|
756
|
+
);
|
|
754
757
|
}
|
|
755
758
|
}
|
|
756
759
|
class ConcurrentModificationException extends ProtocolErrorWithLevel {
|
|
@@ -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\nlet flushCounter = 0;\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 lc.debug?.(`CVR tx started after ${Date.now() - start} ms`);\n return [\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 lc.debug?.(\n `CVR tx completed after ${Date.now() - start} ms ` +\n `(${clientsRows.length} clients, ${queryRows.length} queries, ${desiresRows.length} desires)`,\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 lc: LogContext,\n tx: PostgresTransaction,\n expectedCurrentVersion: CVRVersion,\n lastConnectTime: number,\n ): Promise<void> {\n const start = Date.now();\n lc.debug?.('checking cvr version and ownership');\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 lc.debug?.(\n 'checked cvr version and ownership in ' + (Date.now() - start) + ' ms',\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 lc: LogContext,\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 const start = Date.now();\n lc.debug?.('flush tx beginning');\n const rowsFlushed = await this.#db.begin(Mode.READ_COMMITTED, async tx => {\n lc.debug?.(`flush tx begun after ${Date.now() - start} ms`);\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 lc,\n tx,\n expectedCurrentVersion,\n lastConnectTime,\n ),\n ];\n\n let i = 0;\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 const writeIndex = i++;\n const writeStart = Date.now();\n pipelined.push(\n write\n .write(tx, lastConnectTime)\n .execute()\n .then(() => {\n lc.debug?.(\n `write ${writeIndex}/${this.#writes.size} completed in ${Date.now() - writeStart} ms`,\n );\n }),\n );\n stats.statements++;\n }\n\n const rowUpdates = this.#rowCache.executeRowUpdates(\n tx,\n cvr.version,\n this.#pendingRowRecordUpdates,\n 'allow-defer',\n lc,\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 lc.debug?.(`flush tx returning after ${Date.now() - start} ms`);\n if (rowUpdates.length === 0) {\n stats.rowsDeferred = this.#pendingRowRecordUpdates.size;\n return false;\n }\n stats.rows += this.#pendingRowRecordUpdates.size;\n\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 && this.#upstreamWrites.length) {\n const start = performance.now();\n lc.debug?.('flushing upstream writes');\n await this.#upstreamDb.begin(Mode.READ_COMMITTED, async tx => {\n await Promise.all(this.#upstreamWrites.map(write => write(tx)));\n });\n const elapsed = performance.now() - start;\n lc.debug?.(\n `flushed upstream writes (${this.#upstreamWrites.length} statements) in ${elapsed} ms`,\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 lc = lc.withContext('cvrFlushID', flushCounter++);\n try {\n const stats = await this.#flush(\n lc,\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","start","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\nlet flushCounter = 0;\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 lc.debug?.(`CVR tx started after ${Date.now() - start} ms`);\n return [\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 lc.debug?.(\n `CVR tx completed after ${Date.now() - start} ms ` +\n `(${clientsRows.length} clients, ${queryRows.length} queries, ${desiresRows.length} desires)`,\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 lc: LogContext,\n tx: PostgresTransaction,\n expectedCurrentVersion: CVRVersion,\n lastConnectTime: number,\n ): Promise<void> {\n const start = Date.now();\n lc.debug?.('checking cvr version and ownership');\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 lc.debug?.(\n 'checked cvr version and ownership in ' + (Date.now() - start) + ' ms',\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 lc: LogContext,\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 const start = Date.now();\n lc.debug?.('flush tx beginning');\n const rowsFlushed = await this.#db.begin(Mode.READ_COMMITTED, async tx => {\n lc.debug?.(`flush tx begun after ${Date.now() - start} ms`);\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 lc,\n tx,\n expectedCurrentVersion,\n lastConnectTime,\n ),\n ];\n\n let i = 0;\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 const writeIndex = i++;\n const writeStart = Date.now();\n pipelined.push(\n write\n .write(tx, lastConnectTime)\n .execute()\n .then(() => {\n lc.debug?.(\n `write ${writeIndex}/${this.#writes.size} completed in ${Date.now() - writeStart} ms`,\n );\n }),\n );\n stats.statements++;\n }\n\n const rowUpdates = this.#rowCache.executeRowUpdates(\n tx,\n cvr.version,\n this.#pendingRowRecordUpdates,\n 'allow-defer',\n lc,\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 lc.debug?.(`flush tx returning after ${Date.now() - start} ms`);\n if (rowUpdates.length === 0) {\n stats.rowsDeferred = this.#pendingRowRecordUpdates.size;\n return false;\n }\n stats.rows += this.#pendingRowRecordUpdates.size;\n\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 && this.#upstreamWrites.length) {\n const start = performance.now();\n lc.debug?.('flushing upstream writes');\n await this.#upstreamDb.begin(Mode.READ_COMMITTED, async tx => {\n await Promise.all(this.#upstreamWrites.map(write => write(tx)));\n });\n const elapsed = performance.now() - start;\n lc.debug?.(\n `flushed upstream writes (${this.#upstreamWrites.length} statements) in ${elapsed} ms`,\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 lc = lc.withContext('cvrFlushID', flushCounter++);\n try {\n const stats = await this.#flush(\n lc,\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 {\n kind: ErrorKind.ClientNotFound,\n message,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\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","start","ErrorKind.ClientNotFound","ErrorOrigin.ZeroCache","ErrorKind.Internal","ErrorKind.Rehome","ErrorKind.SchemaVersionNotSupported"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-syncer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/view-syncer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"view-syncer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/view-syncer.ts"],"names":[],"mappings":"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"}
|
|
@@ -202,11 +202,14 @@ class ViewSyncerService {
|
|
|
202
202
|
if (!this.#stateChanges.active) {
|
|
203
203
|
this.#lc.debug?.("state changes are inactive");
|
|
204
204
|
clearTimeout(this.#expiredQueriesTimer);
|
|
205
|
-
throw new ProtocolErrorWithLevel(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
throw new ProtocolErrorWithLevel(
|
|
206
|
+
{
|
|
207
|
+
kind: Rehome,
|
|
208
|
+
message: "Reconnect required",
|
|
209
|
+
origin: ZeroCache
|
|
210
|
+
},
|
|
211
|
+
"info"
|
|
212
|
+
);
|
|
210
213
|
}
|
|
211
214
|
if (await this.#checkForShutdownConditionsInLock()) {
|
|
212
215
|
this.#lc.info?.(`closing clientGroupID=${this.id}`);
|
|
@@ -448,11 +451,14 @@ class ViewSyncerService {
|
|
|
448
451
|
initConnectionMessage,
|
|
449
452
|
async (lc2, clientID2, msg, cvr) => {
|
|
450
453
|
if (cvr.clientSchema === null && !msg.clientSchema) {
|
|
451
|
-
throw new ProtocolErrorWithLevel(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
454
|
+
throw new ProtocolErrorWithLevel(
|
|
455
|
+
{
|
|
456
|
+
kind: InvalidConnectionRequest,
|
|
457
|
+
message: "The initConnection message for a new client group must include client schema.",
|
|
458
|
+
origin: ZeroCache
|
|
459
|
+
},
|
|
460
|
+
"warn"
|
|
461
|
+
);
|
|
456
462
|
}
|
|
457
463
|
await this.#handleConfigUpdate(
|
|
458
464
|
lc2,
|
|
@@ -965,7 +971,11 @@ class ViewSyncerService {
|
|
|
965
971
|
this.userQueryURL
|
|
966
972
|
)
|
|
967
973
|
);
|
|
968
|
-
|
|
974
|
+
if (!Array.isArray(transformedCustomQueries) && transformedCustomQueries.kind === TransformFailed) {
|
|
975
|
+
throw new ProtocolErrorWithLevel(transformedCustomQueries, "warn");
|
|
976
|
+
} else {
|
|
977
|
+
this.#queryTransformations.add(1, { result: "success" });
|
|
978
|
+
}
|
|
969
979
|
} catch (e) {
|
|
970
980
|
this.#queryTransformations.add(1, { result: "error" });
|
|
971
981
|
throw e;
|
|
@@ -973,12 +983,6 @@ class ViewSyncerService {
|
|
|
973
983
|
const transformDuration = (performance.now() - transformStart) / 1e3;
|
|
974
984
|
this.#queryTransformationTime.record(transformDuration);
|
|
975
985
|
}
|
|
976
|
-
if (!Array.isArray(transformedCustomQueries) && transformedCustomQueries.kind === TransformFailed) {
|
|
977
|
-
throw new ProtocolErrorWithLevel(
|
|
978
|
-
transformedCustomQueries,
|
|
979
|
-
getLogLevel(transformedCustomQueries.kind)
|
|
980
|
-
);
|
|
981
|
-
}
|
|
982
986
|
const successfullyTransformed = /* @__PURE__ */ new Map();
|
|
983
987
|
erroredQueryIDs = this.#processTransformedCustomQueries(
|
|
984
988
|
lc,
|