-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
release-23.2: rangefeed: fix premature checkpoint due to intent resolution race #118413
release-23.2: rangefeed: fix premature checkpoint due to intent resolution race #118413
Conversation
Thanks for opening a backport. Please check the backport criteria before merging:
If your backport adds new functionality, please ensure that the following additional criteria are satisfied:
Also, please add a brief release justification to the body of your PR to justify this |
Your pull request contains more than 1000 changes. It is strongly encouraged to split big PRs into smaller chunks. 🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf. |
2b3746c
to
84a81e0
Compare
rts.resolvedTS, op)) | ||
// NB: MVCCLogicalOp.String() is only implemented for pointer receiver. | ||
err := errors.AssertionFailedf( | ||
"resolved timestamp %s equal to or above timestamp of operation %v", rts.resolvedTS, &op) |
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're now passing op
by reference. Does that cause the argument to escape to the heap and result in a new heap allocation even when the assertion is not firing?
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.
Great catch, especially considering I slipped this in here from #118265 -- thanks. You're probably right, I'll check this tomorrow and either shadow it in the branch or revert to passing by value.
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, also in #118265.
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.
Thanks for all the work finding, fixing, and backporting the fixes for this issue!
Reviewable status: complete! 1 of 0 LGTMs obtained (waiting on @erikgrinaker)
84a81e0
to
9a33cbc
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.
LGTM once the discussion from #118265 is resolved.
It was possible for rangefeeds to emit a premature checkpoint, before all writes below its timestamp had been emitted. This in turn would cause changefeeds to not emit these write events at all. This could happen because `PushTxn` may return a false `ABORTED` status for a transaction that has in fact been committed, if the transaction record has been GCed (after resolving all intents). The timestamp cache does not retain sufficient information to disambiguate a committed transaction from an aborted one in this case, so it pessimistically assumes an abort (see `Replica.CanCreateTxnRecord` and `batcheval.SynthesizeTxnFromMeta`). However, the rangefeed txn pusher trusted this `ABORTED` status, ignoring the pending txn intents and allowing the resolved timestamp to advance past them before emitting the committed intents. This can lead to the following scenario: - A rangefeed is running on a lagging follower. - A txn writes an intent, which is replicated to the follower. - The closed timestamp advances past the intent. - The txn commits and resolves the intent at the original write timestamp, then GCs its txn record. This is not yet applied on the follower. - The rangefeed pushes the txn to advance its resolved timestamp. - The txn is GCed, so the push returns ABORTED (it can't know whether the txn was committed or aborted after its record is GCed). - The rangefeed disregards the "aborted" txn and advances the resolved timestamp, emitting a checkpoint. - The follower applies the resolved intent and emits an event below the checkpoint, violating the checkpoint guarantee. - The changefeed sees an event below its frontier and drops it, never emitting these events at all. This patch fixes the bug by submitting a barrier command to the leaseholder which waits for all past and ongoing writes (including intent resolution) to complete and apply, and then waits for the local replica to apply the barrier as well. This ensures any committed intent resolution will be applied and emitted before the transaction is removed from resolved timestamp tracking. Epic: none Release note (bug fix): fixed a bug where a changefeed could omit events in rare cases, logging the error "cdc ux violation: detected timestamp ... that is less or equal to the local frontier". This can happen if a rangefeed runs on a follower replica that lags significantly behind the leaseholder, a transaction commits and removes its transaction record before its intent resolution is applied on the follower, the follower's closed timestamp has advanced past the transaction commit timestamp, and the rangefeed attempts to push the transaction to a new timestamp (at least 10 seconds after the transaction began). This may cause the rangefeed to prematurely emit a checkpoint before emitting writes at lower timestamps, which in turn may cause the changefeed to drop these events entirely, never emitting them.
Epic: none Release note: None
9a33cbc
to
c5792ba
Compare
Just a heads up that I think this currently is not on 23.2.1-rc branch. |
Thanks for the headsup, will bump it over. |
Only the 2 last commits should be reviewed here, the earlier commits in this PR are from the following prerequisite backports:
BarrierRequest.WithLeaseAppliedIndex
#118407PushTxnResponse.AmbiguousAbort
#118409This backport includes new RPC protocol additions that are necessary to fix the bug. The new behavior (applying a
Barrier
command to wait for a Raft pipeline flush) is controlled by a cluster settingkv.rangefeed.push_txns.barrier.enabled
, which defaults totrue
. According to the backport policy, such changes must be opt-in and disabled by default. However, making a bug fix opt-in appears questionable, especially one as serious as this one. I consider the protocol changes to be low-risk high-reward, and recommend we backport this behavior enabled by default.@rharding6373 Assigning you as secondary TL reviewer, since you're the upcoming CDC TL. Let me know if you'd like me to route this elsewhere.
Backport 2/2 commits from #117612. Also pull in parts of #118469 and #118265.
Release justification: fixes a bug which could cause changefeeds to omit events in some scenarios.
/cc @cockroachdb/release
It was possible for rangefeeds to emit a premature checkpoint, before all writes below its timestamp had been emitted. This in turn would cause changefeeds to not emit these write events at all.
This could happen because
PushTxn
may return a falseABORTED
status for a transaction that has in fact been committed, if the transaction record has been GCed (after resolving all intents). The timestamp cache does not retain sufficient information to disambiguate a committed transaction from an aborted one in this case, so it pessimisticallyassumes an abort (see
Replica.CanCreateTxnRecord
andbatcheval.SynthesizeTxnFromMeta
).However, the rangefeed txn pusher trusted this
ABORTED
status, ignoring the pending txn intents and allowing the resolved timestamp to advance past them before emitting the committed intents. This can lead to the following scenario:This patch fixes the bug by submitting a barrier command to the leaseholder which waits for all past and ongoing writes (including intent resolution) to complete and apply, and then waits for the local replica to apply the barrier as well. This ensures any committed intent resolution will be applied and emitted before the transaction is removed from resolved timestamp tracking.
Resolves #104309.
Epic: none
Release note (bug fix): fixed a bug where a changefeed could omit events in rare cases, logging the error "cdc ux violation: detected timestamp ... that is less or equal to the local frontier". This can happen if a rangefeed runs on a follower replica that lags significantly behind the leaseholder, a transaction commits and removes its transaction record before its intent resolution is applied on the follower, the follower's closed timestamp has advanced past the transaction commit timestamp, and the rangefeed attempts to push the transaction to a new timestamp (at least 10 seconds after the transaction began). This may cause the rangefeed to prematurely emit a checkpoint before emitting writes at lower timestamps, which in turn may cause the changefeed to drop these events entirely, never emitting them.