diff options
-rw-r--r-- | jstests/core/tailable_skip_limit.js | 11 | ||||
-rw-r--r-- | src/mongo/db/instance.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/find.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query_test.cpp | 11 | ||||
-rw-r--r-- | src/mongo/s/strategy.cpp | 4 |
6 files changed, 27 insertions, 11 deletions
diff --git a/jstests/core/tailable_skip_limit.js b/jstests/core/tailable_skip_limit.js index 1fae7263a8f..bfb88778910 100644 --- a/jstests/core/tailable_skip_limit.js +++ b/jstests/core/tailable_skip_limit.js @@ -54,15 +54,8 @@ assert(cursor.hasNext()); assert.eq(7, cursor.next()["_id"]); - // Tailable with negative limit - var cursor = t.find().addOption(2).limit(-100); - for (var i = 1; i <= 7; i++) { - assert.eq(i, cursor.next()["_id"]); - } - assert(!cursor.hasNext()); - t.save({_id: 8}); - assert(cursor.hasNext()); - assert.eq(8, cursor.next()["_id"]); + // Tailable with negative limit is an error. + assert.throws(function() { t.find().addOption(2).limit(-100).next(); }); // Tests that a tailable cursor over an empty capped collection produces a dead cursor, intended // to be run on both mongod and mongos. For SERVER-20720. diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index e1cd9230d24..921f507ab00 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -878,6 +878,8 @@ bool receivedGetMore(OperationContext* txn, DbResponse& dbresponse, Message& m, const char* ns = d.getns(); int ntoreturn = d.pullInt(); + uassert( + 34368, str::stream() << "Invalid ntoreturn for OP_GET_MORE: " << ntoreturn, ntoreturn >= 0); long long cursorid = d.pullInt64(); curop.debug().ntoreturn = ntoreturn; diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 89c356a3fe8..a56a282817a 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -252,6 +252,8 @@ QueryResult::View getMore(OperationContext* txn, long long cursorid, bool* exhaust, bool* isCursorAuthorized) { + invariant(ntoreturn >= 0); + CurOp& curop = *CurOp::get(txn); // For testing, we may want to fail if we receive a getmore. diff --git a/src/mongo/db/query/lite_parsed_query.cpp b/src/mongo/db/query/lite_parsed_query.cpp index a4f9696b7a0..672d143c22f 100644 --- a/src/mongo/db/query/lite_parsed_query.cpp +++ b/src/mongo/db/query/lite_parsed_query.cpp @@ -653,13 +653,19 @@ Status LiteParsedQuery::validate() const { "'limit' or 'batchSize' fields can not be set with 'ntoreturn' field."); } - // Tailable cursors cannot have any sort other than {$natural: 1}. if (_tailable) { + // Tailable cursors cannot have any sort other than {$natural: 1}. const BSONObj expectedSort = BSON("$natural" << 1); if (!_sort.isEmpty() && _sort != expectedSort) { return Status(ErrorCodes::BadValue, "cannot use tailable option with a sort other than {$natural: 1}"); } + + // Cannot indicate that you want a 'singleBatch' if the cursor is tailable. + if (!_wantMore) { + return Status(ErrorCodes::BadValue, + "cannot use tailable option with the 'singleBatch' option"); + } } return Status::OK(); diff --git a/src/mongo/db/query/lite_parsed_query_test.cpp b/src/mongo/db/query/lite_parsed_query_test.cpp index d2c1cd92842..4ae2f3096b9 100644 --- a/src/mongo/db/query/lite_parsed_query_test.cpp +++ b/src/mongo/db/query/lite_parsed_query_test.cpp @@ -188,6 +188,17 @@ TEST(LiteParsedQueryTest, ForbidTailableWithNonNaturalSort) { ASSERT_NOT_OK(result.getStatus()); } +TEST(LiteParsedQueryTest, ForbidTailableWithSingleBatch) { + BSONObj cmdObj = fromjson( + "{find: 'testns'," + "tailable: true," + "singleBatch: true}"); + const NamespaceString nss("test.testns"); + bool isExplain = false; + auto result = LiteParsedQuery::makeFromFindCommand(nss, cmdObj, isExplain); + ASSERT_NOT_OK(result.getStatus()); +} + TEST(LiteParsedQueryTest, AllowTailableWithNaturalSort) { BSONObj cmdObj = fromjson( "{find: 'testns'," diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp index 84fb002839c..409c6ad827d 100644 --- a/src/mongo/s/strategy.cpp +++ b/src/mongo/s/strategy.cpp @@ -339,6 +339,8 @@ void Strategy::commandOp(OperationContext* txn, void Strategy::getMore(OperationContext* txn, Request& request) { const char* ns = request.getns(); const int ntoreturn = request.d().pullInt(); + uassert( + 34369, str::stream() << "Invalid ntoreturn for OP_GET_MORE: " << ntoreturn, ntoreturn >= 0); const long long id = request.d().pullInt64(); // TODO: Handle stale config exceptions here from coll being dropped or sharded during op for @@ -354,7 +356,7 @@ void Strategy::getMore(OperationContext* txn, Request& request) { boost::optional<long long> batchSize; if (ntoreturn) { - batchSize = abs(ntoreturn); + batchSize = ntoreturn; } GetMoreRequest getMoreRequest( NamespaceString(ns), id, batchSize, boost::none, boost::none, boost::none); |