@rocicorp/zero 0.26.0 → 0.26.1-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.
Files changed (35) hide show
  1. package/out/zero/package.json.js +1 -1
  2. package/out/zero-cache/src/observability/events.d.ts.map +1 -1
  3. package/out/zero-cache/src/observability/events.js +28 -9
  4. package/out/zero-cache/src/observability/events.js.map +1 -1
  5. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  6. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +26 -13
  7. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  8. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +6 -1
  9. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  10. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +64 -18
  11. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  12. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +26 -0
  13. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  14. package/out/zero-cache/src/services/change-source/protocol/current/data.js +15 -3
  15. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  16. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +30 -0
  17. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  18. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  19. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +10 -0
  20. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  21. package/out/zero-cache/src/services/replicator/change-processor.d.ts +2 -0
  22. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  23. package/out/zero-cache/src/services/replicator/change-processor.js +8 -6
  24. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  25. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  26. package/out/zero-cache/src/services/replicator/incremental-sync.js +39 -1
  27. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  28. package/out/zero-cache/src/services/replicator/replication-status.d.ts +4 -3
  29. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  30. package/out/zero-cache/src/services/replicator/replication-status.js +24 -9
  31. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  32. package/out/zero-client/src/client/version.js +1 -1
  33. package/out/zero-events/src/status.d.ts +8 -0
  34. package/out/zero-events/src/status.d.ts.map +1 -1
  35. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"initial-sync.js","sources":["../../../../../../../zero-cache/src/services/change-source/pg/initial-sync.ts"],"sourcesContent":["import {\n PG_CONFIGURATION_LIMIT_EXCEEDED,\n PG_INSUFFICIENT_PRIVILEGE,\n} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {platform} from 'node:os';\nimport {Writable} from 'node:stream';\nimport {pipeline} from 'node:stream/promises';\nimport postgres from 'postgres';\nimport type {JSONObject} from '../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../shared/src/must.ts';\nimport {equals} from '../../../../../shared/src/set-utils.ts';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport {\n createLiteIndexStatement,\n createLiteTableStatement,\n} from '../../../db/create.ts';\nimport * as Mode from '../../../db/mode-enum.ts';\nimport {TsvParser} from '../../../db/pg-copy.ts';\nimport {\n mapPostgresToLite,\n mapPostgresToLiteIndex,\n} from '../../../db/pg-to-lite.ts';\nimport {getTypeParsers} from '../../../db/pg-type-parser.ts';\nimport {runTx} from '../../../db/run-transaction.ts';\nimport type {IndexSpec, PublishedTableSpec} from '../../../db/specs.ts';\nimport {importSnapshot, TransactionPool} from '../../../db/transaction-pool.ts';\nimport {\n JSON_STRINGIFIED,\n liteValue,\n type LiteValueType,\n} from '../../../types/lite.ts';\nimport {liteTableName} from '../../../types/names.ts';\nimport {\n pgClient,\n type PostgresDB,\n type PostgresTransaction,\n type PostgresValueType,\n} from '../../../types/pg.ts';\nimport {CpuProfiler} from '../../../types/profiler.ts';\nimport type {ShardConfig} from '../../../types/shards.ts';\nimport {ALLOWED_APP_ID_CHARACTERS} from '../../../types/shards.ts';\nimport {id} from '../../../types/sql.ts';\nimport {ReplicationStatusPublisher} from '../../replicator/replication-status.ts';\nimport {ColumnMetadataStore} from '../../replicator/schema/column-metadata.ts';\nimport {initReplicationState} from '../../replicator/schema/replication-state.ts';\nimport {toStateVersionString} from './lsn.ts';\nimport {ensureShardSchema} from './schema/init.ts';\nimport {getPublicationInfo} from './schema/published.ts';\nimport {\n addReplica,\n dropShard,\n getInternalShardConfig,\n newReplicationSlot,\n replicationSlotExpression,\n validatePublications,\n} from './schema/shard.ts';\n\nexport type InitialSyncOptions = {\n tableCopyWorkers: number;\n profileCopy?: boolean | undefined;\n};\n\n/** Server context to store with the initial sync metadata for debugging. */\nexport type ServerContext = JSONObject;\n\nexport async function initialSync(\n lc: LogContext,\n shard: ShardConfig,\n tx: Database,\n upstreamURI: string,\n syncOptions: InitialSyncOptions,\n context: ServerContext,\n) {\n if (!ALLOWED_APP_ID_CHARACTERS.test(shard.appID)) {\n throw new Error(\n 'The App ID may only consist of lower-case letters, numbers, and the underscore character',\n );\n }\n const {tableCopyWorkers, profileCopy} = syncOptions;\n const copyProfiler = profileCopy ? await CpuProfiler.connect() : null;\n const sql = pgClient(lc, upstreamURI);\n const replicationSession = pgClient(lc, upstreamURI, {\n ['fetch_types']: false, // Necessary for the streaming protocol\n connection: {replication: 'database'}, // https://www.postgresql.org/docs/current/protocol-replication.html\n });\n const slotName = newReplicationSlot(shard);\n const statusPublisher = new ReplicationStatusPublisher(tx).publish(\n lc,\n 'Initializing',\n );\n try {\n await checkUpstreamConfig(sql);\n\n const {publications} = await ensurePublishedTables(lc, sql, shard);\n lc.info?.(`Upstream is setup with publications [${publications}]`);\n\n const {database, host} = sql.options;\n lc.info?.(`opening replication session to ${database}@${host}`);\n\n let slot: ReplicationSlot;\n for (let first = true; ; first = false) {\n try {\n slot = await createReplicationSlot(lc, replicationSession, slotName);\n break;\n } catch (e) {\n if (first && e instanceof postgres.PostgresError) {\n if (e.code === PG_INSUFFICIENT_PRIVILEGE) {\n // Some Postgres variants (e.g. Google Cloud SQL) require that\n // the user have the REPLICATION role in order to create a slot.\n // Note that this must be done by the upstreamDB connection, and\n // does not work in the replicationSession itself.\n await sql`ALTER ROLE current_user WITH REPLICATION`;\n lc.info?.(`Added the REPLICATION role to database user`);\n continue;\n }\n if (e.code === PG_CONFIGURATION_LIMIT_EXCEEDED) {\n const slotExpression = replicationSlotExpression(shard);\n\n const dropped = await sql<{slot: string}[]>`\n SELECT slot_name as slot, pg_drop_replication_slot(slot_name) \n FROM pg_replication_slots\n WHERE slot_name LIKE ${slotExpression} AND NOT active`;\n if (dropped.length) {\n lc.warn?.(\n `Dropped inactive replication slots: ${dropped.map(({slot}) => slot)}`,\n e,\n );\n continue;\n }\n lc.error?.(`Unable to drop replication slots`, e);\n }\n }\n throw e;\n }\n }\n const {snapshot_name: snapshot, consistent_point: lsn} = slot;\n const initialVersion = toStateVersionString(lsn);\n\n initReplicationState(tx, publications, initialVersion, context);\n\n // Run up to MAX_WORKERS to copy of tables at the replication slot's snapshot.\n const start = performance.now();\n // Retrieve the published schema at the consistent_point.\n const published = await runTx(\n sql,\n async tx => {\n await tx.unsafe(/* sql*/ `SET TRANSACTION SNAPSHOT '${snapshot}'`);\n return getPublicationInfo(tx, publications);\n },\n {mode: Mode.READONLY},\n );\n // Note: If this throws, initial-sync is aborted.\n validatePublications(lc, published);\n\n // Now that tables have been validated, kick off the copiers.\n const {tables, indexes} = published;\n const numTables = tables.length;\n if (platform() === 'win32' && tableCopyWorkers < numTables) {\n lc.warn?.(\n `Increasing the number of copy workers from ${tableCopyWorkers} to ` +\n `${numTables} to work around a Node/Postgres connection bug`,\n );\n }\n const numWorkers =\n platform() === 'win32'\n ? numTables\n : Math.min(tableCopyWorkers, numTables);\n\n const copyPool = pgClient(lc, upstreamURI, {\n max: numWorkers,\n connection: {['application_name']: 'initial-sync-copy-worker'},\n });\n const copiers = startTableCopyWorkers(\n lc,\n copyPool,\n snapshot,\n numWorkers,\n numTables,\n );\n try {\n createLiteTables(tx, tables, initialVersion);\n statusPublisher.publish(\n lc,\n 'Initializing',\n `Copying ${numTables} upstream tables at version ${initialVersion}`,\n 5000,\n );\n\n void copyProfiler?.start();\n const rowCounts = await Promise.all(\n tables.map(table =>\n copiers.processReadTask((db, lc) =>\n copy(lc, table, copyPool, db, tx),\n ),\n ),\n );\n void copyProfiler?.stopAndDispose(lc, 'initial-copy');\n\n const total = rowCounts.reduce(\n (acc, curr) => ({\n rows: acc.rows + curr.rows,\n flushTime: acc.flushTime + curr.flushTime,\n }),\n {rows: 0, flushTime: 0},\n );\n\n statusPublisher.publish(\n lc,\n 'Indexing',\n `Creating ${indexes.length} indexes`,\n 5000,\n );\n const indexStart = performance.now();\n createLiteIndices(tx, indexes);\n const index = performance.now() - indexStart;\n lc.info?.(`Created indexes (${index.toFixed(3)} ms)`);\n\n await addReplica(\n sql,\n shard,\n slotName,\n initialVersion,\n published,\n context,\n );\n\n const elapsed = performance.now() - start;\n lc.info?.(\n `Synced ${total.rows.toLocaleString()} rows of ${numTables} tables in ${publications} up to ${lsn} ` +\n `(flush: ${total.flushTime.toFixed(3)}, index: ${index.toFixed(3)}, total: ${elapsed.toFixed(3)} ms)`,\n );\n } finally {\n copiers.setDone();\n if (platform() === 'win32') {\n // Workaround a Node bug in Windows in which certain COPY streams result\n // in hanging the connection, which causes this await to never resolve.\n void copyPool.end().catch(e => lc.warn?.(`Error closing copyPool`, e));\n } else {\n await copyPool.end();\n }\n }\n } catch (e) {\n // If initial-sync did not succeed, make a best effort to drop the\n // orphaned replication slot to avoid running out of slots in\n // pathological cases that result in repeated failures.\n lc.warn?.(`dropping replication slot ${slotName}`, e);\n await sql`\n SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots\n WHERE slot_name = ${slotName};\n `.catch(e => lc.warn?.(`Unable to drop replication slot ${slotName}`, e));\n await statusPublisher.publishAndThrowError(lc, 'Initializing', e);\n } finally {\n statusPublisher.stop();\n await replicationSession.end();\n await sql.end();\n }\n}\n\nasync function checkUpstreamConfig(sql: PostgresDB) {\n const {walLevel, version} = (\n await sql<{walLevel: string; version: number}[]>`\n SELECT current_setting('wal_level') as \"walLevel\", \n current_setting('server_version_num') as \"version\";\n `\n )[0];\n\n if (walLevel !== 'logical') {\n throw new Error(\n `Postgres must be configured with \"wal_level = logical\" (currently: \"${walLevel})`,\n );\n }\n if (version < 150000) {\n throw new Error(\n `Must be running Postgres 15 or higher (currently: \"${version}\")`,\n );\n }\n}\n\nasync function ensurePublishedTables(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardConfig,\n validate = true,\n): Promise<{publications: string[]}> {\n const {database, host} = sql.options;\n lc.info?.(`Ensuring upstream PUBLICATION on ${database}@${host}`);\n\n await ensureShardSchema(lc, sql, shard);\n const {publications} = await getInternalShardConfig(sql, shard);\n\n if (validate) {\n let valid = false;\n const nonInternalPublications = publications.filter(\n p => !p.startsWith('_'),\n );\n const exists = await sql`\n SELECT pubname FROM pg_publication WHERE pubname IN ${sql(publications)}\n `.values();\n if (exists.length !== publications.length) {\n lc.warn?.(\n `some configured publications [${publications}] are missing: ` +\n `[${exists.flat()}]. resyncing`,\n );\n } else if (\n !equals(new Set(shard.publications), new Set(nonInternalPublications))\n ) {\n lc.warn?.(\n `requested publications [${shard.publications}] differ from previous` +\n `publications [${nonInternalPublications}]. resyncing`,\n );\n } else {\n valid = true;\n }\n if (!valid) {\n await sql.unsafe(dropShard(shard.appID, shard.shardNum));\n return ensurePublishedTables(lc, sql, shard, false);\n }\n }\n return {publications};\n}\n\nfunction startTableCopyWorkers(\n lc: LogContext,\n db: PostgresDB,\n snapshot: string,\n numWorkers: number,\n numTables: number,\n): TransactionPool {\n const {init} = importSnapshot(snapshot);\n const tableCopiers = new TransactionPool(\n lc,\n Mode.READONLY,\n init,\n undefined,\n numWorkers,\n );\n tableCopiers.run(db);\n\n lc.info?.(`Started ${numWorkers} workers to copy ${numTables} tables`);\n\n if (parseInt(process.versions.node) < 22) {\n lc.warn?.(\n `\\n\\n\\n` +\n `Older versions of Node have a bug that results in an unresponsive\\n` +\n `Postgres connection after running certain combinations of COPY commands.\\n` +\n `If initial sync hangs, run zero-cache with Node v22+. This has the additional\\n` +\n `benefit of being consistent with the Node version run in the production container image.` +\n `\\n\\n\\n`,\n );\n }\n return tableCopiers;\n}\n\n// Row returned by `CREATE_REPLICATION_SLOT`\ntype ReplicationSlot = {\n slot_name: string;\n consistent_point: string;\n snapshot_name: string;\n output_plugin: string;\n};\n\n// Note: The replication connection does not support the extended query protocol,\n// so all commands must be sent using sql.unsafe(). This is technically safe\n// because all placeholder values are under our control (i.e. \"slotName\").\nexport async function createReplicationSlot(\n lc: LogContext,\n session: postgres.Sql,\n slotName: string,\n): Promise<ReplicationSlot> {\n const slot = (\n await session.unsafe<ReplicationSlot[]>(\n /*sql*/ `CREATE_REPLICATION_SLOT \"${slotName}\" LOGICAL pgoutput`,\n )\n )[0];\n lc.info?.(`Created replication slot ${slotName}`, slot);\n return slot;\n}\n\nfunction createLiteTables(\n tx: Database,\n tables: PublishedTableSpec[],\n initialVersion: string,\n) {\n // TODO: Figure out how to reuse the ChangeProcessor here to avoid\n // duplicating the ColumnMetadata logic.\n const columnMetadata = must(ColumnMetadataStore.getInstance(tx));\n for (const t of tables) {\n tx.exec(createLiteTableStatement(mapPostgresToLite(t, initialVersion)));\n const tableName = liteTableName(t);\n for (const [colName, colSpec] of Object.entries(t.columns)) {\n columnMetadata.insert(tableName, colName, colSpec);\n }\n }\n}\n\nfunction createLiteIndices(tx: Database, indices: IndexSpec[]) {\n for (const index of indices) {\n tx.exec(createLiteIndexStatement(mapPostgresToLiteIndex(index)));\n }\n}\n\n// Verified empirically that batches of 50 seem to be the sweet spot,\n// similar to the report in https://sqlite.org/forum/forumpost/8878a512d3652655\n//\n// Exported for testing.\nexport const INSERT_BATCH_SIZE = 50;\n\nconst MB = 1024 * 1024;\nconst MAX_BUFFERED_ROWS = 10_000;\nconst BUFFERED_SIZE_THRESHOLD = 8 * MB;\n\nexport function makeSelectPublishedStmt(\n table: PublishedTableSpec,\n columns: string[],\n) {\n const filterConditions = Object.values(table.publications)\n .map(({rowFilter}) => rowFilter)\n .filter(f => !!f); // remove nulls\n return (\n /*sql*/ `\n SELECT ${columns.map(id).join(',')} FROM ${id(table.schema)}.${id(table.name)}` +\n (filterConditions.length === 0\n ? ''\n : /*sql*/ ` WHERE ${filterConditions.join(' OR ')}`)\n );\n}\n\nasync function copy(\n lc: LogContext,\n table: PublishedTableSpec,\n dbClient: PostgresDB,\n from: PostgresTransaction,\n to: Database,\n) {\n const start = performance.now();\n let rows = 0;\n let flushTime = 0;\n\n const tableName = liteTableName(table);\n const orderedColumns = Object.entries(table.columns);\n\n const columnNames = orderedColumns.map(([c]) => c);\n const columnSpecs = orderedColumns.map(([_name, spec]) => spec);\n const insertColumnList = columnNames.map(c => id(c)).join(',');\n\n // (?,?,?,?,?)\n const valuesSql =\n columnNames.length > 0 ? `(${'?,'.repeat(columnNames.length - 1)}?)` : '()';\n const insertSql = /*sql*/ `\n INSERT INTO \"${tableName}\" (${insertColumnList}) VALUES ${valuesSql}`;\n const insertStmt = to.prepare(insertSql);\n // INSERT VALUES (?,?,?,?,?),... x INSERT_BATCH_SIZE\n const insertBatchStmt = to.prepare(\n insertSql + `,${valuesSql}`.repeat(INSERT_BATCH_SIZE - 1),\n );\n\n const selectStmt = makeSelectPublishedStmt(table, columnNames);\n const valuesPerRow = columnSpecs.length;\n const valuesPerBatch = valuesPerRow * INSERT_BATCH_SIZE;\n\n // Preallocate the buffer of values to reduce memory allocation churn.\n const pendingValues: LiteValueType[] = Array.from({\n length: MAX_BUFFERED_ROWS * valuesPerRow,\n });\n let pendingRows = 0;\n let pendingSize = 0;\n\n function flush() {\n const start = performance.now();\n const flushedRows = pendingRows;\n const flushedSize = pendingSize;\n\n let l = 0;\n for (; pendingRows > INSERT_BATCH_SIZE; pendingRows -= INSERT_BATCH_SIZE) {\n insertBatchStmt.run(pendingValues.slice(l, (l += valuesPerBatch)));\n }\n // Insert the remaining rows individually.\n for (; pendingRows > 0; pendingRows--) {\n insertStmt.run(pendingValues.slice(l, (l += valuesPerRow)));\n }\n for (let i = 0; i < flushedRows; i++) {\n // Reuse the array and unreference the values to allow GC.\n // This is faster than allocating a new array every time.\n pendingValues[i] = undefined as unknown as LiteValueType;\n }\n pendingSize = 0;\n rows += flushedRows;\n\n const elapsed = performance.now() - start;\n flushTime += elapsed;\n lc.debug?.(\n `flushed ${flushedRows} ${tableName} rows (${flushedSize} bytes) in ${elapsed.toFixed(3)} ms`,\n );\n }\n\n lc.info?.(`Starting copy stream of ${tableName}:`, selectStmt);\n const pgParsers = await getTypeParsers(dbClient, {returnJsonAsString: true});\n const parsers = columnSpecs.map(c => {\n const pgParse = pgParsers.getTypeParser(c.typeOID);\n return (val: string) =>\n liteValue(\n pgParse(val) as PostgresValueType,\n c.dataType,\n JSON_STRINGIFIED,\n );\n });\n\n const tsvParser = new TsvParser();\n let col = 0;\n\n await pipeline(\n await from.unsafe(`COPY (${selectStmt}) TO STDOUT`).readable(),\n new Writable({\n highWaterMark: BUFFERED_SIZE_THRESHOLD,\n\n write(\n chunk: Buffer,\n _encoding: string,\n callback: (error?: Error) => void,\n ) {\n try {\n for (const text of tsvParser.parse(chunk)) {\n pendingSize += text === null ? 4 : text.length;\n pendingValues[pendingRows * valuesPerRow + col] =\n text === null ? null : parsers[col](text);\n\n if (++col === parsers.length) {\n col = 0;\n if (\n ++pendingRows >= MAX_BUFFERED_ROWS - valuesPerRow ||\n pendingSize >= BUFFERED_SIZE_THRESHOLD\n ) {\n flush();\n }\n }\n }\n callback();\n } catch (e) {\n callback(e instanceof Error ? e : new Error(String(e)));\n }\n },\n\n final: (callback: (error?: Error) => void) => {\n try {\n flush();\n callback();\n } catch (e) {\n callback(e instanceof Error ? e : new Error(String(e)));\n }\n },\n }),\n );\n\n const elapsed = performance.now() - start;\n lc.info?.(\n `Finished copying ${rows} rows into ${tableName} ` +\n `(flush: ${flushTime.toFixed(3)} ms) (total: ${elapsed.toFixed(3)} ms) `,\n );\n return {rows, flushTime};\n}\n"],"names":["slot","tx","Mode.READONLY","lc","e","start","elapsed"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAkEA,eAAsB,YACpB,IACA,OACA,IACA,aACA,aACA,SACA;AACA,MAAI,CAAC,0BAA0B,KAAK,MAAM,KAAK,GAAG;AAChD,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACA,QAAM,EAAC,kBAAkB,YAAA,IAAe;AACxC,QAAM,eAAe,cAAc,MAAM,YAAY,YAAY;AACjE,QAAM,MAAM,SAAS,IAAI,WAAW;AACpC,QAAM,qBAAqB,SAAS,IAAI,aAAa;AAAA,IACnD,CAAC,aAAa,GAAG;AAAA;AAAA,IACjB,YAAY,EAAC,aAAa,WAAA;AAAA;AAAA,EAAU,CACrC;AACD,QAAM,WAAW,mBAAmB,KAAK;AACzC,QAAM,kBAAkB,IAAI,2BAA2B,EAAE,EAAE;AAAA,IACzD;AAAA,IACA;AAAA,EAAA;AAEF,MAAI;AACF,UAAM,oBAAoB,GAAG;AAE7B,UAAM,EAAC,aAAA,IAAgB,MAAM,sBAAsB,IAAI,KAAK,KAAK;AACjE,OAAG,OAAO,wCAAwC,YAAY,GAAG;AAEjE,UAAM,EAAC,UAAU,KAAA,IAAQ,IAAI;AAC7B,OAAG,OAAO,kCAAkC,QAAQ,IAAI,IAAI,EAAE;AAE9D,QAAI;AACJ,aAAS,QAAQ,QAAQ,QAAQ,OAAO;AACtC,UAAI;AACF,eAAO,MAAM,sBAAsB,IAAI,oBAAoB,QAAQ;AACnE;AAAA,MACF,SAAS,GAAG;AACV,YAAI,SAAS,aAAa,SAAS,eAAe;AAChD,cAAI,EAAE,SAAS,2BAA2B;AAKxC,kBAAM;AACN,eAAG,OAAO,6CAA6C;AACvD;AAAA,UACF;AACA,cAAI,EAAE,SAAS,iCAAiC;AAC9C,kBAAM,iBAAiB,0BAA0B,KAAK;AAEtD,kBAAM,UAAU,MAAM;AAAA;AAAA;AAAA,uCAGK,cAAc;AACzC,gBAAI,QAAQ,QAAQ;AAClB,iBAAG;AAAA,gBACD,uCAAuC,QAAQ,IAAI,CAAC,EAAC,MAAAA,MAAAA,MAAUA,KAAI,CAAC;AAAA,gBACpE;AAAA,cAAA;AAEF;AAAA,YACF;AACA,eAAG,QAAQ,oCAAoC,CAAC;AAAA,UAClD;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AACA,UAAM,EAAC,eAAe,UAAU,kBAAkB,QAAO;AACzD,UAAM,iBAAiB,qBAAqB,GAAG;AAE/C,yBAAqB,IAAI,cAAc,gBAAgB,OAAO;AAG9D,UAAM,QAAQ,YAAY,IAAA;AAE1B,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA,OAAMC,QAAM;AACV,cAAMA,IAAG;AAAA;AAAA,UAAgB,6BAA6B,QAAQ;AAAA,QAAA;AAC9D,eAAO,mBAAmBA,KAAI,YAAY;AAAA,MAC5C;AAAA,MACA,EAAC,MAAMC,SAAK;AAAA,IAAQ;AAGtB,yBAAqB,IAAI,SAAS;AAGlC,UAAM,EAAC,QAAQ,QAAA,IAAW;AAC1B,UAAM,YAAY,OAAO;AACzB,QAAI,SAAA,MAAe,WAAW,mBAAmB,WAAW;AAC1D,SAAG;AAAA,QACD,8CAA8C,gBAAgB,OACzD,SAAS;AAAA,MAAA;AAAA,IAElB;AACA,UAAM,aACJ,eAAe,UACX,YACA,KAAK,IAAI,kBAAkB,SAAS;AAE1C,UAAM,WAAW,SAAS,IAAI,aAAa;AAAA,MACzC,KAAK;AAAA,MACL,YAAY,EAAC,CAAC,kBAAkB,GAAG,2BAAA;AAAA,IAA0B,CAC9D;AACD,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEF,QAAI;AACF,uBAAiB,IAAI,QAAQ,cAAc;AAC3C,sBAAgB;AAAA,QACd;AAAA,QACA;AAAA,QACA,WAAW,SAAS,+BAA+B,cAAc;AAAA,QACjE;AAAA,MAAA;AAGF,WAAK,cAAc,MAAA;AACnB,YAAM,YAAY,MAAM,QAAQ;AAAA,QAC9B,OAAO;AAAA,UAAI,WACT,QAAQ;AAAA,YAAgB,CAAC,IAAIC,QAC3B,KAAKA,KAAI,OAAO,UAAU,IAAI,EAAE;AAAA,UAAA;AAAA,QAClC;AAAA,MACF;AAEF,WAAK,cAAc,eAAe,IAAI,cAAc;AAEpD,YAAM,QAAQ,UAAU;AAAA,QACtB,CAAC,KAAK,UAAU;AAAA,UACd,MAAM,IAAI,OAAO,KAAK;AAAA,UACtB,WAAW,IAAI,YAAY,KAAK;AAAA,QAAA;AAAA,QAElC,EAAC,MAAM,GAAG,WAAW,EAAA;AAAA,MAAC;AAGxB,sBAAgB;AAAA,QACd;AAAA,QACA;AAAA,QACA,YAAY,QAAQ,MAAM;AAAA,QAC1B;AAAA,MAAA;AAEF,YAAM,aAAa,YAAY,IAAA;AAC/B,wBAAkB,IAAI,OAAO;AAC7B,YAAM,QAAQ,YAAY,IAAA,IAAQ;AAClC,SAAG,OAAO,oBAAoB,MAAM,QAAQ,CAAC,CAAC,MAAM;AAEpD,YAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAGF,YAAM,UAAU,YAAY,IAAA,IAAQ;AACpC,SAAG;AAAA,QACD,UAAU,MAAM,KAAK,eAAA,CAAgB,YAAY,SAAS,cAAc,YAAY,UAAU,GAAG,YACpF,MAAM,UAAU,QAAQ,CAAC,CAAC,YAAY,MAAM,QAAQ,CAAC,CAAC,YAAY,QAAQ,QAAQ,CAAC,CAAC;AAAA,MAAA;AAAA,IAErG,UAAA;AACE,cAAQ,QAAA;AACR,UAAI,SAAA,MAAe,SAAS;AAG1B,aAAK,SAAS,MAAM,MAAM,OAAK,GAAG,OAAO,0BAA0B,CAAC,CAAC;AAAA,MACvE,OAAO;AACL,cAAM,SAAS,IAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF,SAAS,GAAG;AAIV,OAAG,OAAO,6BAA6B,QAAQ,IAAI,CAAC;AACpD,UAAM;AAAA;AAAA,4BAEkB,QAAQ;AAAA,MAC9B,MAAM,CAAAC,OAAK,GAAG,OAAO,mCAAmC,QAAQ,IAAIA,EAAC,CAAC;AACxE,UAAM,gBAAgB,qBAAqB,IAAI,gBAAgB,CAAC;AAAA,EAClE,UAAA;AACE,oBAAgB,KAAA;AAChB,UAAM,mBAAmB,IAAA;AACzB,UAAM,IAAI,IAAA;AAAA,EACZ;AACF;AAEA,eAAe,oBAAoB,KAAiB;AAClD,QAAM,EAAC,UAAU,QAAA,KACf,MAAM;AAAA;AAAA;AAAA,KAIN,CAAC;AAEH,MAAI,aAAa,WAAW;AAC1B,UAAM,IAAI;AAAA,MACR,uEAAuE,QAAQ;AAAA,IAAA;AAAA,EAEnF;AACA,MAAI,UAAU,MAAQ;AACpB,UAAM,IAAI;AAAA,MACR,sDAAsD,OAAO;AAAA,IAAA;AAAA,EAEjE;AACF;AAEA,eAAe,sBACb,IACA,KACA,OACA,WAAW,MACwB;AACnC,QAAM,EAAC,UAAU,KAAA,IAAQ,IAAI;AAC7B,KAAG,OAAO,oCAAoC,QAAQ,IAAI,IAAI,EAAE;AAEhE,QAAM,kBAAkB,IAAI,KAAK,KAAK;AACtC,QAAM,EAAC,aAAA,IAAgB,MAAM,uBAAuB,KAAK,KAAK;AAE9D,MAAI,UAAU;AACZ,QAAI,QAAQ;AACZ,UAAM,0BAA0B,aAAa;AAAA,MAC3C,CAAA,MAAK,CAAC,EAAE,WAAW,GAAG;AAAA,IAAA;AAExB,UAAM,SAAS,MAAM;AAAA,4DACmC,IAAI,YAAY,CAAC;AAAA,QACrE,OAAA;AACJ,QAAI,OAAO,WAAW,aAAa,QAAQ;AACzC,SAAG;AAAA,QACD,iCAAiC,YAAY,mBACvC,OAAO,MAAM;AAAA,MAAA;AAAA,IAEvB,WACE,CAAC,OAAO,IAAI,IAAI,MAAM,YAAY,GAAG,IAAI,IAAI,uBAAuB,CAAC,GACrE;AACA,SAAG;AAAA,QACD,2BAA2B,MAAM,YAAY,uCAC1B,uBAAuB;AAAA,MAAA;AAAA,IAE9C,OAAO;AACL,cAAQ;AAAA,IACV;AACA,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,OAAO,UAAU,MAAM,OAAO,MAAM,QAAQ,CAAC;AACvD,aAAO,sBAAsB,IAAI,KAAK,OAAO,KAAK;AAAA,IACpD;AAAA,EACF;AACA,SAAO,EAAC,aAAA;AACV;AAEA,SAAS,sBACP,IACA,IACA,UACA,YACA,WACiB;AACjB,QAAM,EAAC,KAAA,IAAQ,eAAe,QAAQ;AACtC,QAAM,eAAe,IAAI;AAAA,IACvB;AAAA,IACAF;AAAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEF,eAAa,IAAI,EAAE;AAEnB,KAAG,OAAO,WAAW,UAAU,oBAAoB,SAAS,SAAS;AAErE,MAAI,SAAS,QAAQ,SAAS,IAAI,IAAI,IAAI;AACxC,OAAG;AAAA,MACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA;AAAA,EAOJ;AACA,SAAO;AACT;AAaA,eAAsB,sBACpB,IACA,SACA,UAC0B;AAC1B,QAAM,QACJ,MAAM,QAAQ;AAAA;AAAA,IACJ,4BAA4B,QAAQ;AAAA,EAAA,GAE9C,CAAC;AACH,KAAG,OAAO,4BAA4B,QAAQ,IAAI,IAAI;AACtD,SAAO;AACT;AAEA,SAAS,iBACP,IACA,QACA,gBACA;AAGA,QAAM,iBAAiB,KAAK,oBAAoB,YAAY,EAAE,CAAC;AAC/D,aAAW,KAAK,QAAQ;AACtB,OAAG,KAAK,yBAAyB,kBAAkB,GAAG,cAAc,CAAC,CAAC;AACtE,UAAM,YAAY,cAAc,CAAC;AACjC,eAAW,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,EAAE,OAAO,GAAG;AAC1D,qBAAe,OAAO,WAAW,SAAS,OAAO;AAAA,IACnD;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,IAAc,SAAsB;AAC7D,aAAW,SAAS,SAAS;AAC3B,OAAG,KAAK,yBAAyB,uBAAuB,KAAK,CAAC,CAAC;AAAA,EACjE;AACF;AAMO,MAAM,oBAAoB;AAEjC,MAAM,KAAK,OAAO;AAClB,MAAM,oBAAoB;AAC1B,MAAM,0BAA0B,IAAI;AAE7B,SAAS,wBACd,OACA,SACA;AACA,QAAM,mBAAmB,OAAO,OAAO,MAAM,YAAY,EACtD,IAAI,CAAC,EAAC,UAAA,MAAe,SAAS,EAC9B,OAAO,CAAA,MAAK,CAAC,CAAC,CAAC;AAClB;AAAA;AAAA,IACU;AAAA,aACC,QAAQ,IAAI,EAAE,EAAE,KAAK,GAAG,CAAC,SAAS,GAAG,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,MAC5E,iBAAiB,WAAW,IACzB;AAAA;AAAA,MACQ,UAAU,iBAAiB,KAAK,MAAM,CAAC;AAAA;AAAA;AAEvD;AAEA,eAAe,KACb,IACA,OACA,UACA,MACA,IACA;AACA,QAAM,QAAQ,YAAY,IAAA;AAC1B,MAAI,OAAO;AACX,MAAI,YAAY;AAEhB,QAAM,YAAY,cAAc,KAAK;AACrC,QAAM,iBAAiB,OAAO,QAAQ,MAAM,OAAO;AAEnD,QAAM,cAAc,eAAe,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACjD,QAAM,cAAc,eAAe,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,IAAI;AAC9D,QAAM,mBAAmB,YAAY,IAAI,CAAA,MAAK,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG;AAG7D,QAAM,YACJ,YAAY,SAAS,IAAI,IAAI,KAAK,OAAO,YAAY,SAAS,CAAC,CAAC,OAAO;AACzE,QAAM;AAAA;AAAA,IAAoB;AAAA,mBACT,SAAS,MAAM,gBAAgB,YAAY,SAAS;AAAA;AACrE,QAAM,aAAa,GAAG,QAAQ,SAAS;AAEvC,QAAM,kBAAkB,GAAG;AAAA,IACzB,YAAY,IAAI,SAAS,GAAG,OAAO,oBAAoB,CAAC;AAAA,EAAA;AAG1D,QAAM,aAAa,wBAAwB,OAAO,WAAW;AAC7D,QAAM,eAAe,YAAY;AACjC,QAAM,iBAAiB,eAAe;AAGtC,QAAM,gBAAiC,MAAM,KAAK;AAAA,IAChD,QAAQ,oBAAoB;AAAA,EAAA,CAC7B;AACD,MAAI,cAAc;AAClB,MAAI,cAAc;AAElB,WAAS,QAAQ;AACf,UAAMG,SAAQ,YAAY,IAAA;AAC1B,UAAM,cAAc;AACpB,UAAM,cAAc;AAEpB,QAAI,IAAI;AACR,WAAO,cAAc,mBAAmB,eAAe,mBAAmB;AACxE,sBAAgB,IAAI,cAAc,MAAM,GAAI,KAAK,cAAe,CAAC;AAAA,IACnE;AAEA,WAAO,cAAc,GAAG,eAAe;AACrC,iBAAW,IAAI,cAAc,MAAM,GAAI,KAAK,YAAa,CAAC;AAAA,IAC5D;AACA,aAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AAGpC,oBAAc,CAAC,IAAI;AAAA,IACrB;AACA,kBAAc;AACd,YAAQ;AAER,UAAMC,WAAU,YAAY,IAAA,IAAQD;AACpC,iBAAaC;AACb,OAAG;AAAA,MACD,WAAW,WAAW,IAAI,SAAS,UAAU,WAAW,cAAcA,SAAQ,QAAQ,CAAC,CAAC;AAAA,IAAA;AAAA,EAE5F;AAEA,KAAG,OAAO,2BAA2B,SAAS,KAAK,UAAU;AAC7D,QAAM,YAAY,MAAM,eAAe,UAAU,EAAC,oBAAoB,MAAK;AAC3E,QAAM,UAAU,YAAY,IAAI,CAAA,MAAK;AACnC,UAAM,UAAU,UAAU,cAAc,EAAE,OAAO;AACjD,WAAO,CAAC,QACN;AAAA,MACE,QAAQ,GAAG;AAAA,MACX,EAAE;AAAA,MACF;AAAA,IAAA;AAAA,EAEN,CAAC;AAED,QAAM,YAAY,IAAI,UAAA;AACtB,MAAI,MAAM;AAEV,QAAM;AAAA,IACJ,MAAM,KAAK,OAAO,SAAS,UAAU,aAAa,EAAE,SAAA;AAAA,IACpD,IAAI,SAAS;AAAA,MACX,eAAe;AAAA,MAEf,MACE,OACA,WACA,UACA;AACA,YAAI;AACF,qBAAW,QAAQ,UAAU,MAAM,KAAK,GAAG;AACzC,2BAAe,SAAS,OAAO,IAAI,KAAK;AACxC,0BAAc,cAAc,eAAe,GAAG,IAC5C,SAAS,OAAO,OAAO,QAAQ,GAAG,EAAE,IAAI;AAE1C,gBAAI,EAAE,QAAQ,QAAQ,QAAQ;AAC5B,oBAAM;AACN,kBACE,EAAE,eAAe,oBAAoB,gBACrC,eAAe,yBACf;AACA,sBAAA;AAAA,cACF;AAAA,YACF;AAAA,UACF;AACA,mBAAA;AAAA,QACF,SAAS,GAAG;AACV,mBAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,MAEA,OAAO,CAAC,aAAsC;AAC5C,YAAI;AACF,gBAAA;AACA,mBAAA;AAAA,QACF,SAAS,GAAG;AACV,mBAAS,aAAa,QAAQ,IAAI,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IAAA,CACD;AAAA,EAAA;AAGH,QAAM,UAAU,YAAY,IAAA,IAAQ;AACpC,KAAG;AAAA,IACD,oBAAoB,IAAI,cAAc,SAAS,YAClC,UAAU,QAAQ,CAAC,CAAC,gBAAgB,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAAA;AAErE,SAAO,EAAC,MAAM,UAAA;AAChB;"}
1
+ {"version":3,"file":"initial-sync.js","sources":["../../../../../../../zero-cache/src/services/change-source/pg/initial-sync.ts"],"sourcesContent":["import {\n PG_CONFIGURATION_LIMIT_EXCEEDED,\n PG_INSUFFICIENT_PRIVILEGE,\n} from '@drdgvhbh/postgres-error-codes';\nimport type {LogContext} from '@rocicorp/logger';\nimport {platform} from 'node:os';\nimport {Writable} from 'node:stream';\nimport {pipeline} from 'node:stream/promises';\nimport postgres from 'postgres';\nimport type {JSONObject} from '../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../shared/src/must.ts';\nimport {equals} from '../../../../../shared/src/set-utils.ts';\nimport type {DownloadStatus} from '../../../../../zero-events/src/status.ts';\nimport type {Database} from '../../../../../zqlite/src/db.ts';\nimport {\n createLiteIndexStatement,\n createLiteTableStatement,\n} from '../../../db/create.ts';\nimport * as Mode from '../../../db/mode-enum.ts';\nimport {TsvParser} from '../../../db/pg-copy.ts';\nimport {\n mapPostgresToLite,\n mapPostgresToLiteIndex,\n} from '../../../db/pg-to-lite.ts';\nimport {getTypeParsers} from '../../../db/pg-type-parser.ts';\nimport {runTx} from '../../../db/run-transaction.ts';\nimport type {IndexSpec, PublishedTableSpec} from '../../../db/specs.ts';\nimport {importSnapshot, TransactionPool} from '../../../db/transaction-pool.ts';\nimport {\n JSON_STRINGIFIED,\n liteValue,\n type LiteValueType,\n} from '../../../types/lite.ts';\nimport {liteTableName} from '../../../types/names.ts';\nimport {\n pgClient,\n type PostgresDB,\n type PostgresTransaction,\n type PostgresValueType,\n} from '../../../types/pg.ts';\nimport {CpuProfiler} from '../../../types/profiler.ts';\nimport type {ShardConfig} from '../../../types/shards.ts';\nimport {ALLOWED_APP_ID_CHARACTERS} from '../../../types/shards.ts';\nimport {id} from '../../../types/sql.ts';\nimport {ReplicationStatusPublisher} from '../../replicator/replication-status.ts';\nimport {ColumnMetadataStore} from '../../replicator/schema/column-metadata.ts';\nimport {initReplicationState} from '../../replicator/schema/replication-state.ts';\nimport {toStateVersionString} from './lsn.ts';\nimport {ensureShardSchema} from './schema/init.ts';\nimport {getPublicationInfo} from './schema/published.ts';\nimport {\n addReplica,\n dropShard,\n getInternalShardConfig,\n newReplicationSlot,\n replicationSlotExpression,\n validatePublications,\n} from './schema/shard.ts';\n\nexport type InitialSyncOptions = {\n tableCopyWorkers: number;\n profileCopy?: boolean | undefined;\n};\n\n/** Server context to store with the initial sync metadata for debugging. */\nexport type ServerContext = JSONObject;\n\nexport async function initialSync(\n lc: LogContext,\n shard: ShardConfig,\n tx: Database,\n upstreamURI: string,\n syncOptions: InitialSyncOptions,\n context: ServerContext,\n) {\n if (!ALLOWED_APP_ID_CHARACTERS.test(shard.appID)) {\n throw new Error(\n 'The App ID may only consist of lower-case letters, numbers, and the underscore character',\n );\n }\n const {tableCopyWorkers, profileCopy} = syncOptions;\n const copyProfiler = profileCopy ? await CpuProfiler.connect() : null;\n const sql = pgClient(lc, upstreamURI);\n const replicationSession = pgClient(lc, upstreamURI, {\n ['fetch_types']: false, // Necessary for the streaming protocol\n connection: {replication: 'database'}, // https://www.postgresql.org/docs/current/protocol-replication.html\n });\n const slotName = newReplicationSlot(shard);\n const statusPublisher = new ReplicationStatusPublisher(tx).publish(\n lc,\n 'Initializing',\n );\n try {\n await checkUpstreamConfig(sql);\n\n const {publications} = await ensurePublishedTables(lc, sql, shard);\n lc.info?.(`Upstream is setup with publications [${publications}]`);\n\n const {database, host} = sql.options;\n lc.info?.(`opening replication session to ${database}@${host}`);\n\n let slot: ReplicationSlot;\n for (let first = true; ; first = false) {\n try {\n slot = await createReplicationSlot(lc, replicationSession, slotName);\n break;\n } catch (e) {\n if (first && e instanceof postgres.PostgresError) {\n if (e.code === PG_INSUFFICIENT_PRIVILEGE) {\n // Some Postgres variants (e.g. Google Cloud SQL) require that\n // the user have the REPLICATION role in order to create a slot.\n // Note that this must be done by the upstreamDB connection, and\n // does not work in the replicationSession itself.\n await sql`ALTER ROLE current_user WITH REPLICATION`;\n lc.info?.(`Added the REPLICATION role to database user`);\n continue;\n }\n if (e.code === PG_CONFIGURATION_LIMIT_EXCEEDED) {\n const slotExpression = replicationSlotExpression(shard);\n\n const dropped = await sql<{slot: string}[]>`\n SELECT slot_name as slot, pg_drop_replication_slot(slot_name) \n FROM pg_replication_slots\n WHERE slot_name LIKE ${slotExpression} AND NOT active`;\n if (dropped.length) {\n lc.warn?.(\n `Dropped inactive replication slots: ${dropped.map(({slot}) => slot)}`,\n e,\n );\n continue;\n }\n lc.error?.(`Unable to drop replication slots`, e);\n }\n }\n throw e;\n }\n }\n const {snapshot_name: snapshot, consistent_point: lsn} = slot;\n const initialVersion = toStateVersionString(lsn);\n\n initReplicationState(tx, publications, initialVersion, context);\n\n // Run up to MAX_WORKERS to copy of tables at the replication slot's snapshot.\n const start = performance.now();\n // Retrieve the published schema at the consistent_point.\n const published = await runTx(\n sql,\n async tx => {\n await tx.unsafe(/* sql*/ `SET TRANSACTION SNAPSHOT '${snapshot}'`);\n return getPublicationInfo(tx, publications);\n },\n {mode: Mode.READONLY},\n );\n // Note: If this throws, initial-sync is aborted.\n validatePublications(lc, published);\n\n // Now that tables have been validated, kick off the copiers.\n const {tables, indexes} = published;\n const numTables = tables.length;\n if (platform() === 'win32' && tableCopyWorkers < numTables) {\n lc.warn?.(\n `Increasing the number of copy workers from ${tableCopyWorkers} to ` +\n `${numTables} to work around a Node/Postgres connection bug`,\n );\n }\n const numWorkers =\n platform() === 'win32'\n ? numTables\n : Math.min(tableCopyWorkers, numTables);\n\n const copyPool = pgClient(lc, upstreamURI, {\n max: numWorkers,\n connection: {['application_name']: 'initial-sync-copy-worker'},\n });\n const copiers = startTableCopyWorkers(\n lc,\n copyPool,\n snapshot,\n numWorkers,\n numTables,\n );\n try {\n createLiteTables(tx, tables, initialVersion);\n const downloads = await Promise.all(\n tables.map(spec =>\n copiers.processReadTask((db, lc) =>\n getInitialDownloadState(lc, db, spec),\n ),\n ),\n );\n statusPublisher.publish(\n lc,\n 'Initializing',\n `Copying ${numTables} upstream tables at version ${initialVersion}`,\n 5000,\n () => ({downloadStatus: downloads.map(({status}) => status)}),\n );\n\n void copyProfiler?.start();\n const rowCounts = await Promise.all(\n downloads.map(table =>\n copiers.processReadTask((db, lc) =>\n copy(lc, table, copyPool, db, tx),\n ),\n ),\n );\n void copyProfiler?.stopAndDispose(lc, 'initial-copy');\n\n const total = rowCounts.reduce(\n (acc, curr) => ({\n rows: acc.rows + curr.rows,\n flushTime: acc.flushTime + curr.flushTime,\n }),\n {rows: 0, flushTime: 0},\n );\n\n statusPublisher.publish(\n lc,\n 'Indexing',\n `Creating ${indexes.length} indexes`,\n 5000,\n );\n const indexStart = performance.now();\n createLiteIndices(tx, indexes);\n const index = performance.now() - indexStart;\n lc.info?.(`Created indexes (${index.toFixed(3)} ms)`);\n\n await addReplica(\n sql,\n shard,\n slotName,\n initialVersion,\n published,\n context,\n );\n\n const elapsed = performance.now() - start;\n lc.info?.(\n `Synced ${total.rows.toLocaleString()} rows of ${numTables} tables in ${publications} up to ${lsn} ` +\n `(flush: ${total.flushTime.toFixed(3)}, index: ${index.toFixed(3)}, total: ${elapsed.toFixed(3)} ms)`,\n );\n } finally {\n copiers.setDone();\n if (platform() === 'win32') {\n // Workaround a Node bug in Windows in which certain COPY streams result\n // in hanging the connection, which causes this await to never resolve.\n void copyPool.end().catch(e => lc.warn?.(`Error closing copyPool`, e));\n } else {\n await copyPool.end();\n }\n }\n } catch (e) {\n // If initial-sync did not succeed, make a best effort to drop the\n // orphaned replication slot to avoid running out of slots in\n // pathological cases that result in repeated failures.\n lc.warn?.(`dropping replication slot ${slotName}`, e);\n await sql`\n SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots\n WHERE slot_name = ${slotName};\n `.catch(e => lc.warn?.(`Unable to drop replication slot ${slotName}`, e));\n await statusPublisher.publishAndThrowError(lc, 'Initializing', e);\n } finally {\n statusPublisher.stop();\n await replicationSession.end();\n await sql.end();\n }\n}\n\nasync function checkUpstreamConfig(sql: PostgresDB) {\n const {walLevel, version} = (\n await sql<{walLevel: string; version: number}[]>`\n SELECT current_setting('wal_level') as \"walLevel\", \n current_setting('server_version_num') as \"version\";\n `\n )[0];\n\n if (walLevel !== 'logical') {\n throw new Error(\n `Postgres must be configured with \"wal_level = logical\" (currently: \"${walLevel})`,\n );\n }\n if (version < 150000) {\n throw new Error(\n `Must be running Postgres 15 or higher (currently: \"${version}\")`,\n );\n }\n}\n\nasync function ensurePublishedTables(\n lc: LogContext,\n sql: PostgresDB,\n shard: ShardConfig,\n validate = true,\n): Promise<{publications: string[]}> {\n const {database, host} = sql.options;\n lc.info?.(`Ensuring upstream PUBLICATION on ${database}@${host}`);\n\n await ensureShardSchema(lc, sql, shard);\n const {publications} = await getInternalShardConfig(sql, shard);\n\n if (validate) {\n let valid = false;\n const nonInternalPublications = publications.filter(\n p => !p.startsWith('_'),\n );\n const exists = await sql`\n SELECT pubname FROM pg_publication WHERE pubname IN ${sql(publications)}\n `.values();\n if (exists.length !== publications.length) {\n lc.warn?.(\n `some configured publications [${publications}] are missing: ` +\n `[${exists.flat()}]. resyncing`,\n );\n } else if (\n !equals(new Set(shard.publications), new Set(nonInternalPublications))\n ) {\n lc.warn?.(\n `requested publications [${shard.publications}] differ from previous` +\n `publications [${nonInternalPublications}]. resyncing`,\n );\n } else {\n valid = true;\n }\n if (!valid) {\n await sql.unsafe(dropShard(shard.appID, shard.shardNum));\n return ensurePublishedTables(lc, sql, shard, false);\n }\n }\n return {publications};\n}\n\nfunction startTableCopyWorkers(\n lc: LogContext,\n db: PostgresDB,\n snapshot: string,\n numWorkers: number,\n numTables: number,\n): TransactionPool {\n const {init} = importSnapshot(snapshot);\n const tableCopiers = new TransactionPool(\n lc,\n Mode.READONLY,\n init,\n undefined,\n numWorkers,\n );\n tableCopiers.run(db);\n\n lc.info?.(`Started ${numWorkers} workers to copy ${numTables} tables`);\n\n if (parseInt(process.versions.node) < 22) {\n lc.warn?.(\n `\\n\\n\\n` +\n `Older versions of Node have a bug that results in an unresponsive\\n` +\n `Postgres connection after running certain combinations of COPY commands.\\n` +\n `If initial sync hangs, run zero-cache with Node v22+. This has the additional\\n` +\n `benefit of being consistent with the Node version run in the production container image.` +\n `\\n\\n\\n`,\n );\n }\n return tableCopiers;\n}\n\n// Row returned by `CREATE_REPLICATION_SLOT`\ntype ReplicationSlot = {\n slot_name: string;\n consistent_point: string;\n snapshot_name: string;\n output_plugin: string;\n};\n\n// Note: The replication connection does not support the extended query protocol,\n// so all commands must be sent using sql.unsafe(). This is technically safe\n// because all placeholder values are under our control (i.e. \"slotName\").\nexport async function createReplicationSlot(\n lc: LogContext,\n session: postgres.Sql,\n slotName: string,\n): Promise<ReplicationSlot> {\n const slot = (\n await session.unsafe<ReplicationSlot[]>(\n /*sql*/ `CREATE_REPLICATION_SLOT \"${slotName}\" LOGICAL pgoutput`,\n )\n )[0];\n lc.info?.(`Created replication slot ${slotName}`, slot);\n return slot;\n}\n\nfunction createLiteTables(\n tx: Database,\n tables: PublishedTableSpec[],\n initialVersion: string,\n) {\n // TODO: Figure out how to reuse the ChangeProcessor here to avoid\n // duplicating the ColumnMetadata logic.\n const columnMetadata = must(ColumnMetadataStore.getInstance(tx));\n for (const t of tables) {\n tx.exec(createLiteTableStatement(mapPostgresToLite(t, initialVersion)));\n const tableName = liteTableName(t);\n for (const [colName, colSpec] of Object.entries(t.columns)) {\n columnMetadata.insert(tableName, colName, colSpec);\n }\n }\n}\n\nfunction createLiteIndices(tx: Database, indices: IndexSpec[]) {\n for (const index of indices) {\n tx.exec(createLiteIndexStatement(mapPostgresToLiteIndex(index)));\n }\n}\n\n// Verified empirically that batches of 50 seem to be the sweet spot,\n// similar to the report in https://sqlite.org/forum/forumpost/8878a512d3652655\n//\n// Exported for testing.\nexport const INSERT_BATCH_SIZE = 50;\n\nconst MB = 1024 * 1024;\nconst MAX_BUFFERED_ROWS = 10_000;\nconst BUFFERED_SIZE_THRESHOLD = 8 * MB;\n\nexport type DownloadStatements = {\n select: string;\n getTotalRows: string;\n getTotalBytes: string;\n};\n\nexport function makeDownloadStatements(\n table: PublishedTableSpec,\n cols: string[],\n): DownloadStatements {\n const filterConditions = Object.values(table.publications)\n .map(({rowFilter}) => rowFilter)\n .filter(f => !!f); // remove nulls\n const where =\n filterConditions.length === 0\n ? ''\n : /*sql*/ `WHERE ${filterConditions.join(' OR ')}`;\n const fromTable = /*sql*/ `FROM ${id(table.schema)}.${id(table.name)} ${where}`;\n const totalBytes = `(${cols.map(col => `SUM(COALESCE(pg_column_size(${id(col)}), 0))`).join(' + ')})`;\n const stmts = {\n select: /*sql*/ `SELECT ${cols.map(id).join(',')} ${fromTable}`,\n getTotalRows: /*sql*/ `SELECT COUNT(*) AS \"totalRows\" ${fromTable}`,\n getTotalBytes: /*sql*/ `SELECT ${totalBytes} AS \"totalBytes\" ${fromTable}`,\n };\n return stmts;\n}\n\ntype DownloadState = {\n spec: PublishedTableSpec;\n status: DownloadStatus;\n};\n\nasync function getInitialDownloadState(\n lc: LogContext,\n sql: PostgresDB,\n spec: PublishedTableSpec,\n): Promise<DownloadState> {\n const start = performance.now();\n const table = liteTableName(spec);\n const columns = Object.keys(spec.columns);\n const stmts = makeDownloadStatements(spec, columns);\n const rowsResult = sql\n .unsafe<{totalRows: bigint}[]>(stmts.getTotalRows)\n .execute();\n const bytesResult = sql\n .unsafe<{totalBytes: bigint}[]>(stmts.getTotalBytes)\n .execute();\n\n const state: DownloadState = {\n spec,\n status: {\n table,\n columns,\n rows: 0,\n totalRows: Number((await rowsResult)[0].totalRows),\n totalBytes: Number((await bytesResult)[0].totalBytes),\n },\n };\n const elapsed = (performance.now() - start).toFixed(3);\n lc.info?.(`Computed initial download state for ${table} (${elapsed} ms)`, {\n state: state.status,\n });\n return state;\n}\n\nasync function copy(\n lc: LogContext,\n {spec: table, status}: DownloadState,\n dbClient: PostgresDB,\n from: PostgresTransaction,\n to: Database,\n) {\n const start = performance.now();\n let flushTime = 0;\n\n const tableName = liteTableName(table);\n const orderedColumns = Object.entries(table.columns);\n\n const columnNames = orderedColumns.map(([c]) => c);\n const columnSpecs = orderedColumns.map(([_name, spec]) => spec);\n const insertColumnList = columnNames.map(c => id(c)).join(',');\n\n // (?,?,?,?,?)\n const valuesSql =\n columnNames.length > 0 ? `(${'?,'.repeat(columnNames.length - 1)}?)` : '()';\n const insertSql = /*sql*/ `\n INSERT INTO \"${tableName}\" (${insertColumnList}) VALUES ${valuesSql}`;\n const insertStmt = to.prepare(insertSql);\n // INSERT VALUES (?,?,?,?,?),... x INSERT_BATCH_SIZE\n const insertBatchStmt = to.prepare(\n insertSql + `,${valuesSql}`.repeat(INSERT_BATCH_SIZE - 1),\n );\n\n const {select} = makeDownloadStatements(table, columnNames);\n const valuesPerRow = columnSpecs.length;\n const valuesPerBatch = valuesPerRow * INSERT_BATCH_SIZE;\n\n // Preallocate the buffer of values to reduce memory allocation churn.\n const pendingValues: LiteValueType[] = Array.from({\n length: MAX_BUFFERED_ROWS * valuesPerRow,\n });\n let pendingRows = 0;\n let pendingSize = 0;\n\n function flush() {\n const start = performance.now();\n const flushedRows = pendingRows;\n const flushedSize = pendingSize;\n\n let l = 0;\n for (; pendingRows > INSERT_BATCH_SIZE; pendingRows -= INSERT_BATCH_SIZE) {\n insertBatchStmt.run(pendingValues.slice(l, (l += valuesPerBatch)));\n }\n // Insert the remaining rows individually.\n for (; pendingRows > 0; pendingRows--) {\n insertStmt.run(pendingValues.slice(l, (l += valuesPerRow)));\n }\n for (let i = 0; i < flushedRows; i++) {\n // Reuse the array and unreference the values to allow GC.\n // This is faster than allocating a new array every time.\n pendingValues[i] = undefined as unknown as LiteValueType;\n }\n pendingSize = 0;\n status.rows += flushedRows;\n\n const elapsed = performance.now() - start;\n flushTime += elapsed;\n lc.debug?.(\n `flushed ${flushedRows} ${tableName} rows (${flushedSize} bytes) in ${elapsed.toFixed(3)} ms`,\n );\n }\n\n lc.info?.(`Starting copy stream of ${tableName}:`, select);\n const pgParsers = await getTypeParsers(dbClient, {returnJsonAsString: true});\n const parsers = columnSpecs.map(c => {\n const pgParse = pgParsers.getTypeParser(c.typeOID);\n return (val: string) =>\n liteValue(\n pgParse(val) as PostgresValueType,\n c.dataType,\n JSON_STRINGIFIED,\n );\n });\n\n const tsvParser = new TsvParser();\n let col = 0;\n\n await pipeline(\n await from.unsafe(`COPY (${select}) TO STDOUT`).readable(),\n new Writable({\n highWaterMark: BUFFERED_SIZE_THRESHOLD,\n\n write(\n chunk: Buffer,\n _encoding: string,\n callback: (error?: Error) => void,\n ) {\n try {\n for (const text of tsvParser.parse(chunk)) {\n pendingSize += text === null ? 4 : text.length;\n pendingValues[pendingRows * valuesPerRow + col] =\n text === null ? null : parsers[col](text);\n\n if (++col === parsers.length) {\n col = 0;\n if (\n ++pendingRows >= MAX_BUFFERED_ROWS - valuesPerRow ||\n pendingSize >= BUFFERED_SIZE_THRESHOLD\n ) {\n flush();\n }\n }\n }\n callback();\n } catch (e) {\n callback(e instanceof Error ? e : new Error(String(e)));\n }\n },\n\n final: (callback: (error?: Error) => void) => {\n try {\n flush();\n callback();\n } catch (e) {\n callback(e instanceof Error ? e : new Error(String(e)));\n }\n },\n }),\n );\n\n const elapsed = performance.now() - start;\n lc.info?.(\n `Finished copying ${status.rows} rows into ${tableName} ` +\n `(flush: ${flushTime.toFixed(3)} ms) (total: ${elapsed.toFixed(3)} ms) `,\n );\n return {rows: status.rows, flushTime};\n}\n"],"names":["slot","tx","Mode.READONLY","lc","e","start","elapsed"],"mappings":"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"}
@@ -238,6 +238,12 @@ export declare const dropIndexSchema: v.ObjectType<{
238
238
  name: v.Type<string>;
239
239
  }, undefined>;
240
240
  }, undefined>;
