summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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/s/write_ops/batch_upconvert_test.cpp1
-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
40 files changed, 312 insertions, 209 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index c3ed86b1d9b..9abc6ccd67c 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -357,9 +357,8 @@ env.Library(
env.Library('lasterror', [
"db/lasterror.cpp",
],
- LIBDEPS=[
- 'foundation',
- 'service_context',
+ LIBDEPS=['network',
+ 'foundation',
])
def getSysInfo():
@@ -710,8 +709,7 @@ env.Library(
'db/service_context_noop.cpp',
],
LIBDEPS=[
- 'hostandport',
- 'spin_lock',
+ 'lasterror', # TODO(schwerin): REMOVE!
'util/decorable',
])
diff --git a/src/mongo/client/scoped_db_conn_test.cpp b/src/mongo/client/scoped_db_conn_test.cpp
index b8aec56844f..6adfca400cd 100644
--- a/src/mongo/client/scoped_db_conn_test.cpp
+++ b/src/mongo/client/scoped_db_conn_test.cpp
@@ -103,7 +103,9 @@ namespace mongo {
virtual void connected(AbstractMessagingPort* p) {
}
- virtual void process(Message& m, AbstractMessagingPort* por) {
+ virtual void process(Message& m,
+ AbstractMessagingPort* port,
+ LastError * le) {
boost::this_thread::interruption_point();
}
};
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index a2e510f4bb0..cc4a7c69cab 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -83,6 +83,7 @@ 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 63750b69523..f81bc91bf37 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -40,6 +40,7 @@
#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 7dcdab369a2..b8e76b8e0a2 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -43,7 +43,6 @@
#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 54a9fb469d5..b3a6ffe84ec 100644
--- a/src/mongo/db/commands/get_last_error.cpp
+++ b/src/mongo/db/commands/get_last_error.cpp
@@ -72,7 +72,9 @@ namespace mongo {
int,
string& errmsg,
BSONObjBuilder& result) {
- LastError::get(txn->getClient()).reset();
+ LastError *le = lastError.get();
+ verify( le );
+ le->reset();
return true;
}
} cmdResetError;
@@ -86,7 +88,7 @@ namespace mongo {
const BSONObj& cmdObj,
std::vector<Privilege>* out) {} // No auth required
virtual void help( stringstream& help ) const {
- LastError::get(cc()).disable(); // SERVER-11492
+ lastError.disableForCommand(); // 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"
@@ -126,8 +128,7 @@ namespace mongo {
// err is null.
//
- LastError *le = &LastError::get(txn->getClient());
- le->disable();
+ LastError *le = lastError.disableForCommand();
// Always append lastOp and connectionId
Client& c = *txn->getClient();
@@ -172,7 +173,7 @@ namespace mongo {
// Errors aren't reported when wOpTime is used
if ( !lastOpTimePresent ) {
- if ( le->getNPrev() != 1 ) {
+ if ( le->nPrev != 1 ) {
errorOccurred = LastError::noError.appendSelf( result, false );
}
else {
@@ -283,13 +284,12 @@ namespace mongo {
int,
string& errmsg,
BSONObjBuilder& result) {
- LastError *le = &LastError::get(txn->getClient());
- le->disable();
- le->appendSelf(result, true);
- if (le->isValid())
- result.append("nPrev", le->getNPrev());
+ LastError *le = lastError.disableForCommand();
+ le->appendSelf( result );
+ if ( le->valid )
+ result.append( "nPrev", le->nPrev );
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 ae57fdbecbb..72bdb1fc144 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.cpp
+++ b/src/mongo/db/commands/write_commands/batch_executor.cpp
@@ -550,10 +550,8 @@ 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() ) {
@@ -564,7 +562,7 @@ namespace mongo {
++_stats->numUpserted;
}
- if (!error) {
+ if ( !error ) {
_le->recordUpdate( stats.upsertedID.isEmpty() && stats.n > 0,
stats.n,
stats.upsertedID );
@@ -579,8 +577,8 @@ namespace mongo {
currentOp->debug().ndeleted += stats.n;
}
- if (error) {
- _le->setLastError(error->getErrCode(), error->getErrMessage().c_str());
+ if (error && !_le->disabled) {
+ _le->raiseError(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 e5d55a5b9fb..613fb281777 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.h
+++ b/src/mongo/db/commands/write_commands/batch_executor.h
@@ -44,11 +44,12 @@ namespace mongo {
class BSONObjBuilder;
class CurOp;
- class LastError;
class OpCounters;
class OperationContext;
- class WriteBatchStats;
+ struct LastError;
+
struct WriteOpStats;
+ class WriteBatchStats;
/**
* 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 a1d217d7525..d6d6d7ff137 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() ) {
- LastError::get(client).setLastError(status.code(), status.reason());
+ setLastError( status.code(), status.reason().c_str() );
}
return status;
@@ -145,7 +145,7 @@ namespace mongo {
WriteBatchExecutor writeBatchExecutor(txn,
&globalOpCounters,
- &LastError::get(txn->getClient()));
+ lastError.get());
writeBatchExecutor.executeBatch( request, &response );
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index aed1bf00958..92bb4177c91 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -70,6 +70,7 @@
#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"
@@ -156,7 +157,7 @@ namespace mongo {
Client::initThread("conn", p);
}
- virtual void process(Message& m , AbstractMessagingPort* port) {
+ virtual void process( Message& m , AbstractMessagingPort* port , LastError * le) {
OperationContextImpl txn;
while ( true ) {
if ( inShutdown() ) {
@@ -164,6 +165,8 @@ 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 b9a3c7ef6af..c07dc30a1dc 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) {
- LastError::get(txn->getClient()).setLastError(10038, "forced error");
+ setLastError(10038, "forced error");
return false;
}
} cmdForceError;
diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp
index 3aee1750172..41b75377060 100644
--- a/src/mongo/db/dbdirectclient.cpp
+++ b/src/mongo/db/dbdirectclient.cpp
@@ -33,7 +33,6 @@
#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"
@@ -123,7 +122,9 @@ namespace mongo {
bool assertOk,
string* actualServer) {
DirectClientScope directClientScope(_txn);
- LastError::get(_txn->getClient()).startRequest();
+ if (lastError._get()) {
+ lastError.startRequest(toSend, lastError._get());
+ }
DbResponse dbResponse;
assembleResponse(_txn, toSend, dbResponse, dummyHost);
@@ -138,7 +139,9 @@ namespace mongo {
void DBDirectClient::say(Message& toSend, bool isRetry, string* actualServer) {
DirectClientScope directClientScope(_txn);
- LastError::get(_txn->getClient()).startRequest();
+ if (lastError._get()) {
+ lastError.startRequest(toSend, lastError._get());
+ }
DbResponse dbResponse;
assembleResponse(_txn, toSend, dbResponse, dummyHost);
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index 099492d607a..80bf95116ce 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -389,7 +389,6 @@ 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
@@ -557,14 +556,14 @@ namespace {
}
}
catch (const UserException& ue) {
- LastError::get(c).setLastError(ue.getCode(), ue.getInfo().msg);
+ setLastError(ue.getCode(), ue.getInfo().msg.c_str());
MONGO_LOG_COMPONENT(3, responseComponent)
<< " Caught Assertion in " << opToString(op) << ", continuing "
<< ue.toString() << endl;
debug.exceptionInfo = ue.getInfo();
}
catch (const AssertionException& e) {
- LastError::get(c).setLastError(e.getCode(), e.getInfo().msg);
+ setLastError(e.getCode(), e.getInfo().msg.c_str());
MONGO_LOG_COMPONENT(3, responseComponent)
<< " Caught Assertion in " << opToString(op) << ", continuing "
<< e.toString() << endl;
@@ -605,7 +604,6 @@ namespace {
}
void receivedKillCursors(OperationContext* txn, Message& m) {
- LastError::get(txn->getClient()).disable();
DbMessage dbmessage(m);
int n = dbmessage.pullInt();
@@ -702,8 +700,7 @@ namespace {
UpdateResult res = UpdateStage::makeUpdateResult(exec.get(), &op.debug());
// for getlasterror
- LastError::get(txn->getClient()).recordUpdate(
- res.existing, res.numMatched, res.upserted);
+ lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted );
return;
}
break;
@@ -756,8 +753,7 @@ namespace {
uassertStatusOK(exec->executePlan());
UpdateResult res = UpdateStage::makeUpdateResult(exec.get(), &op.debug());
- LastError::get(txn->getClient()).recordUpdate(
- res.existing, res.numMatched, res.upserted);
+ lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted );
} MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "update", nsString.ns());
}
@@ -815,7 +811,7 @@ namespace {
// Run the plan and get the number of docs deleted.
uassertStatusOK(exec->executePlan());
long long n = DeleteStage::getNumDeleted(exec.get());
- LastError::get(txn->getClient()).recordDelete(n);
+ lastError.getSafe()->recordDelete(n);
op.debug().ndeleted = n;
break;
@@ -1005,7 +1001,7 @@ namespace {
globalOpCounters.incInsertInWriteLock(i);
throw;
}
- LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
+ setLastError(ex.getCode(), ex.getInfo().msg.c_str());
// otherwise ignore and keep going
}
}
@@ -1059,7 +1055,7 @@ namespace {
convertSystemIndexInsertsToCommands(d, &allCmdsBuilder);
}
catch (const DBException& ex) {
- LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
+ setLastError(ex.getCode(), ex.getInfo().msg.c_str());
curOp.debug().exceptionInfo = ex.getInfo();
return;
}
@@ -1081,7 +1077,7 @@ namespace {
uassertStatusOK(Command::getStatusFromCommandResult(resultBuilder.done()));
}
catch (const DBException& ex) {
- LastError::get(txn->getClient()).setLastError(ex.getCode(), ex.getInfo().msg);
+ setLastError(ex.getCode(), ex.getInfo().msg.c_str());
curOp.debug().exceptionInfo = ex.getInfo();
if (!keepGoing) {
return;
diff --git a/src/mongo/db/lasterror.cpp b/src/mongo/db/lasterror.cpp
index d242cdedc1a..d0a22d56b51 100644
--- a/src/mongo/db/lasterror.cpp
+++ b/src/mongo/db/lasterror.cpp
@@ -27,91 +27,139 @@
* 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/assert_util.h"
+#include "mongo/util/debug_util.h"
+#include "mongo/util/log.h"
+#include "mongo/util/net/message.h"
namespace mongo {
- LastError LastError::noError;
-
- const Client::Decoration<LastError> LastError::get = Client::declareDecoration<LastError>();
-
- void LastError::reset(bool valid) {
- *this = LastError();
- _valid = valid;
- }
+ using std::endl;
- void LastError::setLastError(int code, std::string msg) {
- if (_disabled) {
- return;
+ 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);
}
- reset(true);
- _code = code;
- _msg = std::move(msg);
- }
-
- void LastError::recordInsert(long long nObjects) {
- reset(true);
- _nObjects = nObjects;
- }
-
- 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;
- }
-
- void LastError::recordDelete(long long nDeleted) {
- reset(true);
- _nObjects = nDeleted;
}
- bool LastError::appendSelf(BSONObjBuilder &b , bool blankErr) const {
+ bool LastError::appendSelf( BSONObjBuilder &b , bool blankErr ) {
- if (!_valid) {
- if (blankErr)
+ if ( !valid ) {
+ if ( blankErr )
b.appendNull( "err" );
b.append( "n", 0 );
return false;
}
- if (_msg.empty()) {
- if (blankErr) {
+ if ( msg.empty() ) {
+ if ( blankErr ) {
b.appendNull( "err" );
}
}
else {
- b.append("err", _msg);
+ b.append( "err", msg );
}
- if (_code)
- b.append("code" , _code);
- if (_updatedExisting != NotUpdate)
- b.appendBool("updatedExisting", _updatedExisting == True);
- if (!_upsertedId.isEmpty()) {
- b.append(_upsertedId[kUpsertedFieldName]);
+ 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);
+ b.appendNumber( "n", nObjects );
+
+ return ! msg.empty();
+ }
- return !_msg.empty();
+ LastErrorHolder::~LastErrorHolder() {
}
- void LastError::disable() {
- invariant(!_disabled);
- _disabled = true;
- _nPrev--; // caller is a command that shouldn't count as an operation
+ 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;
+ }
+
+ LastError * LastErrorHolder::get( bool create ) {
+ LastError *ret = _get( create );
+ if ( ret && !ret->disabled )
+ return ret;
+ return 0;
+ }
+
+ LastError * LastErrorHolder::getSafe() {
+ LastError * le = get(false);
+ if ( ! le ) {
+ error() << " no LastError!" << std::endl;
+ verify( le );
+ }
+ return le;
+ }
+
+ LastError * LastErrorHolder::_get( bool create ) {
+ LastError * le = _tl.get();
+ if ( ! le && create ) {
+ le = new LastError();
+ _tl.reset( le );
+ }
+ return le;
+ }
+
+ void LastErrorHolder::release() {
+ _tl.release();
+ }
+
+ /** ok to call more than once. */
+ void LastErrorHolder::initThread() {
+ if( ! _tl.get() )
+ _tl.reset( new LastError() );
+ }
+
+ 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::startRequest() {
- _disabled = false;
- ++_nPrev;
+ LastError * LastErrorHolder::startRequest( Message& m , LastError * le ) {
+ verify( le );
+ prepareErrForNewRequest( m, le );
+ return le;
}
} // namespace mongo
diff --git a/src/mongo/db/lasterror.h b/src/mongo/db/lasterror.h
index 55a04c8334d..5b04b69a57a 100644
--- a/src/mongo/db/lasterror.h
+++ b/src/mongo/db/lasterror.h
@@ -29,13 +29,16 @@
#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";
@@ -43,80 +46,107 @@ namespace mongo {
static const char kGLEStatsLastOpTimeTermFieldName[] = "lastOpTimeTerm";
static const char kGLEStatsElectionIdFieldName[] = "electionId";
- class LastError {
- public:
- static const Client::Decoration<LastError> get;
+ 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();
+ }
/**
- * Resets the object to a newly constructed state. If "valid" is true, marks the last-error
- * object as "valid".
+ * @return if there is an err
*/
- void reset(bool valid = false);
+ 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;
+ }
+ }
- /**
- * when db receives a message/request, call this
- */
- void startRequest();
+ ~Disabled() {
+ if ( _le )
+ _le->disabled = _prev;
+ }
- /**
- * Disables error recording for the current operation.
- */
- void disable();
+ LastError * _le;
+ bool _prev;
+ };
- /**
- * 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);
+ static LastError noError;
+ };
- void recordInsert(long long nObjects);
+ extern class LastErrorHolder {
+ public:
+ LastErrorHolder(){}
+ ~LastErrorHolder();
- void recordUpdate(bool updateObjects, long long nObjects, BSONObj upsertedId);
+ LastError * get( bool create = false );
+ LastError * getSafe();
+ LastError * _get( bool create = false ); // may return a disabled LastError
- void recordDelete(long long nDeleted);
+ void reset( LastError * le );
- /**
- * 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;
+ /** ok to call more than once. */
+ void initThread();
- bool isValid() const { return _valid; }
- int const getNPrev() const { return _nPrev; }
+ void release();
- class Disabled {
- public:
- explicit Disabled(LastError* le) : _le(le), _prev(le->_disabled) {
- _le->_disabled = true;
- }
+ /** when db receives a message/request, call this */
+ LastError * startRequest( Message& m , LastError * connectionOwned );
- ~Disabled() {
- _le->_disabled = _prev;
- }
+ // 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;
- private:
- LastError * const _le;
- const bool _prev;
+ struct Status {
+ time_t time;
+ LastError *lerr;
};
+ } lastError;
- 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;
- };
+ void setLastError(int code , const char *msg);
} // namespace mongo
diff --git a/src/mongo/db/ops/update_result.cpp b/src/mongo/db/ops/update_result.cpp
index 64b33243131..f5e31c1a3d8 100644
--- a/src/mongo/db/ops/update_result.cpp
+++ b/src/mongo/db/ops/update_result.cpp
@@ -34,7 +34,6 @@
#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 a5303072fbd..f4cd02426a2 100644
--- a/src/mongo/db/repl/replication_info.cpp
+++ b/src/mongo/db/repl/replication_info.cpp
@@ -37,7 +37,6 @@
#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"
@@ -217,7 +216,7 @@ namespace repl {
authenticated.
*/
if ( cmdObj["forShell"].trueValue() )
- LastError::get(txn->getClient()).disable();
+ lastError.disableForCommand();
appendReplicationInfo(txn, result, 0);
diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp
index e4cc257dcb4..d160351c6b0 100644
--- a/src/mongo/db/repl/replset_commands.cpp
+++ b/src/mongo/db/repl/replset_commands.cpp
@@ -41,7 +41,6 @@
#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"
@@ -151,7 +150,7 @@ namespace repl {
string& errmsg,
BSONObjBuilder& result) {
if ( cmdObj["forShell"].trueValue() )
- LastError::get(txn->getClient()).disable();
+ lastError.disableForCommand();
Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result);
if (!status.isOK())
diff --git a/src/mongo/dbtests/directclienttests.cpp b/src/mongo/dbtests/directclienttests.cpp
index fc076a9f926..822db3b58f4 100644
--- a/src/mongo/dbtests/directclienttests.cpp
+++ b/src/mongo/dbtests/directclienttests.cpp
@@ -33,7 +33,6 @@
#include <iostream>
-#include "mongo/db/client.h"
#include "mongo/db/db.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/json.h"
@@ -50,11 +49,15 @@ namespace DirectClientTests {
class ClientBase {
public:
ClientBase() {
- mongo::LastError::get(cc()).reset();
+ _prevError = mongo::lastError._get( false );
+ mongo::lastError.release();
+ mongo::lastError.reset( new LastError() );
}
virtual ~ClientBase() {
- mongo::LastError::get(cc()).reset();
+ mongo::lastError.reset( _prevError );
}
+ private:
+ LastError* _prevError;
};
const char *ns = "a.b";
diff --git a/src/mongo/dbtests/perftests.cpp b/src/mongo/dbtests/perftests.cpp
index 310ae31e3a1..90c0d74c632 100644
--- a/src/mongo/dbtests/perftests.cpp
+++ b/src/mongo/dbtests/perftests.cpp
@@ -49,7 +49,6 @@
#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"
@@ -92,10 +91,12 @@ namespace PerfTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- mongo::LastError::get(_txn.getClient()).reset();
+ _prevError = mongo::lastError._get( false );
+ mongo::lastError.release();
+ mongo::lastError.reset( new LastError() );
}
virtual ~ClientBase() {
- mongo::LastError::get(_txn.getClient()).reset();
+ mongo::lastError.reset( _prevError );
}
protected:
@@ -113,6 +114,7 @@ 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 5aac0a989e5..bab0f1e22fe 100644
--- a/src/mongo/dbtests/querytests.cpp
+++ b/src/mongo/dbtests/querytests.cpp
@@ -216,11 +216,13 @@ namespace QueryTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- mongo::LastError::get(_txn.getClient()).reset();
+ _prevError = mongo::lastError._get( false );
+ mongo::lastError.release();
+ mongo::lastError.reset( new LastError() );
_txn.getCurOp()->reset();
}
virtual ~ClientBase() {
- mongo::LastError::get(_txn.getClient()).reset();
+ mongo::lastError.reset( _prevError );
}
protected:
@@ -236,6 +238,9 @@ 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 fa7271bcb6b..4d2f527c54a 100644
--- a/src/mongo/dbtests/updatetests.cpp
+++ b/src/mongo/dbtests/updatetests.cpp
@@ -54,10 +54,12 @@ namespace UpdateTests {
class ClientBase {
public:
ClientBase() : _client(&_txn) {
- mongo::LastError::get(_txn.getClient()).reset();
+ _prevError = mongo::lastError._get( false );
+ mongo::lastError.release();
+ mongo::lastError.reset( new LastError() );
}
virtual ~ClientBase() {
- mongo::LastError::get(_txn.getClient()).reset();
+ mongo::lastError.reset( _prevError );
}
protected:
@@ -73,6 +75,9 @@ 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 a95ef130618..74bd0e54fc7 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -174,9 +174,8 @@ env.Library(
],
LIBDEPS=[
'$BUILD_DIR/mongo/bson',
- '$BUILD_DIR/mongo/db/common', # for Message
- '$BUILD_DIR/mongo/lasterror',
'cluster_ops',
+ '$BUILD_DIR/mongo/db/common', # for Message
],
)
diff --git a/src/mongo/s/chunk.cpp b/src/mongo/s/chunk.cpp
index 8fe331f9c26..b62a0da7512 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(cc()));
+ LastError::Disabled d( lastError.get() );
try {
_dataWritten += dataWritten;
diff --git a/src/mongo/s/client/shard_connection.cpp b/src/mongo/s/client/shard_connection.cpp
index 6f059b485fa..abce4b04db2 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(cc()));
+ LastError::Disabled ignoreForGLE(lastError.get(false));
// 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 a703d705b6d..2ee08b3aab9 100644
--- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
+++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp
@@ -88,13 +88,12 @@ namespace {
// about 2.4 behavior?
//
- LastError *le = &LastError::get(cc());
- le->disable();
-
+ LastError *le = lastError.disableForCommand();
+ invariant(le);
// Write commands always have the error stored in the mongos last error
bool errorOccurred = false;
- if (le->getNPrev() == 1) {
+ if (le->nPrev == 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 0164fe3cc15..bacb5da705e 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::get(cc()).disable();
+ lastError.disableForCommand();
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 8bc2af039f3..182daedaa66 100644
--- a/src/mongo/s/commands/cluster_reset_error_cmd.cpp
+++ b/src/mongo/s/commands/cluster_reset_error_cmd.cpp
@@ -66,7 +66,10 @@ namespace {
std::string& errmsg,
BSONObjBuilder& result) {
- LastError::get(cc()).reset();
+ LastError* le = lastError.get();
+ if (le) {
+ le->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 83a039a3f3b..925a944eb4d 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()) {
- LastError::get(client).setLastError(status.code(), status.reason());
+ setLastError(status.code(), status.reason().c_str());
}
return status;
@@ -149,7 +149,8 @@ namespace {
ClusterWriter writer(true, 0);
- LastError* cmdLastError = &LastError::get(cc());
+ // NOTE: Sometimes this command is invoked with LE disabled for legacy writes
+ LastError* cmdLastError = lastError.get(false);
{
// Disable the last error object for the duration of the write
@@ -173,9 +174,11 @@ namespace {
dassert(response.isValid(NULL));
}
- // Populate the lastError object based on the write response
- cmdLastError->reset();
- batchErrorToLastError(request, response, cmdLastError);
+ if (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 43600e9eca8..e8dd8e60d44 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(cc()));
+ LastError::Disabled ignoreForGLE(lastError.get(false));
try{
return getChunkManager( ns, shouldReload, forceReload );
diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp
index e7e623eeed9..dd339627668 100644
--- a/src/mongo/s/cursors.cpp
+++ b/src/mongo/s/cursors.cpp
@@ -46,7 +46,6 @@
#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"
@@ -368,7 +367,6 @@ 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 de29c5908e5..09197770db1 100644
--- a/src/mongo/s/d_state.cpp
+++ b/src/mongo/s/d_state.cpp
@@ -48,7 +48,6 @@
#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"
@@ -1029,7 +1028,7 @@ namespace mongo {
// step 1
- LastError::get(txn->getClient()).disable();
+ lastError.disableForCommand();
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 5c231d507c9..8c8b40dc608 100644
--- a/src/mongo/s/request.cpp
+++ b/src/mongo/s/request.cpp
@@ -37,7 +37,6 @@
#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"
@@ -68,7 +67,6 @@ 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 4c51e534d7d..f2f21915b5b 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -141,10 +141,13 @@ namespace mongo {
Client::initThread("conn", getGlobalServiceContext(), p);
}
- virtual void process(Message& m, AbstractMessagingPort* p) {
+ virtual void process( Message& m , AbstractMessagingPort* p , LastError * le) {
verify( p );
Request r( m , p );
+ verify( le );
+ lastError.startRequest( m , le );
+
try {
r.init();
r.process();
@@ -161,7 +164,7 @@ namespace mongo {
}
// We *always* populate the last error for now
- LastError::get(cc()).setLastError(ex.getCode(), ex.what());
+ le->raiseError( ex.getCode() , ex.what() );
}
catch ( const DBException& ex ) {
@@ -175,7 +178,7 @@ namespace mongo {
}
// We *always* populate the last error for now
- LastError::get(cc()).setLastError(ex.getCode(), ex.what());
+ le->raiseError( 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 887595836ee..acffa2e79e1 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(cc()));
+ dassert( lastError.get( false /* don't create */) );
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::get(cc()).startRequest();
+ lastError.startRequest( r.m(), lastError.get( false ) );
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(cc()));
+ LastError::Disabled disableLastError( lastError.get( false ) );
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(cc()).reset();
- bool hadError = batchErrorToLastError(*request, response, &LastError::get(cc()));
+ lastError.get( false )->reset();
+ bool hadError = batchErrorToLastError( *request, response, lastError.get( false ) );
// 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 e81d35ea9db..3df74fd614f 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->setLastError(lastBatchError->getErrCode(),
- errMsg.empty() ? "see code for details" : errMsg.c_str());
+ error->raiseError( lastBatchError->getErrCode(),
+ errMsg.empty() ? "see code for details" : errMsg.c_str() );
return true;
}
diff --git a/src/mongo/s/write_ops/batch_upconvert_test.cpp b/src/mongo/s/write_ops/batch_upconvert_test.cpp
index c802411c9e5..12c60982da1 100644
--- a/src/mongo/s/write_ops/batch_upconvert_test.cpp
+++ b/src/mongo/s/write_ops/batch_upconvert_test.cpp
@@ -25,7 +25,6 @@
* 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/write_ops/batch_upconvert.h"
diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp
index ceafa7375b5..8abfcecbc9f 100644
--- a/src/mongo/shell/dbshell.cpp
+++ b/src/mongo/shell/dbshell.cpp
@@ -424,6 +424,10 @@ 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 );
@@ -584,6 +588,7 @@ 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 7bb9759eeff..66bdec58ad7 100644
--- a/src/mongo/util/net/message_server.h
+++ b/src/mongo/util/net/message_server.h
@@ -38,6 +38,8 @@
namespace mongo {
+ struct LastError;
+
class MessageHandler {
public:
virtual ~MessageHandler() {}
@@ -51,7 +53,7 @@ namespace mongo {
* called every time a message comes in
* handler is responsible for responding to client
*/
- virtual void process(Message& m, AbstractMessagingPort* p) = 0;
+ virtual void process( Message& m , AbstractMessagingPort* p , LastError * err ) = 0;
};
class MessageServer {
diff --git a/src/mongo/util/net/message_server_port.cpp b/src/mongo/util/net/message_server_port.cpp
index 682a7361ede..8db034fbe6e 100644
--- a/src/mongo/util/net/message_server_port.cpp
+++ b/src/mongo/util/net/message_server_port.cpp
@@ -207,6 +207,9 @@ 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() ) {
@@ -224,7 +227,7 @@ namespace {
break;
}
- handler->process(m, portWithHandler.get());
+ handler->process(m, portWithHandler.get(), le);
networkCounter.hit(portWithHandler->psock->getBytesIn(),
portWithHandler->psock->getBytesOut());