Skip to content

Conversation

@yuzefovich
Copy link
Member

@yuzefovich yuzefovich commented Nov 2, 2024

kvstreamer: fix TestStreamerVaryingResponseSizes

Previously the test was fooling itself - the regex for KV gRPC calls line was incorrect, so it was never matched, and we ended up with unset counter (which happened to pass the test); this is now fixed.

Release note: None

kvstreamer: fix pathological behavior in InOrder mode

This commit fixes the case of pathological behavior by the streamer in the InOrder mode in some cases. Namely, when ordering needs to be maintained, the streamer needs to prioritize sub-requests that have higher "urgency" to be served (i.e. those that are closer to the head of the line). This "urgency" is represented by the values in singleRangeBatch.positions slice where the smaller the value, the higher the urgency, and the value at the zeroth index is used as the priority for the whole single-range batch. It is assumed that the values in this slice are increasing, but this assumption could previously be violated when multiple ranges were touched (when the original batch fit within a single range, we have a separate fast-path that is unaffected by this bug). This was the case because we used mustPreserveOrder = false when instantiating the batch truncation helper. As a result, all sub-requests within the single-range batch would get reordered according to the start key of each request, and the original order wouldn't be restored by the batch truncation helper. This, in turn, would result in the streamer evaluating the requests with effectively random urgency which would then consume the working budget. In the extreme, we would use up all available budget for random requests, buffer them, and would keep on doing so until we get lucky to get the next head-of-the-line request randomly. This is now fixed by restoring the order of positions by the truncation helper when the streamer is in the InOrder mode. This commit also adds a test-only assertion for ensuring the ascending invariant is maintained.

Here is a concrete example of the behavior. Say, we have two ranges [a - f) and [f - ...) and requests

  • 0: Get(c)
  • 1: Get(e)
  • 2: Get(d)
  • 3: Get(f)
  • 4: Get(a)
  • 5: Get(b)

