summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYoonsoo Kim <yoonsoo.kim@mongodb.com>2021-07-22 01:48:29 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-07-22 02:13:04 +0000
commit52b6b281105274c3a66312fc6ee8a2c12f4a9e40 (patch)
tree9a641823ca82ac833444183251370dad61f81c6b /src
parent97e7a659d01f8f5ceef69a4f738cdf76396d99db (diff)
downloadmongo-52b6b281105274c3a66312fc6ee8a2c12f4a9e40.tar.gz
SERVER-57390 Remove getLastError implementation
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/client.cpp1
-rw-r--r--src/mongo/db/commands/dbcommands.cpp1
-rw-r--r--src/mongo/db/commands/dbcommands_d.cpp1
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp1
-rw-r--r--src/mongo/db/commands/get_last_error.cpp218
-rw-r--r--src/mongo/db/dbdirectclient.cpp11
-rw-r--r--src/mongo/db/dbdirectclient.h2
-rw-r--r--src/mongo/db/lasterror.cpp36
-rw-r--r--src/mongo/db/lasterror.h12
-rw-r--r--src/mongo/db/repl/repl_set_commands.cpp1
-rw-r--r--src/mongo/db/s/dist_lock_catalog_replset.cpp2
-rw-r--r--src/mongo/dbtests/directclienttests.cpp24
-rw-r--r--src/mongo/dbtests/querytests.cpp7
-rw-r--r--src/mongo/dbtests/updatetests.cpp7
-rw-r--r--src/mongo/rpc/SConscript1
-rw-r--r--src/mongo/rpc/legacy_reply_builder.cpp1
-rw-r--r--src/mongo/rpc/metadata.cpp1
-rw-r--r--src/mongo/rpc/metadata/sharding_metadata.cpp46
-rw-r--r--src/mongo/rpc/metadata/sharding_metadata.h5
-rw-r--r--src/mongo/rpc/metadata/sharding_metadata_test.cpp111
-rw-r--r--src/mongo/rpc/op_legacy_integration_test.cpp40
-rw-r--r--src/mongo/s/SConscript16
-rw-r--r--src/mongo/s/cluster_last_error_info.cpp71
-rw-r--r--src/mongo/s/cluster_last_error_info.h100
-rw-r--r--src/mongo/s/cluster_last_error_info_test.cpp190
-rw-r--r--src/mongo/s/commands/SConscript2
-rw-r--r--src/mongo/s/commands/batch_downconvert.cpp165
-rw-r--r--src/mongo/s/commands/batch_downconvert.h70
-rw-r--r--src/mongo/s/commands/batch_downconvert_test.cpp217
-rw-r--r--src/mongo/s/commands/cluster_command_test_fixture.cpp10
-rw-r--r--src/mongo/s/commands/cluster_get_last_error_cmd.cpp283
-rw-r--r--src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_write_cmd.cpp4
-rw-r--r--src/mongo/s/mongos_main.cpp1
-rw-r--r--src/mongo/s/service_entry_point_mongos.cpp7
-rw-r--r--src/mongo/s/sharding_egress_metadata_hook_for_mongos.cpp2
-rw-r--r--src/mongo/s/sharding_task_executor.cpp38
37 files changed, 40 insertions, 1667 deletions
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 574224f8d3a..6bd225ac266 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -40,7 +40,6 @@
#include <vector>
#include "mongo/base/status.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/operation_cpu_timer.h"
#include "mongo/db/service_context.h"
diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp
index c0a063f4b9c..eb9461f8e16 100644
--- a/src/mongo/db/commands/dbcommands.cpp
+++ b/src/mongo/db/commands/dbcommands.cpp
@@ -70,7 +70,6 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/keypattern.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/ops/insert.h"
diff --git a/src/mongo/db/commands/dbcommands_d.cpp b/src/mongo/db/commands/dbcommands_d.cpp
index 8e9e40ab9b5..e7a6b76d2cf 100644
--- a/src/mongo/db/commands/dbcommands_d.cpp
+++ b/src/mongo/db/commands/dbcommands_d.cpp
@@ -69,7 +69,6 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/keypattern.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/ops/insert.h"
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 4d2377d9c0c..52fd39f3683 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -47,7 +47,6 @@
#include "mongo/db/exec/delete.h"
#include "mongo/db/exec/update_stage.h"
#include "mongo/db/exec/working_set_common.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/matcher/extensions_callback_real.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
diff --git a/src/mongo/db/commands/get_last_error.cpp b/src/mongo/db/commands/get_last_error.cpp
index 7cc13764c65..fab019a7379 100644
--- a/src/mongo/db/commands/get_last_error.cpp
+++ b/src/mongo/db/commands/get_last_error.cpp
@@ -33,23 +33,11 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
-#include "mongo/db/curop.h"
-#include "mongo/db/field_parser.h"
-#include "mongo/db/lasterror.h"
-#include "mongo/db/repl/bson_extract_optime.h"
-#include "mongo/db/repl/repl_client_info.h"
-#include "mongo/db/repl/replication_coordinator.h"
-#include "mongo/db/write_concern.h"
-#include "mongo/idl/command_generic_argument.h"
-#include "mongo/logv2/log.h"
#include "mongo/rpc/warn_deprecated_wire_ops.h"
namespace mongo {
namespace {
-using std::string;
-using std::stringstream;
-
class CmdGetLastError : public ErrmsgCommandDeprecated {
public:
CmdGetLastError() : ErrmsgCommandDeprecated("getLastError", "getlasterror") {}
@@ -68,207 +56,17 @@ public:
}
std::string help() const override {
- return "return error status of the last operation on this connection\n"
- "options:\n"
- " { fsync:true } - fsync before returning, or wait for journal commit if running "
- "with --journal\n"
- " { j:true } - wait for journal commit if running with --journal\n"
- " { w:n } - await replication to n servers (including self) before returning\n"
- " { w:'majority' } - await replication to majority of set\n"
- " { wtimeout:m} - timeout for w in m milliseconds";
+ return "no longer supported";
}
bool errmsgRun(OperationContext* opCtx,
- const string& dbname,
- const BSONObj& cmdObj,
- string& errmsg,
- BSONObjBuilder& result) {
- //
- // Correct behavior here is very finicky.
- //
- // 1. The first step is to append the error that occurred on the previous operation.
- // This adds an "err" field to the command, which is *not* the command failing.
- //
- // 2. Next we parse and validate write concern options. If these options are invalid
- // the command fails no matter what, even if we actually had an error earlier. The
- // reason for checking here is to match legacy behavior on these kind of failures -
- // we'll still get an "err" field for the write error.
- //
- // 3. If we had an error on the previous operation, we then return immediately.
- //
- // 4. Finally, we actually enforce the write concern. All errors *except* timeout are
- // reported with ok : 0.0, to match legacy behavior.
- //
- // There is a special case when "wOpTime" and "wElectionId" are explicitly provided by
- // the client (mongos) - in this case we *only* enforce the write concern if it is
- // valid.
- //
- // We always need to either report "err" (if ok : 1) or "errmsg" (if ok : 0), even if
- // err is null.
- //
-
- LastError* le = &LastError::get(opCtx->getClient());
- le->disable();
-
- // Always append lastOp and connectionId
- Client& c = *opCtx->getClient();
- auto replCoord = repl::ReplicationCoordinator::get(opCtx);
- if (replCoord->getReplicationMode() == repl::ReplicationCoordinator::modeReplSet) {
- const repl::OpTime lastOp = repl::ReplClientInfo::forClient(c).getLastOp();
- if (!lastOp.isNull()) {
- lastOp.append(&result, "lastOp");
- }
- }
-
- warnDeprecation(c, "getLastError");
-
- // for sharding; also useful in general for debugging
- result.appendNumber("connectionId", c.getConnectionId());
-
- repl::OpTime lastOpTime;
- bool lastOpTimePresent = true;
- const BSONElement opTimeElement = cmdObj["wOpTime"];
- if (opTimeElement.eoo()) {
- lastOpTimePresent = false;
- lastOpTime = repl::ReplClientInfo::forClient(c).getLastOp();
- } else if (opTimeElement.type() == bsonTimestamp) {
- lastOpTime = repl::OpTime(opTimeElement.timestamp(), repl::OpTime::kUninitializedTerm);
- } else if (opTimeElement.type() == Date) {
- lastOpTime =
- repl::OpTime(Timestamp(opTimeElement.date()), repl::OpTime::kUninitializedTerm);
- } else if (opTimeElement.type() == Object) {
- Status status = bsonExtractOpTimeField(cmdObj, "wOpTime", &lastOpTime);
- if (!status.isOK()) {
- result.append("badGLE", cmdObj);
- return CommandHelpers::appendCommandStatusNoThrow(result, status);
- }
- } else {
- uasserted(ErrorCodes::TypeMismatch,
- str::stream() << "Expected \"wOpTime\" field in getLastError to "
- "have type Date, Timestamp, or OpTime but found type "
- << typeName(opTimeElement.type()));
- }
-
-
- OID electionId;
- BSONField<OID> wElectionIdField("wElectionId");
- FieldParser::FieldState extracted =
- FieldParser::extract(cmdObj, wElectionIdField, &electionId, &errmsg);
- if (!extracted) {
- result.append("badGLE", cmdObj);
- CommandHelpers::appendSimpleCommandStatus(result, false, errmsg);
- return false;
- }
-
- bool electionIdPresent = extracted != FieldParser::FIELD_NONE;
- bool errorOccurred = false;
-
- // Errors aren't reported when wOpTime is used
- if (!lastOpTimePresent) {
- if (le->getNPrev() != 1) {
- errorOccurred = LastError::noError.appendSelf(result, false);
- } else {
- errorOccurred = le->appendSelf(result, false);
- }
- }
-
- BSONObj writeConcernDoc = ([&] {
- BSONObjBuilder bob;
- for (auto&& elem : cmdObj) {
- if (!isGenericArgument(elem.fieldNameStringData()))
- bob.append(elem);
- }
- return bob.obj();
- }());
-
- WriteConcernOptions writeConcern;
- auto sw = WriteConcernOptions::parse(writeConcernDoc);
- Status status = sw.getStatus();
-
- //
- // Validate write concern no matter what, this matches 2.4 behavior
- //
- if (status.isOK()) {
- writeConcern = sw.getValue();
- status = validateWriteConcern(opCtx, writeConcern);
- }
-
- if (!status.isOK()) {
- result.append("badGLE", writeConcernDoc);
- return CommandHelpers::appendCommandStatusNoThrow(result, status);
- }
-
- // Don't wait for replication if there was an error reported - this matches 2.4 behavior
- if (errorOccurred) {
- dassert(!lastOpTimePresent);
- return true;
- }
-
- // No error occurred, so we won't duplicate these fields with write concern errors
- dassert(result.asTempObj()["err"].eoo());
- dassert(result.asTempObj()["code"].eoo());
-
- // If we got an electionId, make sure it matches
- if (electionIdPresent) {
- if (repl::ReplicationCoordinator::get(opCtx)->getReplicationMode() !=
- repl::ReplicationCoordinator::modeReplSet) {
- // Ignore electionIds of 0 from mongos.
- if (electionId != OID()) {
- errmsg = "wElectionId passed but no replication active";
- result.append("code", ErrorCodes::BadValue);
- result.append("codeName", ErrorCodes::errorString(ErrorCodes::BadValue));
- return false;
- }
- } else {
- if (electionId != repl::ReplicationCoordinator::get(opCtx)->getElectionId()) {
- LOGV2_DEBUG(20476,
- 3,
- "OID passed in is {passedOID}, but our id is {ourOID}",
- "OID mismatch during election",
- "passedOID"_attr = electionId,
- "ourOID"_attr =
- repl::ReplicationCoordinator::get(opCtx)->getElectionId());
- errmsg = "election occurred after write";
- result.append("code", ErrorCodes::WriteConcernFailed);
- result.append("codeName",
- ErrorCodes::errorString(ErrorCodes::WriteConcernFailed));
- return false;
- }
- }
- }
-
- {
- stdx::lock_guard<Client> lk(*opCtx->getClient());
- CurOp::get(opCtx)->setMessage_inlock("waiting for write concern");
- }
-
- WriteConcernResult wcResult;
- status = waitForWriteConcern(opCtx, lastOpTime, writeConcern, &wcResult);
- // getLastError command returns a document that contains the writtenTo array. So we compute
- // the writtenTo array here if we have waited for replication before. The call to
- // getHostsWrittenTo needs to lock the ReplicationCoordinator mutex to guard against
- // topology changes. Thus, we only compute this array here for the getLastError command
- // (instead of in waitForWriteConcern for every single write) to avoid a serialization point
- // for all writes.
- if (!lastOpTime.isNull() && writeConcern.needToWaitForOtherNodes()) {
- wcResult.writtenTo = replCoord->getHostsWrittenTo(
- lastOpTime,
- replCoord->populateUnsetWriteConcernOptionsSyncMode(writeConcern).syncMode ==
- WriteConcernOptions::SyncMode::JOURNAL);
- }
- wcResult.appendTo(&result);
-
- // For backward compatibility with 2.4, wtimeout returns ok : 1.0
- if (wcResult.wTimedOut) {
- dassert(!wcResult.err.empty()); // so we always report err
- dassert(!status.isOK());
- result.append("errmsg", "timed out waiting for secondaries");
- result.append("code", status.code());
- result.append("codeName", ErrorCodes::errorString(status.code()));
- return true;
- }
-
- return CommandHelpers::appendCommandStatusNoThrow(result, status);
+ const std::string&,
+ const BSONObj&,
+ std::string&,
+ BSONObjBuilder&) {
+ warnDeprecation(*opCtx->getClient(), "getLastError");
+ uasserted(5739000, "getLastError command is not supported");
+ return false;
}
} cmdGetLastError;
diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp
index 31d330ea11b..efbdc3db106 100644
--- a/src/mongo/db/dbdirectclient.cpp
+++ b/src/mongo/db/dbdirectclient.cpp
@@ -131,14 +131,9 @@ QueryOptions DBDirectClient::_lookupAvailableOptions() {
}
namespace {
-DbResponse loopbackBuildResponse(OperationContext* const opCtx,
- LastError* lastError,
- Message& toSend) {
+DbResponse loopbackBuildResponse(OperationContext* const opCtx, Message& toSend) {
DirectClientScope directClientScope(opCtx);
- boost::swap(*lastError, LastError::get(opCtx->getClient()));
- ON_BLOCK_EXIT([&] { boost::swap(*lastError, LastError::get(opCtx->getClient())); });
- LastError::get(opCtx->getClient()).startRequest();
CurOp curOp(opCtx);
toSend.header().setId(nextMessageId());
@@ -149,7 +144,7 @@ DbResponse loopbackBuildResponse(OperationContext* const opCtx,
} // namespace
bool DBDirectClient::call(Message& toSend, Message& response, bool assertOk, string* actualServer) {
- auto dbResponse = loopbackBuildResponse(_opCtx, &_lastError, toSend);
+ auto dbResponse = loopbackBuildResponse(_opCtx, toSend);
invariant(!dbResponse.response.empty());
response = std::move(dbResponse.response);
@@ -157,7 +152,7 @@ bool DBDirectClient::call(Message& toSend, Message& response, bool assertOk, str
}
void DBDirectClient::say(Message& toSend, bool isRetry, string* actualServer) {
- auto dbResponse = loopbackBuildResponse(_opCtx, &_lastError, toSend);
+ auto dbResponse = loopbackBuildResponse(_opCtx, toSend);
invariant(dbResponse.response.empty());
}
diff --git a/src/mongo/db/dbdirectclient.h b/src/mongo/db/dbdirectclient.h
index b9097e9c5fd..f3dd6c6393d 100644
--- a/src/mongo/db/dbdirectclient.h
+++ b/src/mongo/db/dbdirectclient.h
@@ -32,7 +32,6 @@
#include "mongo/client/dbclient_base.h"
#include "mongo/config.h"
#include "mongo/db/dbmessage.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/util/net/hostandport.h"
@@ -123,7 +122,6 @@ protected:
private:
OperationContext* _opCtx;
- LastError _lastError; // This LastError will be used for all operations on this client.
};
} // namespace mongo
diff --git a/src/mongo/db/lasterror.cpp b/src/mongo/db/lasterror.cpp
index c81c7565ac9..396e707efb4 100644
--- a/src/mongo/db/lasterror.cpp
+++ b/src/mongo/db/lasterror.cpp
@@ -38,8 +38,6 @@
namespace mongo {
-LastError LastError::noError;
-
const Client::Decoration<LastError> LastError::get = Client::declareDecoration<LastError>();
namespace {
@@ -87,40 +85,6 @@ void LastError::recordDelete(long long nDeleted) {
_nObjects = nDeleted;
}
-bool LastError::appendSelf(BSONObjBuilder& b, bool blankErr) const {
- if (!_valid) {
- if (blankErr)
- b.appendNull("err");
- b.append("n", 0);
- return false;
- }
-
- if (_msg.empty()) {
- if (blankErr) {
- b.appendNull("err");
- }
- } else {
- b.append("err", _msg);
- if (_msg.find("E11000 duplicate key error") != std::string::npos) {
- appendDupKeyFields(b, _msg);
- }
- }
-
- if (_code) {
- b.append("code", _code);
- b.append("codeName", ErrorCodes::errorString(ErrorCodes::Error(_code)));
- }
- if (_updatedExisting != NotUpdate)
- b.appendBool("updatedExisting", _updatedExisting == True);
- if (!_upsertedId.isEmpty()) {
- b.append(_upsertedId[kUpsertedFieldName]);
- }
- b.appendNumber("n", _nObjects);
-
- return !_msg.empty();
-}
-
-
void LastError::disable() {
invariant(!_disabled);
_disabled = true;
diff --git a/src/mongo/db/lasterror.h b/src/mongo/db/lasterror.h
index 1d4414f8865..6eff2f08ef0 100644
--- a/src/mongo/db/lasterror.h
+++ b/src/mongo/db/lasterror.h
@@ -69,16 +69,6 @@ public:
void recordDelete(long long nDeleted);
- /**
- * Writes the last-error state described by this object to "b".
- *
- * If "blankErr" is true, the "err" field will be explicitly set to null in the result
- * instead of being omitted when the error string is empty.
- *
- * Returns true if there is a non-empty error message.
- */
- bool appendSelf(BSONObjBuilder& b, bool blankErr) const;
-
bool isValid() const {
return _valid;
}
@@ -105,8 +95,6 @@ public:
const bool _prev;
};
- static LastError noError;
-
private:
enum UpdatedExistingType { NotUpdate, True, False };
diff --git a/src/mongo/db/repl/repl_set_commands.cpp b/src/mongo/db/repl/repl_set_commands.cpp
index 7e5b7dcecee..bab337d9109 100644
--- a/src/mongo/db/repl/repl_set_commands.cpp
+++ b/src/mongo/db/repl/repl_set_commands.cpp
@@ -49,7 +49,6 @@
#include "mongo/db/commands/server_status_metric.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbhelpers.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/repl/drop_pending_collection_reaper.h"
#include "mongo/db/repl/oplog.h"
diff --git a/src/mongo/db/s/dist_lock_catalog_replset.cpp b/src/mongo/db/s/dist_lock_catalog_replset.cpp
index 7e62b1a9369..5a0dd02d83d 100644
--- a/src/mongo/db/s/dist_lock_catalog_replset.cpp
+++ b/src/mongo/db/s/dist_lock_catalog_replset.cpp
@@ -35,7 +35,6 @@
#include "mongo/bson/util/bson_extract.h"
#include "mongo/client/read_preference.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/repl/hello_gen.h"
#include "mongo/db/repl/read_concern_args.h"
@@ -44,7 +43,6 @@
#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/rpc/metadata.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/grid.h"
#include "mongo/s/write_ops/batched_command_request.h"
diff --git a/src/mongo/dbtests/directclienttests.cpp b/src/mongo/dbtests/directclienttests.cpp
index 2df1ca8ec02..3c9b421ecfa 100644
--- a/src/mongo/dbtests/directclienttests.cpp
+++ b/src/mongo/dbtests/directclienttests.cpp
@@ -44,19 +44,9 @@ namespace DirectClientTests {
using std::unique_ptr;
using std::vector;
-class ClientBase {
-public:
- ClientBase() {
- mongo::LastError::get(cc()).reset();
- }
- virtual ~ClientBase() {
- mongo::LastError::get(cc()).reset();
- }
-};
-
const char* ns = "a.b";
-class InsertMany : ClientBase {
+class InsertMany {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -82,7 +72,7 @@ public:
}
};
-class BadNSCmd : ClientBase {
+class BadNSCmd {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -97,7 +87,7 @@ public:
}
};
-class BadNSQuery : ClientBase {
+class BadNSQuery {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -110,7 +100,7 @@ public:
}
};
-class BadNSGetMore : ClientBase {
+class BadNSGetMore {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -122,7 +112,7 @@ public:
}
};
-class BadNSInsert : ClientBase {
+class BadNSInsert {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -134,7 +124,7 @@ public:
}
};
-class BadNSUpdate : ClientBase {
+class BadNSUpdate {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
@@ -146,7 +136,7 @@ public:
}
};
-class BadNSRemove : ClientBase {
+class BadNSRemove {
public:
virtual void run() {
const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext();
diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp
index 89b52a3f172..b99b686f3bf 100644
--- a/src/mongo/dbtests/querytests.cpp
+++ b/src/mongo/dbtests/querytests.cpp
@@ -260,12 +260,7 @@ public:
class ClientBase {
public:
- ClientBase() : _client(&_opCtx) {
- mongo::LastError::get(_opCtx.getClient()).reset();
- }
- virtual ~ClientBase() {
- mongo::LastError::get(_opCtx.getClient()).reset();
- }
+ ClientBase() : _client(&_opCtx) {}
protected:
void insert(const char* ns, BSONObj o) {
diff --git a/src/mongo/dbtests/updatetests.cpp b/src/mongo/dbtests/updatetests.cpp
index 6ec4144369c..f29ccdb9699 100644
--- a/src/mongo/dbtests/updatetests.cpp
+++ b/src/mongo/dbtests/updatetests.cpp
@@ -58,12 +58,7 @@ namespace dps = ::mongo::dotted_path_support;
class ClientBase {
public:
- ClientBase() : _client(&_opCtx) {
- mongo::LastError::get(_opCtx.getClient()).reset();
- }
- virtual ~ClientBase() {
- mongo::LastError::get(_opCtx.getClient()).reset();
- }
+ ClientBase() : _client(&_opCtx) {}
protected:
const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext();
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript
index cdbbc15db10..2a8ded75b00 100644
--- a/src/mongo/rpc/SConscript
+++ b/src/mongo/rpc/SConscript
@@ -181,7 +181,6 @@ if wiredtiger:
'metadata/egress_metadata_hook_list_test.cpp',
'metadata/oplog_query_metadata_test.cpp',
'metadata/repl_set_metadata_test.cpp',
- 'metadata/sharding_metadata_test.cpp',
'metadata/tracking_metadata_test.cpp',
'metadata_test.cpp',
'object_check_test.cpp',
diff --git a/src/mongo/rpc/legacy_reply_builder.cpp b/src/mongo/rpc/legacy_reply_builder.cpp
index 2ceffbf0df7..39dc8265548 100644
--- a/src/mongo/rpc/legacy_reply_builder.cpp
+++ b/src/mongo/rpc/legacy_reply_builder.cpp
@@ -37,7 +37,6 @@
#include "mongo/db/dbmessage.h"
#include "mongo/db/jsobj.h"
#include "mongo/rpc/metadata.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
#include "mongo/s/stale_exception.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/str.h"
diff --git a/src/mongo/rpc/metadata.cpp b/src/mongo/rpc/metadata.cpp
index 42b85765f42..c965569d25c 100644
--- a/src/mongo/rpc/metadata.cpp
+++ b/src/mongo/rpc/metadata.cpp
@@ -40,7 +40,6 @@
#include "mongo/rpc/metadata/client_metadata.h"
#include "mongo/rpc/metadata/config_server_metadata.h"
#include "mongo/rpc/metadata/impersonated_user_metadata.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
#include "mongo/rpc/metadata/tracking_metadata.h"
#include "mongo/util/string_map.h"
#include "mongo/util/testing_proctor.h"
diff --git a/src/mongo/rpc/metadata/sharding_metadata.cpp b/src/mongo/rpc/metadata/sharding_metadata.cpp
index 9c62f4be82b..07e4f1b4699 100644
--- a/src/mongo/rpc/metadata/sharding_metadata.cpp
+++ b/src/mongo/rpc/metadata/sharding_metadata.cpp
@@ -50,52 +50,6 @@ const char kGLEStatsElectionIdFieldName[] = "electionId";
} // namespace
-StatusWith<ShardingMetadata> ShardingMetadata::readFromMetadata(const BSONObj& metadataObj) {
- BSONElement smElem;
- auto smExtractStatus =
- bsonExtractTypedField(metadataObj, kGLEStatsFieldName, mongo::Object, &smElem);
- if (!smExtractStatus.isOK()) {
- return smExtractStatus;
- }
-
- if (smElem.embeddedObject().nFields() != 2) {
- return Status(ErrorCodes::InvalidOptions,
- str::stream() << "The $gleStats object can only have 2 fields, but got "
- << smElem.embeddedObject().toString());
- }
-
- repl::OpTime opTime;
- const BSONElement opTimeElement = smElem.embeddedObject()[kGLEStatsLastOpTimeFieldName];
- if (opTimeElement.eoo()) {
- return Status(ErrorCodes::NoSuchKey, "lastOpTime field missing");
- } else if (opTimeElement.type() == bsonTimestamp) {
- opTime = repl::OpTime(opTimeElement.timestamp(), repl::OpTime::kUninitializedTerm);
- } else if (opTimeElement.type() == Date) {
- opTime = repl::OpTime(Timestamp(opTimeElement.date()), repl::OpTime::kUninitializedTerm);
- } else if (opTimeElement.type() == Object) {
- Status status =
- bsonExtractOpTimeField(smElem.embeddedObject(), kGLEStatsLastOpTimeFieldName, &opTime);
- if (!status.isOK()) {
- return status;
- }
- } else {
- return Status(ErrorCodes::TypeMismatch,
- str::stream() << "Expected \"" << kGLEStatsLastOpTimeFieldName
- << "\" field in response to replSetHeartbeat "
- "command to have type Date or Timestamp, but found type "
- << typeName(opTimeElement.type()));
- }
-
- BSONElement lastElectionIdElem;
- auto lastElectionIdExtractStatus = bsonExtractTypedField(
- smElem.embeddedObject(), kGLEStatsElectionIdFieldName, mongo::jstOID, &lastElectionIdElem);
- if (!lastElectionIdExtractStatus.isOK()) {
- return lastElectionIdExtractStatus;
- }
-
- return ShardingMetadata(opTime, lastElectionIdElem.OID());
-}
-
Status ShardingMetadata::writeToMetadata(BSONObjBuilder* metadataBob) const {
BSONObjBuilder subobj(metadataBob->subobjStart(kGLEStatsFieldName));
if (getLastOpTime().getTerm() > repl::OpTime::kUninitializedTerm) {
diff --git a/src/mongo/rpc/metadata/sharding_metadata.h b/src/mongo/rpc/metadata/sharding_metadata.h
index f614b1a72a2..21fa75c3db3 100644
--- a/src/mongo/rpc/metadata/sharding_metadata.h
+++ b/src/mongo/rpc/metadata/sharding_metadata.h
@@ -49,11 +49,6 @@ namespace rpc {
class ShardingMetadata {
public:
/**
- * Reads ShardingMetadata from a metadata object.
- */
- static StatusWith<ShardingMetadata> readFromMetadata(const BSONObj& metadataObj);
-
- /**
* Writes ShardingMetadata to a metadata builder.
*/
Status writeToMetadata(BSONObjBuilder* metadataBob) const;
diff --git a/src/mongo/rpc/metadata/sharding_metadata_test.cpp b/src/mongo/rpc/metadata/sharding_metadata_test.cpp
deleted file mode 100644
index dec0fb1c3d1..00000000000
--- a/src/mongo/rpc/metadata/sharding_metadata_test.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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/base/status.h"
-#include "mongo/db/jsobj.h"
-#include "mongo/db/repl/optime.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
-#include "mongo/stdx/chrono.h"
-#include "mongo/unittest/unittest.h"
-
-namespace {
-
-using namespace mongo;
-using namespace mongo::rpc;
-using mongo::unittest::assertGet;
-
-ShardingMetadata checkParse(const BSONObj& metadata) {
- return assertGet(ShardingMetadata::readFromMetadata(metadata));
-}
-
-const auto kElectionId = OID{"541b1a00e8a23afa832b218e"};
-const auto kLastOpTime = repl::OpTime(Timestamp(Seconds{1337}, 800u), 4);
-
-TEST(ShardingMetadata, ReadFromMetadata) {
- {
- auto sm = checkParse(
- BSON("$gleStats" << BSON("lastOpTime" << BSON("ts" << kLastOpTime.getTimestamp() << "t"
- << kLastOpTime.getTerm())
- << "electionId" << kElectionId)));
- ASSERT_EQ(sm.getLastElectionId(), kElectionId);
- ASSERT_EQ(sm.getLastOpTime(), kLastOpTime);
- }
- {
- // We don't care about order.
- auto sm = checkParse(
- BSON("$gleStats" << BSON("electionId" << kElectionId << "lastOpTime"
- << BSON("ts" << kLastOpTime.getTimestamp() << "t"
- << kLastOpTime.getTerm()))));
-
- ASSERT_EQ(sm.getLastElectionId(), kElectionId);
- ASSERT_EQ(sm.getLastOpTime(), kLastOpTime);
- }
-}
-
-void checkParseFails(const BSONObj& metadata, ErrorCodes::Error error) {
- auto sm = ShardingMetadata::readFromMetadata(metadata);
- ASSERT_NOT_OK(sm.getStatus());
- ASSERT_EQ(sm.getStatus(), error);
-}
-
-TEST(ShardingMetadata, ReadFromInvalidMetadata) {
- { checkParseFails(BSONObj(), ErrorCodes::NoSuchKey); }
- { checkParseFails(BSON("$gleStats" << 1), ErrorCodes::TypeMismatch); }
- { checkParseFails(BSON("$gleStats" << BSONObj()), ErrorCodes::InvalidOptions); }
- {
- checkParseFails(BSON("$gleStats" << BSON("lastOpTime" << 3 << "electionId" << kElectionId)),
- ErrorCodes::TypeMismatch);
- }
- {
- checkParseFails(
- BSON("$gleStats" << BSON("lastOpTime" << BSON("ts" << kLastOpTime.getTimestamp() << "t"
- << kLastOpTime.getTerm())
- << "electionId" << 3)),
- ErrorCodes::TypeMismatch);
- }
- {
- checkParseFails(
- BSON("$gleStats" << BSON("lastOpTime" << kElectionId << "electionId"
- << BSON("ts" << kLastOpTime.getTimestamp() << "t"
- << kLastOpTime.getTerm()))),
- ErrorCodes::TypeMismatch);
- }
- {
- checkParseFails(
- BSON("$gleStats" << BSON("lastOpTime" << BSON("ts" << kLastOpTime.getTimestamp() << "t"
- << kLastOpTime.getTerm())
- << "electionId" << kElectionId << "extra"
- << "this should not be here")),
- ErrorCodes::InvalidOptions);
- }
-}
-
-} // namespace
diff --git a/src/mongo/rpc/op_legacy_integration_test.cpp b/src/mongo/rpc/op_legacy_integration_test.cpp
index 4fda3fb8fbc..c2d8614364a 100644
--- a/src/mongo/rpc/op_legacy_integration_test.cpp
+++ b/src/mongo/rpc/op_legacy_integration_test.cpp
@@ -204,28 +204,16 @@ bool wasLogged(DBClientBase* conn, const std::string& opName, const std::string&
return false;
}
-std::string getLastError(DBClientBase* conn) {
- BSONObj info;
- BSONObjBuilder b;
- b.append("getlasterror", 1);
- conn->runCommand("admin", b.obj(), info);
-
- if (info["ok"].trueValue()) {
- BSONElement e = info["err"];
- if (e.eoo())
- return "";
- if (e.type() == Object)
- return e.toString();
- return e.str();
- } else {
- // command failure
- BSONElement e = info["errmsg"];
- if (e.eoo())
- return "";
- if (e.type() == Object)
- return "getLastError command failed: " + e.toString();
- return "getLastError command failed: " + e.str();
- }
+void getLastError(DBClientBase* conn) {
+ static const auto getLastErrorCommand = fromjson(R"({"getlasterror": 1})");
+ BSONObj replyObj;
+ conn->runCommand("admin", getLastErrorCommand, replyObj);
+
+ // getLastError command is no longer supported and must always fails.
+ auto status = getStatusFromCommandResult(replyObj);
+ ASSERT_NOT_OK(status) << replyObj;
+ const auto expectedCode = conn->isMongos() ? 5739001 : 5739000;
+ ASSERT_EQ(status.code(), expectedCode) << replyObj;
}
void exerciseDeprecatedOps(DBClientBase* conn, const std::string& expectedSeverity) {
@@ -256,12 +244,12 @@ void exerciseDeprecatedOps(DBClientBase* conn, const std::string& expectedSeveri
// The first deprecated call after adding a suppression is still logged with elevated severity
// and after it the suppression kicks in. Any deprecated op can be used to start the suppression
// period, here we chose getLastError.
- ASSERT_EQ("", getLastError(conn));
+ getLastError(conn);
ASSERT_THROWS(conn->call(opInsert, ignore), ExceptionForCat<ErrorCategory::NetworkError>);
ASSERT(wasLogged(conn, "insert", expectedSeverity));
- ASSERT_EQ("", getLastError(conn));
+ getLastError(conn);
ASSERT(wasLogged(conn, "getLastError", expectedSeverity));
ASSERT_THROWS(conn->call(opUpdate, ignore), ExceptionForCat<ErrorCategory::NetworkError>);
@@ -340,7 +328,7 @@ TEST(OpLegacy, GenericCommandViaOpQuery) {
// Because we cannot link the log entries to the issued commands, limit the search window for
// the query-related entry in the log by first running a different command (e.g. getLastError).
- ASSERT_EQ("", getLastError(conn.get())); // will start failing soon but will still log
+ getLastError(conn.get());
ASSERT(wasLogged(conn.get(), "getLastError", ""));
// The actual command doesn't matter, as long as it's not 'hello' or 'isMaster'.
@@ -377,7 +365,7 @@ void testAllowedCommand(const char* command) {
// Because we cannot link the log entries to the issued commands, limit the search window for
// the query-related entry in the log by first running a different command (e.g. getLastError).
- ASSERT_EQ("", getLastError(conn.get())); // will start failing soon but will still log
+ getLastError(conn.get());
ASSERT(wasLogged(conn.get(), "getLastError", ""));
auto opQuery = makeDeprecatedQueryMessage("testOpLegacy.$cmd",
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 5b7c317cdd3..d24d3f61e6f 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -250,7 +250,6 @@ env.Library(
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/executor/thread_pool_task_executor',
'$BUILD_DIR/mongo/s/client/sharding_client',
- 'cluster_last_error_info',
'sharding_router_api',
],
)
@@ -317,24 +316,12 @@ env.Library(
)
env.Library(
- target='cluster_last_error_info',
- source=[
- 'cluster_last_error_info.cpp'
- ],
- LIBDEPS=[
- '$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/client/connection_string',
- ]
-)
-
-env.Library(
target='sharding_egress_metadata_hook_for_mongos',
source=[
'sharding_egress_metadata_hook_for_mongos.cpp'
],
LIBDEPS=[
'$BUILD_DIR/mongo/rpc/metadata',
- 'cluster_last_error_info',
'coreshard',
]
)
@@ -518,7 +505,6 @@ env.Library(
'$BUILD_DIR/mongo/util/periodic_runner_factory',
'$BUILD_DIR/mongo/util/signal_handlers',
'client/sharding_client',
- 'cluster_last_error_info',
'commands/cluster_commands',
'committed_optime_metadata_hook',
'mongos_initializers',
@@ -601,7 +587,6 @@ env.CppUnitTest(
'chunk_writes_tracker_test.cpp',
'client/shard_remote_test.cpp',
'cluster_identity_loader_test.cpp',
- 'cluster_last_error_info_test.cpp',
'comparable_chunk_version_test.cpp',
'comparable_database_version_test.cpp',
'hedge_options_util_test.cpp',
@@ -642,7 +627,6 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/util/net/network',
'catalog/sharding_catalog_client_mock',
'chunk_writes_tracker',
- 'cluster_last_error_info',
'coreshard',
'mongos_topology_coordinator',
'sessions_collection_sharded',
diff --git a/src/mongo/s/cluster_last_error_info.cpp b/src/mongo/s/cluster_last_error_info.cpp
deleted file mode 100644
index 2fe697df461..00000000000
--- a/src/mongo/s/cluster_last_error_info.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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/s/cluster_last_error_info.h"
-
-#include "mongo/client/connection_string.h"
-#include "mongo/db/lasterror.h"
-
-namespace mongo {
-
-const Client::Decoration<std::shared_ptr<ClusterLastErrorInfo>> ClusterLastErrorInfo::get =
- Client::declareDecoration<std::shared_ptr<ClusterLastErrorInfo>>();
-
-void ClusterLastErrorInfo::addShardHost(const std::string& shardHost) {
- stdx::lock_guard<Latch> lock(_mutex);
- _cur->shardHostsWritten.insert(shardHost);
-}
-
-void ClusterLastErrorInfo::addHostOpTime(ConnectionString connStr, HostOpTime stat) {
- stdx::lock_guard<Latch> lock(_mutex);
- _cur->hostOpTimes[connStr] = stat;
-}
-
-void ClusterLastErrorInfo::addHostOpTimes(const HostOpTimeMap& hostOpTimes) {
- for (HostOpTimeMap::const_iterator it = hostOpTimes.begin(); it != hostOpTimes.end(); ++it) {
- addHostOpTime(it->first, it->second);
- }
-}
-
-void ClusterLastErrorInfo::newRequest() {
- stdx::lock_guard<Latch> lock(_mutex);
- std::swap(_cur, _prev);
- _cur->clear();
-}
-
-void ClusterLastErrorInfo::disableForCommand() {
- stdx::lock_guard<Latch> lock(_mutex);
- RequestInfo* temp = _cur;
- _cur = _prev;
- _prev = temp;
-}
-
-} // namespace mongo
diff --git a/src/mongo/s/cluster_last_error_info.h b/src/mongo/s/cluster_last_error_info.h
deleted file mode 100644
index af13045099d..00000000000
--- a/src/mongo/s/cluster_last_error_info.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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 <set>
-#include <string>
-
-#include "mongo/db/client.h"
-#include "mongo/s/write_ops/batch_write_exec.h"
-
-namespace mongo {
-
-/**
- * Client decoration that holds information needed to by mongos to process
- * getLastError commands.
- */
-class ClusterLastErrorInfo {
-public:
- static const Client::Decoration<std::shared_ptr<ClusterLastErrorInfo>> get;
-
- /** new request not associated (yet or ever) with a client */
- void newRequest();
-
- /**
- * notes that this client use this shard
- * keeps track of all shards accessed this request
- */
- void addShardHost(const std::string& shardHost);
-
- /**
- * Notes that this client wrote to these particular hosts with write commands.
- */
- void addHostOpTime(ConnectionString connstr, HostOpTime stat);
- void addHostOpTimes(const HostOpTimeMap& hostOpTimes);
-
- /**
- * gets shards used on the previous request
- */
- std::set<std::string>* getPrevShardHosts() const {
- stdx::lock_guard<Latch> lock(_mutex);
- return &_prev->shardHostsWritten;
- }
-
- /**
- * Gets the shards, hosts, and opTimes the client last wrote to with write commands.
- */
- const HostOpTimeMap& getPrevHostOpTimes() const {
- stdx::lock_guard<Latch> lock(_mutex);
- return _prev->hostOpTimes;
- }
-
- void disableForCommand();
-
-private:
- struct RequestInfo {
- void clear() {
- shardHostsWritten.clear();
- hostOpTimes.clear();
- }
-
- std::set<std::string> shardHostsWritten;
- HostOpTimeMap hostOpTimes;
- };
-
- // Protects _infos, _cur, and _prev.
- mutable Mutex _mutex = MONGO_MAKE_LATCH("ClusterLastErrorInfo::_mutex");
-
- // We use 2 so we can flip for getLastError type operations.
- RequestInfo _infos[2];
- RequestInfo* _cur = &_infos[0];
- RequestInfo* _prev = &_infos[1];
-};
-
-} // namespace mongo
diff --git a/src/mongo/s/cluster_last_error_info_test.cpp b/src/mongo/s/cluster_last_error_info_test.cpp
deleted file mode 100644
index 0e210078413..00000000000
--- a/src/mongo/s/cluster_last_error_info_test.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
-
-#include "mongo/platform/basic.h"
-
-#include <vector>
-
-#include "mongo/db/operation_context.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
-#include "mongo/s/cluster_last_error_info.h"
-#include "mongo/s/sharding_router_test_fixture.h"
-#include "mongo/stdx/future.h"
-#include "mongo/util/str.h"
-
-namespace mongo {
-namespace {
-
-using executor::NetworkInterfaceMock;
-using executor::RemoteCommandRequest;
-using executor::RemoteCommandResponse;
-using executor::TaskExecutor;
-
-using ClusterGetLastErrorTest = ShardingTestFixture;
-
-TEST_F(ClusterGetLastErrorTest,
- ClusterLastErrorInfoUpdatedIfInitializedAndReplyHasShardingMetadata) {
- auto client = operationContext()->getClient();
-
- // Ensure the clusterGLE on the Client has not yet been initialized.
- ASSERT(!ClusterLastErrorInfo::get(client));
-
- // Initialize the cluster last error info for the client with a new request.
- ClusterLastErrorInfo::get(client) = std::make_shared<ClusterLastErrorInfo>();
- ASSERT(ClusterLastErrorInfo::get(client));
- auto clusterGLE = ClusterLastErrorInfo::get(client);
- clusterGLE->newRequest();
-
- // Ensure the last error info is initially empty.
- ASSERT_EQUALS(0ul, clusterGLE->getPrevHostOpTimes().size());
-
- // Send a request over the ShardingTaskExecutor.
- HostAndPort host("fakeHost", 12345);
- auto future = launchAsync([&] {
- const RemoteCommandRequest request(host,
- "mydb",
- BSON("unusued"
- << "obj"),
- operationContext());
- executor()
- ->scheduleRemoteCommand(
- request, [=](const executor::TaskExecutor::RemoteCommandCallbackArgs) -> void {})
- .status_with_transitional_ignore();
- });
-
- // Make the reply contain ShardingMetadata.
- repl::OpTime opTime{Timestamp{10, 10}, 10};
- onCommandWithMetadata([&](const RemoteCommandRequest& request) {
- auto bob = BSONObjBuilder(BSON("ok" << 1));
- uassertStatusOK(
- rpc::ShardingMetadata(opTime, OID() /* ignored OID field */).writeToMetadata(&bob));
- return RemoteCommandResponse(bob.obj(), Milliseconds(1));
- });
-
- future.default_timed_get();
-
- // Ensure the last error info was updated with the contacted host and returned opTime.
-
- // Call newRequest() to emulate that the client then sent a getLastError() command. This is
- // required so ClusterLastErrorInfo moves its '_cur' list of hostOpTimes into its '_prev' list.
- clusterGLE->newRequest();
-
- ASSERT_EQUALS(1ul, clusterGLE->getPrevHostOpTimes().size());
-
- auto storedHostOpTimeIt = clusterGLE->getPrevHostOpTimes().begin();
- ASSERT_EQUALS(host.toString(), storedHostOpTimeIt->first.toString());
- ASSERT_EQUALS(opTime, storedHostOpTimeIt->second.opTime);
-}
-
-TEST_F(ClusterGetLastErrorTest, ClusterLastErrorInfoNotUpdatedIfNotInitialized) {
- auto client = operationContext()->getClient();
-
- // Ensure the clusterGLE on the Client has not been initialized.
- ASSERT(!ClusterLastErrorInfo::get(client));
-
- // Send a request over the ShardingTaskExecutor.
- HostAndPort host("fakeHost", 12345);
- auto future = launchAsync([&] {
- const RemoteCommandRequest request(host,
- "mydb",
- BSON("unusued"
- << "obj"),
- operationContext());
- executor()
- ->scheduleRemoteCommand(
- request, [=](const executor::TaskExecutor::RemoteCommandCallbackArgs) -> void {})
- .status_with_transitional_ignore();
- });
-
- // Make the reply contain ShardingMetadata.
- repl::OpTime opTime{Timestamp{10, 10}, 10};
- onCommandWithMetadata([&](const RemoteCommandRequest& request) {
- auto bob = BSONObjBuilder(BSON("ok" << 1));
- uassertStatusOK(
- rpc::ShardingMetadata(opTime, OID() /* ignored OID field */).writeToMetadata(&bob));
- return RemoteCommandResponse(bob.obj(), Milliseconds(1));
- });
-
- future.default_timed_get();
-
- // Ensure the clusterGLE on the Client has still not been initialized.
- ASSERT(!ClusterLastErrorInfo::get(client));
-}
-
-TEST_F(ClusterGetLastErrorTest, ClusterLastErrorInfoNotUpdatedIfReplyDoesntHaveShardingMetadata) {
- auto client = operationContext()->getClient();
-
- // Ensure the clusterGLE on the Client has not yet been initialized.
- ASSERT(!ClusterLastErrorInfo::get(client));
-
- // Initialize the cluster last error info for the client with a new request.
- ClusterLastErrorInfo::get(client) = std::make_shared<ClusterLastErrorInfo>();
- ASSERT(ClusterLastErrorInfo::get(client));
- auto clusterGLE = ClusterLastErrorInfo::get(client);
- clusterGLE->newRequest();
-
- // Ensure the last error info is initially empty.
- ASSERT_EQUALS(0ul, clusterGLE->getPrevHostOpTimes().size());
-
- // Send a request over the ShardingTaskExecutor.
- HostAndPort host("fakeHost", 12345);
- auto future = launchAsync([&] {
- const RemoteCommandRequest request(host,
- "mydb",
- BSON("unusued"
- << "obj"),
- operationContext());
- executor()
- ->scheduleRemoteCommand(
- request, [=](const executor::TaskExecutor::RemoteCommandCallbackArgs) -> void {})
- .status_with_transitional_ignore();
- });
-
- // Do not return ShardingMetadata in the reply.
- repl::OpTime opTime{Timestamp{10, 10}, 10};
- onCommandWithMetadata([&](const RemoteCommandRequest& request) {
- return RemoteCommandResponse(BSON("ok" << 1), Milliseconds(1));
- });
-
- future.default_timed_get();
-
- // Ensure the last error info was not updated.
-
- // Call newRequest() to emulate that the client then sent a getLastError() command. This is
- // required so ClusterLastErrorInfo moves its '_cur' list of hostOpTimes into its '_prev' list.
- clusterGLE->newRequest();
-
- // Ensure the last error info is still empty.
- ASSERT_EQUALS(0ul, clusterGLE->getPrevHostOpTimes().size());
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript
index f0ab2c494ab..cda5515584f 100644
--- a/src/mongo/s/commands/SConscript
+++ b/src/mongo/s/commands/SConscript
@@ -22,7 +22,6 @@ env.Library(
env.Library(
target='cluster_commands',
source=[
- 'batch_downconvert.cpp',
'cluster_abort_transaction_cmd.cpp',
'cluster_add_shard_cmd.cpp',
'cluster_add_shard_to_zone_cmd.cpp',
@@ -152,7 +151,6 @@ env.Library(
'$BUILD_DIR/mongo/idl/server_parameter',
'$BUILD_DIR/mongo/rpc/client_metadata',
'$BUILD_DIR/mongo/rpc/rewrite_state_change_errors',
- '$BUILD_DIR/mongo/s/cluster_last_error_info',
'$BUILD_DIR/mongo/s/mongos_topology_coordinator',
'$BUILD_DIR/mongo/s/query/cluster_aggregate',
'$BUILD_DIR/mongo/s/query/cluster_client_cursor',
diff --git a/src/mongo/s/commands/batch_downconvert.cpp b/src/mongo/s/commands/batch_downconvert.cpp
deleted file mode 100644
index 4f4328fe4c6..00000000000
--- a/src/mongo/s/commands/batch_downconvert.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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/s/commands/batch_downconvert.h"
-
-#include "mongo/bson/bsonmisc.h"
-#include "mongo/db/storage/duplicate_key_error_info.h"
-
-namespace mongo {
-
-Status extractGLEErrors(const BSONObj& gleResponse, GLEErrors* errors) {
- // DRAGONS
- // Parsing GLE responses is incredibly finicky.
- // The order of testing here is extremely important.
-
- ///////////////////////////////////////////////////////////////////////
- // IMPORTANT!
- // Also update extractGLEErrors in batch_api.js for any changes made here.
-
- const bool isOK = gleResponse["ok"].trueValue();
- const std::string err = gleResponse["err"].str();
- const std::string errMsg = gleResponse["errmsg"].str();
- const std::string wNote = gleResponse["wnote"].str();
- const std::string jNote = gleResponse["jnote"].str();
- const int code = gleResponse["code"].numberInt();
- const bool timeout = gleResponse["wtimeout"].trueValue();
-
- if (err == "norepl" || err == "noreplset") {
- // Know this is legacy gle and the repl not enforced - write concern error in 2.4
- errors->wcError.reset(new WriteConcernErrorDetail);
- std::string msg;
- if (!errMsg.empty()) {
- msg = errMsg;
- } else if (!wNote.empty()) {
- msg = wNote;
- } else {
- msg = err;
- }
- errors->wcError->setStatus({ErrorCodes::WriteConcernFailed, msg});
- } else if (timeout) {
- // Know there was no write error
- errors->wcError.reset(new WriteConcernErrorDetail);
- std::string msg;
- if (!errMsg.empty()) {
- msg = errMsg;
- } else {
- msg = err;
- }
- errors->wcError->setStatus({ErrorCodes::WriteConcernFailed, msg});
- errors->wcError->setErrInfo(BSON("wtimeout" << true));
- } else if (code == 10990 /* no longer primary */
- || code == 16805 /* replicatedToNum no longer primary */
- || code == 14830 /* gle wmode changed / invalid */
- // 2.6 Error codes
- || code == ErrorCodes::NotWritablePrimary ||
- code == ErrorCodes::UnknownReplWriteConcern ||
- code == ErrorCodes::WriteConcernFailed || code == ErrorCodes::PrimarySteppedDown) {
- // Write concern errors that get returned as regular errors (result may not be ok: 1.0)
- errors->wcError.reset(new WriteConcernErrorDetail());
- errors->wcError->setStatus({ErrorCodes::Error(code), errMsg});
- } else if (!isOK) {
- //
- // !!! SOME GLE ERROR OCCURRED, UNKNOWN WRITE RESULT !!!
- //
-
- return Status(ErrorCodes::Error(code ? code : ErrorCodes::UnknownError), errMsg);
- } else if (!err.empty()) {
- // Write error
- errors->writeError.reset(new WriteErrorDetail);
- int writeErrorCode = code == 0 ? ErrorCodes::UnknownError : code;
- errors->writeError->setStatus({ErrorCodes::Error(writeErrorCode), err});
- } else if (!jNote.empty()) {
- // Know this is legacy gle and the journaling not enforced - write concern error in 2.4
- errors->wcError.reset(new WriteConcernErrorDetail);
- errors->wcError->setStatus({ErrorCodes::WriteConcernFailed, jNote});
- }
-
- return Status::OK();
-}
-
-/**
- * Suppress the "err" and "code" field if they are coming from a previous write error and
- * are not related to write concern. Also removes any write stats information (e.g. "n")
- *
- * Also, In some cases, 2.4 GLE w/ wOpTime can give us duplicate "err" and "code" fields b/c of
- * reporting a previous error. The later field is what we want - dedup and use later field.
- *
- * Returns the stripped GLE response.
- */
-BSONObj stripNonWCInfo(const BSONObj& gleResponse) {
- BSONObjIterator it(gleResponse);
- BSONObjBuilder builder;
-
- BSONElement codeField; // eoo
- BSONElement errField; // eoo
-
- while (it.more()) {
- BSONElement el = it.next();
- StringData fieldName(el.fieldName());
- if (fieldName.compare("err") == 0) {
- errField = el;
- } else if (fieldName.compare("code") == 0) {
- codeField = el;
- } else if (fieldName.compare("n") == 0 || fieldName.compare("nModified") == 0 ||
- fieldName.compare("upserted") == 0 ||
- fieldName.compare("updatedExisting") == 0) {
- // Suppress field
- } else {
- builder.append(el);
- }
- }
-
- if (!codeField.eoo()) {
- if (!gleResponse["ok"].trueValue()) {
- // The last code will be from the write concern
- builder.append(codeField);
- } else {
- // The code is from a non-wc error on this connection - suppress it
- }
- }
-
- if (!errField.eoo()) {
- std::string err = errField.str();
- if (err == "norepl" || err == "noreplset" || err == "timeout") {
- // Append err if it's from a write concern issue
- builder.append(errField);
- } else {
- // Suppress non-write concern err as null, but we need to report null err if ok
- if (gleResponse["ok"].trueValue())
- builder.appendNull(errField.fieldName());
- }
- }
-
- return builder.obj();
-}
-
-} // namespace mongo
diff --git a/src/mongo/s/commands/batch_downconvert.h b/src/mongo/s/commands/batch_downconvert.h
deleted file mode 100644
index 5f553475ea6..00000000000
--- a/src/mongo/s/commands/batch_downconvert.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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 "mongo/base/status.h"
-#include "mongo/base/string_data.h"
-#include "mongo/bson/bsonobj.h"
-#include "mongo/rpc/write_concern_error_detail.h"
-#include "mongo/s/write_ops/write_error_detail.h"
-
-namespace mongo {
-
-// Used for reporting legacy write concern responses
-struct LegacyWCResponse {
- std::string shardHost;
- BSONObj gleResponse;
- std::string errToReport;
-};
-
-//
-// Below exposed for testing only
-//
-
-// Helper that acts as an auto-ptr for write and wc errors
-struct GLEErrors {
- std::unique_ptr<WriteErrorDetail> writeError;
- std::unique_ptr<WriteConcernErrorDetail> wcError;
-};
-
-/**
- * Given a GLE response, extracts a write error and a write concern error for the previous
- * operation.
- *
- * Returns !OK if the GLE itself failed in an unknown way.
- */
-Status extractGLEErrors(const BSONObj& gleResponse, GLEErrors* errors);
-
-/**
- * Given a GLE response, strips out all non-write-concern related information
- */
-BSONObj stripNonWCInfo(const BSONObj& gleResponse);
-
-} // namespace mongo
diff --git a/src/mongo/s/commands/batch_downconvert_test.cpp b/src/mongo/s/commands/batch_downconvert_test.cpp
deleted file mode 100644
index 8f32e9ee5e0..00000000000
--- a/src/mongo/s/commands/batch_downconvert_test.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * Copyright (C) 2018-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * 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
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * 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 Server Side 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 <deque>
-#include <vector>
-
-#include "mongo/db/json.h"
-#include "mongo/s/commands/batch_downconvert.h"
-#include "mongo/unittest/unittest.h"
-
-namespace mongo {
-namespace {
-
-//
-// Tests for parsing GLE responses into write errors and write concern errors for write
-// commands. These tests essentially document our expected 2.4 GLE behaviors.
-//
-
-TEST(GLEParsing, Empty) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: null}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(!errors.wcError.get());
-}
-
-TEST(GLEParsing, WriteErr) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: 'message', code: 1000}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(errors.writeError.get());
- ASSERT_EQUALS(errors.writeError->toStatus().reason(), "message");
- ASSERT_EQUALS(errors.writeError->toStatus().code(), 1000);
- ASSERT(!errors.wcError.get());
-}
-
-TEST(GLEParsing, JournalFail) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: null, jnote: 'message'}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(errors.wcError.get());
- ASSERT_EQUALS(errors.wcError->toStatus().reason(), "message");
- ASSERT_EQUALS(errors.wcError->toStatus().code(), ErrorCodes::WriteConcernFailed);
-}
-
-TEST(GLEParsing, ReplErr) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: 'norepl', wnote: 'message'}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(errors.wcError.get());
- ASSERT_EQUALS(errors.wcError->toStatus().reason(), "message");
- ASSERT_EQUALS(errors.wcError->toStatus().code(), ErrorCodes::WriteConcernFailed);
-}
-
-TEST(GLEParsing, ReplTimeoutErr) {
- const BSONObj gleResponse =
- fromjson("{ok: 1.0, err: 'timeout', errmsg: 'message', wtimeout: true}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(errors.wcError.get());
- ASSERT_EQUALS(errors.wcError->toStatus().reason(),
- "message; Error details: { wtimeout: true }");
- ASSERT(errors.wcError->getErrInfo()["wtimeout"].trueValue());
- ASSERT_EQUALS(errors.wcError->toStatus().code(), ErrorCodes::WriteConcernFailed);
-}
-
-TEST(GLEParsing, GLEFail) {
- const BSONObj gleResponse = fromjson("{ok: 0.0, err: null, errmsg: 'message', code: 1000}");
-
- GLEErrors errors;
- Status status = extractGLEErrors(gleResponse, &errors);
- ASSERT_NOT_OK(status);
- ASSERT_EQUALS(status.reason(), "message");
- ASSERT_EQUALS(status.code(), 1000);
-}
-
-TEST(GLEParsing, GLEFailNoCode) {
- const BSONObj gleResponse = fromjson("{ok: 0.0, err: null, errmsg: 'message'}");
-
- GLEErrors errors;
- Status status = extractGLEErrors(gleResponse, &errors);
- ASSERT_NOT_OK(status);
- ASSERT_EQUALS(status.reason(), "message");
- ASSERT_EQUALS(status.code(), ErrorCodes::UnknownError);
-}
-
-TEST(GLEParsing, NotMasterGLEFail) {
- // Not master code in response
- const BSONObj gleResponse = fromjson("{ok: 0.0, err: null, errmsg: 'message', code: 10990}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(errors.wcError.get());
- ASSERT_EQUALS(errors.wcError->toStatus().reason(), "message");
- ASSERT_EQUALS(errors.wcError->toStatus().code(), 10990);
-}
-
-TEST(GLEParsing, WriteErrWithStats) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, n: 2, err: 'message', code: 1000}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(errors.writeError.get());
- ASSERT_EQUALS(errors.writeError->toStatus().reason(), "message");
- ASSERT_EQUALS(errors.writeError->toStatus().code(), 1000);
- ASSERT(!errors.wcError.get());
-}
-
-TEST(GLEParsing, ReplTimeoutErrWithStats) {
- const BSONObj gleResponse = fromjson(
- "{ok: 1.0, err: 'timeout', errmsg: 'message', wtimeout: true,"
- " n: 1, upserted: 'abcde'}");
-
- GLEErrors errors;
- ASSERT_OK(extractGLEErrors(gleResponse, &errors));
- ASSERT(!errors.writeError.get());
- ASSERT(errors.wcError.get());
- ASSERT_EQUALS(errors.wcError->toStatus().reason(),
- "message; Error details: { wtimeout: true }");
- ASSERT(errors.wcError->getErrInfo()["wtimeout"].trueValue());
- ASSERT_EQUALS(errors.wcError->toStatus().code(), ErrorCodes::WriteConcernFailed);
-}
-
-//
-// Tests of processing and suppressing non-WC related fields from legacy GLE responses
-//
-
-TEST(LegacyGLESuppress, Basic) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: null}");
-
- BSONObj stripped = stripNonWCInfo(gleResponse);
- ASSERT_EQUALS(stripped.nFields(), 2); // with err, ok : true
- ASSERT(stripped["ok"].trueValue());
-}
-
-TEST(LegacyGLESuppress, BasicStats) {
- const BSONObj gleResponse = fromjson(
- "{ok: 0.0, err: 'message',"
- " n: 1, nModified: 1, upserted: 'abc', updatedExisting: true}");
-
- BSONObj stripped = stripNonWCInfo(gleResponse);
- ASSERT_EQUALS(stripped.nFields(), 1);
- ASSERT(!stripped["ok"].trueValue());
-}
-
-TEST(LegacyGLESuppress, ReplError) {
- const BSONObj gleResponse = fromjson("{ok: 0.0, err: 'norepl', n: 1, wcField: true}");
-
- BSONObj stripped = stripNonWCInfo(gleResponse);
- ASSERT_EQUALS(stripped.nFields(), 3);
- ASSERT(!stripped["ok"].trueValue());
- ASSERT_EQUALS(stripped["err"].str(), "norepl");
- ASSERT(stripped["wcField"].trueValue());
-}
-
-TEST(LegacyGLESuppress, StripCode) {
- const BSONObj gleResponse = fromjson("{ok: 1.0, err: 'message', code: 12345}");
-
- BSONObj stripped = stripNonWCInfo(gleResponse);
- ASSERT_EQUALS(stripped.nFields(), 2); // with err, ok : true
- ASSERT(stripped["ok"].trueValue());
-}
-
-TEST(LegacyGLESuppress, TimeoutDupError24) {
- const BSONObj gleResponse = BSON("ok" << 0.0 << "err"
- << "message"
- << "code" << 12345 << "err"
- << "timeout"
- << "code" << 56789 << "wtimeout" << true);
-
- BSONObj stripped = stripNonWCInfo(gleResponse);
- ASSERT_EQUALS(stripped.nFields(), 4);
- ASSERT(!stripped["ok"].trueValue());
- ASSERT_EQUALS(stripped["err"].str(), "timeout");
- ASSERT_EQUALS(stripped["code"].numberInt(), 56789);
- ASSERT(stripped["wtimeout"].trueValue());
-}
-
-} // namespace
-} // namespace mongo
diff --git a/src/mongo/s/commands/cluster_command_test_fixture.cpp b/src/mongo/s/commands/cluster_command_test_fixture.cpp
index c7573969bd7..6b1daa92292 100644
--- a/src/mongo/s/commands/cluster_command_test_fixture.cpp
+++ b/src/mongo/s/commands/cluster_command_test_fixture.cpp
@@ -41,7 +41,6 @@
#include "mongo/db/logical_time_validator.h"
#include "mongo/db/read_write_concern_defaults.h"
#include "mongo/db/vector_clock.h"
-#include "mongo/s/cluster_last_error_info.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/options_parser/startup_option_init.h"
#include "mongo/util/tick_source_mock.h"
@@ -127,15 +126,6 @@ DbResponse ClusterCommandTestFixture::runCommand(BSONObj cmd) {
const auto opMsgRequest = OpMsgRequest::fromDBAndBody(kNss.db(), cmd);
- // Ensure the clusterGLE on the Client has not yet been initialized.
- ASSERT(!ClusterLastErrorInfo::get(client.get()));
-
- // Initialize the cluster last error info for the client with a new request.
- ClusterLastErrorInfo::get(client.get()) = std::make_shared<ClusterLastErrorInfo>();
- ASSERT(ClusterLastErrorInfo::get(client.get()));
- auto clusterGLE = ClusterLastErrorInfo::get(client.get());
- clusterGLE->newRequest();
-
AlternativeClientRegion acr(client);
auto rec = std::make_shared<RequestExecutionContext>(opCtx.get(), opMsgRequest.serialize());
return Strategy::clientCommand(std::move(rec)).get();
diff --git a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
index 34482d50ccb..9a1d73c015b 100644
--- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
+++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
@@ -27,176 +27,14 @@
* it in the license file.
*/
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
-
#include "mongo/platform/basic.h"
-#include <vector>
-
-#include "mongo/client/remote_command_targeter.h"
-#include "mongo/db/client.h"
#include "mongo/db/commands.h"
-#include "mongo/db/lasterror.h"
-#include "mongo/executor/task_executor_pool.h"
-#include "mongo/logv2/log.h"
#include "mongo/rpc/warn_deprecated_wire_ops.h"
-#include "mongo/s/client/shard_registry.h"
-#include "mongo/s/cluster_commands_helpers.h"
-#include "mongo/s/cluster_last_error_info.h"
-#include "mongo/s/commands/batch_downconvert.h"
-#include "mongo/s/grid.h"
-#include "mongo/s/multi_statement_transaction_requests_sender.h"
namespace mongo {
namespace {
-using std::vector;
-
-// Adds a wOpTime and a wElectionId field to a set of gle options
-BSONObj buildGLECmdWithOpTime(const BSONObj& gleOptions,
- const repl::OpTime& opTime,
- const OID& electionId) {
- BSONObjBuilder builder;
- BSONObjIterator it(gleOptions);
-
- for (int i = 0; it.more(); ++i) {
- BSONElement el = it.next();
-
- // Make sure first element is getLastError : 1
- if (i == 0) {
- StringData elName(el.fieldName());
- if (!elName.equalCaseInsensitive("getLastError")) {
- builder.append("getLastError", 1);
- }
- }
-
- builder.append(el);
- }
- opTime.append(&builder, "wOpTime");
- builder.appendOID("wElectionId", const_cast<OID*>(&electionId));
- return builder.obj();
-}
-
-/**
- * Uses GLE and the shard hosts and opTimes last written by write commands to enforce a
- * write concern across the previously used shards.
- *
- * Returns OK with the LegacyWCResponses containing only write concern error information
- * Returns !OK if there was an error getting a GLE response
- */
-Status enforceLegacyWriteConcern(OperationContext* opCtx,
- StringData dbName,
- const BSONObj& options,
- const HostOpTimeMap& hostOpTimes,
- std::vector<LegacyWCResponse>* legacyWCResponses) {
- if (hostOpTimes.empty()) {
- return Status::OK();
- }
-
- // Assemble requests
- std::vector<AsyncRequestsSender::Request> requests;
- for (HostOpTimeMap::const_iterator it = hostOpTimes.begin(); it != hostOpTimes.end(); ++it) {
- const ConnectionString& shardConnStr = it->first;
- const auto& hot = it->second;
- const repl::OpTime& opTime = hot.opTime;
- const OID& electionId = hot.electionId;
-
- auto swShard = Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardConnStr.toString());
- if (!swShard.isOK()) {
- return swShard.getStatus();
- }
-
- LOGV2_DEBUG(22752,
- 3,
- "Enforcing write concern {options} on {shardId} at opTime "
- "{opTime} with electionID {electionId}",
- "Enforcing write concern on shard",
- "options"_attr = options,
- "shardId"_attr = swShard.getValue()->getId(),
- "opTime"_attr = opTime.getTimestamp().toStringPretty(),
- "electionId"_attr = electionId);
-
- BSONObj gleCmd = buildGLECmdWithOpTime(options, opTime, electionId);
- requests.emplace_back(swShard.getValue()->getId(), gleCmd);
- }
-
- // Send the requests.
-
- const ReadPreferenceSetting readPref(ReadPreference::PrimaryOnly, TagSet());
- MultiStatementTransactionRequestsSender ars(
- opCtx,
- Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(),
- dbName.toString(),
- requests,
- readPref,
- Shard::RetryPolicy::kIdempotent);
-
- // Receive the responses.
-
- vector<Status> failedStatuses;
- while (!ars.done()) {
- // Block until a response is available.
- auto response = ars.next();
-
- // Return immediately if we failed to contact a shard.
- if (!response.shardHostAndPort) {
- invariant(!response.swResponse.isOK());
- return response.swResponse.getStatus();
- }
-
- // We successfully contacted the shard, but it returned some error.
- if (!response.swResponse.isOK()) {
- failedStatuses.push_back(std::move(response.swResponse.getStatus()));
- continue;
- }
-
- BSONObj gleResponse = stripNonWCInfo(response.swResponse.getValue().data);
-
- // Use the downconversion tools to determine if this GLE response is ok, a
- // write concern error, or an unknown error we should immediately abort for.
- GLEErrors errors;
- Status extractStatus = extractGLEErrors(gleResponse, &errors);
- if (!extractStatus.isOK()) {
- failedStatuses.push_back(extractStatus);
- continue;
- }
-
- LegacyWCResponse wcResponse;
- invariant(response.shardHostAndPort);
- wcResponse.shardHost = response.shardHostAndPort->toString();
- wcResponse.gleResponse = gleResponse;
- if (errors.wcError.get()) {
- wcResponse.errToReport = errors.wcError->toString();
- }
-
- legacyWCResponses->push_back(wcResponse);
- }
-
- if (failedStatuses.empty()) {
- return Status::OK();
- }
-
- StringBuilder builder;
- builder << "could not enforce write concern";
-
- for (vector<Status>::const_iterator it = failedStatuses.begin(); it != failedStatuses.end();
- ++it) {
- const Status& failedStatus = *it;
- if (it == failedStatuses.begin()) {
- builder << causedBy(failedStatus.toString());
- } else {
- builder << ":: and ::" << failedStatus.toString();
- }
- }
-
- if (failedStatuses.size() == 1u) {
- return failedStatuses.front();
- } else {
- return Status(ErrorCodes::MultipleErrorsOccurred, builder.str());
- }
-}
-
-
class GetLastErrorCmd : public BasicCommand {
public:
GetLastErrorCmd() : BasicCommand("getLastError", "getlasterror") {}
@@ -210,7 +48,7 @@ public:
}
std::string help() const override {
- return "check for an error on the last command executed";
+ return "no longer supported";
}
virtual void addRequiredPrivileges(const std::string& dbname,
@@ -223,123 +61,10 @@ public:
return false;
}
- virtual bool run(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
- // Mongos GLE - finicky.
- //
- // To emulate mongod, we first append any write errors we had, then try to append
- // write concern error if there was no write error. We need to contact the previous
- // shards regardless to maintain 2.4 behavior.
- //
- // If there are any unexpected or connectivity errors when calling GLE, fail the
- // command.
- //
- // Finally, report the write concern errors IF we don't already have an error.
- // If we only get one write concern error back, report that, otherwise report an
- // aggregated error.
- //
- // TODO: Do we need to contact the prev shards regardless - do we care that much
- // about 2.4 behavior?
- //
-
- LastError* le = &LastError::get(cc());
- le->disable();
-
+ virtual bool run(OperationContext*, const std::string&, const BSONObj&, BSONObjBuilder&) {
warnDeprecation(cc(), "getLastError");
-
- // Write commands always have the error stored in the mongos last error
- bool errorOccurred = false;
- if (le->getNPrev() == 1) {
- errorOccurred = le->appendSelf(result, false);
- }
-
- // For compatibility with 2.4 sharded GLE, we always enforce the write concern
- // across all shards.
- const HostOpTimeMap hostOpTimes(ClusterLastErrorInfo::get(cc())->getPrevHostOpTimes());
-
- std::vector<LegacyWCResponse> wcResponses;
- auto status = enforceLegacyWriteConcern(
- opCtx,
- dbname,
- applyReadWriteConcern(
- opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)),
- hostOpTimes,
- &wcResponses);
-
- // Don't forget about our last hosts, reset the client info
- ClusterLastErrorInfo::get(cc())->disableForCommand();
-
- // We're now done contacting all remote servers, just report results
-
- if (!status.isOK()) {
- // Return immediately if we failed to contact a shard, unexpected GLE issue
- // Can't return code, since it may have been set above (2.4 compatibility)
- result.append("errmsg", status.reason());
- return false;
- }
-
- // Go through all the write concern responses and find errors
- BSONArrayBuilder shards;
- BSONObjBuilder shardRawGLE;
- BSONArrayBuilder errors;
- BSONArrayBuilder errorRawGLE;
-
- int numWCErrors = 0;
- const LegacyWCResponse* lastErrResponse = nullptr;
-
- for (std::vector<LegacyWCResponse>::const_iterator it = wcResponses.begin();
- it != wcResponses.end();
- ++it) {
- const LegacyWCResponse& wcResponse = *it;
-
- shards.append(wcResponse.shardHost);
- shardRawGLE.append(wcResponse.shardHost, wcResponse.gleResponse);
-
- if (!wcResponse.errToReport.empty()) {
- numWCErrors++;
- lastErrResponse = &wcResponse;
- errors.append(wcResponse.errToReport);
- errorRawGLE.append(wcResponse.gleResponse);
- }
- }
-
- // Always report what we found to match 2.4 behavior and for debugging
- if (wcResponses.size() == 1u) {
- result.append("singleShard", wcResponses.front().shardHost);
- } else {
- result.append("shards", shards.arr());
- result.append("shardRawGLE", shardRawGLE.obj());
- }
-
- // Suppress write concern errors if a write error occurred, to match mongod behavior
- if (errorOccurred || numWCErrors == 0) {
- // Still need to return err
- if (!errorOccurred) {
- result.appendNull("err");
- }
-
- return true;
- }
-
- if (numWCErrors == 1) {
- // Return the single write concern error we found, err should be set or not
- // from gle response
- CommandHelpers::filterCommandReplyForPassthrough(lastErrResponse->gleResponse, &result);
- return lastErrResponse->gleResponse["ok"].trueValue();
- } else {
- // Return a generic combined WC error message
- result.append("errs", errors.arr());
- result.append("errObjects", errorRawGLE.arr());
-
- // Need to always return err
- result.appendNull("err");
-
- return CommandHelpers::appendCommandStatusNoThrow(
- result,
- Status(ErrorCodes::WriteConcernFailed, "multiple write concern errors occurred"));
- }
+ uasserted(5739001, "getLastError command is not supported");
+ return false;
}
} cmdGetLastError;
diff --git a/src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp b/src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp
index e4a0a10940b..0cb9e7530eb 100644
--- a/src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp
+++ b/src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp
@@ -32,7 +32,6 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/lasterror.h"
-#include "mongo/s/cluster_last_error_info.h"
namespace mongo {
namespace {
@@ -72,7 +71,6 @@ public:
BSONObjBuilder& result) {
if (cmdObj["forShell"].trueValue()) {
LastError::get(cc()).disable();
- ClusterLastErrorInfo::get(cc())->disableForCommand();
}
errmsg = "replSetGetStatus is not supported through mongos";
diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp
index 189a7b273c3..e4d41e28f23 100644
--- a/src/mongo/s/commands/cluster_write_cmd.cpp
+++ b/src/mongo/s/commands/cluster_write_cmd.cpp
@@ -50,7 +50,6 @@
#include "mongo/s/client/num_hosts_targeted_metrics.h"
#include "mongo/s/client/shard_registry.h"
#include "mongo/s/cluster_commands_helpers.h"
-#include "mongo/s/cluster_last_error_info.h"
#include "mongo/s/cluster_write.h"
#include "mongo/s/commands/cluster_explain.h"
#include "mongo/s/commands/document_shard_key_update_util.h"
@@ -547,9 +546,6 @@ private:
break;
}
- // Save the last opTimes written on each shard for this client, to allow GLE to work
- ClusterLastErrorInfo::get(opCtx->getClient())->addHostOpTimes(stats.getWriteOpTimes());
-
// Record the number of shards targeted by this write.
CurOp::get(opCtx)->debug().nShards =
stats.getTargetedShards().size() + (updatedShardKey ? 1 : 0);
diff --git a/src/mongo/s/mongos_main.cpp b/src/mongo/s/mongos_main.cpp
index faa63d10d06..ef0db47b802 100644
--- a/src/mongo/s/mongos_main.cpp
+++ b/src/mongo/s/mongos_main.cpp
@@ -55,7 +55,6 @@
#include "mongo/db/ftdc/ftdc_mongos.h"
#include "mongo/db/initialize_server_global_state.h"
#include "mongo/db/kill_sessions.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/log_process_details.h"
#include "mongo/db/logical_session_cache_impl.h"
#include "mongo/db/logical_time_validator.h"
diff --git a/src/mongo/s/service_entry_point_mongos.cpp b/src/mongo/s/service_entry_point_mongos.cpp
index 1e9b1664ae8..298432a3c0f 100644
--- a/src/mongo/s/service_entry_point_mongos.cpp
+++ b/src/mongo/s/service_entry_point_mongos.cpp
@@ -48,7 +48,6 @@
#include "mongo/logv2/log.h"
#include "mongo/rpc/message.h"
#include "mongo/rpc/warn_deprecated_wire_ops.h"
-#include "mongo/s/cluster_last_error_info.h"
#include "mongo/s/commands/strategy.h"
namespace mongo {
@@ -74,7 +73,7 @@ struct HandleRequest : public std::enable_shared_from_this<HandleRequest> {
msgId(message.header().getId()),
nsString(getNamespaceString(rec->getDbMessage())) {}
- // Prepares the environment for handling the request (e.g., setting up `ClusterLastErrorInfo`).
+ // Prepares the environment for handling the request.
void setupEnvironment();
// Returns a future that does the heavy lifting of running client commands.
@@ -114,10 +113,6 @@ void HandleRequest::setupEnvironment() {
// Start a new LastError session. Any exceptions thrown from here onwards will be returned
// to the caller (if the type of the message permits it).
auto client = opCtx->getClient();
- if (!ClusterLastErrorInfo::get(client)) {
- ClusterLastErrorInfo::get(client) = std::make_shared<ClusterLastErrorInfo>();
- }
- ClusterLastErrorInfo::get(client)->newRequest();
LastError::get(client).startRequest();
AuthorizationSession::get(opCtx->getClient())->startRequest(opCtx);
diff --git a/src/mongo/s/sharding_egress_metadata_hook_for_mongos.cpp b/src/mongo/s/sharding_egress_metadata_hook_for_mongos.cpp
index a01cb4eab33..90c58dc6ec8 100644
--- a/src/mongo/s/sharding_egress_metadata_hook_for_mongos.cpp
+++ b/src/mongo/s/sharding_egress_metadata_hook_for_mongos.cpp
@@ -34,8 +34,6 @@
#include "mongo/s/sharding_egress_metadata_hook_for_mongos.h"
#include "mongo/db/client.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
-#include "mongo/s/cluster_last_error_info.h"
#include "mongo/s/grid.h"
namespace mongo {
diff --git a/src/mongo/s/sharding_task_executor.cpp b/src/mongo/s/sharding_task_executor.cpp
index 00eaecec9bc..52d3838fafd 100644
--- a/src/mongo/s/sharding_task_executor.cpp
+++ b/src/mongo/s/sharding_task_executor.cpp
@@ -40,9 +40,7 @@
#include "mongo/executor/thread_pool_task_executor.h"
#include "mongo/logv2/log.h"
#include "mongo/rpc/get_status_from_command_result.h"
-#include "mongo/rpc/metadata/sharding_metadata.h"
#include "mongo/s/client/shard_registry.h"
-#include "mongo/s/cluster_last_error_info.h"
#include "mongo/s/grid.h"
#include "mongo/s/is_mongos.h"
#include "mongo/s/transaction_router.h"
@@ -166,13 +164,7 @@ StatusWith<TaskExecutor::CallbackHandle> ShardingTaskExecutor::scheduleRemoteCom
std::shared_ptr<OperationTimeTracker> timeTracker = OperationTimeTracker::get(request.opCtx);
- auto clusterGLE = ClusterLastErrorInfo::get(request.opCtx->getClient());
-
- auto shardingCb = [timeTracker,
- clusterGLE,
- cb,
- grid = Grid::get(request.opCtx),
- hosts = request.target](
+ auto shardingCb = [timeTracker, cb, grid = Grid::get(request.opCtx), hosts = request.target](
const TaskExecutor::RemoteCommandOnAnyCallbackArgs& args) {
ON_BLOCK_EXIT([&cb, &args]() { cb(args); });
@@ -237,34 +229,6 @@ StatusWith<TaskExecutor::CallbackHandle> ShardingTaskExecutor::scheduleRemoteCom
invariant(operationTime.type() == BSONType::bsonTimestamp);
timeTracker->updateOperationTime(LogicalTime(operationTime.timestamp()));
}
-
- // Update getLastError info for the client if we're tracking it.
- if (clusterGLE) {
- auto swShardingMetadata = rpc::ShardingMetadata::readFromMetadata(args.response.data);
- if (swShardingMetadata.isOK()) {
- auto shardingMetadata = std::move(swShardingMetadata.getValue());
-
- auto shardConn = ConnectionString::parse(target.toString());
- if (!shardConn.isOK()) {
- LOGV2_ERROR(22874,
- "Could not parse connection string to update getLastError stats: "
- "{connectionString}",
- "Could not parse connection string to update getLastError stats",
- "connectionString"_attr = target);
- }
-
- clusterGLE->addHostOpTime(shardConn.getValue(),
- HostOpTime(shardingMetadata.getLastOpTime(),
- shardingMetadata.getLastElectionId()));
- } else if (swShardingMetadata.getStatus() != ErrorCodes::NoSuchKey) {
- LOGV2_WARNING(22872,
- "Got invalid sharding metadata {error} "
- "metadata object was '{response}'",
- "Could not parse sharding metadata from response",
- "error"_attr = redact(swShardingMetadata.getStatus()),
- "response"_attr = redact(args.response.data));
- }
- }
};
return _executor->scheduleRemoteCommandOnAny(