Skip to content
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

Change Feed: Fixes pull model request count for NotModified scenario #2405

Merged
merged 17 commits into from
Apr 23, 2021

Conversation

ealsur
Copy link
Member

@ealsur ealsur commented Apr 20, 2021

Expectation

Assuming a FeedRange that spans multiple partitions/EPK ranges, for example, EPK Range 1, 2, and 3.

Change Feed pull model logic when receiving a NotModified should be:

  1. Received 304 (NotModified) on EPK Range 1.
  2. Check EPK Range 2, if received 304 (NotModified), then:
  3. Check EPK Range 3, if received 304 (NotModified) then:
  4. Return 304 (NotModified) to the user, since we tested all ranges and all are returning 304.

If the FeedRange spans a single partition/EPK range, for example, EPK Range 1.

Change Feed pull model logic when receiving a NotModified should be:

  1. Received 304 (NotModified) on EPK Range 1.
  2. Return 304 (NotModified) to the user, since the FeedRange does not span more ranges.

Current behavior

The current behavior is doing one extra request, that on the case of FeedRanges that span a single partition/EPK range, causes a 2x increase in number of requests.

Using the previous example, if the FeedRange spans EPK Range 1, 2, and 3, Change Feed pull model is doing:

  1. Received 304 (NotModified) on EPK Range 1.
  2. Check EPK Range 2, if received 304 (NotModified), then:
  3. Check EPK Range 3, if received 304 (NotModified) then:
  4. Check EPK Range 1, if received 304 (NotModified) then:
  5. Return 304 (NotModified) to the user, since the last EPK Range matches the initial that returned 304.

If the FeedRange spans a single partition/EPK range, for example, EPK Range 1:

  1. Received 304 (NotModified) on EPK Range 1.
  2. Check EPK Range 1 again, if received 304 (NotModified) then:
  3. Return 304 (NotModified) to the user, since the last EPK Range matches the initial that returned 304.

Logical fix

To solve it, we are now adding a TryPeekNext to the CrossPartitionRangePageAsyncEnumerator, which will peek on the internal queue and attempt to return the next state that would be read.

And doing 2 optimizations:

  1. When getting a 304, if the Current range is the same as the Next range, it means the FeedRange spans 1 EPK Range, do nothing and return the 304. This reduces the number of requests to 1 on this scenario.
  2. Call MoveNext on the Enumerator until the Next matches the initial one that received the first 304. This avoids the repeat on the scenario where the FeedRange spans multiple EPK ranges.

The PR contains tests to cover the logic and also updates the Contract tests to match what internal teams are actually really doing, the Contract tests got modified on previous PRs and diverged from what they were meant to cover.

Review tips

The 2 major changes in CrossPartitionChangeFeedAsyncEnumerator were:

From:

while (!(backendPage is ChangeFeedSuccessPage
                                || this.crossPartitionEnumerator.CurrentRange.Equals(originalRange)
                                || this.bufferedException.HasValue));

To:

while (!(backendPage is ChangeFeedSuccessPage
                                || IsNextRangeEqualToOriginal(this.crossPartitionEnumerator, originalRange)
                                || this.bufferedException.HasValue));

And adding a check for a single range scenario:

if (!IsNextRangeEqualToOriginal(this.crossPartitionEnumerator, originalRange))

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Copy link
Member

@kirankumarkolli kirankumarkolli left a comment

Choose a reason for hiding this comment

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

Older Async enumerator contract seems reasonable.
Current/Next model is ambiguous and leads to mis-interpretations.

Can the looping be hardened with the current enumerator contract?

Copy link
Member

@FabianMeiswinkel FabianMeiswinkel left a comment

Choose a reason for hiding this comment

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

LGTM

@ealsur ealsur merged commit ecf90d6 into master Apr 23, 2021
@ealsur ealsur deleted the users/ealsur/cfextra branch April 23, 2021 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working ChangeFeed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants