-
Notifications
You must be signed in to change notification settings - Fork 465
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
persist: Stabilize Schema Evolution #30205
persist: Stabilize Schema Evolution #30205
Conversation
7547fdb
to
73a82eb
Compare
MitigationsCompleting required mitigations increases Resilience Coverage.
Risk Summary:The pull request has a high risk score of 83, primarily driven by the predictors "Avg Line Count In Files" and "Executable Lines Within Files," with 7 modified files identified as hotspots. Historically, PRs with these predictors are 155% more likely to cause a bug than the repository baseline. Additionally, the observed bug trend in the repository is increasing. Note: The risk score is not based on semantic analysis but on historical predictors of bug occurrence in the repository. The attributes above were deemed the strongest predictors based on that history. Predictors and the score may change as the PR evolves in code, time, and review activity. Bug Hotspots:
|
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.
Adapter changes LGTM
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.
Scanned this and everything seems reasonable on the surface, but I think it'll be hard to make time this week for the full detailed review. @bkirwi mind picking up the persist review on this?
73a82eb
to
b5cb8e3
Compare
/// | ||
/// Errors if `new` is less nullable than `old`, or `old` and `new` are different types or have | ||
/// different nested fields. | ||
pub(crate) fn is_atleast_as_nullable(old: &DataType, new: &DataType) -> Result<(), anyhow::Error> { |
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.
Can you expand on the need for this? AFAICT this is ~identical to backward_compatible_typ(old, new).is_some()
, aside from slightly different behaviour when fields are added. OTOH, it will silently allow fields to be dropped...
Is there some way to avoid duplicating the similar logic?
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.
It is nearly identical! We could try and re-use backward_compatible_typ(...)
but because bacward_compatible_typ(...)
allows adding new columns is why I shied away from it.
I do believe we should be able to delete this code after a release or two since the new DataTypes will be migrated, so maybe code reuse isn't super important if we're going to get rid of it?
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.
Okay! I don't know that allowing additions is so much worse than allowing deletes, since neither should come up in practice... but if you're confident we can get rid of this in short order I won't worry about it too much one way or the other.
@@ -208,6 +208,9 @@ pub enum BatchPart<T> { | |||
updates: LazyInlineBatchPart, | |||
ts_rewrite: Option<Antichain<T>>, | |||
schema_id: Option<SchemaId>, | |||
|
|||
/// ID of a schema that has since been deprecated and exists only to cleanly roundtrip. | |||
deprecated_schema_id: Option<SchemaId>, |
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.
There's no real possibility of ever getting rid of this, hey? Since parts would fail to roundtrip if we ever removed it?
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.
I'm not totally sure! I need to think through State
a bit more and how we might support removing fields, but I wouldn't be surprised if we need to do a bit of work to support migration here
Thanks for the followup etc! I'll do a final pass on this today. |
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.
One important-but-hopefully uncontroversial change suggested, but otherwise looks good! Thanks for making the idempotency change... feels much easier to reason about now.
I think we can probably get rid of DatumEncoder
entirely now, since IIUC it only exists to preserve field nullability for DatumColumnEncoder
. But we can leave that as a followup.
63c3efa
to
ec6ef90
Compare
Moving this into draft while I iterate a bit here to figure out the nightly failures |
23d5c11
to
3f5b265
Compare
cb9b7b6
to
2434665
Compare
2434665
to
cbc956b
Compare
Moving back to draft while I iterate more |
cbc956b
to
497a477
Compare
b8ca9ba
to
5e3a637
Compare
This PR disables Persist's compaction when environmentd or clusterd are in read-only mode. As part of #30205 we discovered that during a 0dt deployment the read-only instance of Materialize was scheduling compaction requests which was causing it to write data. We disable compaction by adding a `process_compaction_requests: Arc<AtomicBool>` to the `PersistConfig`, and when setting it to `true` when `clusterd` receives the already existing `AllowWrites` command. Also included is a CYA dyncfg that gates whether or not we check the flag, it's set to `true` by default. I also added a Prometheus metric to count the number of requests dropped because compaction is disabled, a unit test to exercise the basic enable/disable behavior, and manually checked when running a 0dt test that compaction was successfully disabled and then enabled across `environmentd` and all `clusterd`s when a deployment was promoted. ### Motivation Fix issue found in #30205 ### Checklist - [x] This PR has adequate test coverage / QA involvement has been duly considered. ([trigger-ci for additional test/nightly runs](https://trigger-ci.dev.materialize.com/)) - [x] This PR has an associated up-to-date [design doc](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/README.md), is a design doc ([template](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/00000000_template.md)), or is sufficiently small to not require a design. <!-- Reference the design in the description. --> - [x] If this PR evolves [an existing `$T ⇔ Proto$T` mapping](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/command-and-response-binary-encoding.md) (possibly in a backwards-incompatible way), then it is tagged with a `T-proto` label. - [x] If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label ([example](MaterializeInc/cloud#5021)). <!-- Ask in #team-cloud on Slack if you need help preparing the cloud PR. --> - [x] If this PR includes major [user-facing behavior changes](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/guide-changes.md#what-changes-require-a-release-note), I have pinged the relevant PM to schedule a changelog post. --------- Co-authored-by: Nikhil Benesch <[email protected]> Co-authored-by: Ben Kirwin <[email protected]>
5e3a637
to
8bf98b5
Compare
Rebased (apologies if this messed up your review Ben!) and kicked off Nightlies |
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.
Nits and a lingering question, but in any case I think this should be good to go.
// updates to our optimizer. | ||
self.controller | ||
.storage | ||
.evolve_nullability_for_bootstrap(storage_metadata, compute_collections) |
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.
Do I understand correctly that?
- This is a write on the read path: starting the read-only replica irrevocably migrates the collection.
- This is fine in the short term because we're only making things more nullable at the data type level, so all the old writes are valid with the new schema.
- This is fine in the longer term because it should be a noop at the data type level.
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.
Exactly! Also, we only migrate collections for Materialized Views and Continual Tasks, not Tables or Sources
crate::schema::is_atleast_as_nullable(&old_v_datatype, &new_v_datatype); | ||
|
||
// If the Arrow DataType for `k` or `v` has changed, but it's only become more | ||
// nullable, then we allow in-place re-writing of the schema. |
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.
Maybe this is friday brain, but: since we're updating existing schema ids here with a backwards compatible change, what would go wrong if we didn't do the schema-id-deprecation thing? Or nothing breaks, and we're doing it to avoid ambiguity?
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.
Not Friday brain at all, there are a couple of trade-offs here. We could skip deprecating the schema_id
field and just write a new SchemaId(1)
for all collections, but:
- We would have have the same
RelationDesc
mapping to two differentarrow::DataType
s, which I don't think is too bad, but would probably require us to also implement something like persist: Plumb relevantarrow::DataType
s to compaction #30627 in the future. - Right now the Persist
SchemaId
maps 1:1 with the Adapter'sRelationVersion
for Tables. If we evolve the schemas for all collections to be more nullable we'd need some additional mapping in the Adapter layer to supportALTER TABLE
These are all things that we can work around, but also IMO the concept of "starting" over is the cleanest choice.
prost::Message::encode_to_vec(&proto).into() | ||
} | ||
|
||
fn decode_data_type(buf: Bytes) -> Result<DataType, anyhow::Error> { |
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.
Tiny nit, but the names here aren't quite consistent: encoded
vs. decode
.
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.
Fixed!
val, | ||
val_data_type: new_v_encoded_datatype, | ||
}, | ||
); |
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 should give ourselves some way to check if we're hitting this path later than we'd expect. (I think a log is fine if wiring up a metric is a hassle... shouldn't be too high of a multiplicity.)
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.
Wired up a metric which should be easier to observe! We theoretically could write a query over our logs, but wiring that up is maybe harder than adding a prom metric haha
Not sure what to think of the parallel ddl failure... hit restart to see if it's sticky! |
It's a test issue, fixed on main |
* recusively mark all columns as nullable at the Arrow/Parquet level
…alized Views and Continual Tasks, if need be
6068b96
to
93a5822
Compare
The Nightly tests we care about are Green, merging! |
As part of #30205 we check if a new `arrow::DataType` is "at least as nullable" as the previous type, and if so we update the registered data type in-place. This check failed to account for the change we made a little while ago where were use `arrow::DataType::List` for `ScalarType::Map`, instead of `arrow::DataType::Map`. ### Motivation Fixes MaterializeInc/database-issues#8834 ### Tips for reviewer <!-- Leave some tips for your reviewer, like: * The diff is much smaller if viewed with whitespace hidden. * [Some function/module/file] deserves extra attention. * [Some function/module/file] is pure code movement and only needs a skim. Delete this section if no tips. --> ### Checklist - [ ] This PR has adequate test coverage / QA involvement has been duly considered. ([trigger-ci for additional test/nightly runs](https://trigger-ci.dev.materialize.com/)) - [ ] This PR has an associated up-to-date [design doc](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/README.md), is a design doc ([template](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/00000000_template.md)), or is sufficiently small to not require a design. <!-- Reference the design in the description. --> - [ ] If this PR evolves [an existing `$T ⇔ Proto$T` mapping](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/command-and-response-binary-encoding.md) (possibly in a backwards-incompatible way), then it is tagged with a `T-proto` label. - [ ] If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label ([example](MaterializeInc/cloud#5021)). <!-- Ask in #team-cloud on Slack if you need help preparing the cloud PR. --> - [ ] If this PR includes major [user-facing behavior changes](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/guide-changes.md#what-changes-require-a-release-note), I have pinged the relevant PM to schedule a changelog post.
As part of #30205 we check if a new `arrow::DataType` is "at least as nullable" as the previous type, and if so we update the registered data type in-place. This check failed to account for the change we made a little while ago where were use `arrow::DataType::List` for `ScalarType::Map`, instead of `arrow::DataType::Map`. ### Motivation Fixes MaterializeInc/database-issues#8834 ### Tips for reviewer <!-- Leave some tips for your reviewer, like: * The diff is much smaller if viewed with whitespace hidden. * [Some function/module/file] deserves extra attention. * [Some function/module/file] is pure code movement and only needs a skim. Delete this section if no tips. --> ### Checklist - [ ] This PR has adequate test coverage / QA involvement has been duly considered. ([trigger-ci for additional test/nightly runs](https://trigger-ci.dev.materialize.com/)) - [ ] This PR has an associated up-to-date [design doc](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/README.md), is a design doc ([template](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/00000000_template.md)), or is sufficiently small to not require a design. <!-- Reference the design in the description. --> - [ ] If this PR evolves [an existing `$T ⇔ Proto$T` mapping](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/command-and-response-binary-encoding.md) (possibly in a backwards-incompatible way), then it is tagged with a `T-proto` label. - [ ] If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label ([example](MaterializeInc/cloud#5021)). <!-- Ask in #team-cloud on Slack if you need help preparing the cloud PR. --> - [ ] If this PR includes major [user-facing behavior changes](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/guide-changes.md#what-changes-require-a-release-note), I have pinged the relevant PM to schedule a changelog post.
Removes the onetime schema migration that was introduced in #30205. I looked back on 30 days worth of metrics and validated that `mz_persist_one_time_migration_more_nullable` did not show up for any users which indicates that our schema representation should be stable. ### Motivation Code cleanup ### Checklist - [x] This PR has adequate test coverage / QA involvement has been duly considered. ([trigger-ci for additional test/nightly runs](https://trigger-ci.dev.materialize.com/)) - [x] This PR has an associated up-to-date [design doc](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/README.md), is a design doc ([template](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/design/00000000_template.md)), or is sufficiently small to not require a design. <!-- Reference the design in the description. --> - [x] If this PR evolves [an existing `$T ⇔ Proto$T` mapping](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/command-and-response-binary-encoding.md) (possibly in a backwards-incompatible way), then it is tagged with a `T-proto` label. - [x] If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label ([example](MaterializeInc/cloud#5021)). <!-- Ask in #team-cloud on Slack if you need help preparing the cloud PR. --> - [x] If this PR includes major [user-facing behavior changes](https://github.com/MaterializeInc/materialize/blob/main/doc/developer/guide-changes.md#what-changes-require-a-release-note), I have pinged the relevant PM to schedule a changelog post.
Requires #30725 to be merged.
This PR stabilizes Schema Evolution in Persist which unblocks
ALTER TABLE
work. There are a few changes in this one PR, they are all geared around handling the slight instability we have with the nullability of columns in Materialized Views.arrow::DataType
s in Persist's Schema Registery that allows them to be more nullable to account for the changes from [1].SchemaId
s inPart
andRun
metadata. We do this by renaming the existingschema_id
fields todeprecated_schema_id
and introducing aschema_id
field with a new tag. Also a dyncfg is added so we can turn off writing to the newschema_id
field until we're confident all nodes have rolled to a new version.catalog-debug
to validate that theRelationDesc
s as planned by the new version of MZ are compatible with the ones durably recorded in Persist.Also included in this PR are two feature gate changes to disable new features in our tests until >
v0.126
.Both of these features cause the new version of MZ to issue writes during a 0dt upgrade when it's supposed to be in read-only mode. Because this PR changes the Arrow datatypes in a non-forward compatible way, this causes the 0dt tests to fail since the old version panics when it sees the new batches.
Motivation
Fixes https://github.com/MaterializeInc/database-issues/issues/8660
Tips for reviewer
All of these changes have been made in separate commits of the PR which ideally makes reviewing easier.
Checklist
$T ⇔ Proto$T
mapping (possibly in a backwards-incompatible way), then it is tagged with aT-proto
label.