@rocicorp/zero 0.26.0 → 0.26.1-canary.11

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 (149) hide show
  1. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  2. package/out/analyze-query/src/run-ast.js +4 -1
  3. package/out/analyze-query/src/run-ast.js.map +1 -1
  4. package/out/replicache/src/btree/node.js +4 -4
  5. package/out/replicache/src/btree/node.js.map +1 -1
  6. package/out/replicache/src/btree/write.js +2 -2
  7. package/out/replicache/src/btree/write.js.map +1 -1
  8. package/out/replicache/src/dag/gc.js +5 -2
  9. package/out/replicache/src/dag/gc.js.map +1 -1
  10. package/out/replicache/src/db/write.d.ts.map +1 -1
  11. package/out/replicache/src/db/write.js +21 -6
  12. package/out/replicache/src/db/write.js.map +1 -1
  13. package/out/replicache/src/error-responses.d.ts.map +1 -1
  14. package/out/replicache/src/error-responses.js +4 -1
  15. package/out/replicache/src/error-responses.js.map +1 -1
  16. package/out/replicache/src/persist/clients.d.ts.map +1 -1
  17. package/out/replicache/src/persist/clients.js +4 -1
  18. package/out/replicache/src/persist/clients.js.map +1 -1
  19. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  20. package/out/replicache/src/persist/collect-idb-databases.js +2 -1
  21. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  22. package/out/replicache/src/persist/idb-databases-store.d.ts.map +1 -1
  23. package/out/replicache/src/persist/idb-databases-store.js +4 -1
  24. package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
  25. package/out/replicache/src/process-scheduler.js +4 -1
  26. package/out/replicache/src/process-scheduler.js.map +1 -1
  27. package/out/replicache/src/replicache-impl.js +2 -2
  28. package/out/replicache/src/replicache-impl.js.map +1 -1
  29. package/out/replicache/src/subscriptions.d.ts.map +1 -1
  30. package/out/replicache/src/subscriptions.js +5 -2
  31. package/out/replicache/src/subscriptions.js.map +1 -1
  32. package/out/replicache/src/sync/diff.d.ts.map +1 -1
  33. package/out/replicache/src/sync/diff.js +4 -1
  34. package/out/replicache/src/sync/diff.js.map +1 -1
  35. package/out/replicache/src/sync/pull.d.ts.map +1 -1
  36. package/out/replicache/src/sync/pull.js +4 -1
  37. package/out/replicache/src/sync/pull.js.map +1 -1
  38. package/out/replicache/src/sync/push.d.ts.map +1 -1
  39. package/out/replicache/src/sync/push.js +5 -2
  40. package/out/replicache/src/sync/push.js.map +1 -1
  41. package/out/shared/src/asserts.d.ts +1 -1
  42. package/out/shared/src/asserts.d.ts.map +1 -1
  43. package/out/shared/src/asserts.js +1 -1
  44. package/out/shared/src/asserts.js.map +1 -1
  45. package/out/z2s/src/compiler.d.ts.map +1 -1
  46. package/out/z2s/src/compiler.js +8 -2
  47. package/out/z2s/src/compiler.js.map +1 -1
  48. package/out/zero/package.json.js +1 -1
  49. package/out/zero-cache/src/config/zero-config.d.ts +4 -0
  50. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  51. package/out/zero-cache/src/config/zero-config.js +17 -0
  52. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  53. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  54. package/out/zero-cache/src/db/transaction-pool.js +17 -11
  55. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  56. package/out/zero-cache/src/observability/events.d.ts.map +1 -1
  57. package/out/zero-cache/src/observability/events.js +28 -9
  58. package/out/zero-cache/src/observability/events.js.map +1 -1
  59. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  60. package/out/zero-cache/src/server/change-streamer.js +3 -1
  61. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  62. package/out/zero-cache/src/services/analyze.js +1 -0
  63. package/out/zero-cache/src/services/analyze.js.map +1 -1
  64. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  65. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +29 -14
  66. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  67. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +6 -1
  68. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  69. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +69 -25
  70. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  71. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
  72. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +6 -1
  73. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  74. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  75. package/out/zero-cache/src/services/change-source/pg/schema/init.js +12 -8
  76. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  77. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +26 -0
  78. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  79. package/out/zero-cache/src/services/change-source/protocol/current/data.js +15 -3
  80. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  81. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +30 -0
  82. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  83. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  84. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +100 -0
  85. package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -0
  86. package/out/zero-cache/src/services/change-streamer/broadcast.js +171 -0
  87. package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -0
  88. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +1 -1
  89. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  90. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +22 -9
  91. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  92. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +10 -0
  93. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  94. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +17 -1
  95. package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
  96. package/out/zero-cache/src/services/change-streamer/forwarder.js +52 -4
  97. package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
  98. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +18 -0
  99. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  100. package/out/zero-cache/src/services/change-streamer/subscriber.js +68 -12
  101. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  102. package/out/zero-cache/src/services/replicator/change-processor.d.ts +2 -0
  103. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  104. package/out/zero-cache/src/services/replicator/change-processor.js +8 -6
  105. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  106. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  107. package/out/zero-cache/src/services/replicator/incremental-sync.js +39 -1
  108. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  109. package/out/zero-cache/src/services/replicator/replication-status.d.ts +4 -3
  110. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  111. package/out/zero-cache/src/services/replicator/replication-status.js +25 -10
  112. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  113. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  114. package/out/zero-cache/src/services/run-ast.js +22 -2
  115. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  116. package/out/zero-cache/src/services/running-state.d.ts +1 -0
  117. package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/running-state.js +4 -0
  119. package/out/zero-cache/src/services/running-state.js.map +1 -1
  120. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  121. package/out/zero-cache/src/services/view-syncer/cvr.js +8 -2
  122. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  123. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  124. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +10 -1
  125. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  126. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +1 -1
  127. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  128. package/out/zero-cache/src/services/view-syncer/snapshotter.js +15 -7
  129. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  130. package/out/zero-cache/src/types/subscription.d.ts +3 -1
  131. package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
  132. package/out/zero-cache/src/types/subscription.js +21 -9
  133. package/out/zero-cache/src/types/subscription.js.map +1 -1
  134. package/out/zero-client/src/client/http-string.js.map +1 -1
  135. package/out/zero-client/src/client/version.js +1 -1
  136. package/out/zero-client/src/client/zero.js.map +1 -1
  137. package/out/zero-events/src/status.d.ts +8 -0
  138. package/out/zero-events/src/status.d.ts.map +1 -1
  139. package/out/zero-schema/src/permissions.d.ts.map +1 -1
  140. package/out/zero-schema/src/permissions.js +4 -1
  141. package/out/zero-schema/src/permissions.js.map +1 -1
  142. package/out/zero-server/src/process-mutations.d.ts.map +1 -1
  143. package/out/zero-server/src/process-mutations.js +13 -19
  144. package/out/zero-server/src/process-mutations.js.map +1 -1
  145. package/out/zql/src/builder/filter.d.ts.map +1 -1
  146. package/out/zql/src/builder/filter.js +5 -2
  147. package/out/zql/src/builder/filter.js.map +1 -1
  148. package/out/zql/src/ivm/constraint.js.map +1 -1
  149. package/package.json +1 -1
