@rocicorp/zero 0.25.10-canary.13 → 0.25.10-canary.15

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.
@@ -1,4 +1,4 @@
1
- const version = "0.25.10-canary.13";
1
+ const version = "0.25.10-canary.15";
2
2
  const packageJson = {
3
3
  version
4
4
  };
@@ -1,12 +1,8 @@
1
+ import type { LogContext } from '@rocicorp/logger';
1
2
  /**
2
3
  * Run an operation with priority, indicating that IVM should use smaller time
3
4
  * slices to allow this operation to proceed more quickly
4
5
  */
5
- export declare function runPriorityOp<T>(op: () => Promise<T>): Promise<T>;
6
- /**
7
- * If a priority op is running, returns a promise that resolves when it is
8
- * complete, otherwise returns a promise that resolves immediately.
9
- */
10
- export declare function noPriorityOpRunningPromise(): Promise<void>;
6
+ export declare function runPriorityOp<T>(lc: LogContext, description: string, op: () => Promise<T>): Promise<T>;
11
7
  export declare function isPriorityOpRunning(): boolean;
12
8
  //# sourceMappingURL=priority-op.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"priority-op.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/priority-op.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,cAgB1D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,wBAAgB,mBAAmB,YAElC"}
1
+ {"version":3,"file":"priority-op.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/server/priority-op.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAKjD;;;GAGG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,EAAE,EAAE,UAAU,EACd,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,cAmBrB;AAED,wBAAgB,mBAAmB,YAElC"}
@@ -1,34 +1,29 @@
1
- import { resolver } from "@rocicorp/resolver";
2
- import { must } from "../../../shared/src/must.js";
3
- import { assert } from "../../../shared/src/asserts.js";
4
1
  let priorityOpCounter = 0;
