-
Notifications
You must be signed in to change notification settings - Fork 482
persist: register schema at write time, not writer open time #33902
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: register schema at write time, not writer open time #33902
Conversation
395a329 to
04664bf
Compare
| // TODO: Remove the Option once this finishes rolling out and all shards | ||
| // have a registered 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.
Removed this TODO because we need the Option now to support WriteHandles who haven't yet registered their schema.
| let Some(schema_id) = schema_id else { | ||
| panic!("unable to register schemas: {key:?} {val:?}"); | ||
| }; |
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.
Note that previously in open_writer we only soft-asserted that schema registration was successful. That seems dangerous to me. Presumably writing to a shard with an incompatible schema would lead to all kinds of issues? Perhaps it was fine because the CaA logic also performs validation.
Since ensure_schema_registered is only called when we know we will need the schema, it seems fine to panic here. Also fine to return an Option like register_schema does and then unwrap at the call site. Lmk which you prefer!
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.
That seems dangerous to me.
Maybe! Note that prior to this stuff being added, the schema could change ~arbitrarily without Persist noticing, so it was a strict improvement in safety.
But anyways I don't think this assert has tripped at all in the year or so it's been in prod, so it seems safe to strengthen it now.
| mz_ore::soft_panic_or_log!( | ||
| "encountered data shard without a schema; shard_id: {}", | ||
| previous.shard_id(), | ||
| ); |
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.
If we made this a panic/unwrap, the control flow would be a bit cleaner. But it's perhaps a bit scary and the surrounding code also only does soft panics.
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 we also need/want to register the schema when we write a batch?
I don't think it's necessary personally... the append-time check preserves the shard-level invariant, and I can imagine cases where you'd want to start building up batches at a new schema before actually evolving the shard. (If we shifted the self-correction buffer to Persist, for example, that would allow a read-only replica to start spilling to Persist even if the schema it was using wasn't yet registered.)
| let Some(schema_id) = schema_id else { | ||
| panic!("unable to register schemas: {key:?} {val:?}"); | ||
| }; |
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.
That seems dangerous to me.
Maybe! Note that prior to this stuff being added, the schema could change ~arbitrarily without Persist noticing, so it was a strict improvement in safety.
But anyways I don't think this assert has tripped at all in the year or so it's been in prod, so it seems safe to strengthen it now.
| // schema _before_ we publish it to the txns shard. | ||
| for data_write in &mut data_writes { | ||
| data_write.ensure_schema_registered().await; | ||
| } |
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.
Are we confident that read-only replicas don't even register handles for existing shards, even though they'll never actually write to them?
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.
Yes, based on the current code: TxnsHandle::register is only called by TxnsTableWorker, which is only instantiated in leader mode (read-only mode uses read_only_mode_table_worker instead).
We don't know what future code will want to do of course. That's why it would be nice to have some way to assert that "write" operations (e.g. CaA, schema registration) are only performed against shards that have been created by, or upgraded to the current version.
69c6796 to
29577af
Compare
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.
The new method seems good and looks safer to me - thanks for that!
One open thread about the dead code, but however that ends up getting resolved I think we're good to merge.
| // We defer registering the schema until write time, to allow opening | ||
| // write handles in a "read-only" mode where they don't implicitly | ||
| // modify persist state. But it might already be registered, in which | ||
| // case we can fetch its ID. |
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 was a little nervous about how this changed the semantics of the schema_id method... but it turns out that's only used by txn-wal in what looks like a safe pattern. Still a possible footgun, but hopefully one we can mitigate in the future...
29577af to
1233630
Compare
This commit changes persist clients to defer calling `register_schema` on a shard from write handle creation time to the time of the first append operation. The rationale is that we don't need to enforce a schema if we are not attempting to write to a shard. The plan is for 0dt upgrades to make good use of the new, more lenient behavior. Read-only environments can open write handles with evolved schemas without having to durably write down the new schemas. This will allow us to back out of version upgrades without the risk of permanently poisoning the persist state for lower versions.
... and use it to enable shard finalization without a known shard schema.
1233630 to
990ffbb
Compare
|
TFTR! |
This PR changes persist clients to defer calling
register_schemaon a shard from write handle creation time to the time of the first append operation. The rationale is that we don't need to enforce a schema if we are not attempting to write to a shard.The plan is for 0dt upgrades to make good use of the new, more lenient behavior. Read-only environments can open write handles with evolved schemas without having to durably write down the new schemas. This will allow us to back out of version upgrades without the risk of permanently poisoning the persist state for lower versions.
Motivation
Prepares for the design proposed in #33863.
Part of https://github.com/MaterializeInc/database-issues/issues/9793
Tips for reviewer
DataHandles::open_data_write_for_applyin txn-wal expects the given shard to have a schema registered. This PR ensures that by changingTxnsHandle::registerto register the shard schema. This should be fine because according to this comment we can assume a shard is always registered (potentially by a previous envd version) prior to its ID being passed toopen_data_write_for_apply.Also, write handles currently only call
ensure_schema_registeredwhen doing a compare-and-append. I'm not sure this is the right place! Do we also need/want to register the schema when we write a batch?Checklist
$T ⇔ Proto$Tmapping (possibly in a backwards-incompatible way), then it is tagged with aT-protolabel.