@@ -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,
@@ -0,0 +1,100 @@
1
+ import type { LogContext } from '@rocicorp/logger';
2
+ import type { WatermarkedChange } from './change-streamer-service.ts';
3
+ import type { Subscriber } from './subscriber.ts';
4
+ /**
5
+ * Initiates and tracks the progress of a change broadcasted to
6
+ * a set of subscribers.
7
+ *
8
+ * Creating a `Broadcast` automatically initiates the send.
9
+ *
10
+ * By default, {@link Broadcast.done} resolves when all subscribers
11
+ * have acked the change. However, {@link Broadcast.checkProgress()}
12
+ * can be called to resolve the broadcast earlier based on the flow
13
+ * control policy.
14
+ */
15
+ export declare class Broadcast {
16
+ #private;
17
+ /**
18
+ * Sends the change to the subscribers without the tracking machinery.
19
+ * This is suitable for fire-and-forget (i.e. pipelined) sends.
20
+ */
21
+ static withoutTracking(subscribers: Iterable<Subscriber>, change: WatermarkedChange): void;
22
+ /**
23
+ * Broadcasts the `change` to the `subscribers` and tracks their
24
+ * completion.
25
+ */
26
+ constructor(subscribers: Iterable<Subscriber>, change: WatermarkedChange);
27
+ get isDone(): boolean;
28
+ get done(): Promise<void>;
29
+ /**
30
+ * Checks for pathological situations in which flow should be reenabled
31
+ * before all subscribers have acked.
32
+ *
33
+ * ### Background
34
+ *
35
+ * The purpose of flow control is to pull upstream replication changes
36
+ * no faster than the rate as they are processed by downstream subscribers
37
+ * in the steady state. In the change-streamer, this is done by occasionally
38
+ * waiting for ACKs from subscribers before continuing; without doing so,
39
+ * I/O buffers fill up and cause the system to spend most of its time in GC.
40
+ *
41
+ * However, the naive algorithm of always waiting for all subscribers (e.g.
42
+ * `Promise.all()`) can behave poorly in scenarios where subscribers
43
+ * are imbalanced:
44
+ * * New subscribers may have a backlog of changes to catch up with.
45
+ * Having all subscribers wait for the new subscriber to catch up results
46
+ * in delaying the entire application.
47
+ * * Broken TCP connections similarly require all subscribers to wait until
48
+ * connection liveness checks kick in and disconnect the subscriber.
49
+ *
50
+ * A simplistic approach is to add a limit to the amount of time waiting for
51
+ * subscribers, i.e. an ack timeout. However, deciding what this timeout
52
+ * should be is non-trivial because of the heterogeneous nature of changes;
53
+ * while most changes operate on single rows and are relatively predictable
54
+ * in terms of running time, some changes are table-wide operations and can
55
+ * legitimately take an arbitrary amount of time. In such scenarios, a
56
+ * timeout that is too short can stop progress on replication altogether.
57
+ *
58
+ * ### Consensus-based Timeout Algorithm
59
+ *
60
+ * To address these shortcomings, a "consensus-based timeout" algorithm is
61
+ * used:
62
+ * * Wait for more than half of the subscribers to finish. (In
63
+ * case of a single node, or the case of one replication-manager
64
+ * and one view-syncer, this reduces to waiting for all subscribers.)
65
+ * * Once more than half of the subscribers have finished, proceed after
66
+ * a fixed timeout elapses (e.g. 1 second), even if not all subscribers
67
+ * have finished.
68
+ *
69
+ * In other words, the subscribers themselves are used to determine the
70
+ * timeout of each batch of changes; the majority determines this when
71
+ * they complete, upon which a timeout is logically started.
72
+ *
73
+ * In the common case, the remaining subscribers finish soon afterward and
74
+ * the timeout never elapses. However, in pathological cases where a minority
75
+ * of subscribers have a disproportionate amount of load, some will still
76
+ * be processing (or otherwise unresponsive). These subscribers are given
77
+ * a bounded amount of time to catch up at each flushed batch, up to the
78
+ * timeout interval. This guarantees eventual catchup because the
79
+ * subscribers with a backlog of changes necessarily have a higher
80
+ * processing rate than the subscribers that finished (and are made to wait).
81
+ *
82
+ * ### Not implemented: Broken connection detection
83
+ *
84
+ * If a subscriber has not made progress for a certain interval, the
85
+ * algorithm could theoretically drop it preemptively, supplementing the
86
+ * existing websocket-level liveness checks.
87
+ *
88
+ * However, a more reliable approach would be to change the replicator
89
+ * to use non-blocking writes, and subsequently increase the frequency of
90
+ * connection-level liveness checks. The current synchronous replica writes
91
+ * can delay both ping responsiveness and change progress arbitrarily (e.g.
92
+ * a large index creation); an independently liveness check that is not
93
+ * delayed by synchronous writes on the subscriber would be a more failsafe
94
+ * solution.
95
+ *
96
+ * @returns `true` if the broadcast was already done or was marked done.
97
+ */
98
+ checkProgress(lc: LogContext, flowControlConsensusPaddingMs: number, now: number): boolean;
99
+ }
100
+ //# sourceMappingURL=broadcast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,qBAAa,SAAS;;IACpB;;;OAGG;IACH,MAAM,CAAC,eAAe,CACpB,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,EACjC,MAAM,EAAE,iBAAiB;IAkB3B;;;OAGG;gBACS,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,iBAAiB;IAkCxE,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAExB;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAoEG;IACH,aAAa,CACX,EAAE,EAAE,UAAU,EACd,6BAA6B,EAAE,MAAM,EACrC,GAAG,EAAE,MAAM;CA+Cd"}
@@ -0,0 +1,171 @@
1
+ import { resolver } from "@rocicorp/resolver";
2
+ class Broadcast {
3
+ /**
4
+ * Sends the change to the subscribers without the tracking machinery.
5
+ * This is suitable for fire-and-forget (i.e. pipelined) sends.
6
+ */
7
+ static withoutTracking(subscribers, change) {
8
+ for (const sub of subscribers) {
9
+ void sub.send(change);
10
+ }
11
+ }
12
+ #pending;
13
+ #completed;
14
+ #done = resolver();
15
+ #isDone = false;
16
+ #watermark;
17
+ #majority;
18
+ #start = performance.now();
19
+ #latestCompleted = Number.MAX_VALUE;
20
+ /**
21
+ * Broadcasts the `change` to the `subscribers` and tracks their
22
+ * completion.
23
+ */
24
+ constructor(subscribers, change) {
25
+ this.#pending = new Set(subscribers);
26
+ this.#completed = [];
27
+ this.#watermark = change[0];
28
+ this.#majority = Math.floor(this.#pending.size / 2) + 1;
29
+ for (const sub of this.#pending) {
30
+ const changes = sub.numPending + 1;
31
+ void sub.send(change).catch(() => {
32
+ }).finally(() => this.#markCompleted(sub, changes));
33
+ }
34
+ if (this.#pending.size === 0) {
35
+ this.#setDone();
36
+ }
37
+ }
38
+ #markCompleted(sub, changes) {
39
+ const elapsed = (this.#latestCompleted = performance.now()) - this.#start;
40
+ this.#completed.push({ sub, changes, elapsed });
41
+ this.#pending.delete(sub);
42
+ if (this.#pending.size === 0) {
43
+ this.#setDone();
44
+ }
45
+ }
46
+ #setDone() {
47
+ this.#isDone = true;
48
+ this.#done.resolve();
49
+ }
50
+ get isDone() {
51
+ return this.#isDone;
52
+ }
53
+ get done() {
54
+ return this.#done.promise;
55
+ }
56
+ /**
57
+ * Checks for pathological situations in which flow should be reenabled
58
+ * before all subscribers have acked.
59
+ *
60
+ * ### Background
61
+ *
62
+ * The purpose of flow control is to pull upstream replication changes
63
+ * no faster than the rate as they are processed by downstream subscribers
64
+ * in the steady state. In the change-streamer, this is done by occasionally
65
+ * waiting for ACKs from subscribers before continuing; without doing so,
66
+ * I/O buffers fill up and cause the system to spend most of its time in GC.
67
+ *
68
+ * However, the naive algorithm of always waiting for all subscribers (e.g.
69
+ * `Promise.all()`) can behave poorly in scenarios where subscribers
70
+ * are imbalanced:
71
+ * * New subscribers may have a backlog of changes to catch up with.
72
+ * Having all subscribers wait for the new subscriber to catch up results
73
+ * in delaying the entire application.
74
+ * * Broken TCP connections similarly require all subscribers to wait until
75
+ * connection liveness checks kick in and disconnect the subscriber.
76
+ *
77
+ * A simplistic approach is to add a limit to the amount of time waiting for
78
+ * subscribers, i.e. an ack timeout. However, deciding what this timeout
79
+ * should be is non-trivial because of the heterogeneous nature of changes;
80
+ * while most changes operate on single rows and are relatively predictable
81
+ * in terms of running time, some changes are table-wide operations and can
82
+ * legitimately take an arbitrary amount of time. In such scenarios, a
83
+ * timeout that is too short can stop progress on replication altogether.
84
+ *
85
+ * ### Consensus-based Timeout Algorithm
86
+ *
87
+ * To address these shortcomings, a "consensus-based timeout" algorithm is
88
+ * used:
89
+ * * Wait for more than half of the subscribers to finish. (In
90
+ * case of a single node, or the case of one replication-manager
91
+ * and one view-syncer, this reduces to waiting for all subscribers.)
92
+ * * Once more than half of the subscribers have finished, proceed after
93
+ * a fixed timeout elapses (e.g. 1 second), even if not all subscribers
94
+ * have finished.
95
+ *
96
+ * In other words, the subscribers themselves are used to determine the
97
+ * timeout of each batch of changes; the majority determines this when
98
+ * they complete, upon which a timeout is logically started.
99
+ *
100
+ * In the common case, the remaining subscribers finish soon afterward and
101
+ * the timeout never elapses. However, in pathological cases where a minority
102
+ * of subscribers have a disproportionate amount of load, some will still
103
+ * be processing (or otherwise unresponsive). These subscribers are given
104
+ * a bounded amount of time to catch up at each flushed batch, up to the
105
+ * timeout interval. This guarantees eventual catchup because the
106
+ * subscribers with a backlog of changes necessarily have a higher
107
+ * processing rate than the subscribers that finished (and are made to wait).
108
+ *
109
+ * ### Not implemented: Broken connection detection
110
+ *
111
+ * If a subscriber has not made progress for a certain interval, the
112
+ * algorithm could theoretically drop it preemptively, supplementing the
113
+ * existing websocket-level liveness checks.
114
+ *
115
+ * However, a more reliable approach would be to change the replicator
116
+ * to use non-blocking writes, and subsequently increase the frequency of
117
+ * connection-level liveness checks. The current synchronous replica writes
118
+ * can delay both ping responsiveness and change progress arbitrarily (e.g.
119
+ * a large index creation); an independently liveness check that is not
120
+ * delayed by synchronous writes on the subscriber would be a more failsafe
121
+ * solution.
122
+ *
123
+ * @returns `true` if the broadcast was already done or was marked done.
124
+ */
125
+ checkProgress(lc, flowControlConsensusPaddingMs, now) {
126
+ if (this.#pending.size === 0) {
127
+ return true;
128
+ }
129
+ const elapsed = now - this.#start;
130
+ if (this.#completed.length < this.#majority) {
131
+ if (elapsed >= 1e3) {
132
+ this.#logWithState(
133
+ lc,
134
+ `waiting for at least ${this.#majority} subscribers to finish`,
135
+ elapsed
136
+ );
137
+ }
138
+ return false;
139
+ }
140
+ if (now - this.#latestCompleted >= flowControlConsensusPaddingMs) {
141
+ this.#logWithState(
142
+ lc,
143
+ `continuing with ${this.#pending.size} subscriber(s) still pending`,
144
+ elapsed
145
+ );
146
+ this.#setDone();
147
+ return true;
148
+ }
149
+ return false;
150
+ }
151
+ #logWithState(lc, msg, elapsed) {
152
+ lc.withContext("watermark", this.#watermark).info?.(
153
+ `${msg} (${elapsed.toFixed(3)} ms)`,
154
+ {
155
+ completed: this.#completed.map((d) => ({
156
+ id: d.sub.id,
157
+ processed: d.changes,
158
+ elapsed: d.elapsed
159
+ })),
160
+ pending: [...this.#pending].map((sub) => ({
161
+ id: sub.id,
162
+ ...sub.getStats()
163
+ }))
164
+ }
165
+ );
166
+ }
167
+ }
168
+ export {
169
+ Broadcast
170
+ };
171
+ //# sourceMappingURL=broadcast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broadcast.js","sources":["../../../../../../zero-cache/src/services/change-streamer/broadcast.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport type {WatermarkedChange} from './change-streamer-service.ts';\nimport type {Subscriber} from './subscriber.ts';\n\n/**\n * Initiates and tracks the progress of a change broadcasted to\n * a set of subscribers.\n *\n * Creating a `Broadcast` automatically initiates the send.\n *\n * By default, {@link Broadcast.done} resolves when all subscribers\n * have acked the change. However, {@link Broadcast.checkProgress()}\n * can be called to resolve the broadcast earlier based on the flow\n * control policy.\n */\nexport class Broadcast {\n /**\n * Sends the change to the subscribers without the tracking machinery.\n * This is suitable for fire-and-forget (i.e. pipelined) sends.\n */\n static withoutTracking(\n subscribers: Iterable<Subscriber>,\n change: WatermarkedChange,\n ) {\n for (const sub of subscribers) {\n void sub.send(change);\n }\n }\n\n readonly #pending: Set<Subscriber>;\n readonly #completed: Completed[];\n readonly #done = resolver();\n #isDone = false;\n\n readonly #watermark: string;\n readonly #majority: number;\n\n readonly #start = performance.now();\n #latestCompleted = Number.MAX_VALUE;\n\n /**\n * Broadcasts the `change` to the `subscribers` and tracks their\n * completion.\n */\n constructor(subscribers: Iterable<Subscriber>, change: WatermarkedChange) {\n this.#pending = new Set(subscribers);\n this.#completed = [];\n this.#watermark = change[0];\n this.#majority = Math.floor(this.#pending.size / 2) + 1;\n\n for (const sub of this.#pending) {\n const changes = sub.numPending + 1; // add one for this `change`\n void sub\n .send(change)\n .catch(() => {})\n .finally(() => this.#markCompleted(sub, changes));\n }\n\n // set done if there are no subscribers (mainly for tests)\n if (this.#pending.size === 0) {\n this.#setDone();\n }\n }\n\n #markCompleted(sub: Subscriber, changes: number) {\n const elapsed = (this.#latestCompleted = performance.now()) - this.#start;\n this.#completed.push({sub, changes, elapsed});\n this.#pending.delete(sub);\n if (this.#pending.size === 0) {\n this.#setDone();\n }\n }\n\n #setDone() {\n this.#isDone = true;\n this.#done.resolve();\n }\n\n get isDone(): boolean {\n return this.#isDone;\n }\n\n get done(): Promise<void> {\n return this.#done.promise;\n }\n\n /**\n * Checks for pathological situations in which flow should be reenabled\n * before all subscribers have acked.\n *\n * ### Background\n *\n * The purpose of flow control is to pull upstream replication changes\n * no faster than the rate as they are processed by downstream subscribers\n * in the steady state. In the change-streamer, this is done by occasionally\n * waiting for ACKs from subscribers before continuing; without doing so,\n * I/O buffers fill up and cause the system to spend most of its time in GC.\n *\n * However, the naive algorithm of always waiting for all subscribers (e.g.\n * `Promise.all()`) can behave poorly in scenarios where subscribers\n * are imbalanced:\n * * New subscribers may have a backlog of changes to catch up with.\n * Having all subscribers wait for the new subscriber to catch up results\n * in delaying the entire application.\n * * Broken TCP connections similarly require all subscribers to wait until\n * connection liveness checks kick in and disconnect the subscriber.\n *\n * A simplistic approach is to add a limit to the amount of time waiting for\n * subscribers, i.e. an ack timeout. However, deciding what this timeout\n * should be is non-trivial because of the heterogeneous nature of changes;\n * while most changes operate on single rows and are relatively predictable\n * in terms of running time, some changes are table-wide operations and can\n * legitimately take an arbitrary amount of time. In such scenarios, a\n * timeout that is too short can stop progress on replication altogether.\n *\n * ### Consensus-based Timeout Algorithm\n *\n * To address these shortcomings, a \"consensus-based timeout\" algorithm is\n * used:\n * * Wait for more than half of the subscribers to finish. (In\n * case of a single node, or the case of one replication-manager\n * and one view-syncer, this reduces to waiting for all subscribers.)\n * * Once more than half of the subscribers have finished, proceed after\n * a fixed timeout elapses (e.g. 1 second), even if not all subscribers\n * have finished.\n *\n * In other words, the subscribers themselves are used to determine the\n * timeout of each batch of changes; the majority determines this when\n * they complete, upon which a timeout is logically started.\n *\n * In the common case, the remaining subscribers finish soon afterward and\n * the timeout never elapses. However, in pathological cases where a minority\n * of subscribers have a disproportionate amount of load, some will still\n * be processing (or otherwise unresponsive). These subscribers are given\n * a bounded amount of time to catch up at each flushed batch, up to the\n * timeout interval. This guarantees eventual catchup because the\n * subscribers with a backlog of changes necessarily have a higher\n * processing rate than the subscribers that finished (and are made to wait).\n *\n * ### Not implemented: Broken connection detection\n *\n * If a subscriber has not made progress for a certain interval, the\n * algorithm could theoretically drop it preemptively, supplementing the\n * existing websocket-level liveness checks.\n *\n * However, a more reliable approach would be to change the replicator\n * to use non-blocking writes, and subsequently increase the frequency of\n * connection-level liveness checks. The current synchronous replica writes\n * can delay both ping responsiveness and change progress arbitrarily (e.g.\n * a large index creation); an independently liveness check that is not\n * delayed by synchronous writes on the subscriber would be a more failsafe\n * solution.\n *\n * @returns `true` if the broadcast was already done or was marked done.\n */\n checkProgress(\n lc: LogContext,\n flowControlConsensusPaddingMs: number,\n now: number,\n ) {\n if (this.#pending.size === 0) {\n return true;\n }\n const elapsed = now - this.#start;\n if (this.#completed.length < this.#majority) {\n if (elapsed >= 1000) {\n this.#logWithState(\n lc,\n `waiting for at least ${this.#majority} subscribers to finish`,\n elapsed,\n );\n }\n return false;\n }\n // Note: In the implementation, #latestCompleted is always updated,\n // even after the majority is reached. This is fine and does not affect\n // the important properties of the algorithm.\n if (now - this.#latestCompleted >= flowControlConsensusPaddingMs) {\n this.#logWithState(\n lc,\n `continuing with ${this.#pending.size} subscriber(s) still pending`,\n elapsed,\n );\n this.#setDone();\n return true;\n }\n return false;\n }\n\n #logWithState(lc: LogContext, msg: string, elapsed: number) {\n lc.withContext('watermark', this.#watermark).info?.(\n `${msg} (${elapsed.toFixed(3)} ms)`,\n {\n completed: this.#completed.map(d => ({\n id: d.sub.id,\n processed: d.changes,\n elapsed: d.elapsed,\n })),\n pending: [...this.#pending].map(sub => ({\n id: sub.id,\n ...sub.getStats(),\n })),\n },\n );\n }\n}\n\n/** Tracks the completed result of a single subscriber. */\ntype Completed = {\n sub: Subscriber;\n /** The number of changes processed. */\n changes: number;\n /** The elapsed milliseconds. */\n elapsed: number;\n};\n"],"names":[],"mappings":";AAgBO,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,OAAO,gBACL,aACA,QACA;AACA,eAAW,OAAO,aAAa;AAC7B,WAAK,IAAI,KAAK,MAAM;AAAA,IACtB;AAAA,EACF;AAAA,EAES;AAAA,EACA;AAAA,EACA,QAAQ,SAAA;AAAA,EACjB,UAAU;AAAA,EAED;AAAA,EACA;AAAA,EAEA,SAAS,YAAY,IAAA;AAAA,EAC9B,mBAAmB,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,YAAY,aAAmC,QAA2B;AACxE,SAAK,WAAW,IAAI,IAAI,WAAW;AACnC,SAAK,aAAa,CAAA;AAClB,SAAK,aAAa,OAAO,CAAC;AAC1B,SAAK,YAAY,KAAK,MAAM,KAAK,SAAS,OAAO,CAAC,IAAI;AAEtD,eAAW,OAAO,KAAK,UAAU;AAC/B,YAAM,UAAU,IAAI,aAAa;AACjC,WAAK,IACF,KAAK,MAAM,EACX,MAAM,MAAM;AAAA,MAAC,CAAC,EACd,QAAQ,MAAM,KAAK,eAAe,KAAK,OAAO,CAAC;AAAA,IACpD;AAGA,QAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,WAAK,SAAA;AAAA,IACP;AAAA,EACF;AAAA,EAEA,eAAe,KAAiB,SAAiB;AAC/C,UAAM,WAAW,KAAK,mBAAmB,YAAY,IAAA,KAAS,KAAK;AACnE,SAAK,WAAW,KAAK,EAAC,KAAK,SAAS,SAAQ;AAC5C,SAAK,SAAS,OAAO,GAAG;AACxB,QAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,WAAK,SAAA;AAAA,IACP;AAAA,EACF;AAAA,EAEA,WAAW;AACT,SAAK,UAAU;AACf,SAAK,MAAM,QAAA;AAAA,EACb;AAAA,EAEA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,OAAsB;AACxB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuEA,cACE,IACA,+BACA,KACA;AACA,QAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,aAAO;AAAA,IACT;AACA,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,KAAK,WAAW,SAAS,KAAK,WAAW;AAC3C,UAAI,WAAW,KAAM;AACnB,aAAK;AAAA,UACH;AAAA,UACA,wBAAwB,KAAK,SAAS;AAAA,UACtC;AAAA,QAAA;AAAA,MAEJ;AACA,aAAO;AAAA,IACT;AAIA,QAAI,MAAM,KAAK,oBAAoB,+BAA+B;AAChE,WAAK;AAAA,QACH;AAAA,QACA,mBAAmB,KAAK,SAAS,IAAI;AAAA,QACrC;AAAA,MAAA;AAEF,WAAK,SAAA;AACL,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,IAAgB,KAAa,SAAiB;AAC1D,OAAG,YAAY,aAAa,KAAK,UAAU,EAAE;AAAA,MAC3C,GAAG,GAAG,KAAK,QAAQ,QAAQ,CAAC,CAAC;AAAA,MAC7B;AAAA,QACE,WAAW,KAAK,WAAW,IAAI,CAAA,OAAM;AAAA,UACnC,IAAI,EAAE,IAAI;AAAA,UACV,WAAW,EAAE;AAAA,UACb,SAAS,EAAE;AAAA,QAAA,EACX;AAAA,QACF,SAAS,CAAC,GAAG,KAAK,QAAQ,EAAE,IAAI,CAAA,SAAQ;AAAA,UACtC,IAAI,IAAI;AAAA,UACR,GAAG,IAAI,SAAA;AAAA,QAAS,EAChB;AAAA,MAAA;AAAA,IACJ;AAAA,EAEJ;AACF;"}
@@ -8,7 +8,7 @@ import { type ChangeStreamerService } from './change-streamer.ts';
8
8
  /**
9
9
  * Performs initialization and schema migrations to initialize a ChangeStreamerImpl.
10
10
  */