5
- let priorityOpResolver = void 0;
6
- async function runPriorityOp(op) {
7
- priorityOpCounter++;
8
- if (priorityOpResolver === void 0) {
9
- assert(priorityOpResolver === void 0);
10
- priorityOpResolver = resolver();
11
- }
2
+ let runningPriorityOpCounter = 0;
3
+ async function runPriorityOp(lc, description, op) {
4
+ const id = priorityOpCounter++;
5
+ runningPriorityOpCounter++;
6
+ const start = Date.now();
7
+ lc = lc.withContext("priorityOpID", id);
12
8
  try {
13
- return await op();
9
+ lc.debug?.(`running priority op ${description}`);
10
+ const result = await op();
11
+ lc.debug?.(
12
+ `finished priority op ${description} in ${Date.now() - start} ms`
13
+ );
14
+ return result;
15
+ } catch (e) {
16
+ lc.debug?.(`failed priority op ${description} in ${Date.now() - start} ms`);
17
+ throw e;
14
18
  } finally {
15
- priorityOpCounter--;
16
- if (priorityOpCounter === 0) {
17
- const priorityOpResolve = must(priorityOpResolver).resolve;
18
- priorityOpResolver = void 0;
19
- priorityOpResolve();
20
- }
19
+ runningPriorityOpCounter--;
21
20
  }
22
21
  }
23
- function noPriorityOpRunningPromise() {
24
- return priorityOpResolver?.promise ?? Promise.resolve();
25
- }
26
22
  function isPriorityOpRunning() {
27
- return priorityOpCounter > 0;
23
+ return runningPriorityOpCounter > 0;
28
24
  }
29
25
  export {
30
26
  isPriorityOpRunning,
31
- noPriorityOpRunningPromise,
32
27
  runPriorityOp
33
28
  };
34
29
  //# sourceMappingURL=priority-op.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"priority-op.js","sources":["../../../../../zero-cache/src/server/priority-op.ts"],"sourcesContent":["import {resolver, type Resolver} from '@rocicorp/resolver';\nimport {must} from '../../../shared/src/must.ts';\nimport {assert} from '../../../shared/src/asserts.ts';\n\nlet priorityOpCounter = 0;\n\nlet priorityOpResolver: Resolver<void> | undefined = undefined;\n\n/**\n * Run an operation with priority, indicating that IVM should use smaller time\n * slices to allow this operation to proceed more quickly\n */\nexport async function runPriorityOp<T>(op: () => Promise<T>) {\n priorityOpCounter++;\n if (priorityOpResolver === undefined) {\n assert(priorityOpResolver === undefined);\n priorityOpResolver = resolver();\n }\n try {\n return await op();\n } finally {\n priorityOpCounter--;\n if (priorityOpCounter === 0) {\n const priorityOpResolve = must(priorityOpResolver).resolve;\n priorityOpResolver = undefined;\n priorityOpResolve();\n }\n }\n}\n\n/**\n * If a priority op is running, returns a promise that resolves when it is\n * complete, otherwise returns a promise that resolves immediately.\n */\nexport function noPriorityOpRunningPromise(): Promise<void> {\n return priorityOpResolver?.promise ?? Promise.resolve();\n}\n\nexport function isPriorityOpRunning() {\n return priorityOpCounter > 0;\n}\n"],"names":[],"mappings":";;;AAIA,IAAI,oBAAoB;AAExB,IAAI,qBAAiD;AAMrD,eAAsB,cAAiB,IAAsB;AAC3D;AACA,MAAI,uBAAuB,QAAW;AACpC,WAAO,uBAAuB,MAAS;AACvC,yBAAqB,SAAA;AAAA,EACvB;AACA,MAAI;AACF,WAAO,MAAM,GAAA;AAAA,EACf,UAAA;AACE;AACA,QAAI,sBAAsB,GAAG;AAC3B,YAAM,oBAAoB,KAAK,kBAAkB,EAAE;AACnD,2BAAqB;AACrB,wBAAA;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,6BAA4C;AAC1D,SAAO,oBAAoB,WAAW,QAAQ,QAAA;AAChD;AAEO,SAAS,sBAAsB;AACpC,SAAO,oBAAoB;AAC7B;"}
1
+ {"version":3,"file":"priority-op.js","sources":["../../../../../zero-cache/src/server/priority-op.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n\nlet priorityOpCounter = 0;\nlet runningPriorityOpCounter = 0;\n\n/**\n * Run an operation with priority, indicating that IVM should use smaller time\n * slices to allow this operation to proceed more quickly\n */\nexport async function runPriorityOp<T>(\n lc: LogContext,\n description: string,\n op: () => Promise<T>,\n) {\n const id = priorityOpCounter++;\n runningPriorityOpCounter++;\n const start = Date.now();\n lc = lc.withContext('priorityOpID', id);\n try {\n lc.debug?.(`running priority op ${description}`);\n const result = await op();\n lc.debug?.(\n `finished priority op ${description} in ${Date.now() - start} ms`,\n );\n return result;\n } catch (e) {\n lc.debug?.(`failed priority op ${description} in ${Date.now() - start} ms`);\n throw e;\n } finally {\n runningPriorityOpCounter--;\n }\n}\n\nexport function isPriorityOpRunning() {\n return runningPriorityOpCounter > 0;\n}\n"],"names":[],"mappings":"AAEA,IAAI,oBAAoB;AACxB,IAAI,2BAA2B;AAM/B,eAAsB,cACpB,IACA,aACA,IACA;AACA,QAAM,KAAK;AACX;AACA,QAAM,QAAQ,KAAK,IAAA;AACnB,OAAK,GAAG,YAAY,gBAAgB,EAAE;AACtC,MAAI;AACF,OAAG,QAAQ,uBAAuB,WAAW,EAAE;AAC/C,UAAM,SAAS,MAAM,GAAA;AACrB,OAAG;AAAA,MACD,wBAAwB,WAAW,OAAO,KAAK,IAAA,IAAQ,KAAK;AAAA,IAAA;AAE9D,WAAO;AAAA,EACT,SAAS,GAAG;AACV,OAAG,QAAQ,sBAAsB,WAAW,OAAO,KAAK,IAAA,IAAQ,KAAK,KAAK;AAC1E,UAAM;AAAA,EACR,UAAA;AACE;AAAA,EACF;AACF;AAEO,SAAS,sBAAsB;AACpC,SAAO,2BAA2B;AACpC;"}
@@ -1 +1 @@
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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"}
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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"}
@@ -23,6 +23,7 @@ import "pg-format";
23
23
  import "../../../../shared/src/bigint-json.js";
24
24
  import { EMPTY_CVR_VERSION, versionFromString, versionString, queryRecordToQueryRow, cmpVersions } from "./schema/types.js";
25
25
  import { ttlClockFromNumber, ttlClockAsNumber } from "./ttl-clock.js";
26
+ let flushCounter = 0;
26
27
  const tracer = trace.getTracer("cvr-store", version);
27
28
  function asQuery(row) {
28
29
  const maybeVersion = (s) => s === null ? void 0 : versionFromString(s);
@@ -527,7 +528,9 @@ class CVRStore {
527
528
  reader.setDone();
528
529
  }
529
530
  }
530
- async #checkVersionAndOwnership(tx, expectedCurrentVersion, lastConnectTime) {
531
+ async #checkVersionAndOwnership(lc, tx, expectedCurrentVersion, lastConnectTime) {
532
+ const start = Date.now();
533
+ lc.debug?.("checking cvr version and ownership");
531
534
  const expected = versionString(expectedCurrentVersion);
532
535
  const result = await tx`SELECT "version", "owner", "grantedAt" FROM ${this.#cvr("instances")}
533
536
  WHERE "clientGroupID" = ${this.#id}
@@ -537,6 +540,9 @@ class CVRStore {
537
540
  owner: null,
538
541
  grantedAt: null
539
542
  };
543
+ lc.debug?.(
544
+ "checked cvr version and ownership in " + (Date.now() - start) + " ms"
545
+ );
540
546
  if (owner !== this.#taskID && (grantedAt ?? 0) > lastConnectTime) {
541
547
  throw new OwnershipError(owner, grantedAt, lastConnectTime);
542
548
  }
@@ -544,7 +550,7 @@ class CVRStore {
544
550
  throw new ConcurrentModificationException(expected, version2);
545
551
  }
546
552
  }
547
- async #flush(expectedCurrentVersion, cvr, lastConnectTime) {
553
+ async #flush(lc, expectedCurrentVersion, cvr, lastConnectTime) {
548
554
  const stats = {
549
555
  instances: 0,
550
556
  queries: 0,
@@ -578,7 +584,10 @@ class CVRStore {
578
584
  return null;
579
585
  }
580
586
  this.putInstance(cvr);
587
+ const start = Date.now();
588
+ lc.debug?.("flush tx beginning");
581
589
  const rowsFlushed = await this.#db.begin(READ_COMMITTED, async (tx) => {
590
+ lc.debug?.(`flush tx begun after ${Date.now() - start} ms`);
582
591
  const pipelined = [
583
592
  // #checkVersionAndOwnership() executes a `SELECT ... FOR UPDATE`
584
593
  // query to acquire a row-level lock so that version-updating
@@ -588,29 +597,41 @@ class CVRStore {
588
597
  // to this lock and can thus commit / be-committed independently of
589
598
  // cvr.instances.
590
599
  this.#checkVersionAndOwnership(
600
+ lc,
591
601
  tx,
592
602
  expectedCurrentVersion,
593
603
  lastConnectTime
594
604
  )
595
605
  ];
606
+ let i = 0;
596
607
  for (const write of this.#writes) {
597
608
  stats.instances += write.stats.instances ?? 0;
598
609
  stats.queries += write.stats.queries ?? 0;
599
610
  stats.desires += write.stats.desires ?? 0;
600
611
  stats.clients += write.stats.clients ?? 0;
601
612
  stats.rows += write.stats.rows ?? 0;
602
- pipelined.push(write.write(tx, lastConnectTime).execute());
613
+ const writeIndex = i++;
614
+ const writeStart = Date.now();
615
+ pipelined.push(
616
+ write.write(tx, lastConnectTime).execute().then(() => {
617
+ lc.debug?.(
618
+ `write ${writeIndex}/${this.#writes.size} completed in ${Date.now() - writeStart} ms`
619
+ );
620
+ })
621
+ );
603
622
  stats.statements++;
