summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/SConscript8
-rw-r--r--src/mongo/client/scoped_db_conn_test.cpp4
-rw-r--r--src/mongo/db/client.cpp1
-rw-r--r--src/mongo/db/client.h1
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp1
-rw-r--r--src/mongo/db/commands/get_last_error.cpp22
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp10
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.h5
-rw-r--r--src/mongo/db/commands/write_commands/write_commands.cpp4
-rw-r--r--src/mongo/db/db.cpp5
-rw-r--r--src/mongo/db/dbcommands_generic.cpp2
-rw-r--r--src/mongo/db/dbdirectclient.cpp9
-rw-r--r--src/mongo/db/instance.cpp20
-rw-r--r--src/mongo/db/lasterror.cpp156
-rw-r--r--src/mongo/db/lasterror.h150
-rw-r--r--src/mongo/db/ops/update_result.cpp1
-rw-r--r--src/mongo/db/repl/replication_info.cpp3
-rw-r--r--src/mongo/db/repl/replset_commands.cpp3
-rw-r--r--src/mongo/dbtests/directclienttests.cpp9
-rw-r--r--src/mongo/dbtests/perftests.cpp8
-rw-r--r--src/mongo/dbtests/querytests.cpp9
-rw-r--r--src/mongo/dbtests/updatetests.cpp9
-rw-r--r--src/mongo/s/SConscript3
-rw-r--r--src/mongo/s/chunk.cpp2
-rw-r--r--src/mongo/s/client/shard_connection.cpp2
-rw-r--r--src/mongo/s/commands/cluster_get_last_error_cmd.cpp7
-rw-r--r--src/mongo/s/commands/cluster_repl_set_get_status_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_reset_error_cmd.cpp5
-rw-r--r--src/mongo/s/commands/cluster_write_cmd.cpp13
-rw-r--r--src/mongo/s/config.cpp2
-rw-r--r--src/mongo/s/cursors.cpp2
-rw-r--r--src/mongo/s/d_state.cpp3
-rw-r--r--src/mongo/s/request.cpp2
-rw-r--r--src/mongo/s/server.cpp9
-rw-r--r--src/mongo/s/strategy.cpp10
-rw-r--r--src/mongo/s/write_ops/batch_upconvert.cpp4
-rw-r--r--src/mongo/shell/dbshell.cpp5
-rw-r--r--src/mongo/util/net/message_server.h4
-rw-r--r--src/mongo/util/net/message_server_port.cpp5
39 files changed, 208 insertions, 312 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 9abc6ccd67c..c3ed86b1d9b 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -357,8 +357,9 @@ env.Library(
env.Library('lasterror', [
"db/lasterror.cpp",
],
- LIBDEPS=['network',
- 'foundation',
+ LIBDEPS=[
+ 'foundation',
+ 'service_context',
])
def getSysInfo():
@@ -709,7 +710,8 @@ env.Library(
'db/service_context_noop.cpp',
],
LIBDEPS=[
- 'lasterror', # TODO(schwerin): REMOVE!
+ 'hostandport',
+ 'spin_lock',
'util/decorable',
])
diff --git a/src/mongo/client/scoped_db_conn_test.cpp b/src/mongo/client/scoped_db_conn_test.cpp
index 6adfca400cd..b8aec56844f 100644
--- a/src/mongo/client/scoped_db_conn_test.cpp
+++ b/src/mongo/client/scoped_db_conn_test.cpp
@@ -103,9 +103,7 @@ namespace mongo {
virtual void connected(AbstractMessagingPort* p) {
}
- virtual void process(Message& m,
- AbstractMessagingPort* port,
- LastError * le) {
+ virtual void process(Message& m, AbstractMessagingPort* por) {
boost::this_thread::interruption_point();
}
};
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index cc4a7c69cab..a2e510f4bb0 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -83,7 +83,6 @@ namespace mongo {
}
setThreadName(fullDesc.c_str());
- mongo::lastError.initThread();
// Create the client obj, attach to thread
*currentClient.get() = service->makeClient(fullDesc, mp);
diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h
index f81bc91bf37..63750b69523 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -40,7 +40,6 @@
#include <boost/thread/thread.hpp>
#include "mongo/db/client_basic.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/service_context.h"
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index b8e76b8e0a2..7dcdab369a2 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -43,6 +43,7 @@
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/exec/working_set_common.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/delete_request.h"
diff --git a/src/mongo/db/commands/get_last_error.cpp b/src/mongo/db/commands/get_last_error.cpp
index b3a6ffe84ec..54a9fb469d5 100644
--- a/src/mongo/db/commands/get_last_error.cpp
+++ b/src/mongo/db/commands/get_last_error.cpp
@@ -72,9 +72,7 @@ namespace mongo {
int,
string& errmsg,
BSONObjBuilder& result) {
- LastError *le = lastError.get();
- verify( le );
- le->reset();
+ LastError::get(txn->getClient()).reset();
return true;
}
} cmdResetError;
@@ -88,7 +86,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
virtual void help( stringstream& help ) const {
- lastError.disableForCommand(); // SERVER-11492
+ LastError::get(cc()).disable(); // SERVER-11492
help << "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"
@@ -128,7 +126,8 @@ namespace mongo {
// err is null.
//
- LastError *le = lastError.disableForCommand();
+ LastError *le = &LastError::get(txn->getClient());
+ le->disable();
// Always append lastOp and connectionId
Client& c = *txn->getClient();
@@ -173,7 +172,7 @@ namespace mongo {
// Errors aren't reported when wOpTime is used
if ( !lastOpTimePresent ) {
- if ( le->nPrev != 1 ) {
+ if ( le->getNPrev() != 1 ) {
errorOccurred = LastError::noError.appendSelf( result, false );
}
else {
@@ -284,12 +283,13 @@ namespace mongo {
int,
string& errmsg,
BSONObjBuilder& result) {
- LastError *le = lastError.disableForCommand();
- le->appendSelf( result );
- if ( le->valid )
- result.append( "nPrev", le->nPrev );
+ LastError *le = &LastError::get(txn->getClient());
+ le->disable();
+ le->appendSelf(result, true);
+ if (le->isValid())
+ result.append("nPrev", le->getNPrev());
else
- result.append( "nPrev", -1 );
+ result.append("nPrev", -1);
return true;
}
} cmdGetPrevError;
diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp
index 72bdb1fc144..ae57fdbecbb 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.cpp
+++ b/src/mongo/db/commands/write_commands/batch_executor.cpp
@@ -550,8 +550,10 @@ namespace mongo {
if ( currWrite.getOpType() == BatchedCommandRequest::BatchType_Insert ) {
_stats->numInserted += stats.n;
- _le->nObjects = stats.n;
currentOp->debug().ninserted += stats.n;
+ if (!error) {
+ _le->recordInsert(stats.n);
+ }
}
else if ( currWrite.getOpType() == BatchedCommandRequest::BatchType_Update ) {
if ( stats.upsertedID.isEmpty() ) {
@@ -562,7 +564,7 @@ namespace mongo {
++_stats->numUpserted;
}
- if ( !error ) {
+ if (!error) {
_le->recordUpdate( stats.upsertedID.isEmpty() && stats.n > 0,
stats.n,
stats.upsertedID );
@@ -577,8 +579,8 @@ namespace mongo {
currentOp->debug().ndeleted += stats.n;
}
- if (error && !_le->disabled) {
- _le->raiseError(error->getErrCode(), error->getErrMessage().c_str());
+ if (error) {
+ _le->setLastError(error->getErrCode(), error->getErrMessage().c_str());
}
}
diff --git a/src/mongo/db/commands/write_commands/batch_executor.h b/src/mongo/db/commands/write_commands/batch_executor.h
index 613fb281777..e5d55a5b9fb 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.h
+++ b/src/mongo/db/commands/write_commands/batch_executor.h
@@ -44,12 +44,11 @@ namespace mongo {
class BSONObjBuilder;
class CurOp;
+ class LastError;
class OpCounters;
class OperationContext;
- struct LastError;
-
- struct WriteOpStats;
class WriteBatchStats;
+ struct WriteOpStats;
/**
* An instance of WriteBatchExecutor is an object capable of issuing a write batch.
diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp
index d6d6d7ff137..a1d217d7525 100644
--- a/src/mongo/db/commands/write_commands/write_commands.cpp
+++ b/src/mongo/db/commands/write_commands/write_commands.cpp
@@ -104,7 +104,7 @@ namespace mongo {
// TODO: Remove this when we standardize GLE reporting from commands
if ( !status.isOK() ) {
- setLastError( status.code(), status.reason().c_str() );
+ LastError::get(client).setLastError(status.code(), status.reason());
}
return status;
@@ -145,7 +145,7 @@ namespace mongo {
WriteBatchExecutor writeBatchExecutor(txn,
&globalOpCounters,
- lastError.get());
+ &LastError::get(txn->getClient()));
writeBatchExecutor.executeBatch( request, &response );
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 92bb4177c91..aed1bf00958 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -70,7 +70,6 @@
#include "mongo/db/instance.h"
#include "mongo/db/introspect.h"
#include "mongo/db/json.h"
-#include "mongo/db/lasterror.h"
#include "mongo/db/log_process_details.h"
#include "mongo/db/mongod_options.h"
#include "mongo/db/op_observer.h"
@@ -157,7 +156,7 @@ namespace mongo {
Client::initThread("conn", p);
}
- virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
+ virtual void process(Message& m , AbstractMessagingPort* port) {
OperationContextImpl txn;
while ( true ) {
if ( inShutdown() ) {
@@ -165,8 +164,6 @@ namespace mongo {
break;
}
- lastError.startRequest( m , le );
-
DbResponse dbresponse;
assembleResponse(&txn, m, dbresponse, port->remote());
diff --git a/src/mongo/db/dbcommands_generic.cpp b/src/mongo/db/dbcommands_generic.cpp
index c07dc30a1dc..b9a3c7ef6af 100644
--- a/src/mongo/db/dbcommands_generic.cpp
+++ b/src/mongo/db/dbcommands_generic.cpp
@@ -330,7 +330,7 @@ namespace mongo {
int,
string& errmsg,
BSONObjBuilder& result) {
- setLastError(10038, "forced error");
+ LastError::get(txn->getClient()).setLastError(10038, "forced error");
return false;
}
} cmdForceError;
diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp
index 41b75377060..3aee1750172 100644
--- a/src/mongo/db/dbdirectclient.cpp
+++ b/src/mongo/db/dbdirectclient.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
#include "mongo/db/instance.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/operation_context.h"
#include "mongo/util/log.h"
@@ -122,9 +123,7 @@ namespace mongo {
bool assertOk,
string* actualServer) {
DirectClientScope directClientScope(_txn);
- if (lastError._get()) {
- lastError.startRequest(toSend, lastError._get());
- }
+ LastError::get(_txn->getClient()).startRequest();
DbResponse dbResponse;
assembleResponse(_txn, toSend, dbResponse, dummyHost);
@@ -139,9 +138,7 @@ namespace mongo {
void DBDirectClient::say(Message& toSend, bool isRetry, string* actualServer) {
DirectClientScope directClientScope(_txn);
- if (lastError._get()) {
- lastError.startRequest(toSend, lastError._get());
- }
+ LastError::get(_txn->getClient()).startRequest();
DbResponse dbResponse;
assembleResponse(_txn, toSend, dbResponse, dummyHost);
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index 80bf95116ce..099492d607a 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -389,6 +389,7 @@ namespace {
Client& c = *txn->getClient();
if (!c.isInDirectClient()) {
+ LastError::get(c).startRequest();
AuthorizationSession::get(c)->startRequest(txn);
// We should not be holding any locks at this point
@@ -556,14 +557,14 @@ namespace {
}
}
catch (const UserException& ue) {
- setLastError(ue.getCode(), ue.getInfo().msg.c_str());
+ LastError::get(c).setLastError(ue.getCode(), ue.getInfo().msg);
MONGO_LOG_COMPONENT(3, responseComponent)
<< " Caught Assertion in " << opToString(op) << ", continuing "
<< ue.toString() << endl;
debug.exceptionInfo = ue.getInfo();
}
catch (const AssertionException& e) {
- setLastError(e.getCode(), e.getInfo().msg.c_str());
+ LastError::get(c).setLastError(e.getCode(), e.getInfo().msg);
MONGO_LOG_COMPONENT(3, responseComponent)
<< " Caught Assertion in " << opToString(op) << ", continuing "
<< e.toString() << endl;
@@ -604,6 +605,7 @@ namespace {
}
void receivedKillCursors(OperationContext* txn, Message& m) {
+ LastError::get(txn->getClient()).disable();
DbMessage dbmessage(m);
int n = dbmessage.pullInt();
@@ -700,7 +702,8 @@ namespace {
UpdateResult res = UpdateStage::makeUpdateResult(exec.get(), &op.debug());
// for getlasterror
- lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted );
+ LastError::get(txn->getClient()).recordUpdate(
+ res.existing, res.numMatched, res.upserted);
return;
}
break;
@@ -753,7 +756,8 @@ namespace {
uassertStatusOK(exec->executePlan());
UpdateResult res = UpdateStage::makeUpdateResult(exec.get(), &op.debug());
- lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted );
+ LastError::get(txn->getClient()).recordUpdate(
+ res.existing, res.numMatched, res.upserted);
} MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "update", nsString.ns());
}
@@ -811,7 +815,7 @@ namespace {
// Run the plan and get the number of docs deleted.
uassertStatusOK(exec->executePlan());
long long n = DeleteStage::getNumDeleted(exec.get());
- lastError.getSafe()->recordDelete(n);
+ LastError::get(txn->getClient()).recordDelete(n);
op.debug().ndeleted = n;
break;
@@ -1001,7 +1005,7 @@ namespace {
globalOpCounters.incInsertInWriteLock(i);
throw;
}
- setLastError(ex.getCode(), ex.getInfo().msg.c_str());
+ LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
// otherwise ignore and keep going
}
}
@@ -1055,7 +1059,7 @@ namespace {
convertSystemIndexInsertsToCommands(d, &allCmdsBuilder);
}
catch (const DBException& ex) {
- setLastError(ex.getCode(), ex.getInfo().msg.c_str());
+ LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
curOp.debug().exceptionInfo = ex.getInfo();
return;
}
@@ -1077,7 +1081,7 @@ namespace {
uassertStatusOK(Command::getStatusFromCommandResult(resultBuilder.done()));
}
catch (const DBException& ex) {
- setLastError(ex.getCode(), ex.getInfo().msg.c_str());
+ LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
curOp.debug().exceptionInfo = ex.getInfo();
if (!keepGoing) {
return;
diff --git a/src/mongo/db/lasterror.cpp b/src/mongo/db/lasterror.cpp
index d0a22d56b51..d242cdedc1a 100644
--- a/src/mongo/db/lasterror.cpp
+++ b/src/mongo/db/lasterror.cpp
@@ -27,139 +27,91 @@
* then also delete it in the license file.
*/
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
-
#include "mongo/platform/basic.h"
#include "mongo/db/lasterror.h"
#include "mongo/db/jsobj.h"
-#include "mongo/util/debug_util.h"
-#include "mongo/util/log.h"
-#include "mongo/util/net/message.h"
+#include "mongo/util/assert_util.h"
namespace mongo {
- using std::endl;
-
LastError LastError::noError;
- LastErrorHolder lastError;
-
- bool isShell = false;
- void setLastError(int code , const char *msg) {
- LastError *le = lastError.get();
- if ( le == 0 ) {
- /* might be intentional (non-user thread) */
- DEV {
- static unsigned n;
- if( ++n < 4 && !isShell ) log() << "dev: lastError==0 won't report:" << msg << endl;
- }
- }
- else if ( le->disabled ) {
- log() << "lastError disabled, can't report: " << code << ":" << msg << endl;
- }
- else {
- le->raiseError(code, msg);
- }
- }
- bool LastError::appendSelf( BSONObjBuilder &b , bool blankErr ) {
+ const Client::Decoration<LastError> LastError::get = Client::declareDecoration<LastError>();
- 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 );
- }
+ void LastError::reset(bool valid) {
+ *this = LastError();
+ _valid = valid;
+ }
- if ( code )
- b.append( "code" , code );
- if ( updatedExisting != NotUpdate )
- b.appendBool( "updatedExisting", updatedExisting == True );
- if ( !upsertedId.isEmpty() ) {
- b.append( upsertedId[kUpsertedFieldName] );
+ void LastError::setLastError(int code, std::string msg) {
+ if (_disabled) {
+ return;
}
- b.appendNumber( "n", nObjects );
-
- return ! msg.empty();
+ reset(true);
+ _code = code;
+ _msg = std::move(msg);
}
- LastErrorHolder::~LastErrorHolder() {
+ void LastError::recordInsert(long long nObjects) {
+ reset(true);
+ _nObjects = nObjects;
}
-
- LastError * LastErrorHolder::disableForCommand() {
- LastError *le = _get();
- uassert(13649, "no operation yet", le);
- le->disabled = true;
- le->nPrev--; // caller is a command that shouldn't count as an operation
- return le;
+ void LastError::recordUpdate(bool updateObjects, long long nObjects, BSONObj upsertedId) {
+ reset(true);
+ _nObjects = nObjects;
+ _updatedExisting = updateObjects ? True : False;
+ if ( upsertedId.valid() && upsertedId.hasField(kUpsertedFieldName) )
+ _upsertedId = upsertedId;
}
- LastError * LastErrorHolder::get( bool create ) {
- LastError *ret = _get( create );
- if ( ret && !ret->disabled )
- return ret;
- return 0;
+ void LastError::recordDelete(long long nDeleted) {
+ reset(true);
+ _nObjects = nDeleted;
}
- LastError * LastErrorHolder::getSafe() {
- LastError * le = get(false);
- if ( ! le ) {
- error() << " no LastError!" << std::endl;
- verify( le );
+ bool LastError::appendSelf(BSONObjBuilder &b , bool blankErr) const {
+
+ if (!_valid) {
+ if (blankErr)
+ b.appendNull( "err" );
+ b.append( "n", 0 );
+ return false;
}
- return le;
- }
- LastError * LastErrorHolder::_get( bool create ) {
- LastError * le = _tl.get();
- if ( ! le && create ) {
- le = new LastError();
- _tl.reset( le );
+ if (_msg.empty()) {
+ if (blankErr) {
+ b.appendNull( "err" );
+ }
+ }
+ else {
+ b.append("err", _msg);
}
- return le;
- }
- void LastErrorHolder::release() {
- _tl.release();
- }
+ if (_code)
+ b.append("code" , _code);
+ if (_updatedExisting != NotUpdate)
+ b.appendBool("updatedExisting", _updatedExisting == True);
+ if (!_upsertedId.isEmpty()) {
+ b.append(_upsertedId[kUpsertedFieldName]);
+ }
+ b.appendNumber("n", _nObjects);
- /** ok to call more than once. */
- void LastErrorHolder::initThread() {
- if( ! _tl.get() )
- _tl.reset( new LastError() );
+ return !_msg.empty();
}
- void LastErrorHolder::reset( LastError * le ) {
- _tl.reset( le );
- }
- void prepareErrForNewRequest( Message &m, LastError * err ) {
- // a killCursors message shouldn't affect last error
- verify( err );
- if ( m.operation() == dbKillCursors ) {
- err->disabled = true;
- }
- else {
- err->disabled = false;
- err->nPrev++;
- }
+ void LastError::disable() {
+ invariant(!_disabled);
+ _disabled = true;
+ _nPrev--; // caller is a command that shouldn't count as an operation
}
- LastError * LastErrorHolder::startRequest( Message& m , LastError * le ) {
- verify( le );
- prepareErrForNewRequest( m, le );
- return le;
+ void LastError::startRequest() {
+ _disabled = false;
+ ++_nPrev;
}
} // namespace mongo
diff --git a/src/mongo/db/lasterror.h b/src/mongo/db/lasterror.h
index 5b04b69a57a..55a04c8334d 100644
--- a/src/mongo/db/lasterror.h
+++ b/src/mongo/db/lasterror.h
@@ -29,16 +29,13 @@
#pragma once
-#include <boost/noncopyable.hpp>
-#include <boost/thread/tss.hpp>
#include <string>
+#include "mongo/db/client.h"
#include "mongo/db/jsobj.h"
-#include "mongo/bson/oid.h"
namespace mongo {
class BSONObjBuilder;
- class Message;
static const char kUpsertedFieldName[] = "upserted";
static const char kGLEStatsFieldName[] = "$gleStats";
@@ -46,107 +43,80 @@ namespace mongo {
static const char kGLEStatsLastOpTimeTermFieldName[] = "lastOpTimeTerm";
static const char kGLEStatsElectionIdFieldName[] = "electionId";
- struct LastError {
- int code;
- std::string msg;
- enum UpdatedExistingType { NotUpdate, True, False } updatedExisting;
- // _id field value from inserted doc, returned as kUpsertedFieldName (above)
- BSONObj upsertedId;
- long long nObjects;
- int nPrev;
- bool valid;
- bool disabled;
- void raiseError(int _code , const char *_msg) {
- reset( true );
- code = _code;
- msg = _msg;
- }
- void recordUpdate( bool _updateObjects , long long _nObjects , BSONObj _upsertedId ) {
- reset( true );
- nObjects = _nObjects;
- updatedExisting = _updateObjects ? True : False;
- if ( _upsertedId.valid() && _upsertedId.hasField(kUpsertedFieldName) )
- upsertedId = _upsertedId;
-
- }
- void recordDelete( long long nDeleted ) {
- reset( true );
- nObjects = nDeleted;
- }
- LastError() {
- reset();
- }
- void reset( bool _valid = false ) {
- code = 0;
- msg.clear();
- updatedExisting = NotUpdate;
- nObjects = 0;
- nPrev = 1;
- valid = _valid;
- disabled = false;
- upsertedId = BSONObj();
- }
+ class LastError {
+ public:
+ static const Client::Decoration<LastError> get;
/**
- * @return if there is an err
+ * Resets the object to a newly constructed state. If "valid" is true, marks the last-error
+ * object as "valid".
*/
- bool appendSelf( BSONObjBuilder &b , bool blankErr = true );
-
- struct Disabled : boost::noncopyable {
- Disabled( LastError * le ) {
- _le = le;
- if ( _le ) {
- _prev = _le->disabled;
- _le->disabled = true;
- }
- else {
- _prev = false;
- }
- }
+ void reset(bool valid = false);
- ~Disabled() {
- if ( _le )
- _le->disabled = _prev;
- }
+ /**
+ * when db receives a message/request, call this
+ */
+ void startRequest();
- LastError * _le;
- bool _prev;
- };
+ /**
+ * Disables error recording for the current operation.
+ */
+ void disable();
- static LastError noError;
- };
+ /**
+ * Sets the error information for the current operation, if error recording was not
+ * explicitly disabled via a call to disable() since the call to startRequest.
+ */
+ void setLastError(int code, std::string msg);
- extern class LastErrorHolder {
- public:
- LastErrorHolder(){}
- ~LastErrorHolder();
+ void recordInsert(long long nObjects);
- LastError * get( bool create = false );
- LastError * getSafe();
- LastError * _get( bool create = false ); // may return a disabled LastError
+ void recordUpdate(bool updateObjects, long long nObjects, BSONObj upsertedId);
- void reset( LastError * le );
+ void recordDelete(long long nDeleted);
- /** ok to call more than once. */
- void initThread();
+ /**
+ * 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;
- void release();
+ bool isValid() const { return _valid; }
+ int const getNPrev() const { return _nPrev; }
- /** when db receives a message/request, call this */
- LastError * startRequest( Message& m , LastError * connectionOwned );
+ class Disabled {
+ public:
+ explicit Disabled(LastError* le) : _le(le), _prev(le->_disabled) {
+ _le->_disabled = true;
+ }
- // used to disable lastError reporting while processing a killCursors message
- // disable causes get() to return 0.
- LastError *disableForCommand(); // only call once per command invocation!
- private:
- boost::thread_specific_ptr<LastError> _tl;
+ ~Disabled() {
+ _le->_disabled = _prev;
+ }
- struct Status {
- time_t time;
- LastError *lerr;
+ private:
+ LastError * const _le;
+ const bool _prev;
};
- } lastError;
- void setLastError(int code , const char *msg);
+ static LastError noError;
+
+ private:
+ enum UpdatedExistingType { NotUpdate, True, False };
+
+ int _code = 0;
+ std::string _msg = {};
+ UpdatedExistingType _updatedExisting = NotUpdate;
+ // _id field value from inserted doc, returned as kUpsertedFieldName (above)
+ BSONObj _upsertedId = {};
+ long long _nObjects = 0;
+ int _nPrev = 1;
+ bool _valid = false;
+ bool _disabled = false;
+ };
} // namespace mongo
diff --git a/src/mongo/db/ops/update_result.cpp b/src/mongo/db/ops/update_result.cpp
index f5e31c1a3d8..64b33243131 100644
--- a/src/mongo/db/ops/update_result.cpp
+++ b/src/mongo/db/ops/update_result.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/ops/update_result.h"
+#include "mongo/db/lasterror.h"
#include "mongo/util/log.h"
namespace mongo {
diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp
index f4cd02426a2..a5303072fbd 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/is_master_response.h"
@@ -216,7 +217,7 @@ namespace repl {
authenticated.
*/
if ( cmdObj["forShell"].trueValue() )
- lastError.disableForCommand();
+ LastError::get(txn->getClient()).disable();
appendReplicationInfo(txn, result, 0);
diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp
index d160351c6b0..e4cc257dcb4 100644
--- a/src/mongo/db/repl/replset_commands.cpp
+++ b/src/mongo/db/repl/replset_commands.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/service_context.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/repl/initial_sync.h"
@@ -150,7 +151,7 @@ namespace repl {
string& errmsg,
BSONObjBuilder& result) {
if ( cmdObj["forShell"].trueValue() )
- lastError.disableForCommand();
+ LastError::get(txn->getClient()).disable();
Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result);
if (!status.isOK())
diff --git a/src/mongo/dbtests/directclienttests.cpp b/src/mongo/dbtests/directclienttests.cpp
index 822db3b58f4..fc076a9f926 100644
--- a/src/mongo/dbtests/directclienttests.cpp
+++ b/src/mongo/dbtests/directclienttests.cpp
@@ -33,6 +33,7 @@
#include <iostream>
+#include "mongo/db/client.h"
#include "mongo/db/db.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/json.h"
@@ -49,15 +50,11 @@ namespace DirectClientTests {
class ClientBase {
public:
ClientBase() {
- _prevError = mongo::lastError._get( false );
- mongo::lastError.release();
- mongo::lastError.reset( new LastError() );
+ mongo::LastError::get(cc()).reset();
}
virtual ~ClientBase() {
- mongo::lastError.reset( _prevError );
+ mongo::LastError::get(cc()).reset();
}
- private:
- LastError* _prevError;
};
const char *ns = "a.b";
diff --git a/src/mongo/dbtests/perftests.cpp b/src/mongo/dbtests/perftests.cpp
index 90c0d74c632..310ae31e3a1 100644
--- a/src/mongo/dbtests/perftests.cpp
+++ b/src/mongo/dbtests/perftests.cpp
@@ -49,6 +49,7 @@
#include <mutex>
#include "mongo/config.h"
+#include "mongo/db/client.h"
#include "mongo/db/db.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/json.h"
@@ -91,12 +92,10 @@ namespace PerfTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- _prevError = mongo::lastError._get( false );
- mongo::lastError.release();
- mongo::lastError.reset( new LastError() );
+ mongo::LastError::get(_txn.getClient()).reset();
}
virtual ~ClientBase() {
- mongo::lastError.reset( _prevError );
+ mongo::LastError::get(_txn.getClient()).reset();
}
protected:
@@ -114,7 +113,6 @@ namespace PerfTests {
OperationContext* txn() { return &_txn; }
private:
- LastError* _prevError;
OperationContextImpl _txn;
DBDirectClient _client;
};
diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp
index bab0f1e22fe..5aac0a989e5 100644
--- a/src/mongo/dbtests/querytests.cpp
+++ b/src/mongo/dbtests/querytests.cpp
@@ -216,13 +216,11 @@ namespace QueryTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- _prevError = mongo::lastError._get( false );
- mongo::lastError.release();
- mongo::lastError.reset( new LastError() );
+ mongo::LastError::get(_txn.getClient()).reset();
_txn.getCurOp()->reset();
}
virtual ~ClientBase() {
- mongo::lastError.reset( _prevError );
+ mongo::LastError::get(_txn.getClient()).reset();
}
protected:
@@ -238,9 +236,6 @@ namespace QueryTests {
OperationContextImpl _txn;
DBDirectClient _client;
-
- private:
- LastError* _prevError;
};
class BoundedKey : public ClientBase {
diff --git a/src/mongo/dbtests/updatetests.cpp b/src/mongo/dbtests/updatetests.cpp
index 4d2f527c54a..fa7271bcb6b 100644
--- a/src/mongo/dbtests/updatetests.cpp
+++ b/src/mongo/dbtests/updatetests.cpp
@@ -54,12 +54,10 @@ namespace UpdateTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- _prevError = mongo::lastError._get( false );
- mongo::lastError.release();
- mongo::lastError.reset( new LastError() );
+ mongo::LastError::get(_txn.getClient()).reset();
}
virtual ~ClientBase() {
- mongo::lastError.reset( _prevError );
+ mongo::LastError::get(_txn.getClient()).reset();
}
protected:
@@ -75,9 +73,6 @@ namespace UpdateTests {
OperationContextImpl _txn;
DBDirectClient _client;
-
- private:
- LastError* _prevError;
};
class Fail : public ClientBase {
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 74bd0e54fc7..a95ef130618 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -174,8 +174,9 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/bson',
- 'cluster_ops',
'$BUILD_DIR/mongo/db/common', # for Message
+ '$BUILD_DIR/mongo/lasterror',
+ 'cluster_ops',
],
)
diff --git a/src/mongo/s/chunk.cpp b/src/mongo/s/chunk.cpp
index b62a0da7512..8fe331f9c26 100644
--- a/src/mongo/s/chunk.cpp
+++ b/src/mongo/s/chunk.cpp
@@ -532,7 +532,7 @@ namespace {
bool Chunk::splitIfShould( long dataWritten ) const {
dassert( ShouldAutoSplit );
- LastError::Disabled d( lastError.get() );
+ LastError::Disabled d(&LastError::get(cc()));
try {
_dataWritten += dataWritten;
diff --git a/src/mongo/s/client/shard_connection.cpp b/src/mongo/s/client/shard_connection.cpp
index abce4b04db2..6f059b485fa 100644
--- a/src/mongo/s/client/shard_connection.cpp
+++ b/src/mongo/s/client/shard_connection.cpp
@@ -282,7 +282,7 @@ namespace {
Shard::getAllShards( all );
// Don't report exceptions here as errors in GetLastError
- LastError::Disabled ignoreForGLE(lastError.get(false));
+ LastError::Disabled ignoreForGLE(&LastError::get(cc()));
// Now only check top-level shard connections
for ( unsigned i=0; i<all.size(); i++ ) {
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 2ee08b3aab9..a703d705b6d 100644
--- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
+++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
@@ -88,12 +88,13 @@ namespace {
// about 2.4 behavior?
//
- LastError *le = lastError.disableForCommand();
- invariant(le);
+ LastError *le = &LastError::get(cc());
+ le->disable();
+
// Write commands always have the error stored in the mongos last error
bool errorOccurred = false;
- if (le->nPrev == 1) {
+ if (le->getNPrev() == 1) {
errorOccurred = le->appendSelf(result, false);
}
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 bacb5da705e..0164fe3cc15 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
@@ -72,7 +72,7 @@ namespace {
BSONObjBuilder& result) {
if (cmdObj["forShell"].trueValue()) {
- lastError.disableForCommand();
+ LastError::get(cc()).disable();
ClusterLastErrorInfo::get(cc()).disableForCommand();
}
diff --git a/src/mongo/s/commands/cluster_reset_error_cmd.cpp b/src/mongo/s/commands/cluster_reset_error_cmd.cpp
index 182daedaa66..8bc2af039f3 100644
--- a/src/mongo/s/commands/cluster_reset_error_cmd.cpp
+++ b/src/mongo/s/commands/cluster_reset_error_cmd.cpp
@@ -66,10 +66,7 @@ namespace {
std::string& errmsg,
BSONObjBuilder& result) {
- LastError* le = lastError.get();
- if (le) {
- le->reset();
- }
+ LastError::get(cc()).reset();
const std::set<std::string>* shards =
ClusterLastErrorInfo::get(cc()).getPrevShardHosts();
diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp
index 925a944eb4d..83a039a3f3b 100644
--- a/src/mongo/s/commands/cluster_write_cmd.cpp
+++ b/src/mongo/s/commands/cluster_write_cmd.cpp
@@ -85,7 +85,7 @@ namespace {
// TODO: Remove this when we standardize GLE reporting from commands
if (!status.isOK()) {
- setLastError(status.code(), status.reason().c_str());
+ LastError::get(client).setLastError(status.code(), status.reason());
}
return status;
@@ -149,8 +149,7 @@ namespace {
ClusterWriter writer(true, 0);
- // NOTE: Sometimes this command is invoked with LE disabled for legacy writes
- LastError* cmdLastError = lastError.get(false);
+ LastError* cmdLastError = &LastError::get(cc());
{
// Disable the last error object for the duration of the write
@@ -174,11 +173,9 @@ namespace {
dassert(response.isValid(NULL));
}
- if (cmdLastError) {
- // Populate the lastError object based on the write response
- cmdLastError->reset();
- batchErrorToLastError(request, response, cmdLastError);
- }
+ // Populate the lastError object based on the write response
+ cmdLastError->reset();
+ batchErrorToLastError(request, response, cmdLastError);
size_t numAttempts;
diff --git a/src/mongo/s/config.cpp b/src/mongo/s/config.cpp
index e8dd8e60d44..43600e9eca8 100644
--- a/src/mongo/s/config.cpp
+++ b/src/mongo/s/config.cpp
@@ -282,7 +282,7 @@ namespace mongo {
ChunkManagerPtr DBConfig::getChunkManagerIfExists( const string& ns, bool shouldReload, bool forceReload ){
// Don't report exceptions here as errors in GetLastError
- LastError::Disabled ignoreForGLE(lastError.get(false));
+ LastError::Disabled ignoreForGLE(&LastError::get(cc()));
try{
return getChunkManager( ns, shouldReload, forceReload );
diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp
index dd339627668..e7e623eeed9 100644
--- a/src/mongo/s/cursors.cpp
+++ b/src/mongo/s/cursors.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/auth/privilege.h"
#include "mongo/db/commands.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/max_time.h"
#include "mongo/db/server_parameters.h"
#include "mongo/util/concurrency/task.h"
@@ -367,6 +368,7 @@ namespace mongo {
}
void CursorCache::gotKillCursors(Message& m ) {
+ LastError::get(cc()).disable();
DbMessage dbmessage(m);
int n = dbmessage.pullInt();
diff --git a/src/mongo/s/d_state.cpp b/src/mongo/s/d_state.cpp
index 09197770db1..de29c5908e5 100644
--- a/src/mongo/s/d_state.cpp
+++ b/src/mongo/s/d_state.cpp
@@ -48,6 +48,7 @@
#include "mongo/db/db.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/jsobj.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/wire_version.h"
@@ -1028,7 +1029,7 @@ namespace mongo {
// step 1
- lastError.disableForCommand();
+ LastError::get(txn->getClient()).disable();
ShardedConnectionInfo* info = ShardedConnectionInfo::get( true );
bool authoritative = cmdObj.getBoolField( "authoritative" );
diff --git a/src/mongo/s/request.cpp b/src/mongo/s/request.cpp
index 8c8b40dc608..5c231d507c9 100644
--- a/src/mongo/s/request.cpp
+++ b/src/mongo/s/request.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/client.h"
#include "mongo/db/commands.h"
+#include "mongo/db/lasterror.h"
#include "mongo/db/stats/counters.h"
#include "mongo/s/cluster_last_error_info.h"
#include "mongo/s/cursors.h"
@@ -67,6 +68,7 @@ namespace mongo {
}
_m.header().setId(_id);
+ LastError::get(_clientInfo).startRequest();
ClusterLastErrorInfo::get(_clientInfo).clearRequestInfo();
if (_d.messageShouldHaveNs()) {
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index f2f21915b5b..4c51e534d7d 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -141,13 +141,10 @@ namespace mongo {
Client::initThread("conn", getGlobalServiceContext(), p);
}
- virtual void process( Message& m , AbstractMessagingPort* p , LastError * le) {
+ virtual void process(Message& m, AbstractMessagingPort* p) {
verify( p );
Request r( m , p );
- verify( le );
- lastError.startRequest( m , le );
-
try {
r.init();
r.process();
@@ -164,7 +161,7 @@ namespace mongo {
}
// We *always* populate the last error for now
- le->raiseError( ex.getCode() , ex.what() );
+ LastError::get(cc()).setLastError(ex.getCode(), ex.what());
}
catch ( const DBException& ex ) {
@@ -178,7 +175,7 @@ namespace mongo {
}
// We *always* populate the last error for now
- le->raiseError( ex.getCode() , ex.what() );
+ LastError::get(cc()).setLastError(ex.getCode(), ex.what());
}
// Release connections back to pool, if any still cached
diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp
index acffa2e79e1..887595836ee 100644
--- a/src/mongo/s/strategy.cpp
+++ b/src/mongo/s/strategy.cpp
@@ -653,7 +653,7 @@ namespace mongo {
void Strategy::writeOp( int op , Request& r ) {
// make sure we have a last error
- dassert( lastError.get( false /* don't create */) );
+ dassert(&LastError::get(cc()));
OwnedPointerVector<BatchedCommandRequest> requestsOwned;
vector<BatchedCommandRequest*>& requests = requestsOwned.mutableVector();
@@ -665,7 +665,7 @@ namespace mongo {
// Multiple commands registered to last error as multiple requests
if ( it != requests.begin() )
- lastError.startRequest( r.m(), lastError.get( false ) );
+ LastError::get(cc()).startRequest();
BatchedCommandRequest* request = *it;
@@ -680,7 +680,7 @@ namespace mongo {
{
// Disable the last error object for the duration of the write cmd
- LastError::Disabled disableLastError( lastError.get( false ) );
+ LastError::Disabled disableLastError(&LastError::get(cc()));
Command::runAgainstRegistered( cmdNS.c_str(), requestBSON, builder, 0 );
}
@@ -690,8 +690,8 @@ namespace mongo {
dassert( parsed && response.isValid( NULL ) );
// Populate the lastError object based on the write response
- lastError.get( false )->reset();
- bool hadError = batchErrorToLastError( *request, response, lastError.get( false ) );
+ LastError::get(cc()).reset();
+ bool hadError = batchErrorToLastError(*request, response, &LastError::get(cc()));
// Check if this is an ordered batch and we had an error which should stop processing
if ( request->getOrdered() && hadError )
diff --git a/src/mongo/s/write_ops/batch_upconvert.cpp b/src/mongo/s/write_ops/batch_upconvert.cpp
index 3df74fd614f..e81d35ea9db 100644
--- a/src/mongo/s/write_ops/batch_upconvert.cpp
+++ b/src/mongo/s/write_ops/batch_upconvert.cpp
@@ -203,8 +203,8 @@ namespace mongo {
// Record an error if one exists
if ( lastBatchError ) {
string errMsg = lastBatchError->getErrMessage();
- error->raiseError( lastBatchError->getErrCode(),
- errMsg.empty() ? "see code for details" : errMsg.c_str() );
+ error->setLastError(lastBatchError->getErrCode(),
+ errMsg.empty() ? "see code for details" : errMsg.c_str());
return true;
}
diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp
index 8abfcecbc9f..ceafa7375b5 100644
--- a/src/mongo/shell/dbshell.cpp
+++ b/src/mongo/shell/dbshell.cpp
@@ -424,10 +424,6 @@ string finishCode( string code ) {
return code;
}
-namespace mongo {
- extern bool isShell;
-}
-
bool execPrompt( mongo::Scope &scope, const char *promptFunction, string &prompt ) {
string execStatement = string( "__prompt__ = " ) + promptFunction + "();";
scope.exec( "delete __prompt__;", "", false, false, false, 0 );
@@ -588,7 +584,6 @@ static void edit( const string& whatToEdit ) {
}
int _main( int argc, char* argv[], char **envp ) {
- mongo::isShell = true;
setupSignalHandlers(true);
setupSignals();
diff --git a/src/mongo/util/net/message_server.h b/src/mongo/util/net/message_server.h
index 66bdec58ad7..7bb9759eeff 100644
--- a/src/mongo/util/net/message_server.h
+++ b/src/mongo/util/net/message_server.h
@@ -38,8 +38,6 @@
namespace mongo {
- struct LastError;
-
class MessageHandler {
public:
virtual ~MessageHandler() {}
@@ -53,7 +51,7 @@ namespace mongo {
* called every time a message comes in
* handler is responsible for responding to client
*/
- virtual void process( Message& m , AbstractMessagingPort* p , LastError * err ) = 0;
+ virtual void process(Message& m, AbstractMessagingPort* p) = 0;
};
class MessageServer {
diff --git a/src/mongo/util/net/message_server_port.cpp b/src/mongo/util/net/message_server_port.cpp
index 8db034fbe6e..682a7361ede 100644
--- a/src/mongo/util/net/message_server_port.cpp
+++ b/src/mongo/util/net/message_server_port.cpp
@@ -207,9 +207,6 @@ namespace {
Message m;
int64_t counter = 0;
try {
- LastError * le = new LastError();
- lastError.reset( le ); // lastError now has ownership
-
handler->connected(portWithHandler.get());
while ( ! inShutdown() ) {
@@ -227,7 +224,7 @@ namespace {
break;
}
- handler->process(m, portWithHandler.get(), le);
+ handler->process(m, portWithHandler.get());
networkCounter.hit(portWithHandler->psock->getBytesIn(),
portWithHandler->psock->getBytesOut());