241
+ export declare const downloadStatusSchema: v.ObjectType<{
242
+ rows: v.Type<number>;
243
+ totalRows: v.Type<number>;
244
+ totalBytes: v.Optional<number>;
245
+ }, undefined>;
246
+ export type DownloadStatus = v.Infer<typeof downloadStatusSchema>;
241
247
  export declare const backfillSchema: v.ObjectType<{
242
248
  tag: v.Type<"backfill">;
243
249
  relation: v.ObjectType<{
@@ -251,6 +257,11 @@ export declare const backfillSchema: v.ObjectType<{
251
257
  columns: v.ArrayType<v.Type<string>>;
252
258
  watermark: v.Type<string>;
253
259
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../../../shared/src/bigint-json.ts").JSONValue>>>;
260
+ status: v.Optional<{
261
+ totalBytes?: number | undefined;
262
+ rows: number;
263
+ totalRows: number;
264
+ }>;
254
265
  }, undefined>;
255
266
  export declare const backfillCompletedSchema: v.ObjectType<{
256
267
  tag: v.Type<"backfill-completed">;
@@ -264,6 +275,11 @@ export declare const backfillCompletedSchema: v.ObjectType<{
264
275
  }, undefined>;
265
276
  columns: v.ArrayType<v.Type<string>>;
266
277
  watermark: v.Type<string>;
278
+ status: v.Optional<{
279
+ totalBytes?: number | undefined;
280
+ rows: number;
281
+ totalRows: number;
282
+ }>;
267
283
  }, undefined>;
268
284
  export type MessageBegin = v.Infer<typeof beginSchema>;
269
285
  export type MessageCommit = v.Infer<typeof commitSchema>;
@@ -349,6 +365,11 @@ export declare const dataChangeSchema: v.UnionType<[v.ObjectType<{
349
365
  columns: v.ArrayType<v.Type<string>>;
350
366
  watermark: v.Type<string>;
351
367
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../../../shared/src/bigint-json.ts").JSONValue>>>;
368
+ status: v.Optional<{
369
+ totalBytes?: number | undefined;
370
+ rows: number;
371
+ totalRows: number;
372
+ }>;
352
373
  }, undefined>]>;
353
374
  declare const dataChangeTagsSchema: v.Type<"insert" | "update" | "delete" | "truncate" | "backfill">;
354
375
  export type DataChange = Satisfies<JSONObject, // guarantees serialization over IPC or network
@@ -492,6 +513,11 @@ export declare const schemaChangeSchema: v.UnionType<[v.ObjectType<{
492
513
  }, undefined>;
493
514
  columns: v.ArrayType<v.Type<string>>;
494
515
  watermark: v.Type<string>;
516
+ status: v.Optional<{
517
+ totalBytes?: number | undefined;
518
+ rows: number;
519
+ totalRows: number;
520
+ }>;
495
521
  }, undefined>]>;
496
522
  declare const schemaChangeTagsSchema: v.Type<"create-table" | "rename-table" | "update-table-metadata" | "add-column" | "update-column" | "drop-column" | "drop-table" | "create-index" | "drop-index" | "backfill-completed">;
497
523
  export type SchemaChange = Satisfies<JSONObject, v.Infer<typeof schemaChangeSchema>>;
@@ -1 +1 @@
1
- {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import { must } from "../../../../../../shared/src/must.js";
3
3
  import { literalUnion } from "../../../../../../shared/src/valita.js";
4
4
  import { tableSpec, columnSpec, indexSpec } from "../../../../db/specs.js";
5
5
  import { jsonObjectSchema } from "./json.js";
6
- import { object, boolean, literal, array, string, record, union } from "@badrap/valita";
6
+ import { object, boolean, literal, array, string, record, number, union } from "@badrap/valita";
7
7
  const beginSchema = object({
8
8
  tag: literal("begin"),
9
9
  // The format of values of "json"-typed columns (e.g. "JSON" and "JSONB").
@@ -173,6 +173,11 @@ const dropIndexSchema = object({
173
173
  tag: literal("drop-index"),
174
174
  id: identifierSchema
175
175
  });
176
+ const downloadStatusSchema = object({
177
+ rows: number(),
178
+ totalRows: number(),
179
+ totalBytes: number().optional()
180
+ });
176
181
  const backfillSchema = object({
177
182
  tag: literal("backfill"),
178
183
  relation: newRelationSchema,
@@ -194,7 +199,10 @@ const backfillSchema = object({
194
199
  // [...rowKeyValues, ...columnValues], // row 2
195
200
  // ]
196
201
  // ```
197
- rowValues: array(array(jsonValueSchema))
202
+ rowValues: array(array(jsonValueSchema)),
203
+ // Optionally includes the progress of the backfill operation,
204
+ // for display purposes.
205
+ status: downloadStatusSchema.optional()
198
206
  });
199
207
  const backfillCompletedSchema = object({
200
208
  tag: literal("backfill-completed"),
@@ -206,7 +214,10 @@ const backfillCompletedSchema = object({
206
214
  // generally will be different from the commit watermarks of the main change
207
215
  // stream, and in particular, the commit watermark of the backfill change's
208
216
  // enclosing transaction.
209
- watermark: string()
217
+ watermark: string(),
218
+ // Optionally includes the final status of the backfill operation,
219
+ // for display purposes.
220
+ status: downloadStatusSchema.optional()
210
221
  });
211
222
  const dataChangeSchema = union(
212
223
  insertSchema,
@@ -268,6 +279,7 @@ export {
268
279
  createTableSchema,
269
280
  dataChangeSchema,
270
281
  deleteSchema,
282
+ downloadStatusSchema,
271
283
  dropColumnSchema,
272
284
  dropIndexSchema,
273
285
  dropTableSchema,
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"sourcesContent":["/**\n * Data plane messages encapsulate changes that are sent by ChangeSources,\n * forwarded / fanned out to subscribers by the ChangeStreamerService, and\n * stored in the Change DB for catchup of old subscribers.\n */\n\nimport {\n jsonValueSchema,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../../shared/src/must.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {columnSpec, indexSpec, tableSpec} from '../../../../db/specs.ts';\nimport type {Satisfies} from '../../../../types/satisfies.ts';\nimport {jsonObjectSchema} from './json.ts';\n\nexport const beginSchema = v.object({\n tag: v.literal('begin'),\n // The format of values of \"json\"-typed columns (e.g. \"JSON\" and \"JSONB\").\n // - 'p' is for parsed JSON, which may include JSON values or JSON objects.\n // These values are parsed and stringified at every process boundary\n // between the change-source and the replica.\n // - 's' is for stringified JSON. These values skip the parsing and\n // stringification, and are directly ferried to the replica as a JSON\n // string. For JSON values this improves performance by 20~25% in the\n // change-streamer and 25~30% in the replicator.\n //\n // If absent, the format is assumed to be 'p' (parsed JSON objects/values).\n json: v.literalUnion('p', 's').optional(),\n\n // Directs the change-streamer to skip the ACK for the corresponding commit.\n skipAck: v.boolean().optional(),\n});\n\nexport const commitSchema = v.object({\n tag: v.literal('commit'),\n});\n\nexport const rollbackSchema = v.object({\n tag: v.literal('rollback'),\n});\n\nconst rowKeySchema = v.object({\n // The columns used to identify a row in insert, update, and delete changes.\n columns: v.array(v.string()),\n\n // An optional qualifier identifying how the key is chosen. Currently this\n // is postgres-specific, describing the REPLICA IDENTITY, for which replica\n // identity 'full' (FULL) is handled differently; the replicator handles\n // these tables by extracting a row key from the full row based on the\n // table's PRIMARY KEY or UNIQUE INDEX.\n type: v.literalUnion('default', 'nothing', 'full', 'index').optional(),\n});\n\nexport const relationSchema = v\n .object({\n schema: v.string(),\n name: v.string(),\n\n // This will become required.\n rowKey: rowKeySchema.optional(),\n\n /** Deprecated: set the rowKey.columns instead. */\n keyColumns: v.array(v.string()).optional(),\n /** Deprecated: set the rowKey.columns instead. */\n replicaIdentity: v\n .literalUnion('default', 'nothing', 'full', 'index')\n .optional(),\n })\n .map(rel => {\n const {rowKey, ...rest} = rel;\n if (rowKey) {\n return {...rest, rowKey};\n }\n return {\n ...rest,\n rowKey: {\n columns: must(rel.keyColumns),\n type: rel.replicaIdentity,\n },\n };\n });\n\n// The eventual fate of relationSchema\nexport const newRelationSchema = v.object({\n schema: v.string(),\n name: v.string(),\n\n rowKey: rowKeySchema,\n});\n\n// TableMetadata contains table-related configuration that does not affect the\n// actual data in the table, but rather how the table's change messages are\n// handled. The is an opaque object that clients must track (and update) based\n// on `create-table`, `add-column`, and `table-update-metadata` messages, and\n// pass in BackfillRequests when there are columns to be backfilled.\n//\n// Note that the backfill-related change-source implementation does, however,\n// rely on the rowKey (columns) being specified in the message.\nexport const tableMetadataSchema = v\n .object({rowKey: v.record(jsonValueSchema)})\n .rest(jsonValueSchema);\n\nexport type TableMetadata = v.Infer<typeof tableMetadataSchema>;\n\nexport const rowSchema = v.record(jsonValueSchema);\n\nexport const insertSchema = v.object({\n tag: v.literal('insert'),\n relation: relationSchema,\n new: rowSchema,\n});\n\nexport const updateSchema = v.object({\n tag: v.literal('update'),\n relation: relationSchema,\n // `key` is present if the update changed the key of the row, or if the\n // table's replicaIdentity === 'full'\n key: rowSchema.nullable(),\n // `new` is the full row (and not just the updated columns). This is\n // necessary for \"catchup\" replication scenarios such as adding tables\n // to a publication, or resharding.\n new: rowSchema,\n});\n\nexport const deleteSchema = v.object({\n tag: v.literal('delete'),\n relation: relationSchema,\n // key is the full row if replicaIdentity === 'full'\n key: rowSchema,\n});\n\nexport const truncateSchema = v.object({\n tag: v.literal('truncate'),\n relations: v.array(relationSchema),\n});\n\nexport const identifierSchema = v.object({\n schema: v.string(),\n name: v.string(),\n});\n\nexport type Identifier = v.Infer<typeof identifierSchema>;\n\n// A BackfillID is an upstream specific stable identifier for a column\n// that needs backfilling. This id is used to ensure that the schema, table,\n// and column names of a requested backfill still match the original\n// underlying upstream ID.\n//\n// The change-streamer stores these IDs as opaque values while a column is\n// being backfilled, and initiates new change-source streams with the IDs\n// in order to restart backfills that did not complete in previous sessions.\nexport const backfillIDSchema = jsonObjectSchema;\n\nexport type BackfillID = v.Infer<typeof backfillIDSchema>;\n\nexport const createTableSchema = v.object({\n tag: v.literal('create-table'),\n spec: tableSpec,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n metadata: tableMetadataSchema.optional(),\n\n // Indicate that columns of the table require backfilling. These columns\n // should be created on the replica but not yet synced the clients.\n //\n // ## State Persistence\n //\n // To obviate the need for change-source implementations to persist state\n // related to backfill progress, the change-source only tracks backfills\n // **for the current session**. In the event that the session is interrupted\n // before columns have been fully backfilled, it is the responsibility of the\n // change-streamer to send {@link BackfillRequest}s when it reconnects.\n //\n // This means that the change-streamer must track and persist:\n // * the backfill IDs of the columns requiring backfilling\n // * the most current table metadata of the associated table(s)\n //\n // The change-streamer then uses this information to send backfill requests\n // when it reconnects.\n backfill: v.record(backfillIDSchema).optional(),\n});\n\nexport const renameTableSchema = v.object({\n tag: v.literal('rename-table'),\n old: identifierSchema,\n new: identifierSchema,\n});\n\nexport const updateTableMetadataSchema = v.object({\n tag: v.literal('update-table-metadata'),\n table: identifierSchema,\n old: tableMetadataSchema,\n new: tableMetadataSchema,\n});\n\nconst columnSchema = v.object({\n name: v.string(),\n spec: columnSpec,\n});\n\nexport const addColumnSchema = v.object({\n tag: v.literal('add-column'),\n table: identifierSchema,\n column: columnSchema,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n tableMetadata: tableMetadataSchema.optional(),\n\n // See documentation for the `backfill` field of the `create-table` change.\n backfill: backfillIDSchema.optional(),\n});\n\nexport const updateColumnSchema = v.object({\n tag: v.literal('update-column'),\n table: identifierSchema,\n old: columnSchema,\n new: columnSchema,\n});\n\nexport const dropColumnSchema = v.object({\n tag: v.literal('drop-column'),\n table: identifierSchema,\n column: v.string(),\n});\n\nexport const dropTableSchema = v.object({\n tag: v.literal('drop-table'),\n id: identifierSchema,\n});\n\nexport const createIndexSchema = v.object({\n tag: v.literal('create-index'),\n spec: indexSpec,\n});\n\nexport const dropIndexSchema = v.object({\n tag: v.literal('drop-index'),\n id: identifierSchema,\n});\n\n// A batch of rows from a single table containing column values\n// to be backfilled.\nexport const backfillSchema = v.object({\n tag: v.literal('backfill'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // A batch of row values, each row consisting of the `rowKey`\n // values, followed by the `column` values, in the same order in which\n // the column names appear in their respective fields, e.g.\n //\n // ```\n // [\n // [...rowKeyValues, ...columnValues], // row 1\n // [...rowKeyValues, ...columnValues], // row 2\n // ]\n // ```\n rowValues: v.array(v.array(jsonValueSchema)),\n});\n\n// Indicates that the backfill for the specified columns have\n// been successfully backfilled and can be published to clients.\nexport const backfillCompletedSchema = v.object({\n tag: v.literal('backfill-completed'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n});\n\nexport type MessageBegin = v.Infer<typeof beginSchema>;\nexport type MessageCommit = v.Infer<typeof commitSchema>;\nexport type MessageRollback = v.Infer<typeof rollbackSchema>;\n\nexport type MessageRelation = v.Infer<typeof relationSchema>;\nexport type MessageInsert = v.Infer<typeof insertSchema>;\nexport type MessageUpdate = v.Infer<typeof updateSchema>;\nexport type MessageDelete = v.Infer<typeof deleteSchema>;\nexport type MessageTruncate = v.Infer<typeof truncateSchema>;\n\nexport type MessageBackfill = v.Infer<typeof backfillSchema>;\n\nexport type TableCreate = v.Infer<typeof createTableSchema>;\nexport type TableRename = v.Infer<typeof renameTableSchema>;\nexport type TableUpdateMetadata = v.Infer<typeof updateTableMetadataSchema>;\nexport type ColumnAdd = v.Infer<typeof addColumnSchema>;\nexport type ColumnUpdate = v.Infer<typeof updateColumnSchema>;\nexport type ColumnDrop = v.Infer<typeof dropColumnSchema>;\nexport type TableDrop = v.Infer<typeof dropTableSchema>;\nexport type IndexCreate = v.Infer<typeof createIndexSchema>;\nexport type IndexDrop = v.Infer<typeof dropIndexSchema>;\nexport type BackfillCompleted = v.Infer<typeof backfillCompletedSchema>;\n\nexport const dataChangeSchema = v.union(\n insertSchema,\n updateSchema,\n deleteSchema,\n truncateSchema,\n backfillSchema,\n);\n\n// Note: keep in sync or the tag tests will fail\nconst dataChangeTags = [\n 'insert',\n 'update',\n 'delete',\n 'truncate',\n 'backfill',\n] as const;\n\nconst dataChangeTagsSchema = v.literalUnion(...dataChangeTags);\n\nexport type DataChange = Satisfies<\n JSONObject, // guarantees serialization over IPC or network\n v.Infer<typeof dataChangeSchema>\n>;\n\nexport type DataChangeTag = v.Infer<typeof dataChangeTagsSchema>;\n\nconst schemaChanges = [\n createTableSchema,\n renameTableSchema,\n updateTableMetadataSchema,\n addColumnSchema,\n updateColumnSchema,\n dropColumnSchema,\n dropTableSchema,\n createIndexSchema,\n dropIndexSchema,\n backfillCompletedSchema,\n] as const;\n\n// Note: keep in sync or the tag tests will fail\nconst schemaChangeTags = [\n 'create-table',\n 'rename-table',\n 'update-table-metadata',\n 'add-column',\n 'update-column',\n 'drop-column',\n 'drop-table',\n 'create-index',\n 'drop-index',\n 'backfill-completed',\n] as const;\n\nexport const schemaChangeSchema = v.union(...schemaChanges);\n\nconst schemaChangeTagsSchema = v.literalUnion(...schemaChangeTags);\n\nexport type SchemaChange = Satisfies<\n JSONObject,\n v.Infer<typeof schemaChangeSchema>\n>;\n\nexport type SchemaChangeTag = v.Infer<typeof schemaChangeTagsSchema>;\n\nexport type DataOrSchemaChange = DataChange | SchemaChange;\n\nexport type Change =\n | MessageBegin\n | DataOrSchemaChange\n | MessageCommit\n | MessageRollback;\n\nexport type ChangeTag = Change['tag'];\n\nconst schemaChangeTagSet = new Set<string>(schemaChangeTags);\n\nexport function isSchemaChange(change: Change): change is SchemaChange {\n return schemaChangeTagSet.has(change.tag);\n}\n\nconst dataChangeTagSet = new Set<string>(dataChangeTags);\n\nexport function isDataChange(change: Change): change is DataChange {\n return dataChangeTagSet.has(change.tag);\n}\n"],"names":["v.object","v.literal","v.literalUnion","v.boolean","v.array","v.string","v.record","v.union"],"mappings":"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"}
1
+ {"version":3,"file":"data.js","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/data.ts"],"sourcesContent":["/**\n * Data plane messages encapsulate changes that are sent by ChangeSources,\n * forwarded / fanned out to subscribers by the ChangeStreamerService, and\n * stored in the Change DB for catchup of old subscribers.\n */\n\nimport {\n jsonValueSchema,\n type JSONObject,\n} from '../../../../../../shared/src/bigint-json.ts';\nimport {must} from '../../../../../../shared/src/must.ts';\nimport * as v from '../../../../../../shared/src/valita.ts';\nimport {columnSpec, indexSpec, tableSpec} from '../../../../db/specs.ts';\nimport type {Satisfies} from '../../../../types/satisfies.ts';\nimport {jsonObjectSchema} from './json.ts';\n\nexport const beginSchema = v.object({\n tag: v.literal('begin'),\n // The format of values of \"json\"-typed columns (e.g. \"JSON\" and \"JSONB\").\n // - 'p' is for parsed JSON, which may include JSON values or JSON objects.\n // These values are parsed and stringified at every process boundary\n // between the change-source and the replica.\n // - 's' is for stringified JSON. These values skip the parsing and\n // stringification, and are directly ferried to the replica as a JSON\n // string. For JSON values this improves performance by 20~25% in the\n // change-streamer and 25~30% in the replicator.\n //\n // If absent, the format is assumed to be 'p' (parsed JSON objects/values).\n json: v.literalUnion('p', 's').optional(),\n\n // Directs the change-streamer to skip the ACK for the corresponding commit.\n skipAck: v.boolean().optional(),\n});\n\nexport const commitSchema = v.object({\n tag: v.literal('commit'),\n});\n\nexport const rollbackSchema = v.object({\n tag: v.literal('rollback'),\n});\n\nconst rowKeySchema = v.object({\n // The columns used to identify a row in insert, update, and delete changes.\n columns: v.array(v.string()),\n\n // An optional qualifier identifying how the key is chosen. Currently this\n // is postgres-specific, describing the REPLICA IDENTITY, for which replica\n // identity 'full' (FULL) is handled differently; the replicator handles\n // these tables by extracting a row key from the full row based on the\n // table's PRIMARY KEY or UNIQUE INDEX.\n type: v.literalUnion('default', 'nothing', 'full', 'index').optional(),\n});\n\nexport const relationSchema = v\n .object({\n schema: v.string(),\n name: v.string(),\n\n // This will become required.\n rowKey: rowKeySchema.optional(),\n\n /** Deprecated: set the rowKey.columns instead. */\n keyColumns: v.array(v.string()).optional(),\n /** Deprecated: set the rowKey.columns instead. */\n replicaIdentity: v\n .literalUnion('default', 'nothing', 'full', 'index')\n .optional(),\n })\n .map(rel => {\n const {rowKey, ...rest} = rel;\n if (rowKey) {\n return {...rest, rowKey};\n }\n return {\n ...rest,\n rowKey: {\n columns: must(rel.keyColumns),\n type: rel.replicaIdentity,\n },\n };\n });\n\n// The eventual fate of relationSchema\nexport const newRelationSchema = v.object({\n schema: v.string(),\n name: v.string(),\n\n rowKey: rowKeySchema,\n});\n\n// TableMetadata contains table-related configuration that does not affect the\n// actual data in the table, but rather how the table's change messages are\n// handled. The is an opaque object that clients must track (and update) based\n// on `create-table`, `add-column`, and `table-update-metadata` messages, and\n// pass in BackfillRequests when there are columns to be backfilled.\n//\n// Note that the backfill-related change-source implementation does, however,\n// rely on the rowKey (columns) being specified in the message.\nexport const tableMetadataSchema = v\n .object({rowKey: v.record(jsonValueSchema)})\n .rest(jsonValueSchema);\n\nexport type TableMetadata = v.Infer<typeof tableMetadataSchema>;\n\nexport const rowSchema = v.record(jsonValueSchema);\n\nexport const insertSchema = v.object({\n tag: v.literal('insert'),\n relation: relationSchema,\n new: rowSchema,\n});\n\nexport const updateSchema = v.object({\n tag: v.literal('update'),\n relation: relationSchema,\n // `key` is present if the update changed the key of the row, or if the\n // table's replicaIdentity === 'full'\n key: rowSchema.nullable(),\n // `new` is the full row (and not just the updated columns). This is\n // necessary for \"catchup\" replication scenarios such as adding tables\n // to a publication, or resharding.\n new: rowSchema,\n});\n\nexport const deleteSchema = v.object({\n tag: v.literal('delete'),\n relation: relationSchema,\n // key is the full row if replicaIdentity === 'full'\n key: rowSchema,\n});\n\nexport const truncateSchema = v.object({\n tag: v.literal('truncate'),\n relations: v.array(relationSchema),\n});\n\nexport const identifierSchema = v.object({\n schema: v.string(),\n name: v.string(),\n});\n\nexport type Identifier = v.Infer<typeof identifierSchema>;\n\n// A BackfillID is an upstream specific stable identifier for a column\n// that needs backfilling. This id is used to ensure that the schema, table,\n// and column names of a requested backfill still match the original\n// underlying upstream ID.\n//\n// The change-streamer stores these IDs as opaque values while a column is\n// being backfilled, and initiates new change-source streams with the IDs\n// in order to restart backfills that did not complete in previous sessions.\nexport const backfillIDSchema = jsonObjectSchema;\n\nexport type BackfillID = v.Infer<typeof backfillIDSchema>;\n\nexport const createTableSchema = v.object({\n tag: v.literal('create-table'),\n spec: tableSpec,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n metadata: tableMetadataSchema.optional(),\n\n // Indicate that columns of the table require backfilling. These columns\n // should be created on the replica but not yet synced the clients.\n //\n // ## State Persistence\n //\n // To obviate the need for change-source implementations to persist state\n // related to backfill progress, the change-source only tracks backfills\n // **for the current session**. In the event that the session is interrupted\n // before columns have been fully backfilled, it is the responsibility of the\n // change-streamer to send {@link BackfillRequest}s when it reconnects.\n //\n // This means that the change-streamer must track and persist:\n // * the backfill IDs of the columns requiring backfilling\n // * the most current table metadata of the associated table(s)\n //\n // The change-streamer then uses this information to send backfill requests\n // when it reconnects.\n backfill: v.record(backfillIDSchema).optional(),\n});\n\nexport const renameTableSchema = v.object({\n tag: v.literal('rename-table'),\n old: identifierSchema,\n new: identifierSchema,\n});\n\nexport const updateTableMetadataSchema = v.object({\n tag: v.literal('update-table-metadata'),\n table: identifierSchema,\n old: tableMetadataSchema,\n new: tableMetadataSchema,\n});\n\nconst columnSchema = v.object({\n name: v.string(),\n spec: columnSpec,\n});\n\nexport const addColumnSchema = v.object({\n tag: v.literal('add-column'),\n table: identifierSchema,\n column: columnSchema,\n\n // This must be set by change source implementations that support\n // table/column backfill.\n //\n // TODO: to simplify the protocol, see if we can make this required\n tableMetadata: tableMetadataSchema.optional(),\n\n // See documentation for the `backfill` field of the `create-table` change.\n backfill: backfillIDSchema.optional(),\n});\n\nexport const updateColumnSchema = v.object({\n tag: v.literal('update-column'),\n table: identifierSchema,\n old: columnSchema,\n new: columnSchema,\n});\n\nexport const dropColumnSchema = v.object({\n tag: v.literal('drop-column'),\n table: identifierSchema,\n column: v.string(),\n});\n\nexport const dropTableSchema = v.object({\n tag: v.literal('drop-table'),\n id: identifierSchema,\n});\n\nexport const createIndexSchema = v.object({\n tag: v.literal('create-index'),\n spec: indexSpec,\n});\n\nexport const dropIndexSchema = v.object({\n tag: v.literal('drop-index'),\n id: identifierSchema,\n});\n\nexport const downloadStatusSchema = v.object({\n rows: v.number(),\n totalRows: v.number(),\n totalBytes: v.number().optional(),\n});\n\nexport type DownloadStatus = v.Infer<typeof downloadStatusSchema>;\n\n// A batch of rows from a single table containing column values\n// to be backfilled.\nexport const backfillSchema = v.object({\n tag: v.literal('backfill'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // A batch of row values, each row consisting of the `rowKey`\n // values, followed by the `column` values, in the same order in which\n // the column names appear in their respective fields, e.g.\n //\n // ```\n // [\n // [...rowKeyValues, ...columnValues], // row 1\n // [...rowKeyValues, ...columnValues], // row 2\n // ]\n // ```\n rowValues: v.array(v.array(jsonValueSchema)),\n\n // Optionally includes the progress of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\n// Indicates that the backfill for the specified columns have\n// been successfully backfilled and can be published to clients.\nexport const backfillCompletedSchema = v.object({\n tag: v.literal('backfill-completed'),\n\n relation: newRelationSchema,\n\n // The columns to be backfilled. `rowKey` columns are automatically excluded,\n // which means that this field may be empty.\n columns: v.array(v.string()),\n\n // The watermark at which the backfill data was queried. Note that this\n // generally will be different from the commit watermarks of the main change\n // stream, and in particular, the commit watermark of the backfill change's\n // enclosing transaction.\n watermark: v.string(),\n\n // Optionally includes the final status of the backfill operation,\n // for display purposes.\n status: downloadStatusSchema.optional(),\n});\n\nexport type MessageBegin = v.Infer<typeof beginSchema>;\nexport type MessageCommit = v.Infer<typeof commitSchema>;\nexport type MessageRollback = v.Infer<typeof rollbackSchema>;\n\nexport type MessageRelation = v.Infer<typeof relationSchema>;\nexport type MessageInsert = v.Infer<typeof insertSchema>;\nexport type MessageUpdate = v.Infer<typeof updateSchema>;\nexport type MessageDelete = v.Infer<typeof deleteSchema>;\nexport type MessageTruncate = v.Infer<typeof truncateSchema>;\n\nexport type MessageBackfill = v.Infer<typeof backfillSchema>;\n\nexport type TableCreate = v.Infer<typeof createTableSchema>;\nexport type TableRename = v.Infer<typeof renameTableSchema>;\nexport type TableUpdateMetadata = v.Infer<typeof updateTableMetadataSchema>;\nexport type ColumnAdd = v.Infer<typeof addColumnSchema>;\nexport type ColumnUpdate = v.Infer<typeof updateColumnSchema>;\nexport type ColumnDrop = v.Infer<typeof dropColumnSchema>;\nexport type TableDrop = v.Infer<typeof dropTableSchema>;\nexport type IndexCreate = v.Infer<typeof createIndexSchema>;\nexport type IndexDrop = v.Infer<typeof dropIndexSchema>;\nexport type BackfillCompleted = v.Infer<typeof backfillCompletedSchema>;\n\nexport const dataChangeSchema = v.union(\n insertSchema,\n updateSchema,\n deleteSchema,\n truncateSchema,\n backfillSchema,\n);\n\n// Note: keep in sync or the tag tests will fail\nconst dataChangeTags = [\n 'insert',\n 'update',\n 'delete',\n 'truncate',\n 'backfill',\n] as const;\n\nconst dataChangeTagsSchema = v.literalUnion(...dataChangeTags);\n\nexport type DataChange = Satisfies<\n JSONObject, // guarantees serialization over IPC or network\n v.Infer<typeof dataChangeSchema>\n>;\n\nexport type DataChangeTag = v.Infer<typeof dataChangeTagsSchema>;\n\nconst schemaChanges = [\n createTableSchema,\n renameTableSchema,\n updateTableMetadataSchema,\n addColumnSchema,\n updateColumnSchema,\n dropColumnSchema,\n dropTableSchema,\n createIndexSchema,\n dropIndexSchema,\n backfillCompletedSchema,\n] as const;\n\n// Note: keep in sync or the tag tests will fail\nconst schemaChangeTags = [\n 'create-table',\n 'rename-table',\n 'update-table-metadata',\n 'add-column',\n 'update-column',\n 'drop-column',\n 'drop-table',\n 'create-index',\n 'drop-index',\n 'backfill-completed',\n] as const;\n\nexport const schemaChangeSchema = v.union(...schemaChanges);\n\nconst schemaChangeTagsSchema = v.literalUnion(...schemaChangeTags);\n\nexport type SchemaChange = Satisfies<\n JSONObject,\n v.Infer<typeof schemaChangeSchema>\n>;\n\nexport type SchemaChangeTag = v.Infer<typeof schemaChangeTagsSchema>;\n\nexport type DataOrSchemaChange = DataChange | SchemaChange;\n\nexport type Change =\n | MessageBegin\n | DataOrSchemaChange\n | MessageCommit\n | MessageRollback;\n\nexport type ChangeTag = Change['tag'];\n\nconst schemaChangeTagSet = new Set<string>(schemaChangeTags);\n\nexport function isSchemaChange(change: Change): change is SchemaChange {\n return schemaChangeTagSet.has(change.tag);\n}\n\nconst dataChangeTagSet = new Set<string>(dataChangeTags);\n\nexport function isDataChange(change: Change): change is DataChange {\n return dataChangeTagSet.has(change.tag);\n}\n"],"names":["v.object","v.literal","v.literalUnion","v.boolean","v.array","v.string","v.record","v.number","v.union"],"mappings":"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"}
@@ -71,6 +71,11 @@ declare const data: v.TupleType<[v.Type<"data">, v.UnionType<[v.UnionType<[v.Obj
71
71
  columns: v.ArrayType<v.Type<string>>;
72
72
  watermark: v.Type<string>;
73
73
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../../../shared/src/bigint-json.ts").JSONValue>>>;
74
+ status: v.Optional<{
75
+ totalBytes?: number | undefined;
76
+ rows: number;
77
+ totalRows: number;
78
+ }>;
74
79
  }, undefined>]>, v.UnionType<[v.ObjectType<{
75
80
  tag: v.Type<"create-table">;
76
81
  spec: v.ObjectType<Omit<{
@@ -209,6 +214,11 @@ declare const data: v.TupleType<[v.Type<"data">, v.UnionType<[v.UnionType<[v.Obj
209
214
  }, undefined>;
210
215
  columns: v.ArrayType<v.Type<string>>;
211
216
  watermark: v.Type<string>;
217
+ status: v.Optional<{
218
+ totalBytes?: number | undefined;
219
+ rows: number;
220
+ totalRows: number;
221
+ }>;
212
222
  }, undefined>]>]>]>;
213
223
  declare const commit: v.TupleType<[v.Type<"commit">, v.ObjectType<{
214
224
  tag: v.Type<"commit">;
@@ -293,6 +303,11 @@ export declare const changeStreamDataSchema: v.UnionType<[v.TupleType<[v.Type<"b
293
303
  columns: v.ArrayType<v.Type<string>>;
294
304
  watermark: v.Type<string>;
295
305
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../../../shared/src/bigint-json.ts").JSONValue>>>;
306
+ status: v.Optional<{
307
+ totalBytes?: number | undefined;
308
+ rows: number;
309
+ totalRows: number;
310
+ }>;
296
311
  }, undefined>]>, v.UnionType<[v.ObjectType<{
297
312
  tag: v.Type<"create-table">;
298
313
  spec: v.ObjectType<Omit<{
@@ -431,6 +446,11 @@ export declare const changeStreamDataSchema: v.UnionType<[v.TupleType<[v.Type<"b
431
446
  }, undefined>;
432
447
  columns: v.ArrayType<v.Type<string>>;
433
448
  watermark: v.Type<string>;
449
+ status: v.Optional<{
450
+ totalBytes?: number | undefined;
451
+ rows: number;
452
+ totalRows: number;
453
+ }>;
434
454
  }, undefined>]>]>]>, v.TupleType<[v.Type<"commit">, v.ObjectType<{
435
455
  tag: v.Type<"commit">;
436
456
  }, undefined>, v.ObjectType<{
@@ -517,6 +537,11 @@ export declare const changeStreamMessageSchema: v.UnionType<[v.UnionType<[v.Tupl
517
537
  columns: v.ArrayType<v.Type<string>>;
518
538
  watermark: v.Type<string>;
519
539
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../../../shared/src/bigint-json.ts").JSONValue>>>;
540
+ status: v.Optional<{
541
+ totalBytes?: number | undefined;
542
+ rows: number;
543
+ totalRows: number;
544
+ }>;
520
545
  }, undefined>]>, v.UnionType<[v.ObjectType<{
521
546
  tag: v.Type<"create-table">;
522
547
  spec: v.ObjectType<Omit<{
@@ -655,6 +680,11 @@ export declare const changeStreamMessageSchema: v.UnionType<[v.UnionType<[v.Tupl
655
680
  }, undefined>;
656
681
  columns: v.ArrayType<v.Type<string>>;
657
682
  watermark: v.Type<string>;
683
+ status: v.Optional<{
684
+ totalBytes?: number | undefined;
685
+ rows: number;
686
+ totalRows: number;
687
+ }>;
658
688
  }, undefined>]>]>]>, v.TupleType<[v.Type<"commit">, v.ObjectType<{
659
689
  tag: v.Type<"commit">;
660
690
  }, undefined>, v.ObjectType<{
@@ -1 +1 @@
1
- {"version":3,"file":"downstream.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/downstream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,wCAAwC,CAAC;AAW5D,QAAA,MAAM,KAAK;;;;;;eAIT,CAAC;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAGR,CAAC;AACH,QAAA,MAAM,MAAM;;;;eAIV,CAAC;AACH,QAAA,MAAM,QAAQ;;eAAmD,CAAC;AAElE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAyC,CAAC;AAC7E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;eAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
1
+ {"version":3,"file":"downstream.d.ts","sourceRoot":"","sources":["../../../../../../../../zero-cache/src/services/change-source/protocol/current/downstream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,wCAAwC,CAAC;AAW5D,QAAA,MAAM,KAAK;;;;;;eAIT,CAAC;AACH,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAGR,CAAC;AACH,QAAA,MAAM,MAAM;;;;eAIV,CAAC;AACH,QAAA,MAAM,QAAQ;;eAAmD,CAAC;AAElE,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAC1C,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;AACxC,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAC;AAEhD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAyC,CAAC;AAC7E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE,eAAO,MAAM,yBAAyB;;;;eAGpC,CAAC;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIrC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { resetRequiredSchema } from "./current/control.js";
2
- import { addColumnSchema, backfillCompletedSchema, backfillIDSchema, backfillSchema, beginSchema, commitSchema, createIndexSchema, createTableSchema, dataChangeSchema, deleteSchema, dropColumnSchema, dropIndexSchema, dropTableSchema, identifierSchema, insertSchema, isDataChange, isSchemaChange, newRelationSchema, relationSchema, renameTableSchema, rollbackSchema, rowSchema, schemaChangeSchema, tableMetadataSchema, truncateSchema, updateColumnSchema, updateSchema, updateTableMetadataSchema } from "./current/data.js";
2
+ import { addColumnSchema, backfillCompletedSchema, backfillIDSchema, backfillSchema, beginSchema, commitSchema, createIndexSchema, createTableSchema, dataChangeSchema, deleteSchema, downloadStatusSchema, dropColumnSchema, dropIndexSchema, dropTableSchema, identifierSchema, insertSchema, isDataChange, isSchemaChange, newRelationSchema, relationSchema, renameTableSchema, rollbackSchema, rowSchema, schemaChangeSchema, tableMetadataSchema, truncateSchema, updateColumnSchema, updateSchema, updateTableMetadataSchema } from "./current/data.js";
3
3
  import { changeStreamControlSchema, changeStreamDataSchema, changeStreamMessageSchema } from "./current/downstream.js";
4
4
  import { jsonObjectSchema, jsonValueSchema } from "./current/json.js";
5
5
  import { CHANGE_SOURCE_PATH } from "./current/path.js";
@@ -22,6 +22,7 @@ export {
22
22
  createTableSchema,
23
23
  dataChangeSchema,
24
24
  deleteSchema,
25
+ downloadStatusSchema,
25
26
  downstreamStatusMessageSchema,
26
27
  downstreamStatusSchema,
27
28
  dropColumnSchema,
@@ -193,6 +193,11 @@ export declare const downstreamSchema: v.UnionType<[v.TupleType<[v.Type<"status"
193
193
  columns: v.ArrayType<v.Type<string>>;
194
194
  watermark: v.Type<string>;
195
195
  rowValues: v.ArrayType<v.ArrayType<v.Type<import("../../../../shared/src/bigint-json.ts").JSONValue>>>;
196
+ status: v.Optional<{
197
+ totalBytes?: number | undefined;
198
+ rows: number;
199
+ totalRows: number;
200
+ }>;
196
201
  }, undefined>]>, v.UnionType<[v.ObjectType<{
197
202
  tag: v.Type<"create-table">;
198
203
  spec: v.ObjectType<Omit<{
@@ -331,6 +336,11 @@ export declare const downstreamSchema: v.UnionType<[v.TupleType<[v.Type<"status"
331
336
  }, undefined>;
332
337
  columns: v.ArrayType<v.Type<string>>;
333
338
  watermark: v.Type<string>;
339
+ status: v.Optional<{
340
+ totalBytes?: number | undefined;
341
+ rows: number;
342
+ totalRows: number;
343
+ }>;
334
344
  }, undefined>]>]>]>, v.TupleType<[v.Type<"commit">, v.ObjectType<{
335
345
  tag: v.Type<"commit">;
336
346
  }, undefined>, v.ObjectType<{
@@ -1 +1 @@
1
- {"version":3,"file":"change-streamer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,kCAAkC,CAAC;AACtD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAEtE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;CAChE;AAqBD,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY;;aAEvB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;eAA+C,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,QAAA,MAAM,uBAAuB;;;aAG3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,QAAA,MAAM,WAAW;;;eAAyD,CAAC;AAE3E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAI5B,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,MAAM,WAAW,qBAAsB,SAAQ,cAAc,EAAE,OAAO;IACpE;;;;OAIG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC,iBAAiB,IAAI,OAAO,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ"}
1
+ {"version":3,"file":"change-streamer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,kCAAkC,CAAC;AACtD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAEtE,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,eAAe,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,SAAS,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;CAChE;AAqBD,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;OAKG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAC;IAEf;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY;;aAEvB,CAAC;AAEH,eAAO,MAAM,mBAAmB;;eAA+C,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,QAAA,MAAM,uBAAuB;;;aAG3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAExE,QAAA,MAAM,WAAW;;;eAAyD,CAAC;AAE3E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAI5B,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,MAAM,WAAW,qBAAsB,SAAQ,cAAc,EAAE,OAAO;IACpE;;;;OAIG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC,iBAAiB,IAAI,OAAO,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;CACJ"}
@@ -1,10 +1,12 @@
1
1
  import type { LogContext } from '@rocicorp/logger';
2
+ import type { DownloadStatus } from '../../../../zero-events/src/status.ts';
2
3
  import type { StatementRunner } from '../../db/statements.ts';
3
4
  import type { ChangeStreamData } from '../change-source/protocol/current/downstream.ts';
4
5
  import type { ReplicatorMode } from './replicator.ts';
5
6
  export type ChangeProcessorMode = ReplicatorMode | 'initial-sync';
6
7
  export type CommitResult = {
7
8
  watermark: string;
9
+ completedBackfill: DownloadStatus | undefined;
8
10
  schemaUpdated: boolean;
9
11
  changeLogUpdated: boolean;
10
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"change-processor.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/replicator/change-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAuBjD,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AAgC5D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iDAAiD,CAAC;AACtF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AASpD,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,cAAc,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;gBAiBxB,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE,mBAAmB,EACzB,WAAW,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI;IAuBrD,KAAK,CAAC,EAAE,EAAE,UAAU;IAIpB,8CAA8C;IAC9C,cAAc,CACZ,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,gBAAgB,GAC3B,YAAY,GAAG,IAAI;CA6JvB"}
1
+ {"version":3,"file":"change-processor.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/replicator/change-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAMjD,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,uCAAuC,CAAC;AAkB1E,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,wBAAwB,CAAC;AAgC5D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iDAAiD,CAAC;AACtF,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,iBAAiB,CAAC;AASpD,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,cAAc,CAAC;AAElE,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,cAAc,GAAG,SAAS,CAAC;IAC9C,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;;gBAiBxB,EAAE,EAAE,eAAe,EACnB,IAAI,EAAE,mBAAmB,EACzB,WAAW,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,KAAK,IAAI;IAuBrD,KAAK,CAAC,EAAE,EAAE,UAAU;IAIpB,8CAA8C;IAC9C,cAAc,CACZ,EAAE,EAAE,UAAU,EACd,UAAU,EAAE,gBAAgB,GAC3B,YAAY,GAAG,IAAI;CAyJvB"}
@@ -109,11 +109,7 @@ class ChangeProcessor {
109
109
  if (msg.tag === "commit") {
110
110
  this.#currentTx = null;
111
111
  assert(watermark, "watermark is required for commit messages");
112
- const { schemaUpdated, changeLogUpdated } = tx.processCommit(
113
- msg,
114
- watermark
115
- );
116
- return { watermark, schemaUpdated, changeLogUpdated };
112
+ return tx.processCommit(msg, watermark);
117
113
  }
118
114
  if (msg.tag === "rollback") {
119
115
  this.#currentTx?.abort(lc);
@@ -554,7 +550,8 @@ class TransactionProcessor {
554
550
  `backfilled ${backfilled} rows (skipped ${skipped}) into ${tableName}`
555
551
  );
556
552
  }
557
- processBackfillCompleted({ relation, columns }) {
553
+ #completedBackfill;
554
+ processBackfillCompleted({ relation, columns, status }) {
558
555
  const tableName = liteTableName(relation);
559
556
  const rowKeyCols = relation.rowKey.columns;
560
557
  const cols = [...rowKeyCols, ...columns];
@@ -563,6 +560,9 @@ class TransactionProcessor {
563
560
  columnMetadata.clearBackfilling(tableName, col);
564
561
  }
565
562
  this.#bumpVersions(tableName);
563
+ if (status) {
564
+ this.#completedBackfill = { table: tableName, columns: cols, ...status };
565
+ }
566
566
  this.#lc.info?.(`finished backfilling ${tableName}`);
567
567
  }
568
568
  processCommit(commit, watermark) {
@@ -585,6 +585,8 @@ class TransactionProcessor {
585
585
  const elapsedMs = Date.now() - this.#startMs;
586
586
  this.#lc.debug?.(`Committed tx@${this.#version} (${elapsedMs} ms)`);
587
587
  return {
588
+ watermark,
589
+ completedBackfill: this.#completedBackfill,
588
590
  schemaUpdated: this.#schemaChanged,
589
591
  changeLogUpdated: this.#numChangeLogEntries > 0
590
592
  };