604
623
  }
605
624
  const rowUpdates = this.#rowCache.executeRowUpdates(
606
625
  tx,
607
626
  cvr.version,
608
627
  this.#pendingRowRecordUpdates,
609
- "allow-defer"
628
+ "allow-defer",
629
+ lc
610
630
  );
611
631
  pipelined.push(...rowUpdates);
612
632
  stats.statements += rowUpdates.length;
613
633
  await Promise.all(pipelined);
634
+ lc.debug?.(`flush tx returning after ${Date.now() - start} ms`);
614
635
  if (rowUpdates.length === 0) {
615
636
  stats.rowsDeferred = this.#pendingRowRecordUpdates.size;
616
637
  return false;
@@ -625,9 +646,15 @@ class CVRStore {
625
646
  );
626
647
  recordRowsSynced(this.#rowCount);
627
648
  if (this.#upstreamDb) {
649
+ const start2 = performance.now();
650
+ lc.debug?.("flushing upstream writes");
628
651
  await this.#upstreamDb.begin(READ_COMMITTED, async (tx) => {
629
652
  await Promise.all(this.#upstreamWrites.map((write) => write(tx)));
630
653
  });
654
+ const elapsed = performance.now() - start2;
655
+ lc.debug?.(
656
+ `flushed upstream writes (${this.#upstreamWrites.length} statements) in ${elapsed} ms`
657
+ );
631
658
  }
632
659
  return stats;
633
660
  }
@@ -636,8 +663,10 @@ class CVRStore {
636
663
  }
