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

GODRIVER-1831 Avoid accidental extra getMore when using limit on Find #562

Merged
merged 4 commits into from
Jan 27, 2021
Merged

GODRIVER-1831 Avoid accidental extra getMore when using limit on Find #562

merged 4 commits into from
Jan 27, 2021

Conversation

benjirewis
Copy link
Contributor

GODRIVER-1831

Includes change from this PR to legacy batch_cursor#getMore() to fix a bug found by an external user on MDB versioned 2.6.12: when numReturned == limit and batchSize is not set on a batchCursor an extra getMore is run when the cursor should have just been closed

Adds a test to make sure that when batchSize is not set on a batchCursor, a set limit will not be surpassed accidentally.


assert.Equal(mt, int(limit), len(docs), "expected number of docs to be %v, got %v", limit, len(docs))
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Given that this is a bit tricky to reason about, I suggest:

  1. Insert more than 101 documents in the collection. That is the default batch size for find, so we can test what happens on a getMore when using the default batch size.
  2. Adding a table test parameterized on: skip, limit, and batchSize which can check for an expected result count. That will make it easy to add future tests as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added both!

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!

@@ -241,7 +241,7 @@ func (bc *BatchCursor) getMore(ctx context.Context) {

// Required for legacy operations which don't support limit.
numToReturn := bc.batchSize
if bc.limit != 0 && bc.numReturned+bc.batchSize > bc.limit {
if bc.limit != 0 && bc.numReturned+bc.batchSize >= bc.limit {
Copy link
Contributor

Choose a reason for hiding this comment

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

Based on my reading of https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#combining-limit-and-batch-size-for-the-wire-protocol I believe it is ok to use batchSize=0 when a limit is set. So I think this might be ok? I'm still not entirely sure where the limit is enforced after, when batchSize=0 and more than the limit documents are returned. I think tests which query a collection containing more than 101 documents may verify that behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure either, but the tests now query a collection containing more than 101 documents and pass...

Copy link
Contributor

Choose a reason for hiding this comment

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

Great, the new tests cover the case of a getMore being run.

@kevinAlbs kevinAlbs self-requested a review January 21, 2021 13:50
Copy link
Contributor

@iwysiu iwysiu left a comment

Choose a reason for hiding this comment

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

The code change looks good to me, just an additional test case request.

mongo/integration/collection_test.go Outdated Show resolved Hide resolved
@benjirewis benjirewis requested a review from iwysiu January 21, 2021 18:22
@divjotarora divjotarora removed their request for review January 21, 2021 18:26
@divjotarora
Copy link
Contributor

I'm removing myself as a required reviewer here, but once this is approved by other reviewers, the title and final commit message should be changed as this PR actually includes a code change, not just a new test.

@benjirewis benjirewis changed the title GODRIVER-1831 Add find limit test with unset batch size GODRIVER-1831 Avoid accidental extra getMore when using limit on Find Jan 21, 2021
Copy link
Contributor

@kevinAlbs kevinAlbs left a comment

Choose a reason for hiding this comment

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

I have a couple nits about test case names and error messages. Otherwise LGTM!


assert.Equal(mt, int(limit), len(docs), "expected number of docs to be %v, got %v", limit, len(docs))
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!

err = cursor.All(mtest.Background, &docs)
assert.Nil(mt, err, "All error: %v", err)
if (201 - tc.skip) < tc.limit {
assert.Equal(mt, int(201-tc.skip), len(docs), "expected number of docs to be %v, got %v", tc.limit, len(docs))
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
assert.Equal(mt, int(201-tc.skip), len(docs), "expected number of docs to be %v, got %v", tc.limit, len(docs))
assert.Equal(mt, int(201-tc.skip), len(docs), "expected number of docs to be %v, got %v", int(201-tc.skip), len(docs))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Changed.

@@ -241,7 +241,7 @@ func (bc *BatchCursor) getMore(ctx context.Context) {

// Required for legacy operations which don't support limit.
numToReturn := bc.batchSize
if bc.limit != 0 && bc.numReturned+bc.batchSize > bc.limit {
if bc.limit != 0 && bc.numReturned+bc.batchSize >= bc.limit {
Copy link
Contributor

Choose a reason for hiding this comment

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

Great, the new tests cover the case of a getMore being run.

},
}

for _, tc := range testCases {
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest adding a name to the test cases and having the loop use mt.Run:

mt.Run(tc.name, func(mt *mtest.T) { ... }

It will make it easier to identify which test case failed if they are split into cases. Even names as simple as "case 1", "case 2", "case 3", etc. will produce separate output for each test case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah good idea! Used "case 1", etc. since they were difficult to describe succinctly.

assert.Nil(mt, err, "InsertMany error for initial data: %v", err)

for _, limit := range []int64{99, 100, 101, 200} {
opts := options.Find().SetSkip(0).SetLimit(limit)
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, I suggest adding a name to the test cases. Otherwise, it'd be harder to track down which case failed if L949 errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good! Used the limit number as the name for each case.

Copy link
Contributor

@iwysiu iwysiu left a comment

Choose a reason for hiding this comment

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

lgtm!

@benjirewis benjirewis merged commit f893899 into mongodb:master Jan 27, 2021
@benjirewis benjirewis deleted the addFindLimitTests.1831 branch January 27, 2021 22:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants