@rocicorp/zero 0.26.0-canary.0 → 0.26.0-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/shared/src/custom-key-map.d.ts +4 -4
- package/out/shared/src/custom-key-map.d.ts.map +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/iterables.d.ts +6 -8
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +13 -7
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/options.d.ts +1 -0
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +5 -1
- package/out/shared/src/options.js.map +1 -1
- package/out/zero/package.json.js +1 -1
- package/out/zero/src/zero-cache-dev.js +7 -3
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +10 -1
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +27 -7
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/observability/events.d.ts.map +1 -1
- package/out/zero-cache/src/observability/events.js +15 -5
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +10 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +22 -4
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +0 -4
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -10
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +8 -2
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +1 -14
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js +8 -1
- package/out/zero-cache/src/services/change-source/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +5 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +16 -5
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +3 -1
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config.yml +1 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +4 -4
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +9 -24
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +1 -2
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +51 -12
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +4 -3
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -2
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +36 -31
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +5 -6
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +5 -23
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +6 -4
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +1 -8
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -11
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +2 -10
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -2
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +40 -42
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +0 -1
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js +0 -2
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +2 -5
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +1 -4
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-client/src/client/context.js +1 -0
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts +2 -4
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +1 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +7 -0
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js +9 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +1 -0
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +41 -2
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +9 -0
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -0
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.js +1 -0
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/mutate/mutator.js +4 -4
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/query/create-builder.js +3 -5
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/query-registry.js +4 -4
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/package.json +3 -3
- package/out/zero-cache/src/types/schema-versions.d.ts +0 -12
- package/out/zero-cache/src/types/schema-versions.d.ts.map +0 -1
- package/out/zero-cache/src/types/schema-versions.js +0 -28
- package/out/zero-cache/src/types/schema-versions.js.map +0 -1
|
@@ -1,64 +1,70 @@
|
|
|
1
1
|
import { jsonObjectSchema, parse as parse$1, stringify } from "../../../../../shared/src/bigint-json.js";
|
|
2
2
|
import { literalUnion, parse } from "../../../../../shared/src/valita.js";
|
|
3
3
|
import { normalizedKeyOrder } from "../../../types/row-key.js";
|
|
4
|
-
import { object, string } from "@badrap/valita";
|
|
4
|
+
import { object, string, number } from "@badrap/valita";
|
|
5
5
|
const SET_OP = "s";
|
|
6
6
|
const DEL_OP = "d";
|
|
7
7
|
const TRUNCATE_OP = "t";
|
|
8
8
|
const RESET_OP = "r";
|
|
9
9
|
const CREATE_CHANGELOG_SCHEMA = (
|
|
10
10
|
// stateVersion : a.k.a. row version
|
|
11
|
+
// pos : order in which to process the change (within the version)
|
|
11
12
|
// table : The table associated with the change
|
|
12
|
-
// rowKey : JSON row key for a row change. For table-wide changes
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
13
|
+
// rowKey : JSON row key for a row change. For table-wide changes RESET
|
|
14
|
+
// and TRUNCATE, there is no associated row; instead, `pos` is
|
|
15
|
+
// set to -1 and the rowKey is set to the stateVersion,
|
|
16
|
+
// guaranteeing when attempting to process the transaction,
|
|
17
|
+
// the pipeline is reset (and the change log traversal
|
|
18
|
+
// aborted).
|
|
19
|
+
// op : 's' for set (insert/update)
|
|
20
|
+
// : 'd' for delete
|
|
20
21
|
// : 'r' for table reset (schema change)
|
|
21
|
-
//
|
|
22
|
-
//
|
|
22
|
+
// : 't' for table truncation (which also resets the pipeline)
|
|
23
|
+
//
|
|
24
|
+
// Naming note: To maintain compatibility between a new replication-manager
|
|
25
|
+
// and old view-syncers, the previous _zero.changeLog table is preserved
|
|
26
|
+
// and its replacement given a new name "changeLog2".
|
|
23
27
|
`
|
|
24
|
-
CREATE TABLE "_zero.
|
|
28
|
+
CREATE TABLE "_zero.changeLog2" (
|
|
25
29
|
"stateVersion" TEXT NOT NULL,
|
|
30
|
+
"pos" INT NOT NULL,
|
|
26
31
|
"table" TEXT NOT NULL,
|
|
27
|
-
"rowKey" TEXT,
|
|
32
|
+
"rowKey" TEXT NOT NULL,
|
|
28
33
|
"op" TEXT NOT NULL,
|
|
29
|
-
PRIMARY KEY("stateVersion", "
|
|
34
|
+
PRIMARY KEY("stateVersion", "pos"),
|
|
30
35
|
UNIQUE("table", "rowKey")
|
|
31
36
|
)
|
|
32
37
|
`
|
|
33
38
|
);
|
|
34
39
|
const changeLogEntrySchema = object({
|
|
35
40
|
stateVersion: string(),
|
|
41
|
+
pos: number(),
|
|
36
42
|
table: string(),
|
|
37
|
-
rowKey: string()
|
|
43
|
+
rowKey: string(),
|
|
38
44
|
op: literalUnion(SET_OP, DEL_OP, TRUNCATE_OP, RESET_OP)
|
|
39
45
|
}).map((val) => ({
|
|
40
46
|
...val,
|
|
41
|
-
// Note: the
|
|
42
|
-
rowKey: val.
|
|
47
|
+
// Note: sets the rowKey to `null` for table-wide ops / resets
|
|
48
|
+
rowKey: val.op === "t" || val.op === "r" ? null : parse(parse$1(val.rowKey), jsonObjectSchema)
|
|
43
49
|
}));
|
|
44
50
|
function initChangeLog(db) {
|
|
45
51
|
db.exec(CREATE_CHANGELOG_SCHEMA);
|
|
46
52
|
}
|
|
47
|
-
function logSetOp(db, version, table, row) {
|
|
48
|
-
return logRowOp(db, version, table, row, SET_OP);
|
|
53
|
+
function logSetOp(db, version, pos, table, row) {
|
|
54
|
+
return logRowOp(db, version, pos, table, row, SET_OP);
|
|
49
55
|
}
|
|
50
|
-
function logDeleteOp(db, version, table, row) {
|
|
51
|
-
return logRowOp(db, version, table, row, DEL_OP);
|
|
56
|
+
function logDeleteOp(db, version, pos, table, row) {
|
|
57
|
+
return logRowOp(db, version, pos, table, row, DEL_OP);
|
|
52
58
|
}
|
|
53
|
-
function logRowOp(db, version, table, row, op) {
|
|
59
|
+
function logRowOp(db, version, pos, table, row, op) {
|
|
54
60
|
const rowKey = stringify(normalizedKeyOrder(row));
|
|
55
61
|
db.run(
|
|
56
62
|
`
|
|
57
|
-
INSERT OR REPLACE INTO "_zero.
|
|
58
|
-
(stateVersion, "table", rowKey, op)
|
|
59
|
-
VALUES (@version, @table, JSON(@rowKey), @op)
|
|
63
|
+
INSERT OR REPLACE INTO "_zero.changeLog2"
|
|
64
|
+
(stateVersion, pos, "table", rowKey, op)
|
|
65
|
+
VALUES (@version, @pos, @table, JSON(@rowKey), @op)
|
|
60
66
|
`,
|
|
61
|
-
{ version, table, rowKey, op }
|
|
67
|
+
{ version, pos, table, rowKey, op }
|
|
62
68
|
);
|
|
63
69
|
return rowKey;
|
|
64
70
|
}
|
|
@@ -71,18 +77,17 @@ function logResetOp(db, version, table) {
|
|
|
71
77
|
function logTableWideOp(db, version, table, op) {
|
|
72
78
|
db.run(
|
|
73
79
|
`
|
|
74
|
-
DELETE FROM "_zero.
|
|
80
|
+
DELETE FROM "_zero.changeLog2" WHERE stateVersion = ? AND "table" = ?
|
|
75
81
|
`,
|
|
76
82
|
version,
|
|
77
83
|
table
|
|
78
84
|
);
|
|
79
85
|
db.run(
|
|
80
86
|
`
|
|
81
|
-
INSERT OR REPLACE INTO "_zero.
|
|
82
|
-
VALUES (@version, @table, @
|
|
87
|
+
INSERT OR REPLACE INTO "_zero.changeLog2" (stateVersion, pos, "table", rowKey, op)
|
|
88
|
+
VALUES (@version, -1, @table, @version, @op)
|
|
83
89
|
`,
|
|
84
|
-
|
|
85
|
-
{ version, table, rowKey: "", op }
|
|
90
|
+
{ version, table, op }
|
|
86
91
|
);
|
|
87
92
|
}
|
|
88
93
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-log.js","sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"sourcesContent":["import {\n jsonObjectSchema,\n parse,\n stringify,\n} from '../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport type {StatementRunner} from '../../../db/statements.ts';\nimport type {LexiVersion} from '../../../types/lexi-version.ts';\nimport type {LiteRowKey} from '../../../types/lite.ts';\nimport {normalizedKeyOrder} from '../../../types/row-key.ts';\n\n/**\n * The Change Log tracks the last operation (set or delete) for each row in the\n * data base, ordered by state version; in other words, a cross-table\n * index of row changes ordered by version. This facilitates a minimal \"diff\"\n * of row changes needed to advance a pipeline from one state version to another.\n *\n * The Change Log stores identifiers only, i.e. it does not store contents.\n * A database snapshot at the previous version can be used to query a row's\n * old contents, if any, and the current snapshot can be used to query a row's\n * new contents. (In the common case, the new contents will have just been applied\n * and thus has a high likelihood of being in the SQLite cache.)\n *\n * There are two table-wide operations:\n * - `t` corresponds to the postgres `TRUNCATE` operation\n * - `r` represents any schema (i.e. column) change\n *\n * For both operations, the corresponding row changes are not explicitly included\n * in the change log. The consumer has the option of simulating them be reading\n * from pre- and post- snapshots, or resetting their state entirely with the current\n * snapshot.\n *\n * To achieve the desired ordering semantics when processing tables that have been\n * truncated, reset, and modified, the \"rowKey\" is set to `null` for resets and\n * the empty string `\"\"` for truncates. This means that resets will be encountered\n * before truncates, which will be processed before any subsequent row changes.\n *\n * This ordering is chosen because resets are currently the more \"destructive\" op\n * and result in aborting the processing (and starting from scratch); doing this\n * earlier reduces wasted work.\n */\n\nexport const SET_OP = 's';\nexport const DEL_OP = 'd';\nexport const TRUNCATE_OP = 't';\nexport const RESET_OP = 'r';\n\nconst CREATE_CHANGELOG_SCHEMA =\n // stateVersion : a.k.a. row version\n // table : The table associated with the change\n // rowKey : JSON row key for a row change. For table-wide changes
|
|
1
|
+
{"version":3,"file":"change-log.js","sources":["../../../../../../../zero-cache/src/services/replicator/schema/change-log.ts"],"sourcesContent":["import {\n jsonObjectSchema,\n parse,\n stringify,\n} from '../../../../../shared/src/bigint-json.ts';\nimport * as v from '../../../../../shared/src/valita.ts';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport type {StatementRunner} from '../../../db/statements.ts';\nimport type {LexiVersion} from '../../../types/lexi-version.ts';\nimport type {LiteRowKey} from '../../../types/lite.ts';\nimport {normalizedKeyOrder} from '../../../types/row-key.ts';\n\n/**\n * The Change Log tracks the last operation (set or delete) for each row in the\n * data base, ordered by state version; in other words, a cross-table\n * index of row changes ordered by version. This facilitates a minimal \"diff\"\n * of row changes needed to advance a pipeline from one state version to another.\n *\n * The Change Log stores identifiers only, i.e. it does not store contents.\n * A database snapshot at the previous version can be used to query a row's\n * old contents, if any, and the current snapshot can be used to query a row's\n * new contents. (In the common case, the new contents will have just been applied\n * and thus has a high likelihood of being in the SQLite cache.)\n *\n * There are two table-wide operations:\n * - `t` corresponds to the postgres `TRUNCATE` operation\n * - `r` represents any schema (i.e. column) change\n *\n * For both operations, the corresponding row changes are not explicitly included\n * in the change log. The consumer has the option of simulating them be reading\n * from pre- and post- snapshots, or resetting their state entirely with the current\n * snapshot.\n *\n * To achieve the desired ordering semantics when processing tables that have been\n * truncated, reset, and modified, the \"rowKey\" is set to `null` for resets and\n * the empty string `\"\"` for truncates. This means that resets will be encountered\n * before truncates, which will be processed before any subsequent row changes.\n *\n * This ordering is chosen because resets are currently the more \"destructive\" op\n * and result in aborting the processing (and starting from scratch); doing this\n * earlier reduces wasted work.\n */\n\nexport const SET_OP = 's';\nexport const DEL_OP = 'd';\nexport const TRUNCATE_OP = 't';\nexport const RESET_OP = 'r';\n\nconst CREATE_CHANGELOG_SCHEMA =\n // stateVersion : a.k.a. row version\n // pos : order in which to process the change (within the version)\n // table : The table associated with the change\n // rowKey : JSON row key for a row change. For table-wide changes RESET\n // and TRUNCATE, there is no associated row; instead, `pos` is\n // set to -1 and the rowKey is set to the stateVersion,\n // guaranteeing when attempting to process the transaction,\n // the pipeline is reset (and the change log traversal\n // aborted).\n // op : 's' for set (insert/update)\n // : 'd' for delete\n // : 'r' for table reset (schema change)\n // : 't' for table truncation (which also resets the pipeline)\n //\n // Naming note: To maintain compatibility between a new replication-manager\n // and old view-syncers, the previous _zero.changeLog table is preserved\n // and its replacement given a new name \"changeLog2\".\n `\n CREATE TABLE \"_zero.changeLog2\" (\n \"stateVersion\" TEXT NOT NULL,\n \"pos\" INT NOT NULL,\n \"table\" TEXT NOT NULL,\n \"rowKey\" TEXT NOT NULL,\n \"op\" TEXT NOT NULL,\n PRIMARY KEY(\"stateVersion\", \"pos\"),\n UNIQUE(\"table\", \"rowKey\")\n )\n `;\n\nexport const changeLogEntrySchema = v\n .object({\n stateVersion: v.string(),\n pos: v.number(),\n table: v.string(),\n rowKey: v.string(),\n op: v.literalUnion(SET_OP, DEL_OP, TRUNCATE_OP, RESET_OP),\n })\n .map(val => ({\n ...val,\n // Note: sets the rowKey to `null` for table-wide ops / resets\n rowKey:\n val.op === 't' || val.op === 'r'\n ? null\n : v.parse(parse(val.rowKey), jsonObjectSchema),\n }));\n\nexport type ChangeLogEntry = v.Infer<typeof changeLogEntrySchema>;\n\nexport function initChangeLog(db: Database) {\n db.exec(CREATE_CHANGELOG_SCHEMA);\n}\n\nexport function logSetOp(\n db: StatementRunner,\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n): string {\n return logRowOp(db, version, pos, table, row, SET_OP);\n}\n\nexport function logDeleteOp(\n db: StatementRunner,\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n): string {\n return logRowOp(db, version, pos, table, row, DEL_OP);\n}\n\nfunction logRowOp(\n db: StatementRunner,\n version: LexiVersion,\n pos: number,\n table: string,\n row: LiteRowKey,\n op: string,\n): string {\n const rowKey = stringify(normalizedKeyOrder(row));\n db.run(\n `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" \n (stateVersion, pos, \"table\", rowKey, op)\n VALUES (@version, @pos, @table, JSON(@rowKey), @op)\n `,\n {version, pos, table, rowKey, op},\n );\n return rowKey;\n}\nexport function logTruncateOp(\n db: StatementRunner,\n version: LexiVersion,\n table: string,\n) {\n logTableWideOp(db, version, table, TRUNCATE_OP);\n}\n\nexport function logResetOp(\n db: StatementRunner,\n version: LexiVersion,\n table: string,\n) {\n logTableWideOp(db, version, table, RESET_OP);\n}\n\nfunction logTableWideOp(\n db: StatementRunner,\n version: LexiVersion,\n table: string,\n op: 't' | 'r',\n) {\n // Delete any existing changes for the table (in this version) since the\n // table wide op invalidates them.\n db.run(\n `\n DELETE FROM \"_zero.changeLog2\" WHERE stateVersion = ? AND \"table\" = ?\n `,\n version,\n table,\n );\n\n db.run(\n `\n INSERT OR REPLACE INTO \"_zero.changeLog2\" (stateVersion, pos, \"table\", rowKey, op) \n VALUES (@version, -1, @table, @version, @op)\n `,\n {version, table, op},\n );\n}\n"],"names":["v.object","v.string","v.number","v.literalUnion","v.parse","parse"],"mappings":";;;;AA2CO,MAAM,SAAS;AACf,MAAM,SAAS;AACf,MAAM,cAAc;AACpB,MAAM,WAAW;AAExB,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYK,MAAM,uBAAuBA,OAC1B;AAAA,EACN,cAAcC,OAAE;AAAA,EAChB,KAAKC,OAAE;AAAA,EACP,OAAOD,OAAE;AAAA,EACT,QAAQA,OAAE;AAAA,EACV,IAAIE,aAAe,QAAQ,QAAQ,aAAa,QAAQ;AAC1D,CAAC,EACA,IAAI,CAAA,SAAQ;AAAA,EACX,GAAG;AAAA;AAAA,EAEH,QACE,IAAI,OAAO,OAAO,IAAI,OAAO,MACzB,OACAC,MAAQC,QAAM,IAAI,MAAM,GAAG,gBAAgB;AACnD,EAAE;AAIG,SAAS,cAAc,IAAc;AAC1C,KAAG,KAAK,uBAAuB;AACjC;AAEO,SAAS,SACd,IACA,SACA,KACA,OACA,KACQ;AACR,SAAO,SAAS,IAAI,SAAS,KAAK,OAAO,KAAK,MAAM;AACtD;AAEO,SAAS,YACd,IACA,SACA,KACA,OACA,KACQ;AACR,SAAO,SAAS,IAAI,SAAS,KAAK,OAAO,KAAK,MAAM;AACtD;AAEA,SAAS,SACP,IACA,SACA,KACA,OACA,KACA,IACQ;AACR,QAAM,SAAS,UAAU,mBAAmB,GAAG,CAAC;AAChD,KAAG;AAAA,IACD;AAAA;AAAA;AAAA;AAAA;AAAA,IAKA,EAAC,SAAS,KAAK,OAAO,QAAQ,GAAA;AAAA,EAAE;AAElC,SAAO;AACT;AACO,SAAS,cACd,IACA,SACA,OACA;AACA,iBAAe,IAAI,SAAS,OAAO,WAAW;AAChD;AAEO,SAAS,WACd,IACA,SACA,OACA;AACA,iBAAe,IAAI,SAAS,OAAO,QAAQ;AAC7C;AAEA,SAAS,eACP,IACA,SACA,OACA,IACA;AAGA,KAAG;AAAA,IACD;AAAA;AAAA;AAAA,IAGA;AAAA,IACA;AAAA,EAAA;AAGF,KAAG;AAAA,IACD;AAAA;AAAA;AAAA;AAAA,IAIA,EAAC,SAAS,OAAO,GAAA;AAAA,EAAE;AAEvB;"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
2
|
import type { JSONObject } from '../../../../shared/src/bigint-json.ts';
|
|
3
3
|
import { type JSONObject as SafeJSONObject } from '../../../../shared/src/json.ts';
|
|
4
|
+
import type { ErroredQuery } from '../../../../zero-protocol/src/custom-queries.ts';
|
|
4
5
|
import type { Downstream } from '../../../../zero-protocol/src/down.ts';
|
|
6
|
+
import { type TransformFailedBody } from '../../../../zero-protocol/src/error.ts';
|
|
5
7
|
import type { InspectDownBody } from '../../../../zero-protocol/src/inspect-down.ts';
|
|
6
|
-
import { type SchemaVersions } from '../../types/schema-versions.ts';
|
|
7
8
|
import { type ShardID } from '../../types/shards.ts';
|
|
8
9
|
import type { Subscription } from '../../types/subscription.ts';
|
|
9
10
|
import { type CVRVersion, type DelQueryPatch, type NullableCVRVersion, type PutQueryPatch, type RowID } from './schema/types.ts';
|
|
10
|
-
import type { ErroredQuery } from '../../../../zero-protocol/src/custom-queries.ts';
|
|
11
|
-
import { type TransformFailedBody } from '../../../../zero-protocol/src/error.ts';
|
|
12
11
|
export type PutRowPatch = {
|
|
13
12
|
type: 'row';
|
|
14
13
|
op: 'put';
|
|
@@ -33,7 +32,7 @@ export interface PokeHandler {
|
|
|
33
32
|
end(finalVersion: CVRVersion): Promise<void>;
|
|
34
33
|
}
|
|
35
34
|
/** Wraps PokeHandlers for multiple clients in a single PokeHandler. */
|
|
36
|
-
export declare function startPoke(clients: ClientHandler[], tentativeVersion: CVRVersion
|
|
35
|
+
export declare function startPoke(clients: ClientHandler[], tentativeVersion: CVRVersion): PokeHandler;
|
|
37
36
|
/**
|
|
38
37
|
* Handles a single `ViewSyncer` connection.
|
|
39
38
|
*/
|
|
@@ -41,11 +40,11 @@ export declare class ClientHandler {
|
|
|
41
40
|
#private;
|
|
42
41
|
readonly clientID: string;
|
|
43
42
|
readonly wsID: string;
|
|
44
|
-
constructor(lc: LogContext, clientGroupID: string, clientID: string, wsID: string, shard: ShardID, baseCookie: string | null,
|
|
43
|
+
constructor(lc: LogContext, clientGroupID: string, clientID: string, wsID: string, shard: ShardID, baseCookie: string | null, downstream: Subscription<Downstream>);
|
|
45
44
|
version(): NullableCVRVersion;
|
|
46
45
|
fail(e: unknown): void;
|
|
47
46
|
close(reason: string): void;
|
|
48
|
-
startPoke(tentativeVersion: CVRVersion
|
|
47
|
+
startPoke(tentativeVersion: CVRVersion): PokeHandler;
|
|
49
48
|
sendDeleteClients(lc: LogContext, deletedClientIDs: string[], deletedClientGroupIDs: string[]): Promise<void>;
|
|
50
49
|
sendQueryTransformApplicationErrors(errors: ErroredQuery[]): void;
|
|
51
50
|
sendQueryTransformFailedError(error: TransformFailedBody): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-handler.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/client-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uCAAuC,CAAC;AACtE,OAAO,EAEL,KAAK,UAAU,IAAI,cAAc,EAClC,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"client-handler.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/client-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,24 +3,21 @@ import { assertJSONValue } from "../../../../shared/src/json.js";
|
|
|
3
3
|
import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
|
|
4
4
|
import { parse } from "../../../../shared/src/valita.js";
|
|
5
5
|
import { rowSchema } from "../../../../zero-protocol/src/data.js";
|
|
6
|
+
import { ProtocolError } from "../../../../zero-protocol/src/error.js";
|
|
6
7
|
import { primaryKeyValueRecordSchema } from "../../../../zero-protocol/src/primary-key.js";
|
|
7
8
|
import { mutationResultSchema } from "../../../../zero-protocol/src/push.js";
|
|
8
9
|
import { getOrCreateHistogram, getOrCreateCounter } from "../../observability/metrics.js";
|
|
9
10
|
import { getLogLevel, wrapWithProtocolError } from "../../types/error-with-level.js";
|
|
10
|
-
import { getProtocolErrorIfSchemaVersionNotSupported } from "../../types/schema-versions.js";
|
|
11
11
|
import { upstreamSchema } from "../../types/shards.js";
|
|
12
12
|
import { cookieToVersion, versionToCookie, cmpVersions, versionToNullableCookie } from "./schema/types.js";
|
|
13
|
-
import { ProtocolError } from "../../../../zero-protocol/src/error.js";
|
|
14
13
|
import { object, number, string } from "@badrap/valita";
|
|
15
14
|
const NOOP = {
|
|
16
15
|
addPatch: () => promiseVoid,
|
|
17
16
|
cancel: () => promiseVoid,
|
|
18
17
|
end: () => promiseVoid
|
|
19
18
|
};
|
|
20
|
-
function startPoke(clients, tentativeVersion
|
|
21
|
-
const pokers = clients.map(
|
|
22
|
-
(c) => c.startPoke(tentativeVersion, schemaVersions)
|
|
23
|
-
);
|
|
19
|
+
function startPoke(clients, tentativeVersion) {
|
|
20
|
+
const pokers = clients.map((c) => c.startPoke(tentativeVersion));
|
|
24
21
|
return {
|
|
25
22
|
addPatch: async (patch) => {
|
|
26
23
|
await Promise.allSettled(pokers.map((poker) => poker.addPatch(patch)));
|
|
@@ -43,7 +40,6 @@ class ClientHandler {
|
|
|
43
40
|
#lc;
|
|
44
41
|
#downstream;
|
|
45
42
|
#baseVersion;
|
|
46
|
-
#schemaVersion;
|
|
47
43
|
#pokeTime = getOrCreateHistogram("sync", "poke.time", {
|
|
48
44
|
description: "Time elapsed for each poke transaction. Canceled / noop pokes are excluded.",
|
|
49
45
|
unit: "s"
|
|
@@ -58,7 +54,7 @@ class ClientHandler {
|
|
|
58
54
|
"poke.rows",
|
|
59
55
|
"Count of poked rows."
|
|
60
56
|
);
|
|
61
|
-
constructor(lc, clientGroupID, clientID, wsID, shard, baseCookie,
|
|
57
|
+
constructor(lc, clientGroupID, clientID, wsID, shard, baseCookie, downstream) {
|
|
62
58
|
lc.debug?.("new client handler");
|
|
63
59
|
this.#clientGroupID = clientGroupID;
|
|
64
60
|
this.clientID = clientID;
|
|
@@ -68,7 +64,6 @@ class ClientHandler {
|
|
|
68
64
|
this.#lc = lc;
|
|
69
65
|
this.#downstream = downstream;
|
|
70
66
|
this.#baseVersion = cookieToVersion(baseCookie);
|
|
71
|
-
this.#schemaVersion = schemaVersion;
|
|
72
67
|
}
|
|
73
68
|
version() {
|
|
74
69
|
return this.#baseVersion;
|
|
@@ -88,19 +83,9 @@ class ClientHandler {
|
|
|
88
83
|
this.#lc.debug?.(`view-syncer closing connection: ${reason}`);
|
|
89
84
|
this.#downstream.cancel();
|
|
90
85
|
}
|
|
91
|
-
startPoke(tentativeVersion
|
|
86
|
+
startPoke(tentativeVersion) {
|
|
92
87
|
const pokeID = versionToCookie(tentativeVersion);
|
|
93
88
|
const lc = this.#lc.withContext("pokeID", pokeID);
|
|
94
|
-
if (schemaVersions && this.#schemaVersion) {
|
|
95
|
-
const schemaVersionError = getProtocolErrorIfSchemaVersionNotSupported(
|
|
96
|
-
this.#schemaVersion,
|
|
97
|
-
schemaVersions
|
|
98
|
-
);
|
|
99
|
-
if (schemaVersionError) {
|
|
100
|
-
this.fail(schemaVersionError);
|
|
101
|
-
return NOOP;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
89
|
if (cmpVersions(this.#baseVersion, tentativeVersion) >= 0) {
|
|
105
90
|
lc.info?.(`already caught up, not sending poke.`);
|
|
106
91
|
return NOOP;
|
|
@@ -110,9 +95,6 @@ class ClientHandler {
|
|
|
110
95
|
lc.info?.(`starting poke from ${baseCookie} to ${cookie}`);
|
|
111
96
|
const start = performance.now();
|
|
112
97
|
const pokeStart = { pokeID, baseCookie };
|
|
113
|
-
if (schemaVersions) {
|
|
114
|
-
pokeStart.schemaVersions = schemaVersions;
|
|
115
|
-
}
|
|
116
98
|
let pokeStarted = false;
|
|
117
99
|
let body;
|
|
118
100
|
let partCount = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-handler.js","sources":["../../../../../../zero-cache/src/services/view-syncer/client-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport type {JSONObject} from '../../../../shared/src/bigint-json.ts';\nimport {\n assertJSONValue,\n type JSONObject as SafeJSONObject,\n} from '../../../../shared/src/json.ts';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {Writable} from '../../../../shared/src/writable.ts';\nimport {rowSchema} from '../../../../zero-protocol/src/data.ts';\nimport type {DeleteClientsBody} from '../../../../zero-protocol/src/delete-clients.ts';\nimport type {Downstream} from '../../../../zero-protocol/src/down.ts';\nimport type {InspectDownBody} from '../../../../zero-protocol/src/inspect-down.ts';\nimport type {\n PokePartBody,\n PokeStartBody,\n} from '../../../../zero-protocol/src/poke.ts';\nimport {primaryKeyValueRecordSchema} from '../../../../zero-protocol/src/primary-key.ts';\nimport {mutationResultSchema} from '../../../../zero-protocol/src/push.ts';\nimport type {RowPatchOp} from '../../../../zero-protocol/src/row-patch.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport {\n getLogLevel,\n wrapWithProtocolError,\n} from '../../types/error-with-level.ts';\nimport {\n getProtocolErrorIfSchemaVersionNotSupported,\n type SchemaVersions,\n} from '../../types/schema-versions.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport type {Subscription} from '../../types/subscription.ts';\nimport {\n cmpVersions,\n cookieToVersion,\n versionToCookie,\n versionToNullableCookie,\n type CVRVersion,\n type DelQueryPatch,\n type NullableCVRVersion,\n type PutQueryPatch,\n type RowID,\n} from './schema/types.ts';\nimport type {ErroredQuery} from '../../../../zero-protocol/src/custom-queries.ts';\nimport {\n ProtocolError,\n type TransformFailedBody,\n} from '../../../../zero-protocol/src/error.ts';\n\nexport type PutRowPatch = {\n type: 'row';\n op: 'put';\n id: RowID;\n contents: JSONObject;\n};\n\nexport type DeleteRowPatch = {\n type: 'row';\n op: 'del';\n id: RowID;\n};\n\nexport type RowPatch = PutRowPatch | DeleteRowPatch;\nexport type ConfigPatch = DelQueryPatch | PutQueryPatch;\n\nexport type Patch = ConfigPatch | RowPatch;\n\nexport type PatchToVersion = {\n patch: Patch;\n toVersion: CVRVersion;\n};\n\nexport interface PokeHandler {\n addPatch(patch: PatchToVersion): Promise<void>;\n cancel(): Promise<void>;\n end(finalVersion: CVRVersion): Promise<void>;\n}\n\nconst NOOP: PokeHandler = {\n addPatch: () => promiseVoid,\n cancel: () => promiseVoid,\n end: () => promiseVoid,\n};\n\n/** Wraps PokeHandlers for multiple clients in a single PokeHandler. */\nexport function startPoke(\n clients: ClientHandler[],\n tentativeVersion: CVRVersion,\n schemaVersions?: SchemaVersions, // absent for config-only pokes\n): PokeHandler {\n const pokers = clients.map(c =>\n c.startPoke(tentativeVersion, schemaVersions),\n );\n\n // Promise.allSettled() ensures that a failed (e.g. disconnected) client\n // does not prevent other clients from receiving the pokes. However, the\n // rate (per client group) will be limited by the slowest connection.\n return {\n addPatch: async patch => {\n await Promise.allSettled(pokers.map(poker => poker.addPatch(patch)));\n },\n cancel: async () => {\n await Promise.allSettled(pokers.map(poker => poker.cancel()));\n },\n end: async finalVersion => {\n await Promise.allSettled(pokers.map(poker => poker.end(finalVersion)));\n },\n };\n}\n\n// Semi-arbitrary threshold at which poke body parts are flushed.\n// When row size is being computed, that should be used as a threshold instead.\nconst PART_COUNT_FLUSH_THRESHOLD = 100;\n\n/**\n * Handles a single `ViewSyncer` connection.\n */\nexport class ClientHandler {\n readonly #clientGroupID: string;\n readonly clientID: string;\n readonly wsID: string;\n readonly #zeroClientsTable: string;\n readonly #zeroMutationsTable: string;\n readonly #lc: LogContext;\n readonly #downstream: Subscription<Downstream>;\n #baseVersion: NullableCVRVersion;\n readonly #schemaVersion: number | null;\n\n readonly #pokeTime = getOrCreateHistogram('sync', 'poke.time', {\n description:\n 'Time elapsed for each poke transaction. Canceled / noop pokes are excluded.',\n unit: 's',\n });\n\n readonly #pokeTransactions = getOrCreateCounter(\n 'sync',\n 'poke.transactions',\n 'Count of poke transactions.',\n );\n\n readonly #pokedRows = getOrCreateCounter(\n 'sync',\n 'poke.rows',\n 'Count of poked rows.',\n );\n\n constructor(\n lc: LogContext,\n clientGroupID: string,\n clientID: string,\n wsID: string,\n shard: ShardID,\n baseCookie: string | null,\n schemaVersion: number | null,\n downstream: Subscription<Downstream>,\n ) {\n lc.debug?.('new client handler');\n this.#clientGroupID = clientGroupID;\n this.clientID = clientID;\n this.wsID = wsID;\n this.#zeroClientsTable = `${upstreamSchema(shard)}.clients`;\n this.#zeroMutationsTable = `${upstreamSchema(shard)}.mutations`;\n this.#lc = lc;\n this.#downstream = downstream;\n this.#baseVersion = cookieToVersion(baseCookie);\n this.#schemaVersion = schemaVersion;\n }\n\n version(): NullableCVRVersion {\n return this.#baseVersion;\n }\n\n async #push(msg: Downstream): Promise<void> {\n const {result} = this.#downstream.push(msg);\n await result;\n }\n\n fail(e: unknown) {\n this.#lc[getLogLevel(e)]?.(\n `view-syncer closing connection with error: ${String(e)}`,\n e,\n );\n this.#downstream.fail(wrapWithProtocolError(e));\n }\n\n close(reason: string) {\n this.#lc.debug?.(`view-syncer closing connection: ${reason}`);\n this.#downstream.cancel();\n }\n\n startPoke(\n tentativeVersion: CVRVersion,\n schemaVersions?: SchemaVersions, // absent for config-only pokes\n ): PokeHandler {\n const pokeID = versionToCookie(tentativeVersion);\n const lc = this.#lc.withContext('pokeID', pokeID);\n\n if (schemaVersions && this.#schemaVersion) {\n const schemaVersionError = getProtocolErrorIfSchemaVersionNotSupported(\n this.#schemaVersion,\n schemaVersions,\n );\n\n if (schemaVersionError) {\n this.fail(schemaVersionError);\n return NOOP;\n }\n }\n\n if (cmpVersions(this.#baseVersion, tentativeVersion) >= 0) {\n lc.info?.(`already caught up, not sending poke.`);\n return NOOP;\n }\n\n const baseCookie = versionToNullableCookie(this.#baseVersion);\n const cookie = versionToCookie(tentativeVersion);\n lc.info?.(`starting poke from ${baseCookie} to ${cookie}`);\n\n const start = performance.now();\n\n const pokeStart: PokeStartBody = {pokeID, baseCookie};\n if (schemaVersions) {\n pokeStart.schemaVersions = schemaVersions;\n }\n\n let pokeStarted = false;\n let body: PokePartBody | undefined;\n let partCount = 0;\n const ensureBody = async () => {\n if (!pokeStarted) {\n await this.#push(['pokeStart', pokeStart]);\n pokeStarted = true;\n }\n return (body ??= {pokeID});\n };\n const flushBody = async () => {\n if (body) {\n await this.#push(['pokePart', body]);\n body = undefined;\n partCount = 0;\n }\n };\n\n const addPatch = async (patchToVersion: PatchToVersion) => {\n const {patch, toVersion} = patchToVersion;\n if (cmpVersions(toVersion, this.#baseVersion) <= 0) {\n return;\n }\n const body = await ensureBody();\n\n const {type, op} = patch;\n switch (type) {\n case 'query': {\n const patches = patch.clientID\n ? ((body.desiredQueriesPatches ??= {})[patch.clientID] ??= [])\n : (body.gotQueriesPatch ??= []);\n if (op === 'put') {\n patches.push({op, hash: patch.id});\n } else {\n patches.push({op, hash: patch.id});\n }\n break;\n }\n case 'row':\n if (patch.id.table === this.#zeroClientsTable) {\n this.#updateLMIDs((body.lastMutationIDChanges ??= {}), patch);\n } else if (patch.id.table === this.#zeroMutationsTable) {\n const patches = (body.mutationsPatch ??= []);\n if (op === 'put') {\n const row = v.parse(\n ensureSafeJSON(patch.contents),\n mutationRowSchema,\n 'passthrough',\n );\n patches.push({\n op: 'put',\n mutation: {\n id: {\n clientID: row.clientID,\n id: row.mutationID,\n },\n result: row.result,\n },\n });\n } else {\n const {clientID, mutationID} = patch.id.rowKey;\n assert(\n typeof clientID === 'string',\n 'client id must be a string',\n );\n const id = Number(mutationID);\n assert(\n !Number.isNaN(id) && Number.isFinite(id) && id >= 0,\n 'mutation id must be a finite number',\n );\n patches.push({\n op: 'del',\n id: {\n clientID,\n id,\n },\n });\n }\n } else {\n (body.rowsPatch ??= []).push(makeRowPatch(patch));\n }\n break;\n default:\n unreachable(patch);\n }\n\n if (++partCount >= PART_COUNT_FLUSH_THRESHOLD) {\n await flushBody();\n }\n };\n\n return {\n addPatch: async (patchToVersion: PatchToVersion) => {\n try {\n await addPatch(patchToVersion);\n if (patchToVersion.patch.type === 'row') {\n this.#pokedRows.add(1);\n }\n } catch (e) {\n this.#downstream.fail(wrapWithProtocolError(e));\n }\n },\n\n cancel: async () => {\n if (pokeStarted) {\n await this.#push(['pokeEnd', {pokeID, cookie: '', cancel: true}]);\n }\n },\n\n end: async (finalVersion: CVRVersion) => {\n const cookie = versionToCookie(finalVersion);\n if (!pokeStarted) {\n if (cmpVersions(this.#baseVersion, finalVersion) === 0) {\n return; // Nothing changed and nothing was sent.\n }\n await this.#push(['pokeStart', pokeStart]);\n } else if (cmpVersions(this.#baseVersion, finalVersion) >= 0) {\n // Sanity check: If the poke was started, the finalVersion\n // must be > #baseVersion.\n throw new Error(\n `Patches were sent but finalVersion ${finalVersion} is ` +\n `not greater than baseVersion ${this.#baseVersion}`,\n );\n }\n await flushBody();\n await this.#push(['pokeEnd', {pokeID, cookie}]);\n this.#baseVersion = finalVersion;\n\n const elapsed = performance.now() - start;\n this.#pokeTransactions.add(1);\n this.#pokeTime.record(elapsed / 1000);\n },\n };\n }\n\n async sendDeleteClients(\n lc: LogContext,\n deletedClientIDs: string[],\n deletedClientGroupIDs: string[],\n ) {\n const deleteClientsBody: Writable<DeleteClientsBody> = {};\n if (deletedClientIDs.length > 0) {\n deleteClientsBody.clientIDs = deletedClientIDs;\n }\n if (deletedClientGroupIDs.length > 0) {\n deleteClientsBody.clientGroupIDs = deletedClientGroupIDs;\n }\n lc.debug?.('sending deleteClients', deleteClientsBody);\n await this.#push(['deleteClients', deleteClientsBody]);\n }\n\n sendQueryTransformApplicationErrors(errors: ErroredQuery[]) {\n void this.#push(['transformError', errors]);\n }\n\n sendQueryTransformFailedError(error: TransformFailedBody) {\n this.fail(new ProtocolError(error));\n }\n\n sendInspectResponse(lc: LogContext, response: InspectDownBody): void {\n lc.debug?.('sending inspect response', response);\n this.#downstream.push(['inspect', response]);\n }\n\n #updateLMIDs(lmids: Record<string, number>, patch: RowPatch) {\n if (patch.op === 'put') {\n const row = ensureSafeJSON(patch.contents);\n const {clientGroupID, clientID, lastMutationID} = v.parse(\n row,\n lmidRowSchema,\n 'passthrough',\n );\n if (clientGroupID !== this.#clientGroupID) {\n this.#lc.error?.(\n `Received clients row for wrong clientGroupID. Ignoring.`,\n clientGroupID,\n );\n } else {\n lmids[clientID] = lastMutationID;\n }\n } else {\n // The 'constrain' and 'del' ops for clients can be ignored.\n patch.op satisfies 'constrain' | 'del';\n }\n }\n}\n\n// Note: The {APP_ID}_{SHARD_ID}.clients table is set up in replicator/initial-sync.ts.\nconst lmidRowSchema = v.object({\n clientGroupID: v.string(),\n clientID: v.string(),\n lastMutationID: v.number(), // Actually returned as a bigint, but converted by ensureSafeJSON().\n});\n\nconst mutationRowSchema = v.object({\n clientGroupID: v.string(),\n clientID: v.string(),\n mutationID: v.number(),\n result: mutationResultSchema,\n});\n\nfunction makeRowPatch(patch: RowPatch): RowPatchOp {\n const {\n op,\n id: {table: tableName, rowKey: id},\n } = patch;\n\n switch (op) {\n case 'put':\n return {\n op: 'put',\n tableName,\n value: v.parse(ensureSafeJSON(patch.contents), rowSchema),\n };\n\n case 'del':\n return {\n op,\n tableName,\n id: v.parse(id, primaryKeyValueRecordSchema),\n };\n\n default:\n unreachable(op);\n }\n}\n\n/**\n * Column values of type INT8 are returned as the `bigint` from the\n * Postgres library. These are converted to `number` if they are within\n * the safe Number range, allowing the protocol to support numbers larger\n * than 32-bits. Values outside of the safe number range (e.g. > 2^53) will\n * result in an Error.\n */\nexport function ensureSafeJSON(row: JSONObject): SafeJSONObject {\n const modified = Object.entries(row)\n .filter(([k, v]) => {\n if (typeof v === 'bigint') {\n if (v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) {\n return true; // send this entry onto the next map() step.\n }\n throw new Error(`Value of \"${k}\" exceeds safe Number range (${v})`);\n } else if (typeof v === 'object') {\n assertJSONValue(v);\n }\n return false;\n })\n .map(([k, v]) => [k, Number(v)]);\n\n return modified.length\n ? {...row, ...Object.fromEntries(modified)}\n : (row as SafeJSONObject);\n}\n"],"names":["body","v.parse","cookie","v.object","v.string","v.number","v"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client-handler.js","sources":["../../../../../../zero-cache/src/services/view-syncer/client-handler.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport type {JSONObject} from '../../../../shared/src/bigint-json.ts';\nimport {\n assertJSONValue,\n type JSONObject as SafeJSONObject,\n} from '../../../../shared/src/json.ts';\nimport {promiseVoid} from '../../../../shared/src/resolved-promises.ts';\nimport * as v from '../../../../shared/src/valita.ts';\nimport type {Writable} from '../../../../shared/src/writable.ts';\nimport type {ErroredQuery} from '../../../../zero-protocol/src/custom-queries.ts';\nimport {rowSchema} from '../../../../zero-protocol/src/data.ts';\nimport type {DeleteClientsBody} from '../../../../zero-protocol/src/delete-clients.ts';\nimport type {Downstream} from '../../../../zero-protocol/src/down.ts';\nimport {\n ProtocolError,\n type TransformFailedBody,\n} from '../../../../zero-protocol/src/error.ts';\nimport type {InspectDownBody} from '../../../../zero-protocol/src/inspect-down.ts';\nimport type {\n PokePartBody,\n PokeStartBody,\n} from '../../../../zero-protocol/src/poke.ts';\nimport {primaryKeyValueRecordSchema} from '../../../../zero-protocol/src/primary-key.ts';\nimport {mutationResultSchema} from '../../../../zero-protocol/src/push.ts';\nimport type {RowPatchOp} from '../../../../zero-protocol/src/row-patch.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport {\n getLogLevel,\n wrapWithProtocolError,\n} from '../../types/error-with-level.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport type {Subscription} from '../../types/subscription.ts';\nimport {\n cmpVersions,\n cookieToVersion,\n versionToCookie,\n versionToNullableCookie,\n type CVRVersion,\n type DelQueryPatch,\n type NullableCVRVersion,\n type PutQueryPatch,\n type RowID,\n} from './schema/types.ts';\n\nexport type PutRowPatch = {\n type: 'row';\n op: 'put';\n id: RowID;\n contents: JSONObject;\n};\n\nexport type DeleteRowPatch = {\n type: 'row';\n op: 'del';\n id: RowID;\n};\n\nexport type RowPatch = PutRowPatch | DeleteRowPatch;\nexport type ConfigPatch = DelQueryPatch | PutQueryPatch;\n\nexport type Patch = ConfigPatch | RowPatch;\n\nexport type PatchToVersion = {\n patch: Patch;\n toVersion: CVRVersion;\n};\n\nexport interface PokeHandler {\n addPatch(patch: PatchToVersion): Promise<void>;\n cancel(): Promise<void>;\n end(finalVersion: CVRVersion): Promise<void>;\n}\n\nconst NOOP: PokeHandler = {\n addPatch: () => promiseVoid,\n cancel: () => promiseVoid,\n end: () => promiseVoid,\n};\n\n/** Wraps PokeHandlers for multiple clients in a single PokeHandler. */\nexport function startPoke(\n clients: ClientHandler[],\n tentativeVersion: CVRVersion,\n): PokeHandler {\n const pokers = clients.map(c => c.startPoke(tentativeVersion));\n\n // Promise.allSettled() ensures that a failed (e.g. disconnected) client\n // does not prevent other clients from receiving the pokes. However, the\n // rate (per client group) will be limited by the slowest connection.\n return {\n addPatch: async patch => {\n await Promise.allSettled(pokers.map(poker => poker.addPatch(patch)));\n },\n cancel: async () => {\n await Promise.allSettled(pokers.map(poker => poker.cancel()));\n },\n end: async finalVersion => {\n await Promise.allSettled(pokers.map(poker => poker.end(finalVersion)));\n },\n };\n}\n\n// Semi-arbitrary threshold at which poke body parts are flushed.\n// When row size is being computed, that should be used as a threshold instead.\nconst PART_COUNT_FLUSH_THRESHOLD = 100;\n\n/**\n * Handles a single `ViewSyncer` connection.\n */\nexport class ClientHandler {\n readonly #clientGroupID: string;\n readonly clientID: string;\n readonly wsID: string;\n readonly #zeroClientsTable: string;\n readonly #zeroMutationsTable: string;\n readonly #lc: LogContext;\n readonly #downstream: Subscription<Downstream>;\n #baseVersion: NullableCVRVersion;\n\n readonly #pokeTime = getOrCreateHistogram('sync', 'poke.time', {\n description:\n 'Time elapsed for each poke transaction. Canceled / noop pokes are excluded.',\n unit: 's',\n });\n\n readonly #pokeTransactions = getOrCreateCounter(\n 'sync',\n 'poke.transactions',\n 'Count of poke transactions.',\n );\n\n readonly #pokedRows = getOrCreateCounter(\n 'sync',\n 'poke.rows',\n 'Count of poked rows.',\n );\n\n constructor(\n lc: LogContext,\n clientGroupID: string,\n clientID: string,\n wsID: string,\n shard: ShardID,\n baseCookie: string | null,\n downstream: Subscription<Downstream>,\n ) {\n lc.debug?.('new client handler');\n this.#clientGroupID = clientGroupID;\n this.clientID = clientID;\n this.wsID = wsID;\n this.#zeroClientsTable = `${upstreamSchema(shard)}.clients`;\n this.#zeroMutationsTable = `${upstreamSchema(shard)}.mutations`;\n this.#lc = lc;\n this.#downstream = downstream;\n this.#baseVersion = cookieToVersion(baseCookie);\n }\n\n version(): NullableCVRVersion {\n return this.#baseVersion;\n }\n\n async #push(msg: Downstream): Promise<void> {\n const {result} = this.#downstream.push(msg);\n await result;\n }\n\n fail(e: unknown) {\n this.#lc[getLogLevel(e)]?.(\n `view-syncer closing connection with error: ${String(e)}`,\n e,\n );\n this.#downstream.fail(wrapWithProtocolError(e));\n }\n\n close(reason: string) {\n this.#lc.debug?.(`view-syncer closing connection: ${reason}`);\n this.#downstream.cancel();\n }\n\n startPoke(tentativeVersion: CVRVersion): PokeHandler {\n const pokeID = versionToCookie(tentativeVersion);\n const lc = this.#lc.withContext('pokeID', pokeID);\n\n if (cmpVersions(this.#baseVersion, tentativeVersion) >= 0) {\n lc.info?.(`already caught up, not sending poke.`);\n return NOOP;\n }\n\n const baseCookie = versionToNullableCookie(this.#baseVersion);\n const cookie = versionToCookie(tentativeVersion);\n lc.info?.(`starting poke from ${baseCookie} to ${cookie}`);\n\n const start = performance.now();\n\n const pokeStart: PokeStartBody = {pokeID, baseCookie};\n\n let pokeStarted = false;\n let body: PokePartBody | undefined;\n let partCount = 0;\n const ensureBody = async () => {\n if (!pokeStarted) {\n await this.#push(['pokeStart', pokeStart]);\n pokeStarted = true;\n }\n return (body ??= {pokeID});\n };\n const flushBody = async () => {\n if (body) {\n await this.#push(['pokePart', body]);\n body = undefined;\n partCount = 0;\n }\n };\n\n const addPatch = async (patchToVersion: PatchToVersion) => {\n const {patch, toVersion} = patchToVersion;\n if (cmpVersions(toVersion, this.#baseVersion) <= 0) {\n return;\n }\n const body = await ensureBody();\n\n const {type, op} = patch;\n switch (type) {\n case 'query': {\n const patches = patch.clientID\n ? ((body.desiredQueriesPatches ??= {})[patch.clientID] ??= [])\n : (body.gotQueriesPatch ??= []);\n if (op === 'put') {\n patches.push({op, hash: patch.id});\n } else {\n patches.push({op, hash: patch.id});\n }\n break;\n }\n case 'row':\n if (patch.id.table === this.#zeroClientsTable) {\n this.#updateLMIDs((body.lastMutationIDChanges ??= {}), patch);\n } else if (patch.id.table === this.#zeroMutationsTable) {\n const patches = (body.mutationsPatch ??= []);\n if (op === 'put') {\n const row = v.parse(\n ensureSafeJSON(patch.contents),\n mutationRowSchema,\n 'passthrough',\n );\n patches.push({\n op: 'put',\n mutation: {\n id: {\n clientID: row.clientID,\n id: row.mutationID,\n },\n result: row.result,\n },\n });\n } else {\n const {clientID, mutationID} = patch.id.rowKey;\n assert(\n typeof clientID === 'string',\n 'client id must be a string',\n );\n const id = Number(mutationID);\n assert(\n !Number.isNaN(id) && Number.isFinite(id) && id >= 0,\n 'mutation id must be a finite number',\n );\n patches.push({\n op: 'del',\n id: {\n clientID,\n id,\n },\n });\n }\n } else {\n (body.rowsPatch ??= []).push(makeRowPatch(patch));\n }\n break;\n default:\n unreachable(patch);\n }\n\n if (++partCount >= PART_COUNT_FLUSH_THRESHOLD) {\n await flushBody();\n }\n };\n\n return {\n addPatch: async (patchToVersion: PatchToVersion) => {\n try {\n await addPatch(patchToVersion);\n if (patchToVersion.patch.type === 'row') {\n this.#pokedRows.add(1);\n }\n } catch (e) {\n this.#downstream.fail(wrapWithProtocolError(e));\n }\n },\n\n cancel: async () => {\n if (pokeStarted) {\n await this.#push(['pokeEnd', {pokeID, cookie: '', cancel: true}]);\n }\n },\n\n end: async (finalVersion: CVRVersion) => {\n const cookie = versionToCookie(finalVersion);\n if (!pokeStarted) {\n if (cmpVersions(this.#baseVersion, finalVersion) === 0) {\n return; // Nothing changed and nothing was sent.\n }\n await this.#push(['pokeStart', pokeStart]);\n } else if (cmpVersions(this.#baseVersion, finalVersion) >= 0) {\n // Sanity check: If the poke was started, the finalVersion\n // must be > #baseVersion.\n throw new Error(\n `Patches were sent but finalVersion ${finalVersion} is ` +\n `not greater than baseVersion ${this.#baseVersion}`,\n );\n }\n await flushBody();\n await this.#push(['pokeEnd', {pokeID, cookie}]);\n this.#baseVersion = finalVersion;\n\n const elapsed = performance.now() - start;\n this.#pokeTransactions.add(1);\n this.#pokeTime.record(elapsed / 1000);\n },\n };\n }\n\n async sendDeleteClients(\n lc: LogContext,\n deletedClientIDs: string[],\n deletedClientGroupIDs: string[],\n ) {\n const deleteClientsBody: Writable<DeleteClientsBody> = {};\n if (deletedClientIDs.length > 0) {\n deleteClientsBody.clientIDs = deletedClientIDs;\n }\n if (deletedClientGroupIDs.length > 0) {\n deleteClientsBody.clientGroupIDs = deletedClientGroupIDs;\n }\n lc.debug?.('sending deleteClients', deleteClientsBody);\n await this.#push(['deleteClients', deleteClientsBody]);\n }\n\n sendQueryTransformApplicationErrors(errors: ErroredQuery[]) {\n void this.#push(['transformError', errors]);\n }\n\n sendQueryTransformFailedError(error: TransformFailedBody) {\n this.fail(new ProtocolError(error));\n }\n\n sendInspectResponse(lc: LogContext, response: InspectDownBody): void {\n lc.debug?.('sending inspect response', response);\n this.#downstream.push(['inspect', response]);\n }\n\n #updateLMIDs(lmids: Record<string, number>, patch: RowPatch) {\n if (patch.op === 'put') {\n const row = ensureSafeJSON(patch.contents);\n const {clientGroupID, clientID, lastMutationID} = v.parse(\n row,\n lmidRowSchema,\n 'passthrough',\n );\n if (clientGroupID !== this.#clientGroupID) {\n this.#lc.error?.(\n `Received clients row for wrong clientGroupID. Ignoring.`,\n clientGroupID,\n );\n } else {\n lmids[clientID] = lastMutationID;\n }\n } else {\n // The 'constrain' and 'del' ops for clients can be ignored.\n patch.op satisfies 'constrain' | 'del';\n }\n }\n}\n\n// Note: The {APP_ID}_{SHARD_ID}.clients table is set up in replicator/initial-sync.ts.\nconst lmidRowSchema = v.object({\n clientGroupID: v.string(),\n clientID: v.string(),\n lastMutationID: v.number(), // Actually returned as a bigint, but converted by ensureSafeJSON().\n});\n\nconst mutationRowSchema = v.object({\n clientGroupID: v.string(),\n clientID: v.string(),\n mutationID: v.number(),\n result: mutationResultSchema,\n});\n\nfunction makeRowPatch(patch: RowPatch): RowPatchOp {\n const {\n op,\n id: {table: tableName, rowKey: id},\n } = patch;\n\n switch (op) {\n case 'put':\n return {\n op: 'put',\n tableName,\n value: v.parse(ensureSafeJSON(patch.contents), rowSchema),\n };\n\n case 'del':\n return {\n op,\n tableName,\n id: v.parse(id, primaryKeyValueRecordSchema),\n };\n\n default:\n unreachable(op);\n }\n}\n\n/**\n * Column values of type INT8 are returned as the `bigint` from the\n * Postgres library. These are converted to `number` if they are within\n * the safe Number range, allowing the protocol to support numbers larger\n * than 32-bits. Values outside of the safe number range (e.g. > 2^53) will\n * result in an Error.\n */\nexport function ensureSafeJSON(row: JSONObject): SafeJSONObject {\n const modified = Object.entries(row)\n .filter(([k, v]) => {\n if (typeof v === 'bigint') {\n if (v >= Number.MIN_SAFE_INTEGER && v <= Number.MAX_SAFE_INTEGER) {\n return true; // send this entry onto the next map() step.\n }\n throw new Error(`Value of \"${k}\" exceeds safe Number range (${v})`);\n } else if (typeof v === 'object') {\n assertJSONValue(v);\n }\n return false;\n })\n .map(([k, v]) => [k, Number(v)]);\n\n return modified.length\n ? {...row, ...Object.fromEntries(modified)}\n : (row as SafeJSONObject);\n}\n"],"names":["body","v.parse","cookie","v.object","v.string","v.number","v"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cvr-store.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAiBjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,+CAA+C,CAAC;AAKnF,OAAO,EAAC,sBAAsB,EAAC,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAC,UAAU,EAAE,mBAAmB,EAAC,MAAM,mBAAmB,CAAC;AAEvE,OAAO,EAAY,KAAK,OAAO,EAAiB,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAQ,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAC,GAAG,EAAE,WAAW,EAAC,MAAM,UAAU,CAAC;AAE/C,OAAO,EAKL,KAAK,OAAO,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAEL,KAAK,YAAY,EAGjB,KAAK,UAAU,EAGf,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,WAAW,EAEhB,KAAK,KAAK,EACV,KAAK,SAAS,EAGf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,QAAQ,EAGd,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;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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"}
|
|
@@ -239,12 +239,14 @@ class CVRStore {
|
|
|
239
239
|
}
|
|
240
240
|
for (const row of desiresRows) {
|
|
241
241
|
const client = cvr.clients[row.clientID];
|
|
242
|
-
if (
|
|
243
|
-
if (
|
|
242
|
+
if (!row.deleted && row.inactivatedAt === null) {
|
|
243
|
+
if (client) {
|
|
244
244
|
client.desiredQueryIDs.push(row.queryHash);
|
|
245
|
+
} else {
|
|
246
|
+
lc.debug?.(
|
|
247
|
+
`Not adding to desiredQueryIDs for client ${row.clientID} because it has been deleted.`
|
|
248
|
+
);
|
|
245
249
|
}
|
|
246
|
-
} else {
|
|
247
|
-
lc.debug?.(`Client ${row.clientID} not found`);
|
|
248
250
|
}
|
|
249
251
|
const query = cvr.queries[row.queryHash];
|
|
250
252
|
if (query && query.type !== "internal" && (!row.deleted || row.inactivatedAt !== null)) {
|