637
664
  async flush(lc, expectedCurrentVersion, cvr, lastConnectTime) {
638
665
  const start = performance.now();
666
+ lc = lc.withContext("cvrFlushID", flushCounter++);
639
667
  try {
640
668
  const stats = await this.#flush(
669
+ lc,
641
670
  expectedCurrentVersion,
642
671
  cvr,
643
672
  lastConnectTime
@@ -1 +1 @@
1
- {"version":3,"file":"cvr-store.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"sourcesContent":["import {trace} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {MaybeRow, PendingQuery} from 'postgres';\nimport {startAsyncSpan} from '../../../../otel/src/span.ts';\nimport {version} from '../../../../otel/src/version.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {CustomKeyMap} from '../../../../shared/src/custom-key-map.ts';\nimport {CustomKeySet} from '../../../../shared/src/custom-key-set.ts';\nimport {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {sleep} from '../../../../shared/src/sleep.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../zero-protocol/src/ast.ts';\nimport {clientSchemaSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {InspectQueryRow} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {clampTTL, DEFAULT_TTL_MS} from '../../../../zql/src/query/ttl.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {TransactionPool} from '../../db/transaction-pool.ts';\nimport {recordRowsSynced} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {rowIDString} from '../../types/row-key.ts';\nimport {cvrSchema, type ShardID, upstreamSchema} from '../../types/shards.ts';\nimport type {Patch, PatchToVersion} from './client-handler.ts';\nimport type {CVR, CVRSnapshot} from './cvr.ts';\nimport {RowRecordCache} from './row-record-cache.ts';\nimport {\n type ClientsRow,\n type DesiresRow,\n type InstancesRow,\n type QueriesRow,\n type RowsRow,\n} from './schema/cvr.ts';\nimport {\n type ClientQueryRecord,\n type ClientRecord,\n cmpVersions,\n type CustomQueryRecord,\n type CVRVersion,\n EMPTY_CVR_VERSION,\n type InternalQueryRecord,\n type NullableCVRVersion,\n type QueryPatch,\n type QueryRecord,\n queryRecordToQueryRow,\n type RowID,\n type RowRecord,\n versionFromString,\n versionString,\n} from './schema/types.ts';\nimport {\n type TTLClock,\n ttlClockAsNumber,\n ttlClockFromNumber,\n} from './ttl-clock.ts';\n\nexport type CVRFlushStats = {\n instances: number;\n queries: number;\n desires: number;\n clients: number;\n rows: number;\n rowsDeferred: number;\n statements: number;\n};\n\nconst tracer = trace.getTracer('cvr-store', version);\n\nfunction asQuery(row: QueriesRow): QueryRecord {\n const maybeVersion = (s: string | null) =>\n s === null ? undefined : versionFromString(s);\n\n if (row.clientAST === null) {\n // custom query\n assert(\n row.queryName !== null && row.queryArgs !== null,\n 'queryName and queryArgs must be set for custom queries',\n );\n return {\n type: 'custom',\n id: row.queryHash,\n name: row.queryName,\n args: row.queryArgs,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies CustomQueryRecord;\n }\n\n const ast = astSchema.parse(row.clientAST);\n return row.internal\n ? ({\n type: 'internal',\n id: row.queryHash,\n ast,\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies InternalQueryRecord)\n : ({\n type: 'client',\n id: row.queryHash,\n ast,\n patchVersion: maybeVersion(row.patchVersion),\n clientState: {},\n transformationHash: row.transformationHash ?? undefined,\n transformationVersion: maybeVersion(row.transformationVersion),\n } satisfies ClientQueryRecord);\n}\n\n// The time to wait between load attempts.\nconst LOAD_ATTEMPT_INTERVAL_MS = 500;\n// The maximum number of load() attempts if the rowsVersion is behind.\n// This currently results in a maximum catchup time of ~5 seconds, after\n// which we give up and consider the CVR invalid.\n//\n// TODO: Make this configurable with something like --max-catchup-wait-ms,\n// as it is technically application specific.\nconst MAX_LOAD_ATTEMPTS = 10;\n\nexport class CVRStore {\n readonly #schema: string;\n readonly #taskID: string;\n readonly #id: string;\n readonly #failService: (e: unknown) => void;\n readonly #db: PostgresDB;\n readonly #upstreamDb: PostgresDB | undefined;\n readonly #writes: Set<{\n stats: Partial<CVRFlushStats>;\n write: (\n tx: PostgresTransaction,\n lastConnectTime: number,\n ) => PendingQuery<MaybeRow[]>;\n }> = new Set();\n readonly #upstreamWrites: ((\n tx: PostgresTransaction,\n ) => PendingQuery<MaybeRow[]>)[] = [];\n readonly #pendingRowRecordUpdates = new CustomKeyMap<RowID, RowRecord | null>(\n rowIDString,\n );\n readonly #forceUpdates = new CustomKeySet<RowID>(rowIDString);\n readonly #rowCache: RowRecordCache;\n readonly #loadAttemptIntervalMs: number;\n readonly #maxLoadAttempts: number;\n readonly #upstreamSchemaName: string;\n #rowCount: number = 0;\n\n constructor(\n lc: LogContext,\n cvrDb: PostgresDB,\n // Optionally undefined to deal with custom upstreams.\n // This is temporary until we have a more principled protocol to deal with\n // custom upstreams and clearing their custom mutator responses.\n // An implementor could simply clear them after N minutes for the time being.\n upstreamDb: PostgresDB | undefined,\n shard: ShardID,\n taskID: string,\n cvrID: string,\n failService: (e: unknown) => void,\n loadAttemptIntervalMs = LOAD_ATTEMPT_INTERVAL_MS,\n maxLoadAttempts = MAX_LOAD_ATTEMPTS,\n deferredRowFlushThreshold = 100, // somewhat arbitrary\n setTimeoutFn = setTimeout,\n ) {\n this.#failService = failService;\n this.#db = cvrDb;\n this.#upstreamDb = upstreamDb;\n this.#schema = cvrSchema(shard);\n this.#taskID = taskID;\n this.#id = cvrID;\n this.#rowCache = new RowRecordCache(\n lc,\n cvrDb,\n shard,\n cvrID,\n failService,\n deferredRowFlushThreshold,\n setTimeoutFn,\n );\n this.#loadAttemptIntervalMs = loadAttemptIntervalMs;\n this.#maxLoadAttempts = maxLoadAttempts;\n this.#upstreamSchemaName = upstreamSchema(shard);\n }\n\n #cvr(table: string) {\n return this.#db(`${this.#schema}.${table}`);\n }\n\n load(lc: LogContext, lastConnectTime: number): Promise<CVR> {\n return startAsyncSpan(tracer, 'cvr.load', async () => {\n let err: RowsVersionBehindError | undefined;\n for (let i = 0; i < this.#maxLoadAttempts; i++) {\n if (i > 0) {\n await sleep(this.#loadAttemptIntervalMs);\n }\n const result = await this.#load(lc, lastConnectTime);\n if (result instanceof RowsVersionBehindError) {\n lc.info?.(`attempt ${i + 1}: ${String(result)}`);\n err = result;\n continue;\n }\n return result;\n }\n assert(err);\n throw new ClientNotFoundError(\n `max attempts exceeded waiting for CVR@${err.cvrVersion} to catch up from ${err.rowsVersion}`,\n );\n });\n }\n\n async #load(\n lc: LogContext,\n lastConnectTime: number,\n ): Promise<CVR | RowsVersionBehindError> {\n const start = Date.now();\n\n const id = this.#id;\n const cvr: CVR = {\n id,\n version: EMPTY_CVR_VERSION,\n lastActive: 0,\n ttlClock: ttlClockFromNumber(0), // TTL clock starts at 0, not Date.now()\n replicaVersion: null,\n clients: {},\n queries: {},\n clientSchema: null,\n profileID: null,\n };\n\n const [instance, clientsRows, queryRows, desiresRows] =\n await this.#db.begin(Mode.READONLY, tx => {\n 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 tx: PostgresTransaction,\n expectedCurrentVersion: CVRVersion,\n lastConnectTime: number,\n ): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<\n Pick<InstancesRow, 'version' | 'owner' | 'grantedAt'>[]\n >`SELECT \"version\", \"owner\", \"grantedAt\" FROM ${this.#cvr('instances')}\n WHERE \"clientGroupID\" = ${this.#id}\n FOR UPDATE`.execute(); // Note: execute() immediately to send the query before others.\n const {version, owner, grantedAt} =\n result.length > 0\n ? result[0]\n : {\n version: EMPTY_CVR_VERSION.stateVersion,\n owner: null,\n grantedAt: null,\n };\n if (owner !== this.#taskID && (grantedAt ?? 0) > lastConnectTime) {\n throw new OwnershipError(owner, grantedAt, lastConnectTime);\n }\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n }\n\n async #flush(\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const stats: CVRFlushStats = {\n instances: 0,\n queries: 0,\n desires: 0,\n clients: 0,\n rows: 0,\n rowsDeferred: 0,\n statements: 0,\n };\n if (this.#pendingRowRecordUpdates.size) {\n const existingRowRecords = await this.getRowRecords();\n this.#rowCount = existingRowRecords.size;\n for (const [id, row] of this.#pendingRowRecordUpdates.entries()) {\n if (this.#forceUpdates.has(id)) {\n continue;\n }\n const existing = existingRowRecords.get(id);\n if (\n // Don't delete or add an unreferenced row if it's not in the CVR.\n (existing === undefined && !row?.refCounts) ||\n // Don't write a row record that exactly matches what's in the CVR.\n deepEqual(\n (row ?? undefined) as ReadonlyJSONValue | undefined,\n existing as ReadonlyJSONValue | undefined,\n )\n ) {\n this.#pendingRowRecordUpdates.delete(id);\n }\n }\n }\n if (this.#pendingRowRecordUpdates.size === 0 && this.#writes.size === 0) {\n return null;\n }\n // Note: The CVR instance itself is only updated if there are material\n // changes (i.e. changes to the CVR contents) to flush.\n this.putInstance(cvr);\n\n const rowsFlushed = await this.#db.begin(Mode.READ_COMMITTED, async tx => {\n const pipelined: Promise<unknown>[] = [\n // #checkVersionAndOwnership() executes a `SELECT ... FOR UPDATE`\n // query to acquire a row-level lock so that version-updating\n // transactions are effectively serialized per cvr.instance.\n //\n // Note that `rowsVersion` updates, on the other hand, are not subject\n // to this lock and can thus commit / be-committed independently of\n // cvr.instances.\n this.#checkVersionAndOwnership(\n tx,\n expectedCurrentVersion,\n lastConnectTime,\n ),\n ];\n\n for (const write of this.#writes) {\n stats.instances += write.stats.instances ?? 0;\n stats.queries += write.stats.queries ?? 0;\n stats.desires += write.stats.desires ?? 0;\n stats.clients += write.stats.clients ?? 0;\n stats.rows += write.stats.rows ?? 0;\n\n pipelined.push(write.write(tx, lastConnectTime).execute());\n stats.statements++;\n }\n\n const rowUpdates = this.#rowCache.executeRowUpdates(\n tx,\n cvr.version,\n this.#pendingRowRecordUpdates,\n 'allow-defer',\n );\n pipelined.push(...rowUpdates);\n stats.statements += rowUpdates.length;\n\n // Make sure Errors thrown by pipelined statements\n // are propagated up the stack.\n await Promise.all(pipelined);\n\n if (rowUpdates.length === 0) {\n stats.rowsDeferred = this.#pendingRowRecordUpdates.size;\n return false;\n }\n stats.rows += this.#pendingRowRecordUpdates.size;\n return true;\n });\n\n this.#rowCount = await this.#rowCache.apply(\n this.#pendingRowRecordUpdates,\n cvr.version,\n rowsFlushed,\n );\n recordRowsSynced(this.#rowCount);\n\n if (this.#upstreamDb) {\n await this.#upstreamDb.begin(Mode.READ_COMMITTED, async tx => {\n await Promise.all(this.#upstreamWrites.map(write => write(tx)));\n });\n }\n\n return stats;\n }\n\n get rowCount(): number {\n return this.#rowCount;\n }\n\n async flush(\n lc: LogContext,\n expectedCurrentVersion: CVRVersion,\n cvr: CVRSnapshot,\n lastConnectTime: number,\n ): Promise<CVRFlushStats | null> {\n const start = performance.now();\n try {\n const stats = await this.#flush(\n expectedCurrentVersion,\n cvr,\n lastConnectTime,\n );\n if (stats) {\n const elapsed = performance.now() - start;\n lc.debug?.(\n `flushed cvr@${versionString(cvr.version)} ` +\n `${JSON.stringify(stats)} in (${elapsed} ms)`,\n );\n this.#rowCache.recordSyncFlushStats(stats, elapsed);\n }\n return stats;\n } catch (e) {\n // Clear cached state if an error (e.g. ConcurrentModificationException) is encountered.\n this.#rowCache.clear();\n throw e;\n } finally {\n this.#writes.clear();\n this.#upstreamWrites.length = 0;\n this.#pendingRowRecordUpdates.clear();\n this.#forceUpdates.clear();\n }\n }\n\n hasPendingUpdates(): boolean {\n return this.#rowCache.hasPendingUpdates();\n }\n\n /** Resolves when all pending updates are flushed. */\n flushed(lc: LogContext): Promise<void> {\n return this.#rowCache.flushed(lc);\n }\n\n async inspectQueries(\n lc: LogContext,\n ttlClock: TTLClock,\n clientID?: string,\n ): Promise<InspectQueryRow[]> {\n const db = this.#db;\n const clientGroupID = this.#id;\n\n const reader = new TransactionPool(lc, Mode.READONLY).run(db);\n try {\n return await reader.processReadTask(\n tx => tx<InspectQueryRow[]>`\n SELECT DISTINCT ON (d.\"clientID\", d.\"queryHash\")\n d.\"clientID\",\n d.\"queryHash\" AS \"queryID\",\n COALESCE(d.\"ttlMs\", ${DEFAULT_TTL_MS}) AS \"ttl\",\n d.\"inactivatedAtMs\" AS \"inactivatedAt\",\n (SELECT COUNT(*)::INT FROM ${this.#cvr('rows')} r \n WHERE r.\"clientGroupID\" = d.\"clientGroupID\" \n AND r.\"refCounts\" ? d.\"queryHash\") AS \"rowCount\",\n q.\"clientAST\" AS \"ast\",\n (q.\"patchVersion\" IS NOT NULL) AS \"got\",\n COALESCE(d.\"deleted\", FALSE) AS \"deleted\",\n q.\"queryName\" AS \"name\",\n q.\"queryArgs\" AS \"args\"\n FROM ${this.#cvr('desires')} d\n LEFT JOIN ${this.#cvr('queries')} q\n ON q.\"clientGroupID\" = d.\"clientGroupID\"\n AND q.\"queryHash\" = d.\"queryHash\"\n WHERE d.\"clientGroupID\" = ${clientGroupID}\n ${clientID ? tx`AND d.\"clientID\" = ${clientID}` : tx``}\n AND NOT (\n d.\"inactivatedAtMs\" IS NOT NULL \n AND d.\"ttlMs\" IS NOT NULL \n AND (d.\"inactivatedAtMs\" + d.\"ttlMs\") <= ${ttlClockAsNumber(ttlClock)}\n )\n ORDER BY d.\"clientID\", d.\"queryHash\"`,\n );\n } finally {\n reader.setDone();\n }\n }\n}\n\n/**\n * This is similar to {@link CVRStore.#checkVersionAndOwnership} except\n * that it only checks the version and is suitable for snapshot reads\n * (i.e. by doing a plain `SELECT` rather than a `SELECT ... FOR UPDATE`).\n */\nexport async function checkVersion(\n tx: PostgresTransaction,\n schema: string,\n clientGroupID: string,\n expectedCurrentVersion: CVRVersion,\n): Promise<void> {\n const expected = versionString(expectedCurrentVersion);\n const result = await tx<Pick<InstancesRow, 'version'>[]>`\n SELECT version FROM ${tx(schema)}.instances \n WHERE \"clientGroupID\" = ${clientGroupID}`;\n const {version} =\n result.length > 0 ? result[0] : {version: EMPTY_CVR_VERSION.stateVersion};\n if (version !== expected) {\n throw new ConcurrentModificationException(expected, version);\n }\n}\n\nexport class ClientNotFoundError extends ProtocolErrorWithLevel {\n constructor(message: string) {\n super({\n kind: ErrorKind.ClientNotFound,\n message,\n origin: ErrorOrigin.ZeroCache,\n });\n }\n}\n\nexport class ConcurrentModificationException extends ProtocolErrorWithLevel {\n readonly name = 'ConcurrentModificationException';\n\n constructor(expectedVersion: string, actualVersion: string) {\n super(\n {\n kind: ErrorKind.Internal,\n message: `CVR has been concurrently modified. Expected ${expectedVersion}, got ${actualVersion}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n );\n }\n}\n\nexport class OwnershipError extends ProtocolErrorWithLevel {\n readonly name = 'OwnershipError';\n\n constructor(\n owner: string | null,\n grantedAt: number | null,\n lastConnectTime: number,\n ) {\n super(\n {\n kind: ErrorKind.Rehome,\n message:\n `CVR ownership was transferred to ${owner} at ` +\n `${new Date(grantedAt ?? 0).toISOString()} ` +\n `(last connect time: ${new Date(lastConnectTime).toISOString()})`,\n maxBackoffMs: 0,\n origin: ErrorOrigin.ZeroCache,\n },\n 'info',\n );\n }\n}\n\nexport class InvalidClientSchemaError extends ProtocolErrorWithLevel {\n readonly name = 'InvalidClientSchemaError';\n\n constructor(cause: unknown) {\n super(\n {\n kind: ErrorKind.SchemaVersionNotSupported,\n message: `Could not parse clientSchema stored in CVR: ${String(cause)}`,\n origin: ErrorOrigin.ZeroCache,\n },\n 'warn',\n {cause},\n );\n }\n}\n\nexport class RowsVersionBehindError extends Error {\n readonly name = 'RowsVersionBehindError';\n readonly cvrVersion: string;\n readonly rowsVersion: string | null;\n\n constructor(cvrVersion: string, rowsVersion: string | null) {\n super(`rowsVersion (${rowsVersion}) is behind CVR ${cvrVersion}`);\n this.cvrVersion = cvrVersion;\n this.rowsVersion = rowsVersion;\n }\n}\n"],"names":["Mode.READONLY","version","v.parse","v","Mode.READ_COMMITTED","ErrorKind.ClientNotFound","ErrorOrigin.ZeroCache","ErrorKind.Internal","ErrorKind.Rehome","ErrorKind.SchemaVersionNotSupported"],"mappings":"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"}
1
+ {"version":3,"file":"cvr-store.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"sourcesContent":["import {trace} from '@opentelemetry/api';\nimport type {LogContext} from '@rocicorp/logger';\nimport type {MaybeRow, PendingQuery} from 'postgres';\nimport {startAsyncSpan} from '../../../../otel/src/span.ts';\nimport {version} from '../../../../otel/src/version.ts';\nimport {assert} from '../../../../shared/src/asserts.ts';\nimport {CustomKeyMap} from '../../../../shared/src/custom-key-map.ts';\nimport {CustomKeySet} from '../../../../shared/src/custom-key-set.ts';\nimport {\n deepEqual,\n type ReadonlyJSONValue,\n} from '../../../../shared/src/json.ts';\nimport {sleep} from '../../../../shared/src/sleep.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport {astSchema} from '../../../../zero-protocol/src/ast.ts';\nimport {clientSchemaSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport {ErrorKind} from '../../../../zero-protocol/src/error-kind.ts';\nimport {ErrorOrigin} from '../../../../zero-protocol/src/error-origin.ts';\nimport type {InspectQueryRow} from '../../../../zero-protocol/src/inspect-down.ts';\nimport {clampTTL, DEFAULT_TTL_MS} from '../../../../zql/src/query/ttl.ts';\nimport * as Mode from '../../db/mode-enum.ts';\nimport {TransactionPool} from '../../db/transaction-pool.ts';\nimport {recordRowsSynced} from '../../server/anonymous-otel-start.ts';\nimport {ProtocolErrorWithLevel} from '../../types/error-with-level.ts';\nimport type {PostgresDB, PostgresTransaction} from '../../types/pg.ts';\nimport {rowIDString} from '../../types/row-key.ts';\nimport {cvrSchema, type ShardID, upstreamSchema} from '../../types/shards.ts';\nimport type {Patch, PatchToVersion} from './client-handler.ts';\nimport type {CVR, CVRSnapshot} from './cvr.ts';\nimport {RowRecordCache} from './row-record-cache.ts';\nimport {\n type ClientsRow,\n type DesiresRow,\n type InstancesRow,\n type QueriesRow,\n type RowsRow,\n} from './schema/cvr.ts';\nimport {\n type ClientQueryRecord,\n type ClientRecord,\n cmpVersions,\n type CustomQueryRecord,\n type CVRVersion,\n EMPTY_CVR_VERSION,\n type InternalQueryRecord,\n type NullableCVRVersion,\n type QueryPatch,\n type QueryRecord,\n queryRecordToQueryRow,\n type RowID,\n type RowRecord,\n versionFromString,\n versionString,\n} from './schema/types.ts';\nimport {\n type TTLClock,\n ttlClockAsNumber,\n ttlClockFromNumber,\n} from './ttl-clock.ts';\n\nexport type CVRFlushStats = {\n instances: number;\n queries: number;\n desires: number;\n clients: number;\n rows: number;\n rowsDeferred: number;\n statements: number;\n};\n\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) {\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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"}
@@ -85,6 +85,6 @@ export declare class RowRecordCache {
85
85
  flushed(lc: LogContext): Promise<void>;
86
86
  clear(): void;
87
87
  catchupRowPatches(lc: LogContext, afterVersion: NullableCVRVersion, upToCVR: CVRSnapshot, current: CVRVersion, excludeQueryHashes?: string[]): AsyncGenerator<RowsRow[], void, undefined>;
88
- executeRowUpdates(tx: PostgresTransaction, version: CVRVersion, rowUpdates: Map<RowID, RowRecord | null>, mode: 'allow-defer' | 'force'): PendingQuery<Row[]>[];
88
+ executeRowUpdates(tx: PostgresTransaction, version: CVRVersion, rowUpdates: Map<RowID, RowRecord | null>, mode: 'allow-defer' | 'force', lc?: LogContext<unknown[], unknown[], unknown[], unknown[]>): PendingQuery<Row[]>[];
89
89
  }
90
90
  //# sourceMappingURL=row-record-cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"row-record-cache.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/row-record-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,YAAY,EAAE,GAAG,EAAC,MAAM,UAAU,CAAC;AAUhD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAe,KAAK,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAC1C,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,KAAK,EACV,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,cAAc;;gBAgCvB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EACjC,yBAAyB,SAAM,EAC/B,YAAY,oBAAa;IAW3B,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM;IAgD5D,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAIvD;;;;;;;;;;;;;;OAcG;IACG,KAAK,CACT,UAAU,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,EACxC,WAAW,EAAE,UAAU,EACvB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC;IAmElB,iBAAiB;IAIjB;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtC,KAAK;IAOE,iBAAiB,CACtB,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;IAmD7C,iBAAiB,CACf,EAAE,EAAE,mBAAmB,EACvB,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,EACxC,IAAI,EAAE,aAAa,GAAG,OAAO,GAC5B,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE;CAiEzB"}
1
+ {"version":3,"file":"row-record-cache.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/row-record-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,YAAY,EAAE,GAAG,EAAC,MAAM,UAAU,CAAC;AAUhD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,mBAAmB,EACzB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAe,KAAK,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,UAAU,CAAC;AAC1C,OAAO,EAEL,KAAK,OAAO,EAEb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,KAAK,EACV,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAI3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,cAAc;;gBAgCvB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EACjC,yBAAyB,SAAM,EAC/B,YAAY,oBAAa;IAW3B,oBAAoB,CAAC,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM;IAgD5D,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IAIvD;;;;;;;;;;;;;;OAcG;IACG,KAAK,CACT,UAAU,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,EACxC,WAAW,EAAE,UAAU,EACvB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC;IAmElB,iBAAiB;IAIjB;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtC,KAAK;IAOE,iBAAiB,CACtB,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;IAmD7C,iBAAiB,CACf,EAAE,EAAE,mBAAmB,EACvB,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC,EACxC,IAAI,EAAE,aAAa,GAAG,OAAO,EAC7B,EAAE,yDAAW,GACZ,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE;CAiEzB"}
@@ -213,7 +213,7 @@ class RowRecordCache {
213
213
  `finished row catchup (flush: ${flushMs} ms, total: ${totalMs} ms)`
214
214
  );
215
215
  }
216
- executeRowUpdates(tx, version, rowUpdates, mode) {
216
+ executeRowUpdates(tx, version, rowUpdates, mode, lc = this.#lc) {
217
217
  if (mode === "allow-defer" && // defer if pending rows are being flushed
218
218
  (this.#flushing !== null || // or if the new batch is above the limit.
219
219
  rowUpdates.size > this.#deferredRowFlushThreshold)) {
@@ -265,7 +265,7 @@ class RowRecordCache {
265
265
  "refCounts" = excluded."refCounts"
266
266
  `.execute()
267
267
  );
268
- this.#lc.debug?.(
268
+ lc.debug?.(
269
269
  `flushing ${rowUpdates.size} rows (${rowRecordRows.length} inserts, ${rowUpdates.size - rowRecordRows.length} deletes)`
270
270
  );
271
271
  }