@rocicorp/zero 1.4.0-canary.0 → 1.4.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/analyze-query/src/analyze-cli.d.ts +1 -1
- package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
- package/out/analyze-query/src/analyze-cli.js +13 -3
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/analyze-query/src/bin-analyze.js +1 -1
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/analyze-query/src/bin-transform.js +1 -1
- package/out/analyze-query/src/bin-transform.js.map +1 -1
- package/out/replicache/src/btree/node.d.ts +1 -1
- package/out/replicache/src/btree/node.d.ts.map +1 -1
- package/out/replicache/src/btree/node.js +34 -21
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/btree/write.js +1 -2
- package/out/replicache/src/btree/write.js.map +1 -1
- package/out/shared/src/btree-set.d.ts +6 -0
- package/out/shared/src/btree-set.d.ts.map +1 -1
- package/out/shared/src/btree-set.js +34 -0
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/bindings.js +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +18 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +35 -3
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/scripts/decommission.d.ts.map +1 -1
- package/out/zero-cache/src/scripts/decommission.js +3 -3
- package/out/zero-cache/src/scripts/decommission.js.map +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +2 -5
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +6 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
- package/out/zero-cache/src/server/reaper.js +1 -4
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js +35 -0
- package/out/zero-cache/src/server/shadow-syncer.js.map +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +2 -8
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.d.ts +1 -0
- package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js +2 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +8 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +31 -18
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +44 -46
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +6 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +62 -22
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +5 -6
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js +49 -0
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -0
- package/out/zero-cache/src/services/statz.js +3 -3
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +1 -0
- 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 +34 -11
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +16 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +19 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -0
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +46 -3
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts +17 -0
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/row-set-signature.js +29 -0
- package/out/zero-cache/src/services/view-syncer/row-set-signature.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +1 -0
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js +1 -0
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.js +5 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +105 -0
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +8 -4
- package/out/zero-cache/src/services/view-syncer/schema/types.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 +2 -2
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/pg.d.ts +1 -1
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +8 -2
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/timeout.d.ts +11 -0
- package/out/zero-cache/src/types/timeout.d.ts.map +1 -0
- package/out/zero-cache/src/types/timeout.js +26 -0
- package/out/zero-cache/src/types/timeout.js.map +1 -0
- package/out/zero-cache/src/workers/connection.js +5 -5
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-client/src/client/bindings.js +1 -1
- package/out/zero-client/src/client/log-options.d.ts +1 -0
- package/out/zero-client/src/client/log-options.d.ts.map +1 -1
- package/out/zero-client/src/client/log-options.js +3 -2
- package/out/zero-client/src/client/log-options.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +13 -1
- package/out/zero-client/src/client/options.d.ts.map +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.map +1 -1
- package/out/zero-client/src/client/zero.js +2 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-react/src/bindings.js +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-solid/src/bindings.js +1 -1
- package/out/zero-solid/src/solid-view.js +1 -1
- package/out/zql/src/ivm/array-view.js +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +4 -4
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +1 -1
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +2 -4
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/skip-yields.d.ts +4 -0
- package/out/zql/src/ivm/skip-yields.d.ts.map +1 -0
- package/out/zql/src/ivm/skip-yields.js +33 -0
- package/out/zql/src/ivm/skip-yields.js.map +1 -0
- package/out/zql/src/ivm/view-apply-change.js +1 -1
- package/out/zql/src/query/query-internals.d.ts.map +1 -1
- package/out/zql/src/query/query-internals.js +1 -1
- package/out/zql/src/query/query-internals.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
|
|
2
|
+
import { RunningState } from "../running-state.js";
|
|
3
|
+
import { shadowInitialSync } from "../change-source/pg/initial-sync.js";
|
|
4
|
+
//#region ../zero-cache/src/services/shadow-sync/shadow-sync-service.ts
|
|
5
|
+
var ShadowSyncService = class {
|
|
6
|
+
id = "shadow-syncer";
|
|
7
|
+
#lc;
|
|
8
|
+
#shard;
|
|
9
|
+
#upstreamURI;
|
|
10
|
+
#context;
|
|
11
|
+
#options;
|
|
12
|
+
#state = new RunningState("shadow-syncer");
|
|
13
|
+
constructor(lc, shard, upstreamURI, context, options) {
|
|
14
|
+
this.#lc = lc;
|
|
15
|
+
this.#shard = shard;
|
|
16
|
+
this.#upstreamURI = upstreamURI;
|
|
17
|
+
this.#context = context;
|
|
18
|
+
this.#options = options;
|
|
19
|
+
}
|
|
20
|
+
async run() {
|
|
21
|
+
const { intervalMs, sampleRate, maxRowsPerTable, textCopy } = this.#options;
|
|
22
|
+
const firstRunDelay = intervalMs + Math.floor(Math.random() * intervalMs);
|
|
23
|
+
this.#lc.info?.(`shadow-syncer started; first run in ${firstRunDelay} ms, then every ${intervalMs} ms`);
|
|
24
|
+
await this.#state.sleep(firstRunDelay);
|
|
25
|
+
while (this.#state.shouldRun()) {
|
|
26
|
+
const start = performance.now();
|
|
27
|
+
try {
|
|
28
|
+
await shadowInitialSync(this.#lc, this.#shard, this.#upstreamURI, {
|
|
29
|
+
sampleRate,
|
|
30
|
+
maxRowsPerTable
|
|
31
|
+
}, this.#context, textCopy !== void 0 ? { textCopy } : void 0);
|
|
32
|
+
const elapsed = performance.now() - start;
|
|
33
|
+
this.#lc.info?.(`shadow initial-sync completed (${elapsed.toFixed(0)} ms)`);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
const elapsed = performance.now() - start;
|
|
36
|
+
this.#lc.error?.(`shadow initial-sync failed after ${elapsed.toFixed(0)} ms`, e);
|
|
37
|
+
}
|
|
38
|
+
await this.#state.sleep(intervalMs);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
stop() {
|
|
42
|
+
this.#state.stop(this.#lc);
|
|
43
|
+
return promiseVoid;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { ShadowSyncService };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=shadow-sync-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow-sync-service.js","names":["#lc","#shard","#upstreamURI","#context","#options","#state"],"sources":["../../../../../../zero-cache/src/services/shadow-sync/shadow-sync-service.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport type {ShardConfig} from '../../types/shards.ts';\nimport type {ServerContext} from '../change-source/pg/initial-sync.ts';\nimport {shadowInitialSync} from '../change-source/pg/initial-sync.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {Service} from '../service.ts';\n\nexport type ShadowSyncOptions = {\n intervalMs: number;\n sampleRate: number;\n maxRowsPerTable: number;\n textCopy?: boolean | undefined;\n};\n\nexport class ShadowSyncService implements Service {\n readonly id = 'shadow-syncer';\n\n readonly #lc: LogContext;\n readonly #shard: ShardConfig;\n readonly #upstreamURI: string;\n readonly #context: ServerContext;\n readonly #options: ShadowSyncOptions;\n readonly #state = new RunningState('shadow-syncer');\n\n constructor(\n lc: LogContext,\n shard: ShardConfig,\n upstreamURI: string,\n context: ServerContext,\n options: ShadowSyncOptions,\n ) {\n this.#lc = lc;\n this.#shard = shard;\n this.#upstreamURI = upstreamURI;\n this.#context = context;\n this.#options = options;\n }\n\n async run() {\n const {intervalMs, sampleRate, maxRowsPerTable, textCopy} = this.#options;\n\n // Why: wait at least one full interval before the first run so shadow\n // sync never fires immediately on task startup, and add a random\n // fraction of the interval on top so a fleet-wide restart does not\n // cause every task to canary simultaneously.\n const firstRunDelay = intervalMs + Math.floor(Math.random() * intervalMs);\n this.#lc.info?.(\n `shadow-syncer started; first run in ${firstRunDelay} ms, then every ${intervalMs} ms`,\n );\n await this.#state.sleep(firstRunDelay);\n\n while (this.#state.shouldRun()) {\n const start = performance.now();\n try {\n await shadowInitialSync(\n this.#lc,\n this.#shard,\n this.#upstreamURI,\n {sampleRate, maxRowsPerTable},\n this.#context,\n textCopy !== undefined ? {textCopy} : undefined,\n );\n const elapsed = performance.now() - start;\n this.#lc.info?.(\n `shadow initial-sync completed (${elapsed.toFixed(0)} ms)`,\n );\n } catch (e) {\n const elapsed = performance.now() - start;\n this.#lc.error?.(\n `shadow initial-sync failed after ${elapsed.toFixed(0)} ms`,\n e,\n );\n }\n await this.#state.sleep(intervalMs);\n }\n }\n\n stop(): Promise<void> {\n this.#state.stop(this.#lc);\n return promiseVoid;\n }\n}\n"],"mappings":";;;;AAeA,IAAa,oBAAb,MAAkD;CAChD,KAAc;CAEd;CACA;CACA;CACA;CACA;CACA,SAAkB,IAAI,aAAa,gBAAgB;CAEnD,YACE,IACA,OACA,aACA,SACA,SACA;AACA,QAAA,KAAW;AACX,QAAA,QAAc;AACd,QAAA,cAAoB;AACpB,QAAA,UAAgB;AAChB,QAAA,UAAgB;;CAGlB,MAAM,MAAM;EACV,MAAM,EAAC,YAAY,YAAY,iBAAiB,aAAY,MAAA;EAM5D,MAAM,gBAAgB,aAAa,KAAK,MAAM,KAAK,QAAQ,GAAG,WAAW;AACzE,QAAA,GAAS,OACP,uCAAuC,cAAc,kBAAkB,WAAW,KACnF;AACD,QAAM,MAAA,MAAY,MAAM,cAAc;AAEtC,SAAO,MAAA,MAAY,WAAW,EAAE;GAC9B,MAAM,QAAQ,YAAY,KAAK;AAC/B,OAAI;AACF,UAAM,kBACJ,MAAA,IACA,MAAA,OACA,MAAA,aACA;KAAC;KAAY;KAAgB,EAC7B,MAAA,SACA,aAAa,KAAA,IAAY,EAAC,UAAS,GAAG,KAAA,EACvC;IACD,MAAM,UAAU,YAAY,KAAK,GAAG;AACpC,UAAA,GAAS,OACP,kCAAkC,QAAQ,QAAQ,EAAE,CAAC,MACtD;YACM,GAAG;IACV,MAAM,UAAU,YAAY,KAAK,GAAG;AACpC,UAAA,GAAS,QACP,oCAAoC,QAAQ,QAAQ,EAAE,CAAC,MACvD,EACD;;AAEH,SAAM,MAAA,MAAY,MAAM,WAAW;;;CAIvC,OAAsB;AACpB,QAAA,MAAY,KAAK,MAAA,GAAS;AAC1B,SAAO"}
|
|
@@ -12,7 +12,7 @@ import auth from "basic-auth";
|
|
|
12
12
|
//#region ../zero-cache/src/services/statz.ts
|
|
13
13
|
async function upstreamStats(lc, config) {
|
|
14
14
|
const schema = upstreamSchema(getShardID(config));
|
|
15
|
-
const sql = pgClient(lc, config.upstream.db);
|
|
15
|
+
const sql = pgClient(lc, config.upstream.db, "statz-upstream");
|
|
16
16
|
try {
|
|
17
17
|
return await getPgStats([
|
|
18
18
|
["numReplicas", sql`SELECT COUNT(*) as "c" FROM ${sql(schema)}."replicas"`],
|
|
@@ -25,7 +25,7 @@ async function upstreamStats(lc, config) {
|
|
|
25
25
|
}
|
|
26
26
|
async function cvrStats(lc, config) {
|
|
27
27
|
const schema = upstreamSchema(getShardID(config)) + "/cvr";
|
|
28
|
-
const sql = pgClient(lc, config.cvr.db);
|
|
28
|
+
const sql = pgClient(lc, config.cvr.db, "statz-cvr");
|
|
29
29
|
function numQueriesPerClientGroup(active) {
|
|
30
30
|
const filter = active ? sql`WHERE "inactivatedAt" IS NULL AND deleted = false` : sql`WHERE "inactivatedAt" IS NOT NULL AND ("inactivatedAt" + "ttl") > NOW()`;
|
|
31
31
|
return sql`WITH
|
|
@@ -136,7 +136,7 @@ async function cvrStats(lc, config) {
|
|
|
136
136
|
}
|
|
137
137
|
async function changeLogStats(lc, config) {
|
|
138
138
|
const schema = upstreamSchema(getShardID(config)) + "/cdc";
|
|
139
|
-
const sql = pgClient(lc, config.change.db);
|
|
139
|
+
const sql = pgClient(lc, config.change.db, "statz-change");
|
|
140
140
|
try {
|
|
141
141
|
return await getPgStats([["changeLogSize", sql`SELECT COUNT(*) as "change_log_size" FROM ${sql(schema)}."changeLog"`]]);
|
|
142
142
|
} finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statz.js","names":[],"sources":["../../../../../zero-cache/src/services/statz.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport type {LogContext} from '@rocicorp/logger';\nimport auth from 'basic-auth';\nimport type {FastifyReply, FastifyRequest} from 'fastify';\nimport {BigIntJSON} from '../../../shared/src/bigint-json.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {NormalizedZeroConfig as ZeroConfig} from '../config/normalize.ts';\nimport {isAdminPasswordValid} from '../config/zero-config.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {getShardID, upstreamSchema} from '../types/shards.ts';\nimport {fromStateVersionString} from './change-source/pg/lsn.ts';\nimport {getReplicationState} from './replicator/schema/replication-state.ts';\n\nasync function upstreamStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config));\n const sql = pgClient(lc, config.upstream.db);\n try {\n return await getPgStats([\n [\n 'numReplicas',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"replicas\"`,\n ],\n [\n 'numClientsWithMutations',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n [\n 'numMutationsProcessed',\n sql`SELECT SUM(\"lastMutationID\") as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nasync function cvrStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cvr';\n const sql = pgClient(lc, config.cvr.db);\n\n function numQueriesPerClientGroup(\n active: boolean,\n ): ReturnType<ReturnType<typeof pgClient>> {\n const filter = active\n ? sql`WHERE \"inactivatedAt\" IS NULL AND deleted = false`\n : sql`WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`;\n return sql`WITH\n group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(*) AS num_queries\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n ),\n -- Count distinct clientIDs per clientGroupID\n client_per_group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(DISTINCT \"clientID\") AS num_clients\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n )\n -- Combine all the information\n SELECT\n g.\"clientGroupID\",\n cpg.num_clients,\n g.num_queries\n FROM group_counts g\n JOIN client_per_group_counts cpg ON g.\"clientGroupID\" = cpg.\"clientGroupID\"\n ORDER BY g.num_queries DESC;`;\n }\n\n try {\n return await getPgStats([\n [\n 'totalNumQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\"`,\n ],\n [\n 'numUniqueQueryHashes',\n sql`SELECT COUNT(DISTINCT \"queryHash\") as \"c\" FROM ${sql(\n schema,\n )}.\"desires\"`,\n ],\n [\n 'numActiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NULL AND \"deleted\" = false`,\n ],\n [\n 'numInactiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`,\n ],\n [\n 'numDeletedQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"deleted\" = true`,\n ],\n [\n 'freshQueriesPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS fresh_count\n FROM ${sql(schema)}.\"desires\"\n WHERE\n (\"inactivatedAt\" IS NOT NULL\n AND (\"inactivatedAt\" + \"ttl\") > NOW()) OR (\"inactivatedAt\" IS NULL\n AND deleted = false)\n GROUP BY \"clientGroupID\"\n )\n\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY fresh_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY fresh_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY fresh_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY fresh_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY fresh_count) AS \"p99\",\n MIN(fresh_count) AS \"min\",\n MAX(fresh_count) AS \"max\",\n AVG(fresh_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n 'rowsPerClientGroupPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\"\n GROUP BY \"clientGroupID\"\n )\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY row_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY row_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY row_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY row_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY row_count) AS \"p99\",\n MIN(row_count) AS \"min\",\n MAX(row_count) AS \"max\",\n AVG(row_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n // check for AST blowup due to DNF conversion.\n 'astSizes',\n sql`SELECT\n percentile_cont(0.25) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"25th_percentile\",\n percentile_cont(0.5) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"50th_percentile\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"75th_percentile\",\n percentile_cont(0.9) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"90th_percentile\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"95th_percentile\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"99th_percentile\",\n MIN(length(\"clientAST\"::text)) AS \"minimum_length\",\n MAX(length(\"clientAST\"::text)) AS \"maximum_length\",\n AVG(length(\"clientAST\"::text))::integer AS \"average_length\",\n COUNT(*) AS \"total_records\"\n FROM ${sql(schema)}.\"queries\";`,\n ],\n [\n // output the hash of the largest AST\n 'biggestAstHash',\n sql`SELECT \"queryHash\", length(\"clientAST\"::text) AS \"ast_length\"\n FROM ${sql(schema)}.\"queries\"\n ORDER BY length(\"clientAST\"::text) DESC\n LIMIT 1;`,\n ],\n [\n 'totalActiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(true),\n ],\n [\n 'totalInactiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(false),\n ],\n [\n 'totalRowsPerClientGroup',\n sql`SELECT \"clientGroupID\", COUNT(*) as \"c\" FROM ${sql(\n schema,\n )}.\"rows\" GROUP BY \"clientGroupID\" ORDER BY \"c\" DESC`,\n ],\n [\n 'numRowsPerQuery',\n sql`SELECT\n k.key AS \"queryHash\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\" r,\n LATERAL jsonb_each(r.\"refCounts\") k\n GROUP BY k.key\n ORDER BY row_count DESC;`,\n ],\n ] satisfies [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][]);\n } finally {\n await sql.end();\n }\n}\n\nasync function changeLogStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cdc';\n const sql = pgClient(lc, config.change.db);\n\n try {\n return await getPgStats([\n [\n 'changeLogSize',\n sql`SELECT COUNT(*) as \"change_log_size\" FROM ${sql(schema)}.\"changeLog\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nfunction replicaStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return Object.fromEntries([\n ['wal checkpoint', pick(first(db.pragma('WAL_CHECKPOINT')))],\n ['page count', pick(first(db.pragma('PAGE_COUNT')))],\n ['page size', pick(first(db.pragma('PAGE_SIZE')))],\n ['journal mode', pick(first(db.pragma('JOURNAL_MODE')))],\n ['synchronous', pick(first(db.pragma('SYNCHRONOUS')))],\n ['cache size', pick(first(db.pragma('CACHE_SIZE')))],\n ['auto vacuum', pick(first(db.pragma('AUTO_VACUUM')))],\n ['freelist count', pick(first(db.pragma('FREELIST_COUNT')))],\n ['wal autocheckpoint', pick(first(db.pragma('WAL_AUTOCHECKPOINT')))],\n ['db file stats', fs.statSync(config.replica.file)],\n ] as const);\n } finally {\n db.close();\n }\n}\n\nfunction replicationStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return getReplicationStats(db);\n } finally {\n db.close();\n }\n}\n\nfunction getReplicationStats(db: Database) {\n const {stateVersion} = getReplicationState(new StatementRunner(db));\n const lsn = fromStateVersionString(stateVersion);\n return {lsn};\n}\n\nfunction osStats() {\n return Object.fromEntries([\n ['load avg', os.loadavg()],\n ['uptime', os.uptime()],\n ['total mem', os.totalmem()],\n ['free mem', os.freemem()],\n ['cpus', os.cpus().length],\n ['available parallelism', os.availableParallelism()],\n ['platform', os.platform()],\n ['arch', os.arch()],\n ['release', os.release()],\n ] as const);\n}\n\nasync function getPgStats(\n pendingQueries: [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][],\n) {\n const results = await Promise.all(\n pendingQueries.map(async ([name, query]) => [name, await query] as const),\n );\n return Object.fromEntries(results);\n}\n\ntype StatsObject = Record<string, unknown>;\n\nfunction printStats(group: string, statsObject: StatsObject): string {\n const lines: string[] = ['\\n' + header(group)];\n for (const [name, result] of Object.entries(statsObject)) {\n lines.push('\\n' + name + ': ' + BigIntJSON.stringify(result, null, 2));\n }\n lines.push('\\n');\n return lines.join('');\n}\n\n/**\n * HTTP query parameters:\n * * `group`: restricts the groups for which stats are computed\n * * `format=json`: returns the stats as a JSON object\n * * `pretty`: formats the JSON object with indentation\n */\nexport async function handleStatzRequest(\n lc: LogContext,\n config: ZeroConfig,\n req: FastifyRequest,\n res: FastifyReply,\n) {\n const credentials = auth(req);\n if (!isAdminPasswordValid(lc, config, credentials?.pass)) {\n void res\n .code(401)\n .header('WWW-Authenticate', 'Basic realm=\"Statz Protected Area\"')\n .send('Unauthorized');\n return;\n }\n\n const statsFns: Record<string, () => Promise<StatsObject> | StatsObject> = {\n upstream: () => upstreamStats(lc, config),\n cvr: () => cvrStats(lc, config),\n changeLog: () => changeLogStats(lc, config),\n replica: () => replicaStats(lc, config),\n replication: () => replicationStats(lc, config),\n os: () => osStats(),\n };\n\n async function computeStats(group: string): Promise<[string, StatsObject]> {\n try {\n return [group, await statsFns[group]()];\n } catch (e) {\n lc.error?.(`error computing ${group} stats`, e);\n return [group, {error: String(e)}];\n }\n }\n\n const query = req.query as Record<string, unknown>;\n const groups =\n typeof query.group === 'string'\n ? query.group.split(',')\n : Array.isArray(query.group)\n ? query.group\n : undefined;\n\n const stats = await Promise.all(\n groups\n ? groups.filter(g => g in statsFns).map(computeStats)\n : Object.keys(statsFns).map(computeStats),\n );\n\n if (query.format === 'json') {\n const indent = query.pretty !== undefined ? 2 : undefined;\n await res\n .header('Content-Type', 'application/json')\n .send(BigIntJSON.stringify(Object.fromEntries(stats), null, indent));\n return;\n } else {\n const body = stats\n .map(([group, statsObject]) => printStats(group, statsObject))\n .join('');\n await res.header('Content-Type', 'text/plain; charset=utf-8').send(body);\n }\n}\n\nfunction first(x: object[]): object {\n return x[0];\n}\n\nfunction pick(x: object): unknown {\n return Object.values(x)[0];\n}\n\nfunction header(name: string): string {\n return `=== ${name} ===\\n`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"statz.js","names":[],"sources":["../../../../../zero-cache/src/services/statz.ts"],"sourcesContent":["import fs from 'fs';\nimport os from 'os';\nimport type {LogContext} from '@rocicorp/logger';\nimport auth from 'basic-auth';\nimport type {FastifyReply, FastifyRequest} from 'fastify';\nimport {BigIntJSON} from '../../../shared/src/bigint-json.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport type {NormalizedZeroConfig as ZeroConfig} from '../config/normalize.ts';\nimport {isAdminPasswordValid} from '../config/zero-config.ts';\nimport {StatementRunner} from '../db/statements.ts';\nimport {pgClient} from '../types/pg.ts';\nimport {getShardID, upstreamSchema} from '../types/shards.ts';\nimport {fromStateVersionString} from './change-source/pg/lsn.ts';\nimport {getReplicationState} from './replicator/schema/replication-state.ts';\n\nasync function upstreamStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config));\n const sql = pgClient(lc, config.upstream.db, 'statz-upstream');\n try {\n return await getPgStats([\n [\n 'numReplicas',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"replicas\"`,\n ],\n [\n 'numClientsWithMutations',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n [\n 'numMutationsProcessed',\n sql`SELECT SUM(\"lastMutationID\") as \"c\" FROM ${sql(schema)}.\"clients\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nasync function cvrStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cvr';\n const sql = pgClient(lc, config.cvr.db, 'statz-cvr');\n\n function numQueriesPerClientGroup(\n active: boolean,\n ): ReturnType<ReturnType<typeof pgClient>> {\n const filter = active\n ? sql`WHERE \"inactivatedAt\" IS NULL AND deleted = false`\n : sql`WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`;\n return sql`WITH\n group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(*) AS num_queries\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n ),\n -- Count distinct clientIDs per clientGroupID\n client_per_group_counts AS (\n SELECT\n \"clientGroupID\",\n COUNT(DISTINCT \"clientID\") AS num_clients\n FROM ${sql(schema)}.\"desires\"\n ${filter}\n GROUP BY \"clientGroupID\"\n )\n -- Combine all the information\n SELECT\n g.\"clientGroupID\",\n cpg.num_clients,\n g.num_queries\n FROM group_counts g\n JOIN client_per_group_counts cpg ON g.\"clientGroupID\" = cpg.\"clientGroupID\"\n ORDER BY g.num_queries DESC;`;\n }\n\n try {\n return await getPgStats([\n [\n 'totalNumQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\"`,\n ],\n [\n 'numUniqueQueryHashes',\n sql`SELECT COUNT(DISTINCT \"queryHash\") as \"c\" FROM ${sql(\n schema,\n )}.\"desires\"`,\n ],\n [\n 'numActiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NULL AND \"deleted\" = false`,\n ],\n [\n 'numInactiveQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"inactivatedAt\" IS NOT NULL AND (\"inactivatedAt\" + \"ttl\") > NOW()`,\n ],\n [\n 'numDeletedQueries',\n sql`SELECT COUNT(*) as \"c\" FROM ${sql(schema)}.\"desires\" WHERE \"deleted\" = true`,\n ],\n [\n 'freshQueriesPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS fresh_count\n FROM ${sql(schema)}.\"desires\"\n WHERE\n (\"inactivatedAt\" IS NOT NULL\n AND (\"inactivatedAt\" + \"ttl\") > NOW()) OR (\"inactivatedAt\" IS NULL\n AND deleted = false)\n GROUP BY \"clientGroupID\"\n )\n\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY fresh_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY fresh_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY fresh_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY fresh_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY fresh_count) AS \"p99\",\n MIN(fresh_count) AS \"min\",\n MAX(fresh_count) AS \"max\",\n AVG(fresh_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n 'rowsPerClientGroupPercentiles',\n sql`WITH client_group_counts AS (\n -- Count inactive desires per clientGroupID\n SELECT\n \"clientGroupID\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\"\n GROUP BY \"clientGroupID\"\n )\n SELECT\n percentile_cont(0.50) WITHIN GROUP (ORDER BY row_count) AS \"p50\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY row_count) AS \"p75\",\n percentile_cont(0.90) WITHIN GROUP (ORDER BY row_count) AS \"p90\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY row_count) AS \"p95\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY row_count) AS \"p99\",\n MIN(row_count) AS \"min\",\n MAX(row_count) AS \"max\",\n AVG(row_count) AS \"avg\"\n FROM client_group_counts;`,\n ],\n [\n // check for AST blowup due to DNF conversion.\n 'astSizes',\n sql`SELECT\n percentile_cont(0.25) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"25th_percentile\",\n percentile_cont(0.5) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"50th_percentile\",\n percentile_cont(0.75) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"75th_percentile\",\n percentile_cont(0.9) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"90th_percentile\",\n percentile_cont(0.95) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"95th_percentile\",\n percentile_cont(0.99) WITHIN GROUP (ORDER BY length(\"clientAST\"::text)) AS \"99th_percentile\",\n MIN(length(\"clientAST\"::text)) AS \"minimum_length\",\n MAX(length(\"clientAST\"::text)) AS \"maximum_length\",\n AVG(length(\"clientAST\"::text))::integer AS \"average_length\",\n COUNT(*) AS \"total_records\"\n FROM ${sql(schema)}.\"queries\";`,\n ],\n [\n // output the hash of the largest AST\n 'biggestAstHash',\n sql`SELECT \"queryHash\", length(\"clientAST\"::text) AS \"ast_length\"\n FROM ${sql(schema)}.\"queries\"\n ORDER BY length(\"clientAST\"::text) DESC\n LIMIT 1;`,\n ],\n [\n 'totalActiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(true),\n ],\n [\n 'totalInactiveQueriesPerClientAndClientGroup',\n numQueriesPerClientGroup(false),\n ],\n [\n 'totalRowsPerClientGroup',\n sql`SELECT \"clientGroupID\", COUNT(*) as \"c\" FROM ${sql(\n schema,\n )}.\"rows\" GROUP BY \"clientGroupID\" ORDER BY \"c\" DESC`,\n ],\n [\n 'numRowsPerQuery',\n sql`SELECT\n k.key AS \"queryHash\",\n COUNT(*) AS row_count\n FROM ${sql(schema)}.\"rows\" r,\n LATERAL jsonb_each(r.\"refCounts\") k\n GROUP BY k.key\n ORDER BY row_count DESC;`,\n ],\n ] satisfies [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][]);\n } finally {\n await sql.end();\n }\n}\n\nasync function changeLogStats(lc: LogContext, config: ZeroConfig) {\n const schema = upstreamSchema(getShardID(config)) + '/cdc';\n const sql = pgClient(lc, config.change.db, 'statz-change');\n\n try {\n return await getPgStats([\n [\n 'changeLogSize',\n sql`SELECT COUNT(*) as \"change_log_size\" FROM ${sql(schema)}.\"changeLog\"`,\n ],\n ]);\n } finally {\n await sql.end();\n }\n}\n\nfunction replicaStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return Object.fromEntries([\n ['wal checkpoint', pick(first(db.pragma('WAL_CHECKPOINT')))],\n ['page count', pick(first(db.pragma('PAGE_COUNT')))],\n ['page size', pick(first(db.pragma('PAGE_SIZE')))],\n ['journal mode', pick(first(db.pragma('JOURNAL_MODE')))],\n ['synchronous', pick(first(db.pragma('SYNCHRONOUS')))],\n ['cache size', pick(first(db.pragma('CACHE_SIZE')))],\n ['auto vacuum', pick(first(db.pragma('AUTO_VACUUM')))],\n ['freelist count', pick(first(db.pragma('FREELIST_COUNT')))],\n ['wal autocheckpoint', pick(first(db.pragma('WAL_AUTOCHECKPOINT')))],\n ['db file stats', fs.statSync(config.replica.file)],\n ] as const);\n } finally {\n db.close();\n }\n}\n\nfunction replicationStats(lc: LogContext, config: ZeroConfig) {\n const db = new Database(lc, config.replica.file);\n try {\n return getReplicationStats(db);\n } finally {\n db.close();\n }\n}\n\nfunction getReplicationStats(db: Database) {\n const {stateVersion} = getReplicationState(new StatementRunner(db));\n const lsn = fromStateVersionString(stateVersion);\n return {lsn};\n}\n\nfunction osStats() {\n return Object.fromEntries([\n ['load avg', os.loadavg()],\n ['uptime', os.uptime()],\n ['total mem', os.totalmem()],\n ['free mem', os.freemem()],\n ['cpus', os.cpus().length],\n ['available parallelism', os.availableParallelism()],\n ['platform', os.platform()],\n ['arch', os.arch()],\n ['release', os.release()],\n ] as const);\n}\n\nasync function getPgStats(\n pendingQueries: [\n name: string,\n query: ReturnType<ReturnType<typeof pgClient>>,\n ][],\n) {\n const results = await Promise.all(\n pendingQueries.map(async ([name, query]) => [name, await query] as const),\n );\n return Object.fromEntries(results);\n}\n\ntype StatsObject = Record<string, unknown>;\n\nfunction printStats(group: string, statsObject: StatsObject): string {\n const lines: string[] = ['\\n' + header(group)];\n for (const [name, result] of Object.entries(statsObject)) {\n lines.push('\\n' + name + ': ' + BigIntJSON.stringify(result, null, 2));\n }\n lines.push('\\n');\n return lines.join('');\n}\n\n/**\n * HTTP query parameters:\n * * `group`: restricts the groups for which stats are computed\n * * `format=json`: returns the stats as a JSON object\n * * `pretty`: formats the JSON object with indentation\n */\nexport async function handleStatzRequest(\n lc: LogContext,\n config: ZeroConfig,\n req: FastifyRequest,\n res: FastifyReply,\n) {\n const credentials = auth(req);\n if (!isAdminPasswordValid(lc, config, credentials?.pass)) {\n void res\n .code(401)\n .header('WWW-Authenticate', 'Basic realm=\"Statz Protected Area\"')\n .send('Unauthorized');\n return;\n }\n\n const statsFns: Record<string, () => Promise<StatsObject> | StatsObject> = {\n upstream: () => upstreamStats(lc, config),\n cvr: () => cvrStats(lc, config),\n changeLog: () => changeLogStats(lc, config),\n replica: () => replicaStats(lc, config),\n replication: () => replicationStats(lc, config),\n os: () => osStats(),\n };\n\n async function computeStats(group: string): Promise<[string, StatsObject]> {\n try {\n return [group, await statsFns[group]()];\n } catch (e) {\n lc.error?.(`error computing ${group} stats`, e);\n return [group, {error: String(e)}];\n }\n }\n\n const query = req.query as Record<string, unknown>;\n const groups =\n typeof query.group === 'string'\n ? query.group.split(',')\n : Array.isArray(query.group)\n ? query.group\n : undefined;\n\n const stats = await Promise.all(\n groups\n ? groups.filter(g => g in statsFns).map(computeStats)\n : Object.keys(statsFns).map(computeStats),\n );\n\n if (query.format === 'json') {\n const indent = query.pretty !== undefined ? 2 : undefined;\n await res\n .header('Content-Type', 'application/json')\n .send(BigIntJSON.stringify(Object.fromEntries(stats), null, indent));\n return;\n } else {\n const body = stats\n .map(([group, statsObject]) => printStats(group, statsObject))\n .join('');\n await res.header('Content-Type', 'text/plain; charset=utf-8').send(body);\n }\n}\n\nfunction first(x: object[]): object {\n return x[0];\n}\n\nfunction pick(x: object): unknown {\n return Object.values(x)[0];\n}\n\nfunction header(name: string): string {\n return `=== ${name} ===\\n`;\n}\n"],"mappings":"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"}
|
|
@@ -56,6 +56,7 @@ export declare class CVRStore {
|
|
|
56
56
|
markQueryAsDeleted(version: CVRVersion, queryPatch: QueryPatch): void;
|
|
57
57
|
putQuery(query: QueryRecord): void;
|
|
58
58
|
updateQuery(query: QueryRecord): void;
|
|
59
|
+
updateRowSetSignature(queryHash: string, signature: string): void;
|
|
59
60
|
insertClient(client: ClientRecord): void;
|
|
60
61
|
deleteClient(clientID: string): void;
|
|
61
62
|
putDesiredQuery(newVersion: CVRVersion, query: {
|
|
@@ -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;AAMnF,OAAO,EAAC,sBAAsB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAC9D,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;
|
|
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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"}
|
|
@@ -41,6 +41,7 @@ function convertTTLValues(inactivatedAt, ttl) {
|
|
|
41
41
|
var tracer = trace.getTracer("cvr-store", version);
|
|
42
42
|
function asQuery(row) {
|
|
43
43
|
const maybeVersion = (s) => s === null ? void 0 : versionFromString(s);
|
|
44
|
+
const sigField = row.rowSetSignature ? { rowSetSignature: row.rowSetSignature } : {};
|
|
44
45
|
if (row.clientAST === null) {
|
|
45
46
|
assert(row.queryName !== null && row.queryArgs !== null, "queryName and queryArgs must be set for custom queries");
|
|
46
47
|
return {
|
|
@@ -51,7 +52,8 @@ function asQuery(row) {
|
|
|
51
52
|
patchVersion: maybeVersion(row.patchVersion),
|
|
52
53
|
clientState: {},
|
|
53
54
|
transformationHash: row.transformationHash ?? void 0,
|
|
54
|
-
transformationVersion: maybeVersion(row.transformationVersion)
|
|
55
|
+
transformationVersion: maybeVersion(row.transformationVersion),
|
|
56
|
+
...sigField
|
|
55
57
|
};
|
|
56
58
|
}
|
|
57
59
|
const ast = astSchema.parse(row.clientAST);
|
|
@@ -60,7 +62,8 @@ function asQuery(row) {
|
|
|
60
62
|
id: row.queryHash,
|
|
61
63
|
ast,
|
|
62
64
|
transformationHash: row.transformationHash ?? void 0,
|
|
63
|
-
transformationVersion: maybeVersion(row.transformationVersion)
|
|
65
|
+
transformationVersion: maybeVersion(row.transformationVersion),
|
|
66
|
+
...sigField
|
|
64
67
|
} : {
|
|
65
68
|
type: "client",
|
|
66
69
|
id: row.queryHash,
|
|
@@ -68,7 +71,8 @@ function asQuery(row) {
|
|
|
68
71
|
patchVersion: maybeVersion(row.patchVersion),
|
|
69
72
|
clientState: {},
|
|
70
73
|
transformationHash: row.transformationHash ?? void 0,
|
|
71
|
-
transformationVersion: maybeVersion(row.transformationVersion)
|
|
74
|
+
transformationVersion: maybeVersion(row.transformationVersion),
|
|
75
|
+
...sigField
|
|
72
76
|
};
|
|
73
77
|
}
|
|
74
78
|
var LOAD_ATTEMPT_INTERVAL_MS = 500;
|
|
@@ -104,7 +108,11 @@ var CVRStore = class {
|
|
|
104
108
|
return this.#db(`${this.#schema}.${table}`);
|
|
105
109
|
}
|
|
106
110
|
#updateQueryFields(queryHash, fields) {
|
|
107
|
-
this.#pendingQueryPartialUpdates.
|
|
111
|
+
const existing = this.#pendingQueryPartialUpdates.get(queryHash);
|
|
112
|
+
this.#pendingQueryPartialUpdates.set(queryHash, existing ? {
|
|
113
|
+
...existing,
|
|
114
|
+
...fields
|
|
115
|
+
} : fields);
|
|
108
116
|
}
|
|
109
117
|
load(lc, lastConnectTime) {
|
|
110
118
|
return startAsyncSpan(tracer, "cvr.load", async () => {
|
|
@@ -322,6 +330,9 @@ var CVRStore = class {
|
|
|
322
330
|
deleted: false
|
|
323
331
|
});
|
|
324
332
|
}
|
|
333
|
+
updateRowSetSignature(queryHash, signature) {
|
|
334
|
+
this.#updateQueryFields(queryHash, { rowSetSignature: signature });
|
|
335
|
+
}
|
|
325
336
|
insertClient(client) {
|
|
326
337
|
const change = {
|
|
327
338
|
clientGroupID: this.#id,
|
|
@@ -440,7 +451,8 @@ var CVRStore = class {
|
|
|
440
451
|
"transformationHash",
|
|
441
452
|
"transformationVersion",
|
|
442
453
|
"internal",
|
|
443
|
-
"deleted"
|
|
454
|
+
"deleted",
|
|
455
|
+
"rowSetSignature"
|
|
444
456
|
)
|
|
445
457
|
SELECT
|
|
446
458
|
"clientGroupID",
|
|
@@ -455,7 +467,8 @@ var CVRStore = class {
|
|
|
455
467
|
"transformationHash",
|
|
456
468
|
"transformationVersion",
|
|
457
469
|
"internal",
|
|
458
|
-
"deleted"
|
|
470
|
+
"deleted",
|
|
471
|
+
"rowSetSignature"
|
|
459
472
|
FROM json_to_recordset(${rows}) AS x(
|
|
460
473
|
"clientGroupID" TEXT,
|
|
461
474
|
"queryHash" TEXT,
|
|
@@ -466,12 +479,13 @@ var CVRStore = class {
|
|
|
466
479
|
"transformationHash" TEXT,
|
|
467
480
|
"transformationVersion" TEXT,
|
|
468
481
|
"internal" BOOLEAN,
|
|
469
|
-
"deleted" BOOLEAN
|
|
482
|
+
"deleted" BOOLEAN,
|
|
483
|
+
"rowSetSignature" TEXT
|
|
470
484
|
)
|
|
471
485
|
ON CONFLICT ("clientGroupID", "queryHash") DO UPDATE SET
|
|
472
486
|
"clientAST" = excluded."clientAST",
|
|
473
487
|
"queryName" = excluded."queryName",
|
|
474
|
-
"queryArgs" = CASE
|
|
488
|
+
"queryArgs" = CASE
|
|
475
489
|
WHEN excluded."queryArgs" IS NULL THEN NULL
|
|
476
490
|
ELSE excluded."queryArgs"::json
|
|
477
491
|
END,
|
|
@@ -479,7 +493,8 @@ var CVRStore = class {
|
|
|
479
493
|
"transformationHash" = excluded."transformationHash",
|
|
480
494
|
"transformationVersion" = excluded."transformationVersion",
|
|
481
495
|
"internal" = excluded."internal",
|
|
482
|
-
"deleted" = excluded."deleted"
|
|
496
|
+
"deleted" = excluded."deleted",
|
|
497
|
+
"rowSetSignature" = excluded."rowSetSignature"
|
|
483
498
|
`);
|
|
484
499
|
}
|
|
485
500
|
if (partialOnly.size > 0) {
|
|
@@ -494,7 +509,9 @@ var CVRStore = class {
|
|
|
494
509
|
transformationHashSet: partial.transformationHash !== void 0,
|
|
495
510
|
transformationHash: partial.transformationHash ?? null,
|
|
496
511
|
transformationVersionSet: partial.transformationVersion !== void 0,
|
|
497
|
-
transformationVersion: partial.transformationVersion ?? null
|
|
512
|
+
transformationVersion: partial.transformationVersion ?? null,
|
|
513
|
+
rowSetSignatureSet: partial.rowSetSignature !== void 0,
|
|
514
|
+
rowSetSignature: partial.rowSetSignature ?? null
|
|
498
515
|
}));
|
|
499
516
|
queries.push(tx`
|
|
500
517
|
UPDATE ${this.#cvr("queries")} AS q
|
|
@@ -514,6 +531,10 @@ var CVRStore = class {
|
|
|
514
531
|
"transformationVersion" = CASE
|
|
515
532
|
WHEN u."transformationVersionSet" THEN u."transformationVersion"
|
|
516
533
|
ELSE q."transformationVersion"
|
|
534
|
+
END,
|
|
535
|
+
"rowSetSignature" = CASE
|
|
536
|
+
WHEN u."rowSetSignatureSet" THEN u."rowSetSignature"
|
|
537
|
+
ELSE q."rowSetSignature"
|
|
517
538
|
END
|
|
518
539
|
FROM json_to_recordset(${rows}) AS u(
|
|
519
540
|
"clientGroupID" TEXT,
|
|
@@ -525,7 +546,9 @@ var CVRStore = class {
|
|
|
525
546
|
"transformationHashSet" BOOLEAN,
|
|
526
547
|
"transformationHash" TEXT,
|
|
527
548
|
"transformationVersionSet" BOOLEAN,
|
|
528
|
-
"transformationVersion" TEXT
|
|
549
|
+
"transformationVersion" TEXT,
|
|
550
|
+
"rowSetSignatureSet" BOOLEAN,
|
|
551
|
+
"rowSetSignature" TEXT
|
|
529
552
|
)
|
|
530
553
|
WHERE q."clientGroupID" = u."clientGroupID"
|
|
531
554
|
AND q."queryHash" = u."queryHash"
|