The batch truncation helper will first order all requests by the start key, so it'll process them in the order 4 - 5 - 0 - 2 - 1 - 3. When truncating to the first range [a - f), it'll populate positions as [4, 5, 0, 2, 1] (request 3 is outside of the range, so it'll stop). This slice is what we would previously include into singleRangeBatch.positions, so we would first evaluate the 4th request, then the 5th, etc. Previously, we would also incorrectly compare singleRangeBatches between each other for "in order" priority.

AFAICT this bug has been present since the introduction of the batch truncation helper in 645c154. The assumption of the InOrder mode was already there, in the comment, but wasn't enforced and was overlooked.

Fixes: #133043.

Release note (bug fix): Previously, when executing queries with index / lookup joins when the ordering needs to be maintained, CockroachDB in some cases could get into a pathological behavior which would lead to increased query latency, possibly by several orders of magnitude. This bug was introduced in 22.2 and is now fixed.

@cockroach-teamcity
Copy link
Member

This change is Reviewable

@yuzefovich yuzefovich changed the title kvstreamer: fix TestStreamerVaryingResponseSizes kvstreamer: fix pathological behavior in InOrder mode Nov 2, 2024
Previously the test was fooling itself - the regex for `KV gRPC calls`
line was incorrect, so it was never matched, and we ended up with unset
counter (which happened to pass the test); this is now fixed.

Release note: None
This commit fixes the case of pathological behavior by the streamer in
the InOrder mode in some cases. Namely, when ordering needs to be
maintained, the streamer needs to prioritize sub-requests that have
higher "urgency" to be served (i.e. those that are closer to the head of
the line). This "urgency" is represented by the values in
`singleRangeBatch.positions` slice where the smaller the value, the
higher the urgency, and the value at the zeroth index is used as the
priority for the whole single-range batch. It is assumed that the values
in this slice are increasing, but this assumption could previously be
violated when multiple ranges were touched (when the original batch fit
within a single range, we have a separate fast-path that is unaffected
by this bug). This was the case because we used
`mustPreserveOrder = false` when instantiating the batch truncation
helper. As a result, all sub-requests within the single-range batch
would get reordered according to the start key of each request, and the
original order wouldn't be restored by the batch truncation helper. This,
in turn, would result in the streamer evaluating the requests with
effectively random urgency which would then consume the working budget.
In the extreme, we would use up all available budget for random requests,
buffer them, and would keep on doing so until we get lucky to get the next
head-of-the-line request randomly. This is now fixed by restoring the
order of `positions` by the truncation helper when the streamer is in the
InOrder mode. This commit also adds a test-only assertion for ensuring the
ascending invariant is maintained.

Here is a concrete example of the behavior. Say, we have two ranges
[a - f) and [f - ...) and requests
0: Get(c)
1: Get(e)
2: Get(d)
3: Get(f)
4: Get(a)
5: Get(b)

The batch truncation helper will first order all requests by the start
key, so it'll process them in the order 4 - 5 - 0 - 2 - 1 - 3. When
truncating to the first range [a - f), it'll populate `positions` as
`[4, 5, 0, 2, 1]` (request 3 is outside of the range, so it'll stop).
This slice is what we would previously include into
`singleRangeBatch.positions`, so we would first evaluate the 4th
request, then the 5th, etc. Previously, we would also incorrectly
compare `singleRangeBatch`es between each other for "in order" priority.

AFAICT this bug has been present since the introduction of the batch
truncation helper in 645c154. The
assumption of the InOrder mode was already there, in the comment, but
wasn't enforced and was overlooked.

Release note (bug fix): Previously, when executing queries with
index / lookup joins when the ordering needs to be maintained,
CockroachDB in some cases could get into a pathological behavior
which would lead to increased query latency, possibly by several
orders of magnitude. This bug was introduced in 22.2 and is now fixed.
@yuzefovich yuzefovich added backport-23.1.x PAST MAINTENANCE SUPPORT: 23.1 patch releases via ER request only backport-23.2.x PAST MAINTENANCE SUPPORT: 23.2 patch releases via ER request only backport-24.1.x Flags PRs that need to be backported to 24.1. backport-24.2.x backport-24.3.x Flags PRs that need to be backported to 24.3 labels Nov 4, 2024
@yuzefovich yuzefovich marked this pull request as ready for review November 4, 2024 22:19
@yuzefovich yuzefovich requested a review from a team as a code owner November 4, 2024 22:19
Copy link
Collaborator

@DrewKimball DrewKimball left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm: Nice job finding this!

Reviewed 1 of 1 files at r1, 2 of 2 files at r2, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @michae2)

@yuzefovich
Copy link
Member Author

TFTR!

bors r+

@yuzefovich
Copy link
Member Author

bors retry

@craig craig bot merged commit a0bbd5d into cockroachdb:master Nov 6, 2024
23 checks passed
@blathers-crl
Copy link

blathers-crl bot commented Nov 6, 2024

Based on the specified backports for this PR, I applied new labels to the following linked issue(s). Please adjust the labels as needed to match the branches actually affected by the issue(s), including adding any known older branches.


Issue #133043: branch-release-23.1, branch-release-23.2, branch-release-24.1, branch-release-24.3.


🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

Copy link
Collaborator

@mgartner mgartner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracking this one down!

Reviewed 1 of 1 files at r1, 2 of 2 files at r2, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained


pkg/kv/kvclient/kvstreamer/streamer.go line 1379 at r2 (raw file):

					for i := range req.positions[:len(req.positions)-1] {
						if req.positions[i] >= req.positions[i+1] {
							w.s.results.setError(errors.AssertionFailedf(

Great idea to add this assertion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-23.1.x PAST MAINTENANCE SUPPORT: 23.1 patch releases via ER request only backport-23.2.x PAST MAINTENANCE SUPPORT: 23.2 patch releases via ER request only backport-24.1.x Flags PRs that need to be backported to 24.1. backport-24.3.x Flags PRs that need to be backported to 24.3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kvstreamer: super-linear increase in latency and number of gPRC calls in InOrder mode

4 participants