11
- export declare function initializeStreamer(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, changeDB: PostgresDB, changeSource: ChangeSource, subscriptionState: SubscriptionState, autoReset: boolean, backPressureLimitHeapProportion: number, setTimeoutFn?: typeof setTimeout): Promise<ChangeStreamerService>;
11
+ export declare function initializeStreamer(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, changeDB: PostgresDB, changeSource: ChangeSource, subscriptionState: SubscriptionState, autoReset: boolean, backPressureLimitHeapProportion: number, flowControlConsensusPaddingSeconds: number, setTimeoutFn?: typeof setTimeout): Promise<ChangeStreamerService>;
12
12
  /**
13
13
  * Internally all Downstream messages (not just commits) are given a watermark.
14
14
  * These are used for internal ordering for:
@@ -1 +1 @@
1
- {"version":3,"file":"change-streamer-service.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAUjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,iDAAiD,CAAC;AAEzD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,2CAA2C,CAAC;AAMjF,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,sBAAsB,CAAC;AAY9B;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,YAAY,EAC1B,iBAAiB,EAAE,iBAAiB,EACpC,SAAS,EAAE,OAAO,EAClB,+BAA+B,EAAE,MAAM,EACvC,YAAY,oBAAa,GACxB,OAAO,CAAC,qBAAqB,CAAC,CAyBhC;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"change-streamer-service.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAYjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,iDAAiD,CAAC;AAKzD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,2CAA2C,CAAC;AAMjF,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,sBAAsB,CAAC;AAY9B;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,YAAY,EAC1B,iBAAiB,EAAE,iBAAiB,EACpC,SAAS,EAAE,OAAO,EAClB,+BAA+B,EAAE,MAAM,EACvC,kCAAkC,EAAE,MAAM,EAC1C,YAAY,oBAAa,GACxB,OAAO,CAAC,qBAAqB,CAAC,CA0BhC;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC"}
@@ -1,11 +1,13 @@
1
1
  import { resolver } from "@rocicorp/resolver";
2
2
  import { getDefaultHighWaterMark } from "node:stream";
3
3
  import { unreachable } from "../../../../shared/src/asserts.js";
4
+ import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
5
+ import { publishCriticalEvent } from "../../observability/events.js";
4
6
  import { getOrCreateCounter } from "../../observability/metrics.js";
5
7
  import { min } from "../../types/lexi-version.js";
6
8
  import { Subscription } from "../../types/subscription.js";
7
9
  import "../change-source/protocol/current/downstream.js";
8
- import { publishReplicationError } from "../replicator/replication-status.js";
10
+ import { replicationStatusError, publishReplicationError } from "../replicator/replication-status.js";
9
11
  import { RunningState, UnrecoverableError, DEFAULT_MAX_RETRY_DELAY_MS } from "../running-state.js";
10
12
  import "./change-streamer.js";
11
13
  import { WrongReplicaVersion } from "./error-type-enum.js";
@@ -14,7 +16,7 @@ import { initChangeStreamerSchema } from "./schema/init.js";
14
16
  import { ensureReplicationConfig, markResetRequired, AutoResetSignal } from "./schema/tables.js";
15
17
  import { Storer } from "./storer.js";
16
18
  import { Subscriber } from "./subscriber.js";
17
- async function initializeStreamer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, changeSource, subscriptionState, autoReset, backPressureLimitHeapProportion, setTimeoutFn = setTimeout) {
19
+ async function initializeStreamer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, changeSource, subscriptionState, autoReset, backPressureLimitHeapProportion, flowControlConsensusPaddingSeconds, setTimeoutFn = setTimeout) {
18
20
  await initChangeStreamerSchema(lc, changeDB, shard);
19
21
  await ensureReplicationConfig(
20
22
  lc,
@@ -35,6 +37,7 @@ async function initializeStreamer(lc, shard, taskID, discoveryAddress, discovery
35
37
  changeSource,
36
38
  autoReset,
37
39
  backPressureLimitHeapProportion,
40
+ flowControlConsensusPaddingSeconds,
38
41
  setTimeoutFn
39
42
  );
40
43
  }
@@ -65,7 +68,7 @@ class ChangeStreamerImpl {
65
68
  "Count of replicated transactions"
66
69
  );
67
70
  #stream;
68
- constructor(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, source, autoReset, backPressureLimitHeapProportion, setTimeoutFn = setTimeout) {
71
+ constructor(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, source, autoReset, backPressureLimitHeapProportion, flowControlConsensusPaddingSeconds, setTimeoutFn = setTimeout) {
69
72
  this.id = `change-streamer`;
70
73
  this.#lc = lc.withContext("component", "change-streamer");
71
74
  this.#shard = shard;
@@ -84,12 +87,15 @@ class ChangeStreamerImpl {
84
87
  (err) => this.stop(err),
85
88
  backPressureLimitHeapProportion
86
89
  );
87
- this.#forwarder = new Forwarder();
90
+ this.#forwarder = new Forwarder(lc, {
91
+ flowControlConsensusPaddingSeconds
92
+ });
88
93
  this.#autoReset = autoReset;
89
94
  this.#state = new RunningState(this.id, void 0, setTimeoutFn);
90
95
  }
91
96
  async run() {
92
97
  this.#lc.info?.("starting change stream");
98
+ this.#forwarder.startProgressMonitor();
93
99
  await this.#storer.assumeOwnership();
94
100
  const flushBytesThreshold = getDefaultHighWaterMark(false);
95
101
  while (this.#state.shouldRun()) {
@@ -137,10 +143,12 @@ class ChangeStreamerImpl {
137
143
  }
138
144
  break;
139
145
  }
140
- unflushedBytes += this.#storer.store([watermark, change]);
141
- const sent = this.#forwarder.forward([watermark, change]);
142
- if (unflushedBytes >= flushBytesThreshold) {
143
- await sent;
146
+ const entry = [watermark, change];
147
+ unflushedBytes += this.#storer.store(entry);
148
+ if (unflushedBytes < flushBytesThreshold) {
149
+ this.#forwarder.forward(entry);
150
+ } else {
151
+ await this.#forwarder.forwardWithFlowControl(entry);
144
152
  unflushedBytes = 0;
145
153
  }
146
154
  if (type === "commit" || type === "rollback") {
@@ -167,9 +175,14 @@ class ChangeStreamerImpl {
167
175
  }
168
176
  await Promise.all([
169
177
  this.#storer.stop(),
170
- this.#state.backoff(this.#lc, err)
178
+ this.#state.backoff(this.#lc, err),
179
+ this.#state.retryDelay > 5e3 ? publishCriticalEvent(
180
+ this.#lc,
181
+ replicationStatusError(this.#lc, "Replicating", err)
182
+ ) : promiseVoid
171
183
  ]);
172
184
  }
185
+ this.#forwarder.stopProgressMonitor();
173
186
  this.#lc.info?.("ChangeStreamer stopped");
174
187
  }
175
188
  async #handleControlMessage(msg) {