From 66028bde22d641a1fbf96e7e3f76554e059cc221 Mon Sep 17 00:00:00 2001 From: Jason Rassi Date: Fri, 28 Aug 2015 01:59:12 -0400 Subject: SERVER-19569 Combine getmore_response.h with cursor_responses.h --- src/mongo/db/query/SConscript | 5 +- src/mongo/db/query/cursor_response.cpp | 164 ++++++++++++++++++++ src/mongo/db/query/cursor_response.h | 94 ++++++++++++ src/mongo/db/query/cursor_response_test.cpp | 215 +++++++++++++++++++++++++++ src/mongo/db/query/cursor_responses.cpp | 59 -------- src/mongo/db/query/cursor_responses.h | 65 -------- src/mongo/db/query/getmore_response.cpp | 142 ------------------ src/mongo/db/query/getmore_response.h | 66 -------- src/mongo/db/query/getmore_response_test.cpp | 215 --------------------------- 9 files changed, 475 insertions(+), 550 deletions(-) create mode 100644 src/mongo/db/query/cursor_response.cpp create mode 100644 src/mongo/db/query/cursor_response.h create mode 100644 src/mongo/db/query/cursor_response_test.cpp delete mode 100644 src/mongo/db/query/cursor_responses.cpp delete mode 100644 src/mongo/db/query/cursor_responses.h delete mode 100644 src/mongo/db/query/getmore_response.cpp delete mode 100644 src/mongo/db/query/getmore_response.h delete mode 100644 src/mongo/db/query/getmore_response_test.cpp (limited to 'src/mongo/db/query') diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript index cc543afead5..dfcb8f9265c 100644 --- a/src/mongo/db/query/SConscript +++ b/src/mongo/db/query/SConscript @@ -113,10 +113,9 @@ env.Library( target='command_request_response', source=[ 'count_request.cpp', - 'cursor_responses.cpp', + 'cursor_response.cpp', 'find_and_modify_request.cpp', 'getmore_request.cpp', - 'getmore_response.cpp', 'killcursors_request.cpp', 'killcursors_response.cpp', ], @@ -132,9 +131,9 @@ env.CppUnitTest( target='command_request_response_test', source=[ 'count_request_test.cpp', + 'cursor_response_test.cpp', 'find_and_modify_request_test.cpp', 'getmore_request_test.cpp', - 'getmore_response_test.cpp', 'killcursors_request_test.cpp', 'killcursors_response_test.cpp', ], diff --git a/src/mongo/db/query/cursor_response.cpp b/src/mongo/db/query/cursor_response.cpp new file mode 100644 index 00000000000..85afd949b1d --- /dev/null +++ b/src/mongo/db/query/cursor_response.cpp @@ -0,0 +1,164 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kQuery + +#include "mongo/platform/basic.h" + +#include "mongo/db/query/cursor_response.h" + +#include "mongo/bson/bsontypes.h" +#include "mongo/rpc/get_status_from_command_result.h" + +namespace mongo { + +namespace { + +const char kCursorField[] = "cursor"; +const char kIdField[] = "id"; +const char kNsField[] = "ns"; +const char kBatchField[] = "nextBatch"; +const char kBatchFieldInitial[] = "firstBatch"; + +} // namespace + +void appendCursorResponseObject(long long cursorId, + StringData cursorNamespace, + BSONArray firstBatch, + BSONObjBuilder* builder) { + BSONObjBuilder cursorObj(builder->subobjStart(kCursorField)); + cursorObj.append(kIdField, cursorId); + cursorObj.append(kNsField, cursorNamespace); + cursorObj.append(kBatchFieldInitial, firstBatch); + cursorObj.done(); +} + +void appendGetMoreResponseObject(long long cursorId, + StringData cursorNamespace, + BSONArray nextBatch, + BSONObjBuilder* builder) { + BSONObjBuilder cursorObj(builder->subobjStart(kCursorField)); + cursorObj.append(kIdField, cursorId); + cursorObj.append(kNsField, cursorNamespace); + cursorObj.append(kBatchField, nextBatch); + cursorObj.done(); +} + +CursorResponse::CursorResponse(NamespaceString namespaceString, + CursorId id, + std::vector objs, + boost::optional nReturnedSoFar) + : nss(std::move(namespaceString)), + cursorId(id), + batch(std::move(objs)), + numReturnedSoFar(nReturnedSoFar) {} + +StatusWith CursorResponse::parseFromBSON(const BSONObj& cmdResponse) { + Status cmdStatus = getStatusFromCommandResult(cmdResponse); + if (!cmdStatus.isOK()) { + return cmdStatus; + } + + std::string fullns; + BSONObj batchObj; + CursorId cursorId; + + BSONElement cursorElt = cmdResponse[kCursorField]; + if (cursorElt.type() != BSONType::Object) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Field '" << kCursorField + << "' must be a nested object in: " << cmdResponse}; + } + BSONObj cursorObj = cursorElt.Obj(); + + BSONElement idElt = cursorObj[kIdField]; + if (idElt.type() != BSONType::NumberLong) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Field '" << kIdField + << "' must be of type long in: " << cmdResponse}; + } + cursorId = idElt.Long(); + + BSONElement nsElt = cursorObj[kNsField]; + if (nsElt.type() != BSONType::String) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Field '" << kNsField + << "' must be of type string in: " << cmdResponse}; + } + fullns = nsElt.String(); + + BSONElement batchElt = cursorObj[kBatchField]; + if (batchElt.eoo()) { + batchElt = cursorObj[kBatchFieldInitial]; + } + + if (batchElt.type() != BSONType::Array) { + return {ErrorCodes::TypeMismatch, + str::stream() << "Must have array field '" << kBatchFieldInitial << "' or '" + << kBatchField << "' in: " << cmdResponse}; + } + batchObj = batchElt.Obj(); + + std::vector batch; + for (BSONElement elt : batchObj) { + if (elt.type() != BSONType::Object) { + return { + ErrorCodes::BadValue, + str::stream() << "getMore response batch contains a non-object element: " << elt}; + } + + batch.push_back(elt.Obj().getOwned()); + } + + return {{NamespaceString(fullns), cursorId, batch}}; +} + +void CursorResponse::addToBSON(BSONObjBuilder* builder) const { + BSONObjBuilder cursorBuilder(builder->subobjStart(kCursorField)); + + cursorBuilder.append(kIdField, cursorId); + cursorBuilder.append(kNsField, nss.ns()); + + BSONArrayBuilder batchBuilder(cursorBuilder.subarrayStart(kBatchField)); + for (const BSONObj& obj : batch) { + batchBuilder.append(obj); + } + batchBuilder.doneFast(); + + cursorBuilder.doneFast(); + + builder->append("ok", 1.0); +} + +BSONObj CursorResponse::toBSON() const { + BSONObjBuilder builder; + addToBSON(&builder); + return builder.obj(); +} + +} // namespace mongo diff --git a/src/mongo/db/query/cursor_response.h b/src/mongo/db/query/cursor_response.h new file mode 100644 index 00000000000..e606dcd1559 --- /dev/null +++ b/src/mongo/db/query/cursor_response.h @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#pragma once + +#include + +#include "mongo/base/status_with.h" +#include "mongo/bson/bsonobj.h" +#include "mongo/db/clientcursor.h" +#include "mongo/db/namespace_string.h" + +namespace mongo { + +/** + * Builds a cursor response object from the provided cursor identifiers and "firstBatch", + * and appends the response object to the provided builder under the field name "cursor". + * + * The response object has the following format: + * { id: , ns: , firstBatch: }. + * + * This function is deprecated. Prefer CursorResponse::toBSON() instead. + */ +void appendCursorResponseObject(long long cursorId, + StringData cursorNamespace, + BSONArray firstBatch, + BSONObjBuilder* builder); + +/** + * Builds a getMore response object from the provided cursor identifiers and "nextBatch", + * and appends the response object to the provided builder under the field name "cursor". + * + * The response object has the following format: + * { id: , ns: , nextBatch: }. + * + * This function is deprecated. Prefer CursorResponse::toBSON() instead. + */ +void appendGetMoreResponseObject(long long cursorId, + StringData cursorNamespace, + BSONArray nextBatch, + BSONObjBuilder* builder); + +struct CursorResponse { + /** + * Constructs from values for each of the fields. + */ + CursorResponse(NamespaceString namspaceString, + CursorId id, + std::vector objs, + boost::optional nReturnedSoFar = boost::none); + + /** + * Constructs a CursorResponse from the command BSON response. + */ + static StatusWith parseFromBSON(const BSONObj& cmdResponse); + + /** + * Converts this response to its raw BSON representation. + */ + BSONObj toBSON() const; + void addToBSON(BSONObjBuilder* builder) const; + + const NamespaceString nss; + const CursorId cursorId; + const std::vector batch; + const boost::optional numReturnedSoFar; +}; + +} // namespace mongo diff --git a/src/mongo/db/query/cursor_response_test.cpp b/src/mongo/db/query/cursor_response_test.cpp new file mode 100644 index 00000000000..37f426d8eb9 --- /dev/null +++ b/src/mongo/db/query/cursor_response_test.cpp @@ -0,0 +1,215 @@ +/** + * Copyright 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/query/cursor_response.h" + +#include "mongo/unittest/unittest.h" + +namespace mongo { + +namespace { + +TEST(CursorResponseTest, parseFromBSONFirstBatch) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "firstBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1)); + ASSERT_OK(result.getStatus()); + + CursorResponse response = result.getValue(); + ASSERT_EQ(response.cursorId, CursorId(123)); + ASSERT_EQ(response.nss.ns(), "db.coll"); + ASSERT_EQ(response.batch.size(), 2U); + ASSERT_EQ(response.batch[0], BSON("_id" << 1)); + ASSERT_EQ(response.batch[1], BSON("_id" << 2)); +} + +TEST(CursorResponseTest, parseFromBSONNextBatch) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1)); + ASSERT_OK(result.getStatus()); + + CursorResponse response = result.getValue(); + ASSERT_EQ(response.cursorId, CursorId(123)); + ASSERT_EQ(response.nss.ns(), "db.coll"); + ASSERT_EQ(response.batch.size(), 2U); + ASSERT_EQ(response.batch[0], BSON("_id" << 1)); + ASSERT_EQ(response.batch[1], BSON("_id" << 2)); +} + +TEST(CursorResponseTest, parseFromBSONCursorIdZero) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(0) << "ns" + << "db.coll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1)); + ASSERT_OK(result.getStatus()); + + CursorResponse response = result.getValue(); + ASSERT_EQ(response.cursorId, CursorId(0)); + ASSERT_EQ(response.nss.ns(), "db.coll"); + ASSERT_EQ(response.batch.size(), 2U); + ASSERT_EQ(response.batch[0], BSON("_id" << 1)); + ASSERT_EQ(response.batch[1], BSON("_id" << 2)); +} + +TEST(CursorResponseTest, parseFromBSONEmptyBatch) { + StatusWith result = CursorResponse::parseFromBSON( + BSON("cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "nextBatch" << BSONArrayBuilder().arr()) << "ok" << 1)); + ASSERT_OK(result.getStatus()); + + CursorResponse response = result.getValue(); + ASSERT_EQ(response.cursorId, CursorId(123)); + ASSERT_EQ(response.nss.ns(), "db.coll"); + ASSERT_EQ(response.batch.size(), 0U); +} + +TEST(CursorResponseTest, parseFromBSONMissingCursorField) { + StatusWith result = CursorResponse::parseFromBSON(BSON("ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONCursorFieldWrongType) { + StatusWith result = + CursorResponse::parseFromBSON(BSON("cursor" << 3 << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONNsFieldMissing) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(123) << "firstBatch" + << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONNsFieldWrongType) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" << 456 << "firstBatch" + << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONIdFieldMissing) { + StatusWith result = CursorResponse::parseFromBSON( + BSON("cursor" << BSON("ns" + << "db.coll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONIdFieldWrongType) { + StatusWith result = CursorResponse::parseFromBSON( + BSON("cursor" << BSON("id" + << "123" + << "ns" + << "db.coll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONBatchFieldMissing) { + StatusWith result = + CursorResponse::parseFromBSON(BSON("cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll") << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONFirstBatchFieldWrongType) { + StatusWith result = CursorResponse::parseFromBSON( + BSON("cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "firstBatch" << BSON("_id" << 1)) << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONNextBatchFieldWrongType) { + StatusWith result = CursorResponse::parseFromBSON( + BSON("cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "nextBatch" << BSON("_id" << 1)) << "ok" << 1)); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONOkFieldMissing) { + StatusWith result = CursorResponse::parseFromBSON(BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" + << "db.coll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))))); + ASSERT_NOT_OK(result.getStatus()); +} + +TEST(CursorResponseTest, parseFromBSONHandleErrorResponse) { + StatusWith result = + CursorResponse::parseFromBSON(BSON("ok" << 0 << "code" << 123 << "errmsg" + << "does not work")); + ASSERT_NOT_OK(result.getStatus()); + ASSERT_EQ(result.getStatus().code(), 123); + ASSERT_EQ(result.getStatus().reason(), "does not work"); +} + +TEST(CursorResponseTest, toBSON) { + std::vector batch = {BSON("_id" << 1), BSON("_id" << 2)}; + CursorResponse response(NamespaceString("testdb.testcoll"), CursorId(123), batch); + BSONObj responseObj = response.toBSON(); + BSONObj expectedResponse = BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" + << "testdb.testcoll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1.0); + ASSERT_EQ(responseObj, expectedResponse); +} + +TEST(CursorResponseTest, addToBSON) { + std::vector batch = {BSON("_id" << 1), BSON("_id" << 2)}; + CursorResponse response(NamespaceString("testdb.testcoll"), CursorId(123), batch); + + BSONObjBuilder builder; + response.addToBSON(&builder); + BSONObj responseObj = builder.obj(); + + BSONObj expectedResponse = BSON( + "cursor" << BSON("id" << CursorId(123) << "ns" + << "testdb.testcoll" + << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) + << "ok" << 1.0); + ASSERT_EQ(responseObj, expectedResponse); +} + +} // namespace + +} // namespace mongo diff --git a/src/mongo/db/query/cursor_responses.cpp b/src/mongo/db/query/cursor_responses.cpp deleted file mode 100644 index 9165c498e37..00000000000 --- a/src/mongo/db/query/cursor_responses.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/query/cursor_responses.h" - -#include "mongo/db/jsobj.h" - -namespace mongo { - -void appendCursorResponseObject(long long cursorId, - StringData cursorNamespace, - BSONArray firstBatch, - BSONObjBuilder* builder) { - BSONObjBuilder cursorObj(builder->subobjStart("cursor")); - cursorObj.append("id", cursorId); - cursorObj.append("ns", cursorNamespace); - cursorObj.append("firstBatch", firstBatch); - cursorObj.done(); -} - -void appendGetMoreResponseObject(long long cursorId, - StringData cursorNamespace, - BSONArray nextBatch, - BSONObjBuilder* builder) { - BSONObjBuilder cursorObj(builder->subobjStart("cursor")); - cursorObj.append("id", cursorId); - cursorObj.append("ns", cursorNamespace); - cursorObj.append("nextBatch", nextBatch); - cursorObj.done(); -} - -} // namespace mongo diff --git a/src/mongo/db/query/cursor_responses.h b/src/mongo/db/query/cursor_responses.h deleted file mode 100644 index 06f2f268e63..00000000000 --- a/src/mongo/db/query/cursor_responses.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -namespace mongo { - -class BSONObjBuilder; -class StringData; -struct BSONArray; - -/** - * Builds a cursor response object from the provided cursor identifiers and "firstBatch", - * and appends the response object to the provided builder under the field name "cursor". - * If the node is a member of a replSet, also appends the current term, primary, and - * lastOp information. - * - * The response object has the following format: - * { id: , ns: , firstBatch: }. - */ -void appendCursorResponseObject(long long cursorId, - StringData cursorNamespace, - BSONArray firstBatch, - BSONObjBuilder* builder); - -/** - * Builds a getMore response object from the provided cursor identifiers and "nextBatch", - * and appends the response object to the provided builder under the field name "cursor". - * If the node is a member of a replSet, also appends the current term, primary, and - * lastOp information. - * - * The response object has the following format: - * { id: , ns: , nextBatch: }. - */ -void appendGetMoreResponseObject(long long cursorId, - StringData cursorNamespace, - BSONArray nextBatch, - BSONObjBuilder* builder); - -} // namespace mongo diff --git a/src/mongo/db/query/getmore_response.cpp b/src/mongo/db/query/getmore_response.cpp deleted file mode 100644 index ce64c7a717a..00000000000 --- a/src/mongo/db/query/getmore_response.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kQuery - -#include "mongo/platform/basic.h" - -#include "mongo/db/query/getmore_response.h" - -#include "mongo/bson/bsontypes.h" -#include "mongo/rpc/get_status_from_command_result.h" - -namespace mongo { - -namespace { - -const char kCursorField[] = "cursor"; -const char kIdField[] = "id"; -const char kNsField[] = "ns"; -const char kBatchField[] = "nextBatch"; -const char kBatchFieldAlt[] = "firstBatch"; - -} // namespace - -GetMoreResponse::GetMoreResponse(NamespaceString namespaceString, - CursorId id, - std::vector objs, - boost::optional nReturnedSoFar) - : nss(std::move(namespaceString)), - cursorId(id), - batch(std::move(objs)), - numReturnedSoFar(nReturnedSoFar) {} - -StatusWith GetMoreResponse::parseFromBSON(const BSONObj& cmdResponse) { - Status cmdStatus = getStatusFromCommandResult(cmdResponse); - if (!cmdStatus.isOK()) { - return cmdStatus; - } - - std::string fullns; - BSONObj batchObj; - CursorId cursorId; - - BSONElement cursorElt = cmdResponse[kCursorField]; - if (cursorElt.type() != BSONType::Object) { - return {ErrorCodes::TypeMismatch, - str::stream() << "Field '" << kCursorField - << "' must be a nested object in: " << cmdResponse}; - } - BSONObj cursorObj = cursorElt.Obj(); - - BSONElement idElt = cursorObj[kIdField]; - if (idElt.type() != BSONType::NumberLong) { - return {ErrorCodes::TypeMismatch, - str::stream() << "Field '" << kIdField - << "' must be of type long in: " << cmdResponse}; - } - cursorId = idElt.Long(); - - BSONElement nsElt = cursorObj[kNsField]; - if (nsElt.type() != BSONType::String) { - return {ErrorCodes::TypeMismatch, - str::stream() << "Field '" << kNsField - << "' must be of type string in: " << cmdResponse}; - } - fullns = nsElt.String(); - - BSONElement batchElt = cursorObj[kBatchField]; - if (batchElt.eoo()) { - batchElt = cursorObj[kBatchFieldAlt]; - } - - if (batchElt.type() != BSONType::Array) { - return {ErrorCodes::TypeMismatch, - str::stream() << "Must have array field '" << kBatchFieldAlt << "' or '" - << kBatchField << "' in: " << cmdResponse}; - } - batchObj = batchElt.Obj(); - - std::vector batch; - for (BSONElement elt : batchObj) { - if (elt.type() != BSONType::Object) { - return { - ErrorCodes::BadValue, - str::stream() << "getMore response batch contains a non-object element: " << elt}; - } - - batch.push_back(elt.Obj().getOwned()); - } - - return {{NamespaceString(fullns), cursorId, batch}}; -} - -void GetMoreResponse::toBSON(BSONObjBuilder* builder) const { - BSONObjBuilder cursorBuilder(builder->subobjStart(kCursorField)); - - cursorBuilder.append(kIdField, cursorId); - cursorBuilder.append(kNsField, nss.ns()); - - BSONArrayBuilder batchBuilder(cursorBuilder.subarrayStart(kBatchField)); - for (const BSONObj& obj : batch) { - batchBuilder.append(obj); - } - batchBuilder.doneFast(); - - cursorBuilder.doneFast(); - - builder->append("ok", 1.0); -} - -BSONObj GetMoreResponse::toBSON() const { - BSONObjBuilder builder; - toBSON(&builder); - return builder.obj(); -} - -} // namespace mongo diff --git a/src/mongo/db/query/getmore_response.h b/src/mongo/db/query/getmore_response.h deleted file mode 100644 index 9164c5ebbc9..00000000000 --- a/src/mongo/db/query/getmore_response.h +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (C) 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include - -#include "mongo/base/status_with.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/db/clientcursor.h" -#include "mongo/db/namespace_string.h" - -namespace mongo { - -struct GetMoreResponse { - /** - * Constructs from values for each of the fields. - */ - GetMoreResponse(NamespaceString namspaceString, - CursorId id, - std::vector objs, - boost::optional nReturnedSoFar = boost::none); - - /** - * Constructs a GetMoreResponse from the command BSON response. - */ - static StatusWith parseFromBSON(const BSONObj& cmdResponse); - - /** - * Converts this response to its raw BSON representation. - */ - BSONObj toBSON() const; - void toBSON(BSONObjBuilder* builder) const; - - const NamespaceString nss; - const CursorId cursorId; - const std::vector batch; - const boost::optional numReturnedSoFar; -}; - -} // namespace mongo diff --git a/src/mongo/db/query/getmore_response_test.cpp b/src/mongo/db/query/getmore_response_test.cpp deleted file mode 100644 index 3c9db3dba6b..00000000000 --- a/src/mongo/db/query/getmore_response_test.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Copyright 2015 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/query/getmore_response.h" - -#include "mongo/unittest/unittest.h" - -namespace mongo { - -namespace { - -TEST(GetMoreResponseTest, parseFromBSONFirstBatch) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "firstBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1)); - ASSERT_OK(result.getStatus()); - - GetMoreResponse response = result.getValue(); - ASSERT_EQ(response.cursorId, CursorId(123)); - ASSERT_EQ(response.nss.ns(), "db.coll"); - ASSERT_EQ(response.batch.size(), 2U); - ASSERT_EQ(response.batch[0], BSON("_id" << 1)); - ASSERT_EQ(response.batch[1], BSON("_id" << 2)); -} - -TEST(GetMoreResponseTest, parseFromBSONNextBatch) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1)); - ASSERT_OK(result.getStatus()); - - GetMoreResponse response = result.getValue(); - ASSERT_EQ(response.cursorId, CursorId(123)); - ASSERT_EQ(response.nss.ns(), "db.coll"); - ASSERT_EQ(response.batch.size(), 2U); - ASSERT_EQ(response.batch[0], BSON("_id" << 1)); - ASSERT_EQ(response.batch[1], BSON("_id" << 2)); -} - -TEST(GetMoreResponseTest, parseFromBSONCursorIdZero) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(0) << "ns" - << "db.coll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1)); - ASSERT_OK(result.getStatus()); - - GetMoreResponse response = result.getValue(); - ASSERT_EQ(response.cursorId, CursorId(0)); - ASSERT_EQ(response.nss.ns(), "db.coll"); - ASSERT_EQ(response.batch.size(), 2U); - ASSERT_EQ(response.batch[0], BSON("_id" << 1)); - ASSERT_EQ(response.batch[1], BSON("_id" << 2)); -} - -TEST(GetMoreResponseTest, parseFromBSONEmptyBatch) { - StatusWith result = GetMoreResponse::parseFromBSON( - BSON("cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "nextBatch" << BSONArrayBuilder().arr()) << "ok" << 1)); - ASSERT_OK(result.getStatus()); - - GetMoreResponse response = result.getValue(); - ASSERT_EQ(response.cursorId, CursorId(123)); - ASSERT_EQ(response.nss.ns(), "db.coll"); - ASSERT_EQ(response.batch.size(), 0U); -} - -TEST(GetMoreResponseTest, parseFromBSONMissingCursorField) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON("ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONCursorFieldWrongType) { - StatusWith result = - GetMoreResponse::parseFromBSON(BSON("cursor" << 3 << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONNsFieldMissing) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(123) << "firstBatch" - << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONNsFieldWrongType) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" << 456 << "firstBatch" - << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONIdFieldMissing) { - StatusWith result = GetMoreResponse::parseFromBSON( - BSON("cursor" << BSON("ns" - << "db.coll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONIdFieldWrongType) { - StatusWith result = GetMoreResponse::parseFromBSON( - BSON("cursor" << BSON("id" - << "123" - << "ns" - << "db.coll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONBatchFieldMissing) { - StatusWith result = - GetMoreResponse::parseFromBSON(BSON("cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll") << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONFirstBatchFieldWrongType) { - StatusWith result = GetMoreResponse::parseFromBSON( - BSON("cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "firstBatch" << BSON("_id" << 1)) << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONNextBatchFieldWrongType) { - StatusWith result = GetMoreResponse::parseFromBSON( - BSON("cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "nextBatch" << BSON("_id" << 1)) << "ok" << 1)); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONOkFieldMissing) { - StatusWith result = GetMoreResponse::parseFromBSON(BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" - << "db.coll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))))); - ASSERT_NOT_OK(result.getStatus()); -} - -TEST(GetMoreResponseTest, parseFromBSONHandleErrorResponse) { - StatusWith result = - GetMoreResponse::parseFromBSON(BSON("ok" << 0 << "code" << 123 << "errmsg" - << "does not work")); - ASSERT_NOT_OK(result.getStatus()); - ASSERT_EQ(result.getStatus().code(), 123); - ASSERT_EQ(result.getStatus().reason(), "does not work"); -} - -TEST(GetMoreResponseTest, toBSON) { - std::vector batch = {BSON("_id" << 1), BSON("_id" << 2)}; - GetMoreResponse response(NamespaceString("testdb.testcoll"), CursorId(123), batch); - BSONObj responseObj = response.toBSON(); - BSONObj expectedResponse = BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" - << "testdb.testcoll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1.0); - ASSERT_EQ(responseObj, expectedResponse); -} - -TEST(GetMoreResponseTest, toBSONWithBuilder) { - std::vector batch = {BSON("_id" << 1), BSON("_id" << 2)}; - GetMoreResponse response(NamespaceString("testdb.testcoll"), CursorId(123), batch); - - BSONObjBuilder builder; - response.toBSON(&builder); - BSONObj responseObj = builder.obj(); - - BSONObj expectedResponse = BSON( - "cursor" << BSON("id" << CursorId(123) << "ns" - << "testdb.testcoll" - << "nextBatch" << BSON_ARRAY(BSON("_id" << 1) << BSON("_id" << 2))) - << "ok" << 1.0); - ASSERT_EQ(responseObj, expectedResponse); -} - -} // namespace - -} // namespace mongo -- cgit v1.2.1