-
Notifications
You must be signed in to change notification settings - Fork 512
adapter: collect durable replica hydration history #38512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
4ac3ffc
03e5ca1
34e3b19
155226c
c453b5c
dd64244
6ebb99e
cdd0af6
b1c53bf
92c2974
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| # Durable Replica Hydration History | ||
|
|
||
| ## Context | ||
|
|
||
| The [durable object hydration history](20260817_durable_object_hydration_history.md) | ||
| records successful hydration for individual dataflows. This design extends that | ||
| collector with replica-wide hydration episodes and the resource high-water marks | ||
| visible when each episode is recorded. | ||
|
|
||
| The extension reuses the object collector's scheduling, replica-targeted | ||
| read-then-write path, exact-timestamp OCC, retention, and migration protections. | ||
| This document describes only the replica-level additions. | ||
|
|
||
| ## Episode boundaries | ||
|
|
||
| Each live non-transient compute export contributes an interval from its earliest | ||
| worker installation to its latest worker hydration. The collector waits until | ||
| every visible worker of every live non-transient export has hydrated. Transient | ||
| query dataflows are excluded because the collection query itself creates one. | ||
|
|
||
| A replica episode is a connected component in the union of those export | ||
| intervals. Two intervals belong to one episode if they overlap directly or | ||
| through a chain of overlapping intervals. A gap means the replica was fully | ||
| hydrated before the next export was installed, so the next interval starts a | ||
| new episode. | ||
|
|
||
| Each sweep records only the latest completed episode visible in its snapshot. | ||
| Episodes that complete between sweeps and exports that retract before a sweep | ||
| leave no evidence. The current inputs can therefore record successful episodes | ||
| only. Failed, canceled, and OOM-killed outcomes need an additional durable | ||
| replica signal. | ||
|
|
||
| Process-local clocks stamp both interval endpoints. Clock skew can merge | ||
| episodes that did not overlap in real time. Once an episode is recorded, a | ||
| monotonic history guard prevents a later snapshot from interpreting retracted | ||
| intervals as an earlier or overlapping episode. | ||
|
|
||
| ## Resource interpretation | ||
|
|
||
| `peak_memory_bytes` is the maximum `cgroup memory_peak` across replica | ||
| processes. `peak_disk_bytes` is the maximum sampled `statvfs fs_used_peak` when a | ||
| scratch filesystem is present. Otherwise it is the maximum kernel-maintained | ||
| `cgroup swap_peak`. | ||
|
|
||
| Replica memory and disk limits apply independently to each process. The maximum | ||
| process peak therefore answers whether any process approached its limit. Adding | ||
| process maxima would combine peaks that may not have occurred simultaneously. | ||
|
|
||
| The operating system's peaks cover the process lifetime through the collector's | ||
| observation. They are not bounded by `finished_at`, so work after hydration and | ||
| before collection can raise them. Later episodes can also include an earlier | ||
| high-water mark. A true episode peak requires a reset or a separately retained | ||
| interval maximum at the replica. | ||
|
|
||
| The collector requires at least one resource observation from every configured | ||
| process before writing. Individual peak metrics can still be absent, which is | ||
| represented by `NULL` rather than a zero sentinel. | ||
|
|
||
| ## History table | ||
|
|
||
| ```text | ||
| mz_internal.mz_replica_hydration_history | ||
| replica_id text not null | ||
| cluster_id text not null | ||
| started_at timestamptz not null | ||
| finished_at timestamptz null | ||
| object_count uint8 not null | ||
| peak_memory_bytes uint8 null | ||
| peak_disk_bytes uint8 null | ||
| status text not null | ||
| ``` | ||
|
|
||
| An episode is identified operationally by `(replica_id, started_at)`. The table | ||
| does not declare a key or index. Collection runs on the selected replica, so a | ||
| catalog-server index would not avoid importing and arranging the history there. | ||
|
|
||
| Rows currently have a populated `finished_at` and the status `hydrated`. | ||
| Resource columns are nullable because the available kernel and filesystem | ||
| observations depend on the replica platform. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -429,11 +429,11 @@ pub const HYDRATION_HISTORY_COLLECTION_INTERVAL: Config<Duration> = Config::new( | |
| ParameterScope::Environment, | ||
| ); | ||
|
|
||
| /// How long to retain completed object hydration episodes. | ||
| /// How long to retain completed object and replica hydration episodes. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaving it: keeping that description stable was an explicit ask in an earlier round (it is durable, user-visible state), and object episodes remain the primary content of the sweep it describes. |
||
| pub const HYDRATION_HISTORY_RETENTION_PERIOD: Config<Duration> = Config::new( | ||
| "hydration_history_retention_period", | ||
| Duration::from_hours(30 * 24), | ||
| "How long to retain rows in mz_internal.mz_object_hydration_history.", | ||
| "How long to retain rows in mz_internal.mz_object_hydration_history and mz_internal.mz_replica_hydration_history.", | ||
| ParameterScope::Environment, | ||
| ); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -100,7 +100,7 @@ use mz_auth::password::Password; | |
| use mz_build_info::BuildInfo; | ||
| use mz_catalog::builtin::{ | ||
| BUILTINS, BUILTINS_STATIC, MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY, MZ_OBJECT_HYDRATION_HISTORY, | ||
| MZ_STORAGE_USAGE_BY_SHARD, | ||
| MZ_REPLICA_HYDRATION_HISTORY, MZ_STORAGE_USAGE_BY_SHARD, | ||
| }; | ||
| use mz_catalog::config::{AwsPrincipalContext, BuiltinItemMigrationConfig, ClusterReplicaSizeMap}; | ||
| use mz_catalog::durable::OpenableDurableCatalogState; | ||
|
|
@@ -3186,6 +3186,8 @@ impl Coordinator { | |
| .resolve_builtin_table(&MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY), | ||
| self.catalog() | ||
| .resolve_builtin_table(&MZ_OBJECT_HYDRATION_HISTORY), | ||
| self.catalog() | ||
| .resolve_builtin_table(&MZ_REPLICA_HYDRATION_HISTORY), | ||
| ]); | ||
|
|
||
| let mut retraction_tasks = Vec::new(); | ||
|
|
@@ -4337,6 +4339,14 @@ impl Coordinator { | |
| } | ||
| } | ||
| } | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why'd we need this change?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The active sweep owns a PeekClient that can cache an Arc to the batching timestamp oracle without keeping the coordinator command channel open. Dropping AbortOnDropHandle requests cancellation but is not a completion barrier. Build 132852 exposed the race when the oracle worker stopped first and panicked at batching_oracle.rs:115 because the sweep still held a sender. The abort and await in 34e3b19 releases the sweep oracle client and outstanding read timestamp while global_timelines still owns the oracle worker. |
||
| // The sweep can own timestamp-oracle senders through its background | ||
| // client. Release them before the coordinator runtime starts shutting | ||
| // down the oracle workers. | ||
| if let Some(sweep) = self.hydration_history_sweep.take() { | ||
| sweep.abort_and_wait().await; | ||
| } | ||
|
|
||
| // Try and cleanup as a best effort. There may be some async tasks out there holding a | ||
| // reference that prevents us from cleaning up. | ||
| if let Some(catalog) = Arc::into_inner(self.catalog) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we need to cut this down quite a bit, we can rever to the other hystory design doc for reference, and really only describe here the bits we add
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in c453b5c. The replica design now references the durable object hydration history design for shared collector mechanics and is limited to replica episode boundaries, resource interpretation, and table shape.