@rocicorp/zero 0.25.0-canary.18 → 0.25.0-canary.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/replicache/src/persist/idb-databases-store.d.ts +1 -0
- package/out/replicache/src/persist/idb-databases-store.d.ts.map +1 -1
- package/out/replicache/src/persist/idb-databases-store.js +13 -2
- package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/adapters/drizzle.d.ts +1 -1
- package/out/zero/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero/src/adapters/drizzle.js +4 -1
- package/out/zero/src/bindings.d.ts +2 -0
- package/out/zero/src/bindings.d.ts.map +1 -0
- package/out/zero/src/bindings.js +27 -0
- package/out/zero/src/bindings.js.map +1 -0
- package/out/zero/src/react.js +2 -4
- package/out/zero/src/react.js.map +1 -1
- package/out/zero/src/solid.js +2 -2
- package/out/zero/src/zero.js +3 -5
- package/out/zero-cache/src/auth/read-authorizer.d.ts +1 -1
- package/out/zero-cache/src/auth/read-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +5 -4
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +24 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +23 -4
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts +10 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +34 -18
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +1 -0
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.d.ts +1 -1
- package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
- package/out/zero-cache/src/services/analyze.js +5 -5
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +4 -4
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +2 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +26 -13
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js +39 -15
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +4 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +31 -9
- 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 +3 -0
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +11 -0
- 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 +1 -2
- 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 +6 -6
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- 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 +23 -10
- 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 +31 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -0
- 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 +20 -16
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -0
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +2 -0
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +2 -0
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-client/src/client/bindings.d.ts +12 -41
- package/out/zero-client/src/client/bindings.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +3 -0
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js +3 -0
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/delete-clients-manager.d.ts +1 -1
- package/out/zero-client/src/client/delete-clients-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/delete-clients-manager.js +30 -3
- package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +1 -3
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +1 -0
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +43 -26
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +6 -4
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-protocol/src/analyze-query-result.d.ts +2 -2
- package/out/zero-protocol/src/analyze-query-result.js +2 -2
- package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +2 -2
- package/out/zero-protocol/src/inspect-down.d.ts +6 -6
- package/out/zero-protocol/src/inspect-up.d.ts +4 -4
- package/out/zero-protocol/src/inspect-up.js +1 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +1 -1
- package/out/zero-react/src/bindings.d.ts +2 -0
- package/out/zero-react/src/bindings.d.ts.map +1 -0
- package/out/zero-react/src/mod.d.ts +1 -10
- package/out/zero-react/src/mod.d.ts.map +1 -1
- package/out/zero-react/src/{use-zero-connection-state.d.ts → use-connection-state.d.ts} +3 -3
- package/out/zero-react/src/use-connection-state.d.ts.map +1 -0
- package/out/zero-react/src/{use-zero-connection-state.js → use-connection-state.js} +3 -3
- package/out/zero-react/src/use-connection-state.js.map +1 -0
- package/out/zero-react/src/use-query.d.ts +2 -10
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +24 -22
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/use-zero-online.d.ts +1 -1
- package/out/zero-react/src/use-zero-online.js.map +1 -1
- package/out/zero-react/src/zero-provider.d.ts +1 -5
- package/out/zero-react/src/zero-provider.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.js +16 -0
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-react/src/zero.d.ts +2 -0
- package/out/zero-react/src/zero.d.ts.map +1 -0
- package/out/zero-schema/src/permissions.d.ts.map +1 -1
- package/out/zero-schema/src/permissions.js +2 -8
- package/out/zero-schema/src/permissions.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +3 -0
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +3 -0
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-solid/src/bindings.d.ts +2 -0
- package/out/zero-solid/src/bindings.d.ts.map +1 -0
- package/out/zero-solid/src/mod.d.ts +1 -8
- package/out/zero-solid/src/mod.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +1 -8
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +31 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/{use-zero-connection-state.d.ts → use-connection-state.d.ts} +3 -3
- package/out/zero-solid/src/use-connection-state.d.ts.map +1 -0
- package/out/zero-solid/src/{use-zero-connection-state.js → use-connection-state.js} +3 -3
- package/out/zero-solid/src/use-connection-state.js.map +1 -0
- package/out/zero-solid/src/use-query.d.ts +1 -7
- package/out/zero-solid/src/use-query.d.ts.map +1 -1
- package/out/zero-solid/src/use-query.js +43 -12
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero-online.d.ts +1 -1
- package/out/zero-solid/src/use-zero-online.js.map +1 -1
- package/out/zero-solid/src/use-zero.d.ts +1 -5
- package/out/zero-solid/src/use-zero.d.ts.map +1 -1
- package/out/zero-solid/src/use-zero.js +16 -0
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zero-solid/src/zero.d.ts +2 -0
- package/out/zero-solid/src/zero.d.ts.map +1 -0
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +29 -27
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-utils.d.ts +7 -1
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +12 -0
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +11 -25
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +3 -0
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts +2 -2
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +1 -1
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +3 -3
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/query/create-builder.d.ts +2 -1
- package/out/zql/src/query/create-builder.d.ts.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -0
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +39 -6
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +414 -23
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts +2 -2
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +2 -2
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +2 -2
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/schema-query.d.ts +4 -2
- package/out/zql/src/query/schema-query.d.ts.map +1 -1
- package/out/zql/src/query/static-query.d.ts +2 -16
- package/out/zql/src/query/static-query.d.ts.map +1 -1
- package/out/zql/src/query/static-query.js +10 -37
- package/out/zql/src/query/static-query.js.map +1 -1
- package/package.json +7 -3
- package/out/zero-client/src/client/bindings.js +0 -33
- package/out/zero-client/src/client/bindings.js.map +0 -1
- package/out/zero-react/src/components/inspector.d.ts +0 -9
- package/out/zero-react/src/components/inspector.d.ts.map +0 -1
- package/out/zero-react/src/components/inspector.js +0 -38
- package/out/zero-react/src/components/inspector.js.map +0 -1
- package/out/zero-react/src/components/mark-icon.d.ts +0 -3
- package/out/zero-react/src/components/mark-icon.d.ts.map +0 -1
- package/out/zero-react/src/components/mark-icon.js +0 -28
- package/out/zero-react/src/components/mark-icon.js.map +0 -1
- package/out/zero-react/src/components/zero-inspector.d.ts +0 -8
- package/out/zero-react/src/components/zero-inspector.d.ts.map +0 -1
- package/out/zero-react/src/components/zero-inspector.js +0 -44
- package/out/zero-react/src/components/zero-inspector.js.map +0 -1
- package/out/zero-react/src/use-zero-connection-state.d.ts.map +0 -1
- package/out/zero-react/src/use-zero-connection-state.js.map +0 -1
- package/out/zero-solid/src/use-zero-connection-state.d.ts.map +0 -1
- package/out/zero-solid/src/use-zero-connection-state.js.map +0 -1
- package/out/zql/src/query/abstract-query.d.ts +0 -42
- package/out/zql/src/query/abstract-query.d.ts.map +0 -1
- package/out/zql/src/query/abstract-query.js +0 -405
- package/out/zql/src/query/abstract-query.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oDAAoD,CAAC;AAC3F,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,mCAAmC,CAAC;AAC3D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kDAAkD,CAAC;AAWxF,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAIjE,OAAO,EAAiB,KAAK,SAAS,EAAC,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6CAA6C,CAAC;AAI9E,wBAAsB,YAAY,CAChC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,oBAAoB,EAC5B,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,UAAU,UAAO,EACjB,UAAU,UAAQ,EAClB,WAAW,CAAC,EAAE,iBAAiB,EAC/B,QAAQ,CAAC,EAAE,SAAS,EACpB,
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../../../../zero-cache/src/services/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,oDAAoD,CAAC;AAC3F,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,mCAAmC,CAAC;AAC3D,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,kDAAkD,CAAC;AAWxF,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wBAAwB,CAAC;AAIjE,OAAO,EAAiB,KAAK,SAAS,EAAC,MAAM,8BAA8B,CAAC;AAC5E,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6CAA6C,CAAC;AAI9E,wBAAsB,YAAY,CAChC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,oBAAoB,EAC5B,YAAY,EAAE,YAAY,EAC1B,GAAG,EAAE,GAAG,EACR,UAAU,UAAO,EACjB,UAAU,UAAQ,EAClB,WAAW,CAAC,EAAE,iBAAiB,EAC/B,QAAQ,CAAC,EAAE,SAAS,EACpB,SAAS,UAAQ,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAwE7B"}
|
|
@@ -54,7 +54,7 @@ import { computeZqlSpecs, mustGetTableSpec } from "../db/lite-tables.js";
|
|
|
54
54
|
import { runAst } from "./run-ast.js";
|
|
55
55
|
import { TimeSliceTimer } from "./view-syncer/view-syncer.js";
|
|
56
56
|
const TIME_SLICE_LAP_THRESHOLD_MS = 200;
|
|
57
|
-
async function analyzeQuery(lc, config, clientSchema, ast, syncedRows = true, vendedRows = false, permissions, authData,
|
|
57
|
+
async function analyzeQuery(lc, config, clientSchema, ast, syncedRows = true, vendedRows = false, permissions, authData, joinPlans = false) {
|
|
58
58
|
var _stack = [];
|
|
59
59
|
try {
|
|
60
60
|
const db = __using(_stack, new Database(lc, config.replica.file));
|
|
@@ -62,8 +62,8 @@ async function analyzeQuery(lc, config, clientSchema, ast, syncedRows = true, ve
|
|
|
62
62
|
const tableSpecs = /* @__PURE__ */ new Map();
|
|
63
63
|
const tables = /* @__PURE__ */ new Map();
|
|
64
64
|
computeZqlSpecs(lc, db, tableSpecs, fullTables);
|
|
65
|
-
const planDebugger =
|
|
66
|
-
const costModel =
|
|
65
|
+
const planDebugger = joinPlans ? new AccumulatorDebugger() : void 0;
|
|
66
|
+
const costModel = joinPlans ? createSQLiteCostModel(db, tableSpecs) : void 0;
|
|
67
67
|
const timer = await new TimeSliceTimer().start();
|
|
68
68
|
const shouldYield = () => timer.elapsedLap() > TIME_SLICE_LAP_THRESHOLD_MS;
|
|
69
69
|
const yieldProcess = () => timer.yieldProcess();
|
|
@@ -113,9 +113,9 @@ async function analyzeQuery(lc, config, clientSchema, ast, syncedRows = true, ve
|
|
|
113
113
|
},
|
|
114
114
|
yieldProcess
|
|
115
115
|
);
|
|
116
|
-
result.
|
|
116
|
+
result.sqlitePlans = explainQueries(result.readRowCountsByQuery ?? {}, db);
|
|
117
117
|
if (planDebugger) {
|
|
118
|
-
result.
|
|
118
|
+
result.joinPlans = serializePlanDebugEvents(planDebugger.events);
|
|
119
119
|
}
|
|
120
120
|
return result;
|
|
121
121
|
} catch (_) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","sources":["../../../../../zero-cache/src/services/analyze.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport {Debug} from '../../../zql/src/builder/debug-delegate.ts';\nimport {MemoryStorage} from '../../../zql/src/ivm/memory-storage.ts';\nimport {\n AccumulatorDebugger,\n serializePlanDebugEvents,\n} from '../../../zql/src/planner/planner-debug.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport {explainQueries} from '../../../zqlite/src/explain-queries.ts';\nimport {createSQLiteCostModel} from '../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../zqlite/src/table-source.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../db/specs.ts';\nimport {runAst} from './run-ast.ts';\nimport {TimeSliceTimer, type TokenData} from './view-syncer/view-syncer.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\n\nconst TIME_SLICE_LAP_THRESHOLD_MS = 200;\n\nexport async function analyzeQuery(\n lc: LogContext,\n config: NormalizedZeroConfig,\n clientSchema: ClientSchema,\n ast: AST,\n syncedRows = true,\n vendedRows = false,\n permissions?: PermissionsConfig,\n authData?: TokenData,\n
|
|
1
|
+
{"version":3,"file":"analyze.js","sources":["../../../../../zero-cache/src/services/analyze.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport {Debug} from '../../../zql/src/builder/debug-delegate.ts';\nimport {MemoryStorage} from '../../../zql/src/ivm/memory-storage.ts';\nimport {\n AccumulatorDebugger,\n serializePlanDebugEvents,\n} from '../../../zql/src/planner/planner-debug.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport {explainQueries} from '../../../zqlite/src/explain-queries.ts';\nimport {createSQLiteCostModel} from '../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../zqlite/src/table-source.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../db/specs.ts';\nimport {runAst} from './run-ast.ts';\nimport {TimeSliceTimer, type TokenData} from './view-syncer/view-syncer.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\n\nconst TIME_SLICE_LAP_THRESHOLD_MS = 200;\n\nexport async function analyzeQuery(\n lc: LogContext,\n config: NormalizedZeroConfig,\n clientSchema: ClientSchema,\n ast: AST,\n syncedRows = true,\n vendedRows = false,\n permissions?: PermissionsConfig,\n authData?: TokenData,\n joinPlans = false,\n): Promise<AnalyzeQueryResult> {\n using db = new Database(lc, config.replica.file);\n const fullTables = new Map<string, LiteTableSpec>();\n const tableSpecs = new Map<string, LiteAndZqlSpec>();\n const tables = new Map<string, TableSource>();\n\n computeZqlSpecs(lc, db, tableSpecs, fullTables);\n\n const planDebugger = joinPlans ? new AccumulatorDebugger() : undefined;\n const costModel = joinPlans\n ? createSQLiteCostModel(db, tableSpecs)\n : undefined;\n const timer = await new TimeSliceTimer().start();\n const shouldYield = () => timer.elapsedLap() > TIME_SLICE_LAP_THRESHOLD_MS;\n const yieldProcess = () => timer.yieldProcess();\n const result = await runAst(\n lc,\n clientSchema,\n ast,\n true,\n {\n applyPermissions: permissions !== undefined,\n syncedRows,\n vendedRows,\n authData,\n db,\n tableSpecs,\n permissions,\n costModel,\n planDebugger,\n host: {\n debug: new Debug(),\n getSource(tableName: string) {\n let source = tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(tableSpecs, tableName);\n const {primaryKey} = tableSpec.tableSpec;\n\n source = new TableSource(\n lc,\n config.log,\n db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n shouldYield,\n );\n tables.set(tableName, source);\n return source;\n },\n createStorage() {\n return new MemoryStorage();\n },\n decorateSourceInput: input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n },\n yieldProcess,\n );\n\n result.sqlitePlans = explainQueries(result.readRowCountsByQuery ?? {}, db);\n\n if (planDebugger) {\n result.joinPlans = serializePlanDebugEvents(planDebugger.events);\n }\n\n return result;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,8BAA8B;AAEpC,eAAsB,aACpB,IACA,QACA,cACA,KACA,aAAa,MACb,aAAa,OACb,aACA,UACA,YAAY,OACiB;AAC7B;AAAA;AAAA,UAAM,KAAK,oBAAI,SAAS,IAAI,OAAO,QAAQ,IAAI;AAC/C,UAAM,iCAAiB,IAAA;AACvB,UAAM,iCAAiB,IAAA;AACvB,UAAM,6BAAa,IAAA;AAEnB,oBAAgB,IAAI,IAAI,YAAY,UAAU;AAE9C,UAAM,eAAe,YAAY,IAAI,oBAAA,IAAwB;AAC7D,UAAM,YAAY,YACd,sBAAsB,IAAI,UAAU,IACpC;AACJ,UAAM,QAAQ,MAAM,IAAI,eAAA,EAAiB,MAAA;AACzC,UAAM,cAAc,MAAM,MAAM,WAAA,IAAe;AAC/C,UAAM,eAAe,MAAM,MAAM,aAAA;AACjC,UAAM,SAAS,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,QACE,kBAAkB,gBAAgB;AAAA,QAClC;AAAA,QACA;AAAA,QACA;AAAA,QAGA;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,UACJ,OAAO,IAAI,MAAA;AAAA,UACX,UAAU,WAAmB;AAC3B,gBAAI,SAAS,OAAO,IAAI,SAAS;AACjC,gBAAI,QAAQ;AACV,qBAAO;AAAA,YACT;AAEA,kBAAM,YAAY,iBAAiB,YAAY,SAAS;AACxD,kBAAM,EAAC,eAAc,UAAU;AAE/B,qBAAS,IAAI;AAAA,cACX;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA;AAAA,cACA,UAAU;AAAA,cACV;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,IAAI,WAAW,MAAM;AAC5B,mBAAO;AAAA,UACT;AAAA,UACA,gBAAgB;AACd,mBAAO,IAAI,cAAA;AAAA,UACb;AAAA,UACA,qBAAqB,CAAA,UAAS;AAAA,UAC9B,eAAe,CAAA,UAAS;AAAA,UACxB,UAAU;AAAA,UAAC;AAAA,UACX,qBAAqB,CAAA,UAAS;AAAA,QAAA;AAAA,MAChC;AAAA,MAEF;AAAA,IAAA;AAGF,WAAO,cAAc,eAAe,OAAO,wBAAwB,CAAA,GAAI,EAAE;AAEzE,QAAI,cAAc;AAChB,aAAO,YAAY,yBAAyB,aAAa,MAAM;AAAA,IACjE;AAEA,WAAO;AAAA,WAtEP;AAAA;AAAA;AAAA;AAAA;AAuEF;"}
|
|
@@ -135,12 +135,12 @@ export declare class PusherService implements Service, Pusher {
|
|
|
135
135
|
afterPermissions?: string | undefined;
|
|
136
136
|
vendedRowCounts?: Record<string, Record<string, number>> | undefined;
|
|
137
137
|
vendedRows?: Record<string, Record<string, Readonly<Record<string, import("../../../../shared/src/json.ts").ReadonlyJSONValue | undefined>>[]>> | undefined;
|
|
138
|
-
|
|
138
|
+
sqlitePlans?: Record<string, string[]> | undefined;
|
|
139
139
|
readRows?: Record<string, Record<string, Readonly<Record<string, import("../../../../shared/src/json.ts").ReadonlyJSONValue | undefined>>[]>> | undefined;
|
|
140
140
|
readRowCountsByQuery?: Record<string, Record<string, number>> | undefined;
|
|
141
141
|
readRowCount?: number | undefined;
|
|
142
142
|
dbScansByQuery?: Record<string, Record<string, number>> | undefined;
|
|
143
|
-
|
|
143
|
+
joinPlans?: ({
|
|
144
144
|
type: "attempt-start";
|
|
145
145
|
attemptNumber: number;
|
|
146
146
|
totalAttempts: number;
|
|
@@ -434,12 +434,12 @@ export declare class PusherService implements Service, Pusher {
|
|
|
434
434
|
afterPermissions?: string | undefined;
|
|
435
435
|
vendedRowCounts?: Record<string, Record<string, number>> | undefined;
|
|
436
436
|
vendedRows?: Record<string, Record<string, Readonly<Record<string, import("../../../../shared/src/json.ts").ReadonlyJSONValue | undefined>>[]>> | undefined;
|
|
437
|
-
|
|
437
|
+
sqlitePlans?: Record<string, string[]> | undefined;
|
|
438
438
|
readRows?: Record<string, Record<string, Readonly<Record<string, import("../../../../shared/src/json.ts").ReadonlyJSONValue | undefined>>[]>> | undefined;
|
|
439
439
|
readRowCountsByQuery?: Record<string, Record<string, number>> | undefined;
|
|
440
440
|
readRowCount?: number | undefined;
|
|
441
441
|
dbScansByQuery?: Record<string, Record<string, number>> | undefined;
|
|
442
|
-
|
|
442
|
+
joinPlans?: ({
|
|
443
443
|
type: "attempt-start";
|
|
444
444
|
attemptNumber: number;
|
|
445
445
|
totalAttempts: number;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
|
+
import { type ActiveUsers } from '../../server/anonymous-otel-start.ts';
|
|
2
3
|
import type { PostgresDB } from '../../types/pg.ts';
|
|
3
4
|
import { type ShardID } from '../../types/shards.ts';
|
|
4
5
|
import type { Service } from '../service.ts';
|
|
@@ -8,7 +9,7 @@ type Options = {
|
|
|
8
9
|
export declare class ActiveUsersGauge implements Service {
|
|
9
10
|
#private;
|
|
10
11
|
readonly id = "active-users-gauge";
|
|
11
|
-
constructor(lc: LogContext, db: PostgresDB, shard: ShardID, opts?: Options);
|
|
12
|
+
constructor(lc: LogContext, db: PostgresDB, shard: ShardID, opts?: Options, setActiveUsersGetterFn?: (getter: () => ActiveUsers) => void);
|
|
12
13
|
run(): Promise<void>;
|
|
13
14
|
stop(): Promise<void>;
|
|
14
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-users-gauge.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/active-users-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"active-users-gauge.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/active-users-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAEL,KAAK,WAAW,EACjB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAK3C,KAAK,OAAO,GAAG;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,qBAAa,gBAAiB,YAAW,OAAO;;IAC9C,QAAQ,CAAC,EAAE,wBAAwB;gBAajC,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,OAAY,EAClB,sBAAsB,sCAAuB;IASzC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IA8C1B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAItB"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { must } from "../../../../shared/src/must.js";
|
|
2
|
+
import { mapValues } from "../../../../shared/src/objects.js";
|
|
1
3
|
import { setActiveUsersGetter } from "../../server/anonymous-otel-start.js";
|
|
2
4
|
import { cvrSchema } from "../../types/shards.js";
|
|
3
5
|
import { RunningState } from "../running-state.js";
|
|
@@ -10,30 +12,41 @@ class ActiveUsersGauge {
|
|
|
10
12
|
#schema;
|
|
11
13
|
#updateIntervalMs;
|
|
12
14
|
#state = new RunningState("active-users-gauge");
|
|
15
|
+
#setActiveUsersGetter;
|
|
13
16
|
// latest computed value exposed via the observable gauge callback
|
|
14
|
-
#
|
|
15
|
-
|
|
16
|
-
constructor(lc, db, shard, opts = {}) {
|
|
17
|
+
#lastActiveUsers;
|
|
18
|
+
constructor(lc, db, shard, opts = {}, setActiveUsersGetterFn = setActiveUsersGetter) {
|
|
17
19
|
this.#lc = lc;
|
|
18
20
|
this.#db = db;
|
|
19
21
|
this.#schema = cvrSchema(shard);
|
|
20
22
|
this.#updateIntervalMs = opts.updateIntervalMs ?? 60 * 1e3;
|
|
23
|
+
this.#setActiveUsersGetter = setActiveUsersGetterFn;
|
|
21
24
|
}
|
|
22
25
|
async run() {
|
|
23
26
|
while (this.#state.shouldRun()) {
|
|
24
27
|
try {
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
const since30day = now - DAY * 30;
|
|
30
|
+
const since7day = now - DAY * 7;
|
|
31
|
+
const since1day = now - DAY;
|
|
32
|
+
const [actives] = await this.#db`
|
|
33
|
+
SELECT
|
|
34
|
+
COUNT(*) FILTER (WHERE "lastActive" >= ${since1day}) AS active_users_last_day,
|
|
35
|
+
COUNT(DISTINCT("profileID")) FILTER (WHERE "lastActive" >= ${since1day} AND starts_with("profileID", 'p')) AS users_1da,
|
|
36
|
+
COUNT(DISTINCT("profileID")) FILTER (WHERE "lastActive" >= ${since7day} AND starts_with("profileID", 'p')) AS users_7da,
|
|
37
|
+
COUNT(DISTINCT("profileID")) FILTER (WHERE starts_with("profileID", 'p')) AS users_30da,
|
|
38
|
+
COUNT(DISTINCT("profileID")) FILTER (WHERE "lastActive" >= ${since1day}) AS users_1da_legacy,
|
|
39
|
+
COUNT(DISTINCT("profileID")) FILTER (WHERE "lastActive" >= ${since7day}) AS users_7da_legacy,
|
|
40
|
+
COUNT(DISTINCT("profileID")) AS users_30da_legacy
|
|
41
|
+
FROM ${this.#db(this.#schema)}.instances
|
|
42
|
+
WHERE "lastActive" >= ${since30day}
|
|
30
43
|
`;
|
|
31
|
-
this.#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.#
|
|
44
|
+
const setGetter = this.#lastActiveUsers === void 0;
|
|
45
|
+
this.#lastActiveUsers = mapValues(actives, (bigVal) => Number(bigVal));
|
|
46
|
+
if (setGetter) {
|
|
47
|
+
this.#setActiveUsersGetter(() => must(this.#lastActiveUsers));
|
|
35
48
|
}
|
|
36
|
-
this.#lc.debug?.(`updated active-users gauge
|
|
49
|
+
this.#lc.debug?.(`updated active-users gauge`, this.#lastActiveUsers);
|
|
37
50
|
} catch (e) {
|
|
38
51
|
this.#lc.warn?.("error updating active-users gauge", e);
|
|
39
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"active-users-gauge.js","sources":["../../../../../../zero-cache/src/services/view-syncer/active-users-gauge.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {setActiveUsersGetter} from '../../server/anonymous-otel-start.ts';\nimport type {PostgresDB} from '../../types/pg.ts';\nimport {cvrSchema, type ShardID} from '../../types/shards.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {Service} from '../service.ts';\n\nconst MINUTE = 60 * 1000;\nconst DAY = 24 * 60 * MINUTE;\n\ntype Options = {\n updateIntervalMs?: number;\n};\n\nexport class ActiveUsersGauge implements Service {\n readonly id = 'active-users-gauge';\n\n readonly #lc: LogContext;\n readonly #db: PostgresDB;\n readonly #schema: string;\n readonly #updateIntervalMs: number;\n readonly #state = new RunningState('active-users-gauge');\n\n // latest computed value exposed via the observable gauge callback\n #
|
|
1
|
+
{"version":3,"file":"active-users-gauge.js","sources":["../../../../../../zero-cache/src/services/view-syncer/active-users-gauge.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {must} from '../../../../shared/src/must.ts';\nimport {mapValues} from '../../../../shared/src/objects.ts';\nimport {\n setActiveUsersGetter,\n type ActiveUsers,\n} from '../../server/anonymous-otel-start.ts';\nimport type {PostgresDB} from '../../types/pg.ts';\nimport {cvrSchema, type ShardID} from '../../types/shards.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {Service} from '../service.ts';\n\nconst MINUTE = 60 * 1000;\nconst DAY = 24 * 60 * MINUTE;\n\ntype Options = {\n updateIntervalMs?: number;\n};\n\nexport class ActiveUsersGauge implements Service {\n readonly id = 'active-users-gauge';\n\n readonly #lc: LogContext;\n readonly #db: PostgresDB;\n readonly #schema: string;\n readonly #updateIntervalMs: number;\n readonly #state = new RunningState('active-users-gauge');\n readonly #setActiveUsersGetter: typeof setActiveUsersGetter;\n\n // latest computed value exposed via the observable gauge callback\n #lastActiveUsers: ActiveUsers | undefined;\n\n constructor(\n lc: LogContext,\n db: PostgresDB,\n shard: ShardID,\n opts: Options = {},\n setActiveUsersGetterFn = setActiveUsersGetter,\n ) {\n this.#lc = lc;\n this.#db = db;\n this.#schema = cvrSchema(shard);\n this.#updateIntervalMs = opts.updateIntervalMs ?? 60 * 1000; // default 1 minute\n this.#setActiveUsersGetter = setActiveUsersGetterFn;\n }\n\n async run(): Promise<void> {\n while (this.#state.shouldRun()) {\n try {\n const now = Date.now();\n const since30day = now - DAY * 30;\n const since7day = now - DAY * 7;\n const since1day = now - DAY;\n\n // This query performs a single scan over the `profile_ids_last_active`\n // index to compute aggregated results for all of our active user\n // metric variants.\n //\n // The eventually-correct metrics are `users_#da` which count distinct\n // profileIDs produced by the zero-client (i.e. starting with 'p').\n // The `users_#da_legacy` metrics include back-filled profileIDs (which\n // start with `cg`) and will over-count users on apps using memstore.\n const [actives] = await this.#db<[ActiveUsers]> /*sql*/ `\n SELECT \n COUNT(*) FILTER (WHERE \"lastActive\" >= ${since1day}) AS active_users_last_day,\n COUNT(DISTINCT(\"profileID\")) FILTER (WHERE \"lastActive\" >= ${since1day} AND starts_with(\"profileID\", 'p')) AS users_1da,\n COUNT(DISTINCT(\"profileID\")) FILTER (WHERE \"lastActive\" >= ${since7day} AND starts_with(\"profileID\", 'p')) AS users_7da,\n COUNT(DISTINCT(\"profileID\")) FILTER (WHERE starts_with(\"profileID\", 'p')) AS users_30da,\n COUNT(DISTINCT(\"profileID\")) FILTER (WHERE \"lastActive\" >= ${since1day}) AS users_1da_legacy,\n COUNT(DISTINCT(\"profileID\")) FILTER (WHERE \"lastActive\" >= ${since7day}) AS users_7da_legacy,\n COUNT(DISTINCT(\"profileID\")) AS users_30da_legacy\n FROM ${this.#db(this.#schema)}.instances\n WHERE \"lastActive\" >= ${since30day}\n `;\n // Determine if the getter needs to be set (i.e. the first time).\n const setGetter = this.#lastActiveUsers === undefined;\n this.#lastActiveUsers = mapValues(actives, bigVal => Number(bigVal));\n\n // Set the getter after the first value is computed\n if (setGetter) {\n this.#setActiveUsersGetter(() => must(this.#lastActiveUsers));\n }\n\n this.#lc.debug?.(`updated active-users gauge`, this.#lastActiveUsers);\n } catch (e) {\n this.#lc.warn?.('error updating active-users gauge', e);\n }\n\n await this.#state.sleep(this.#updateIntervalMs);\n }\n }\n\n stop(): Promise<void> {\n this.#state.stop(this.#lc);\n return this.#state.stopped();\n }\n}\n"],"names":[],"mappings":";;;;;AAYA,MAAM,SAAS,KAAK;AACpB,MAAM,MAAM,KAAK,KAAK;AAMf,MAAM,iBAAoC;AAAA,EACtC,KAAK;AAAA,EAEL;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,IAAI,aAAa,oBAAoB;AAAA,EAC9C;AAAA;AAAA,EAGT;AAAA,EAEA,YACE,IACA,IACA,OACA,OAAgB,CAAA,GAChB,yBAAyB,sBACzB;AACA,SAAK,MAAM;AACX,SAAK,MAAM;AACX,SAAK,UAAU,UAAU,KAAK;AAC9B,SAAK,oBAAoB,KAAK,oBAAoB,KAAK;AACvD,SAAK,wBAAwB;AAAA,EAC/B;AAAA,EAEA,MAAM,MAAqB;AACzB,WAAO,KAAK,OAAO,aAAa;AAC9B,UAAI;AACF,cAAM,MAAM,KAAK,IAAA;AACjB,cAAM,aAAa,MAAM,MAAM;AAC/B,cAAM,YAAY,MAAM,MAAM;AAC9B,cAAM,YAAY,MAAM;AAUxB,cAAM,CAAC,OAAO,IAAI,MAAM,KAAK;AAAA;AAAA,qDAEgB,SAAS;AAAA,yEACW,SAAS;AAAA,yEACT,SAAS;AAAA;AAAA,yEAET,SAAS;AAAA,yEACT,SAAS;AAAA;AAAA,mBAE/D,KAAK,IAAI,KAAK,OAAO,CAAC;AAAA,oCACL,UAAU;AAAA;AAGtC,cAAM,YAAY,KAAK,qBAAqB;AAC5C,aAAK,mBAAmB,UAAU,SAAS,CAAA,WAAU,OAAO,MAAM,CAAC;AAGnE,YAAI,WAAW;AACb,eAAK,sBAAsB,MAAM,KAAK,KAAK,gBAAgB,CAAC;AAAA,QAC9D;AAEA,aAAK,IAAI,QAAQ,8BAA8B,KAAK,gBAAgB;AAAA,MACtE,SAAS,GAAG;AACV,aAAK,IAAI,OAAO,qCAAqC,CAAC;AAAA,MACxD;AAEA,YAAM,KAAK,OAAO,MAAM,KAAK,iBAAiB;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,OAAsB;AACpB,SAAK,OAAO,KAAK,KAAK,GAAG;AACzB,WAAO,KAAK,OAAO,QAAA;AAAA,EACrB;AACF;"}
|
|
@@ -10,7 +10,7 @@ type Options = {
|
|
|
10
10
|
export declare class CVRPurger implements Service {
|
|
11
11
|
#private;
|
|
12
12
|
readonly id = "reaper";
|
|
13
|
-
constructor(lc: LogContext, db: PostgresDB, shard: ShardID, { inactivityThresholdMs, initialBatchSize, initialIntervalMs }: Options);
|
|
13
|
+
constructor(lc: LogContext, db: PostgresDB, shard: ShardID, { inactivityThresholdMs, initialBatchSize, initialIntervalMs }: Options, tombstonePurgeThreshold?: number);
|
|
14
14
|
run(): Promise<void>;
|
|
15
15
|
purgeInactiveCVRs(maxCVRs: number): Promise<{
|
|
16
16
|
purged: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-purger.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-purger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAA0B,KAAK,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cvr-purger.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-purger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAA0B,KAAK,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAY,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAQ3C,KAAK,OAAO,GAAG;IACb,qBAAqB,EAAE,MAAM,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,qBAAa,SAAU,YAAW,OAAO;;IACvC,QAAQ,CAAC,EAAE,YAAY;gBAYrB,EAAE,EAAE,UAAU,EACd,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,EAAC,qBAAqB,EAAE,gBAAgB,EAAE,iBAAiB,EAAC,EAAE,OAAO,EACrE,uBAAuB,SAA4B;IAc/C,GAAG;IAgDT,iBAAiB,CACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC;IAgF/C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAItB"}
|
|
@@ -5,20 +5,26 @@ import { cvrSchema } from "../../types/shards.js";
|
|
|
5
5
|
import { RunningState } from "../running-state.js";
|
|
6
6
|
const MINUTE = 60 * 1e3;
|
|
7
7
|
const MAX_PURGE_INTERVAL_MS = 16 * MINUTE;
|
|
8
|
+
const TOMBSTONE_PURGE_THRESHOLD = 31 * 24 * 60 * 60 * 1e3;
|
|
8
9
|
class CVRPurger {
|
|
9
10
|
id = "reaper";
|
|
10
11
|
#lc;
|
|
11
12
|
#db;
|
|
12
13
|
#schema;
|
|
13
14
|
#inactivityThresholdMs;
|
|
15
|
+
#tombstonePurgeThresholdMs;
|
|
14
16
|
#initialBatchSize;
|
|
15
17
|
#initialIntervalMs;
|
|
16
18
|
#state = new RunningState("reaper");
|
|
17
|
-
constructor(lc, db, shard, { inactivityThresholdMs, initialBatchSize, initialIntervalMs }) {
|
|
19
|
+
constructor(lc, db, shard, { inactivityThresholdMs, initialBatchSize, initialIntervalMs }, tombstonePurgeThreshold = TOMBSTONE_PURGE_THRESHOLD) {
|
|
18
20
|
this.#lc = lc;
|
|
19
21
|
this.#db = db;
|
|
20
22
|
this.#schema = cvrSchema(shard);
|
|
21
23
|
this.#inactivityThresholdMs = inactivityThresholdMs;
|
|
24
|
+
this.#tombstonePurgeThresholdMs = Math.max(
|
|
25
|
+
tombstonePurgeThreshold,
|
|
26
|
+
inactivityThresholdMs
|
|
27
|
+
);
|
|
22
28
|
this.#initialBatchSize = initialBatchSize;
|
|
23
29
|
this.#initialIntervalMs = initialIntervalMs;
|
|
24
30
|
}
|
|
@@ -61,33 +67,51 @@ class CVRPurger {
|
|
|
61
67
|
purgeInactiveCVRs(maxCVRs) {
|
|
62
68
|
return this.#db.begin(READ_COMMITTED, async (sql) => {
|
|
63
69
|
disableStatementTimeout(sql);
|
|
64
|
-
const
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
const threshold = now - this.#inactivityThresholdMs;
|
|
72
|
+
const tombstonePurgeThreshold = now - this.#tombstonePurgeThresholdMs;
|
|
65
73
|
const ids = (await sql`
|
|
66
74
|
SELECT "clientGroupID" FROM ${sql(this.#schema)}.instances
|
|
67
|
-
WHERE "lastActive" < ${threshold}
|
|
75
|
+
WHERE NOT "deleted" AND "lastActive" < ${threshold}
|
|
68
76
|
ORDER BY "lastActive" ASC
|
|
69
77
|
LIMIT ${maxCVRs}
|
|
70
78
|
FOR UPDATE SKIP LOCKED
|
|
71
79
|
`.values()).flat();
|
|
72
80
|
if (ids.length > 0) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
].map(
|
|
82
|
-
(table) => sql`
|
|
81
|
+
const stmts = [
|
|
82
|
+
"desires",
|
|
83
|
+
"queries",
|
|
84
|
+
"clients",
|
|
85
|
+
"rows",
|
|
86
|
+
"rowsVersion"
|
|
87
|
+
].map(
|
|
88
|
+
(table) => sql`
|
|
83
89
|
DELETE FROM ${sql(this.#schema)}.${sql(table)}
|
|
84
90
|
WHERE "clientGroupID" IN ${sql(ids)}`.execute()
|
|
85
|
-
)
|
|
86
91
|
);
|
|
92
|
+
stmts.push(
|
|
93
|
+
sql`
|
|
94
|
+
UPDATE ${sql(this.#schema)}.instances
|
|
95
|
+
SET "deleted" = TRUE,
|
|
96
|
+
"version" = '00',
|
|
97
|
+
"ttlClock" = 0,
|
|
98
|
+
"replicaVersion" = NULL,
|
|
99
|
+
"owner" = NULL,
|
|
100
|
+
"grantedAt" = NULL,
|
|
101
|
+
"clientSchema" = NULL
|
|
102
|
+
WHERE "clientGroupID" IN ${sql(ids)}`.execute()
|
|
103
|
+
);
|
|
104
|
+
stmts.push(
|
|
105
|
+
sql`
|
|
106
|
+
DELETE FROM ${sql(this.#schema)}.instances
|
|
107
|
+
WHERE "deleted" AND "lastActive" < ${tombstonePurgeThreshold}
|
|
108
|
+
`.execute()
|
|
109
|
+
);
|
|
110
|
+
await Promise.all(stmts);
|
|
87
111
|
}
|
|
88
112
|
const [{ remaining }] = await sql`
|
|
89
113
|
SELECT COUNT(*) AS remaining FROM ${sql(this.#schema)}.instances
|
|
90
|
-
WHERE "lastActive" < ${threshold}
|
|
114
|
+
WHERE NOT "deleted" AND "lastActive" < ${threshold}
|
|
91
115
|
`;
|
|
92
116
|
return { purged: ids.length, remaining: Number(remaining) };
|
|
93
117
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-purger.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-purger.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport {READ_COMMITTED} from '../../db/mode-enum.ts';\nimport {disableStatementTimeout, type PostgresDB} from '../../types/pg.ts';\nimport {cvrSchema, type ShardID} from '../../types/shards.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {Service} from '../service.ts';\n\nconst MINUTE = 60 * 1000;\nconst MAX_PURGE_INTERVAL_MS = 16 * MINUTE;\n\ntype Options = {\n inactivityThresholdMs: number;\n initialBatchSize: number;\n initialIntervalMs: number;\n};\n\nexport class CVRPurger implements Service {\n readonly id = 'reaper';\n\n readonly #lc: LogContext;\n readonly #db: PostgresDB;\n readonly #schema: string;\n readonly #inactivityThresholdMs: number;\n readonly #initialBatchSize: number;\n readonly #initialIntervalMs: number;\n readonly #state = new RunningState('reaper');\n\n constructor(\n lc: LogContext,\n db: PostgresDB,\n shard: ShardID,\n {inactivityThresholdMs, initialBatchSize, initialIntervalMs}: Options,\n ) {\n this.#lc = lc;\n this.#db = db;\n this.#schema = cvrSchema(shard);\n this.#inactivityThresholdMs = inactivityThresholdMs;\n this.#initialBatchSize = initialBatchSize;\n this.#initialIntervalMs = initialIntervalMs;\n }\n\n async run() {\n let purgeable: number | undefined;\n let maxCVRsPerPurge = this.#initialBatchSize;\n let purgeInterval = this.#initialIntervalMs;\n\n if (this.#initialBatchSize === 0) {\n this.#lc.warn?.(\n `CVR garbage collection is disabled (initialBatchSize = 0)`,\n );\n // Do nothing and just wait to be stopped.\n await this.#state.stopped();\n } else {\n this.#lc.info?.(\n `running cvr-purger with`,\n await this.#db`SHOW statement_timeout`,\n );\n }\n\n while (this.#state.shouldRun()) {\n try {\n const start = performance.now();\n const {purged, remaining} =\n await this.purgeInactiveCVRs(maxCVRsPerPurge);\n\n if (purgeable !== undefined && remaining > purgeable) {\n // If the number of purgeable CVRs has grown even after the purge,\n // increase the number purged per round to achieve a steady state.\n maxCVRsPerPurge += this.#initialBatchSize;\n this.#lc.info?.(`increased CVRs per purge to ${maxCVRsPerPurge}`);\n }\n purgeable = remaining;\n\n purgeInterval =\n purgeable > 0\n ? this.#initialIntervalMs\n : Math.min(purgeInterval * 2, MAX_PURGE_INTERVAL_MS);\n const elapsed = performance.now() - start;\n this.#lc.info?.(\n `purged ${purged} inactive CVRs (${elapsed.toFixed(2)} ms). Next purge in ${purgeInterval} ms`,\n );\n await this.#state.sleep(purgeInterval);\n } catch (e) {\n this.#lc.warn?.(`error encountered while garbage collecting CVRs`, e);\n }\n }\n }\n\n // Exported for testing.\n purgeInactiveCVRs(\n maxCVRs: number,\n ): Promise<{purged: number; remaining: number}> {\n return this.#db.begin(READ_COMMITTED, async sql => {\n disableStatementTimeout(sql);\n\n const
|
|
1
|
+
{"version":3,"file":"cvr-purger.js","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-purger.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport {READ_COMMITTED} from '../../db/mode-enum.ts';\nimport {disableStatementTimeout, type PostgresDB} from '../../types/pg.ts';\nimport {cvrSchema, type ShardID} from '../../types/shards.ts';\nimport {RunningState} from '../running-state.ts';\nimport type {Service} from '../service.ts';\n\nconst MINUTE = 60 * 1000;\nconst MAX_PURGE_INTERVAL_MS = 16 * MINUTE;\n\n// Purge tombstones after 31 days to facilitate up to a 30-day actives metric.\nconst TOMBSTONE_PURGE_THRESHOLD = 31 * 24 * 60 * 60 * 1000;\n\ntype Options = {\n inactivityThresholdMs: number;\n initialBatchSize: number;\n initialIntervalMs: number;\n};\n\nexport class CVRPurger implements Service {\n readonly id = 'reaper';\n\n readonly #lc: LogContext;\n readonly #db: PostgresDB;\n readonly #schema: string;\n readonly #inactivityThresholdMs: number;\n readonly #tombstonePurgeThresholdMs: number;\n readonly #initialBatchSize: number;\n readonly #initialIntervalMs: number;\n readonly #state = new RunningState('reaper');\n\n constructor(\n lc: LogContext,\n db: PostgresDB,\n shard: ShardID,\n {inactivityThresholdMs, initialBatchSize, initialIntervalMs}: Options,\n tombstonePurgeThreshold = TOMBSTONE_PURGE_THRESHOLD,\n ) {\n this.#lc = lc;\n this.#db = db;\n this.#schema = cvrSchema(shard);\n this.#inactivityThresholdMs = inactivityThresholdMs;\n this.#tombstonePurgeThresholdMs = Math.max(\n tombstonePurgeThreshold,\n inactivityThresholdMs,\n );\n this.#initialBatchSize = initialBatchSize;\n this.#initialIntervalMs = initialIntervalMs;\n }\n\n async run() {\n let purgeable: number | undefined;\n let maxCVRsPerPurge = this.#initialBatchSize;\n let purgeInterval = this.#initialIntervalMs;\n\n if (this.#initialBatchSize === 0) {\n this.#lc.warn?.(\n `CVR garbage collection is disabled (initialBatchSize = 0)`,\n );\n // Do nothing and just wait to be stopped.\n await this.#state.stopped();\n } else {\n this.#lc.info?.(\n `running cvr-purger with`,\n await this.#db`SHOW statement_timeout`,\n );\n }\n\n while (this.#state.shouldRun()) {\n try {\n const start = performance.now();\n const {purged, remaining} =\n await this.purgeInactiveCVRs(maxCVRsPerPurge);\n\n if (purgeable !== undefined && remaining > purgeable) {\n // If the number of purgeable CVRs has grown even after the purge,\n // increase the number purged per round to achieve a steady state.\n maxCVRsPerPurge += this.#initialBatchSize;\n this.#lc.info?.(`increased CVRs per purge to ${maxCVRsPerPurge}`);\n }\n purgeable = remaining;\n\n purgeInterval =\n purgeable > 0\n ? this.#initialIntervalMs\n : Math.min(purgeInterval * 2, MAX_PURGE_INTERVAL_MS);\n const elapsed = performance.now() - start;\n this.#lc.info?.(\n `purged ${purged} inactive CVRs (${elapsed.toFixed(2)} ms). Next purge in ${purgeInterval} ms`,\n );\n await this.#state.sleep(purgeInterval);\n } catch (e) {\n this.#lc.warn?.(`error encountered while garbage collecting CVRs`, e);\n }\n }\n }\n\n // Exported for testing.\n purgeInactiveCVRs(\n maxCVRs: number,\n ): Promise<{purged: number; remaining: number}> {\n return this.#db.begin(READ_COMMITTED, async sql => {\n disableStatementTimeout(sql);\n\n const now = Date.now();\n const threshold = now - this.#inactivityThresholdMs;\n const tombstonePurgeThreshold = now - this.#tombstonePurgeThresholdMs;\n // Implementation note: `FOR UPDATE` will prevent a syncer from\n // concurrently updating the CVR, since the update also performs\n // a `SELECT ... FOR UPDATE`, instead causing that update to\n // fail, which will cause the client to create a new CVR.\n //\n // `SKIP LOCKED` will skip over CVRs that a syncer is already\n // in the process of updating. In this manner, an in-progress\n // update effectively excludes the CVR from the purge.\n const ids = (\n await sql<{clientGroupID: string}[]>`\n SELECT \"clientGroupID\" FROM ${sql(this.#schema)}.instances\n WHERE NOT \"deleted\" AND \"lastActive\" < ${threshold}\n ORDER BY \"lastActive\" ASC\n LIMIT ${maxCVRs}\n FOR UPDATE SKIP LOCKED\n `.values()\n ).flat();\n\n if (ids.length > 0) {\n // Explicitly delete rows from cvr tables from \"bottom\" up. Relying on\n // foreign key cascading deletes can be suboptimal when the foreign key\n // is not a prefix of the primary key (e.g. the \"desires\" foreign key\n // reference to the \"queries\" table is not a prefix of the \"desires\"\n // primary key).\n const stmts = [\n 'desires',\n 'queries',\n 'clients',\n 'rows',\n 'rowsVersion',\n ].map(table =>\n sql`\n DELETE FROM ${sql(this.#schema)}.${sql(table)} \n WHERE \"clientGroupID\" IN ${sql(ids)}`.execute(),\n );\n // Tombstones are written for the `instances` rows, preserving the\n // \"profileID\" and \"lastActive\" columns for computing usage stats.\n //\n // For backwards compatibility (i.e. older zero-caches that do not\n // check the \"deleted\" column) reset the \"version\" to '00' to trigger\n // the ClientNotFound error via\n // view-syncer.ts:checkClientAndCVRVersions()\n stmts.push(\n sql`\n UPDATE ${sql(this.#schema)}.instances\n SET \"deleted\" = TRUE, \n \"version\" = '00', \n \"ttlClock\" = 0,\n \"replicaVersion\" = NULL, \n \"owner\" = NULL,\n \"grantedAt\" = NULL,\n \"clientSchema\" = NULL\n WHERE \"clientGroupID\" IN ${sql(ids)}`.execute(),\n );\n // Tombstone rows are deleted after the tombstonePurgeThreshold.\n stmts.push(\n sql`\n DELETE FROM ${sql(this.#schema)}.instances\n WHERE \"deleted\" AND \"lastActive\" < ${tombstonePurgeThreshold}\n `.execute(),\n );\n await Promise.all(stmts);\n }\n\n const [{remaining}] = await sql<[{remaining: bigint}]>`\n SELECT COUNT(*) AS remaining FROM ${sql(this.#schema)}.instances\n WHERE NOT \"deleted\" AND \"lastActive\" < ${threshold}\n `;\n\n return {purged: ids.length, remaining: Number(remaining)};\n });\n }\n\n stop(): Promise<void> {\n this.#state.stop(this.#lc);\n return promiseVoid;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -52,7 +52,7 @@ export declare class CVRStore {
|
|
|
52
52
|
* `undefined`.
|
|
53
53
|
*/
|
|
54
54
|
getTTLClock(): Promise<TTLClock | undefined>;
|
|
55
|
-
putInstance({ version, replicaVersion, lastActive, clientSchema, ttlClock, }: Pick<CVRSnapshot, 'version' | 'replicaVersion' | 'lastActive' | 'clientSchema' | 'ttlClock'>): void;
|
|
55
|
+
putInstance({ version, replicaVersion, lastActive, clientSchema, profileID, ttlClock, }: Pick<CVRSnapshot, 'version' | 'replicaVersion' | 'lastActive' | 'clientSchema' | 'profileID' | 'ttlClock'>): void;
|
|
56
56
|
markQueryAsDeleted(version: CVRVersion, queryPatch: QueryPatch): void;
|
|
57
57
|
putQuery(query: QueryRecord): void;
|
|
58
58
|
updateQuery(query: QueryRecord): void;
|
|
@@ -78,6 +78,9 @@ export declare class CVRStore {
|
|
|
78
78
|
* (i.e. by doing a plain `SELECT` rather than a `SELECT ... FOR UPDATE`).
|
|
79
79
|
*/
|
|
80
80
|
export declare function checkVersion(tx: PostgresTransaction, schema: string, clientGroupID: string, expectedCurrentVersion: CVRVersion): Promise<void>;
|
|
81
|
+
export declare class ClientNotFoundError extends ProtocolErrorWithLevel {
|
|
82
|
+
constructor(message: string);
|
|
83
|
+
}
|
|
81
84
|
export declare class ConcurrentModificationException extends ProtocolErrorWithLevel {
|
|
82
85
|
readonly name = "ConcurrentModificationException";
|
|
83
86
|
constructor(expectedVersion: string, actualVersion: string);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAiBjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+CAA+C,CAAC;AAKnF,OAAO,EAAC,sBAAsB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAY,KAAK,OAAO,EAAiB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAQ,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAC,GAAG,EAAE,WAAW,EAAC,MAAM,UAAU,CAAC;AAE/C,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,KAAK,YAAY,EAGjB,KAAK,UAAU,EAGf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,KAAK,EACV,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,QAAQ,EAGd,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAwDF,qBAAa,QAAQ;;gBA4BjB,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,UAAU,EAKjB,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,EACjC,qBAAqB,SAA2B,EAChD,eAAe,SAAoB,EACnC,yBAAyB,SAAM,EAAE,qBAAqB;IACtD,YAAY,oBAAa;IA0B3B,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;
|
|
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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"}
|
|
@@ -118,11 +118,9 @@ class CVRStore {
|
|
|
118
118
|
return result;
|
|
119
119
|
}
|
|
120
120
|
assert(err);
|
|
121
|
-
throw new
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
origin: ZeroCache
|
|
125
|
-
});
|
|
121
|
+
throw new ClientNotFoundError(
|
|
122
|
+
`max attempts exceeded waiting for CVR@${err.cvrVersion} to catch up from ${err.rowsVersion}`
|
|
123
|
+
);
|
|
126
124
|
});
|
|
127
125
|
}
|
|
128
126
|
async #load(lc, lastConnectTime) {
|
|
@@ -137,7 +135,8 @@ class CVRStore {
|
|
|
137
135
|
replicaVersion: null,
|
|
138
136
|
clients: {},
|
|
139
137
|
queries: {},
|
|
140
|
-
clientSchema: null
|
|
138
|
+
clientSchema: null,
|
|
139
|
+
profileID: null
|
|
141
140
|
};
|
|
142
141
|
const [instance, clientsRows, queryRows, desiresRows] = await this.#db.begin(READONLY, (tx) => [
|
|
143
142
|
tx`SELECT cvr."version",
|
|
@@ -147,6 +146,8 @@ class CVRStore {
|
|
|
147
146
|
"owner",
|
|
148
147
|
"grantedAt",
|
|
149
148
|
"clientSchema",
|
|
149
|
+
"profileID",
|
|
150
|
+
"deleted",
|
|
150
151
|
rows."version" as "rowsVersion"
|
|
151
152
|
FROM ${this.#cvr("instances")} AS cvr
|
|
152
153
|
LEFT JOIN ${this.#cvr("rowsVersion")} AS rows
|
|
@@ -176,7 +177,8 @@ class CVRStore {
|
|
|
176
177
|
ttlClock: ttlClockFromNumber(0),
|
|
177
178
|
// TTL clock starts at 0 for new instances
|
|
178
179
|
replicaVersion: null,
|
|
179
|
-
clientSchema: null
|
|
180
|
+
clientSchema: null,
|
|
181
|
+
profileID: null
|
|
180
182
|
});
|
|
181
183
|
} else {
|
|
182
184
|
assert(instance.length === 1);
|
|
@@ -188,8 +190,15 @@ class CVRStore {
|
|
|
188
190
|
owner,
|
|
189
191
|
grantedAt,
|
|
190
192
|
rowsVersion,
|
|
191
|
-
clientSchema
|
|
193
|
+
clientSchema,
|
|
194
|
+
profileID,
|
|
195
|
+
deleted
|
|
192
196
|
} = instance[0];
|
|
197
|
+
if (deleted) {
|
|
198
|
+
throw new ClientNotFoundError(
|
|
199
|
+
"Client has been purged due to inactivity"
|
|
200
|
+
);
|
|
201
|
+
}
|
|
193
202
|
if (owner !== this.#taskID) {
|
|
194
203
|
if ((grantedAt ?? 0) > lastConnectTime) {
|
|
195
204
|
throw new OwnershipError(owner, grantedAt, lastConnectTime);
|
|
@@ -211,6 +220,7 @@ class CVRStore {
|
|
|
211
220
|
cvr.lastActive = lastActive;
|
|
212
221
|
cvr.ttlClock = ttlClock;
|
|
213
222
|
cvr.replicaVersion = replicaVersion;
|
|
223
|
+
cvr.profileID = profileID;
|
|
214
224
|
try {
|
|
215
225
|
cvr.clientSchema = clientSchema === null ? null : parse(clientSchema, clientSchemaSchema);
|
|
216
226
|
} catch (e) {
|
|
@@ -309,6 +319,7 @@ class CVRStore {
|
|
|
309
319
|
replicaVersion,
|
|
310
320
|
lastActive,
|
|
311
321
|
clientSchema,
|
|
322
|
+
profileID,
|
|
312
323
|
ttlClock
|
|
313
324
|
}) {
|
|
314
325
|
this.#writes.add({
|
|
@@ -322,7 +333,8 @@ class CVRStore {
|
|
|
322
333
|
replicaVersion,
|
|
323
334
|
owner: this.#taskID,
|
|
324
335
|
grantedAt: lastConnectTime,
|
|
325
|
-
clientSchema
|
|
336
|
+
clientSchema,
|
|
337
|
+
profileID
|
|
326
338
|
};
|
|
327
339
|
return tx`
|
|
328
340
|
INSERT INTO ${this.#cvr("instances")} ${tx(change)}
|
|
@@ -697,6 +709,15 @@ async function checkVersion(tx, schema, clientGroupID, expectedCurrentVersion) {
|
|
|
697
709
|
throw new ConcurrentModificationException(expected, version2);
|
|
698
710
|
}
|
|
699
711
|
}
|
|
712
|
+
class ClientNotFoundError extends ProtocolErrorWithLevel {
|
|
713
|
+
constructor(message) {
|
|
714
|
+
super({
|
|
715
|
+
kind: ClientNotFound,
|
|
716
|
+
message,
|
|
717
|
+
origin: ZeroCache
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
700
721
|
class ConcurrentModificationException extends ProtocolErrorWithLevel {
|
|
701
722
|
name = "ConcurrentModificationException";
|
|
702
723
|
constructor(expectedVersion, actualVersion) {
|
|
@@ -750,6 +771,7 @@ class RowsVersionBehindError extends Error {
|
|
|
750
771
|
}
|
|
751
772
|
export {
|
|
752
773
|
CVRStore,
|
|
774
|
+
ClientNotFoundError,
|
|
753
775
|
ConcurrentModificationException,
|
|
754
776
|
InvalidClientSchemaError,
|
|
755
777
|
OwnershipError,
|