From da31be34dc6664d76868543e9ccdaecad4f504c6 Mon Sep 17 00:00:00 2001 From: Andy Schwerin Date: Mon, 20 Apr 2015 18:51:35 -0400 Subject: SERVER-18131 Clean up LastError. Makes LastError a decoration on Client. Removes behavior that was specific to the dbKillCursors wire protocol message into the processing for that message, and out of last error. Simplifies lifetime of LastError. It always exists on Clients, so there's no checking for its existence, and no passing it around through parts of the networking library. --- src/mongo/SConscript | 8 +- src/mongo/client/scoped_db_conn_test.cpp | 4 +- src/mongo/db/client.cpp | 1 - src/mongo/db/client.h | 1 - src/mongo/db/commands/find_and_modify.cpp | 1 + src/mongo/db/commands/get_last_error.cpp | 22 +-- .../db/commands/write_commands/batch_executor.cpp | 10 +- .../db/commands/write_commands/batch_executor.h | 5 +- .../db/commands/write_commands/write_commands.cpp | 4 +- src/mongo/db/db.cpp | 5 +- src/mongo/db/dbcommands_generic.cpp | 2 +- src/mongo/db/dbdirectclient.cpp | 9 +- src/mongo/db/instance.cpp | 20 +-- src/mongo/db/lasterror.cpp | 156 +++++++-------------- src/mongo/db/lasterror.h | 150 ++++++++------------ src/mongo/db/ops/update_result.cpp | 1 + src/mongo/db/repl/replication_info.cpp | 3 +- src/mongo/db/repl/replset_commands.cpp | 3 +- src/mongo/dbtests/directclienttests.cpp | 9 +- src/mongo/dbtests/perftests.cpp | 8 +- src/mongo/dbtests/querytests.cpp | 9 +- src/mongo/dbtests/updatetests.cpp | 9 +- src/mongo/s/SConscript | 3 +- src/mongo/s/balance.cpp | 2 + src/mongo/s/chunk.cpp | 2 +- src/mongo/s/client/shard_connection.cpp | 2 +- .../s/commands/cluster_get_last_error_cmd.cpp | 7 +- .../s/commands/cluster_repl_set_get_status_cmd.cpp | 2 +- src/mongo/s/commands/cluster_reset_error_cmd.cpp | 5 +- src/mongo/s/commands/cluster_write_cmd.cpp | 13 +- src/mongo/s/config.cpp | 2 +- src/mongo/s/cursors.cpp | 2 + src/mongo/s/d_state.cpp | 3 +- src/mongo/s/request.cpp | 2 + src/mongo/s/server.cpp | 9 +- src/mongo/s/strategy.cpp | 10 +- src/mongo/s/write_ops/batch_upconvert.cpp | 4 +- src/mongo/s/write_ops/batch_upconvert_test.cpp | 1 + src/mongo/shell/dbshell.cpp | 5 - src/mongo/util/net/message_server.h | 4 +- src/mongo/util/net/message_server_port.cpp | 5 +- 41 files changed, 211 insertions(+), 312 deletions(-) (limited to 'src/mongo') diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 1804251f3aa..8f54fddfdc5 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -156,8 +156,9 @@ env.Library( env.Library('lasterror', [ "db/lasterror.cpp", ], - LIBDEPS=['util/net/network', - 'util/foundation', + LIBDEPS=[ + 'service_context', + 'util/foundation', ]) def getSysInfo(): @@ -508,8 +509,9 @@ env.Library( 'db/service_context_noop.cpp', ], LIBDEPS=[ - 'lasterror', # TODO(schwerin): REMOVE! + 'util/concurrency/spin_lock', 'util/decorable', + 'util/net/hostandport', ]) # Memory-mapped files support. Used by mongod and some tools. 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 #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 e94771683c2..7de1b1ff966 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* 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..e01790b0b73 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(cc()).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 c39978787f8..2a5bc8eb4e9 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -391,6 +391,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 @@ -558,14 +559,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; @@ -606,6 +607,7 @@ namespace { } void receivedKillCursors(OperationContext* txn, Message& m) { + LastError::get(txn->getClient()).disable(); DbMessage dbmessage(m); int n = dbmessage.pullInt(); @@ -702,7 +704,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; @@ -755,7 +758,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()); } @@ -813,7 +817,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; @@ -1003,7 +1007,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 } } @@ -1057,7 +1061,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; } @@ -1079,7 +1083,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::get = Client::declareDecoration(); - 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 -#include #include +#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 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 _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 bedbf59a05a..342ee8e514b 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" @@ -152,7 +153,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 +#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 #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 aa3583ddb4a..2051f239ad7 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -169,8 +169,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/balance.cpp b/src/mongo/s/balance.cpp index 6e52b7e1346..a42738e512d 100644 --- a/src/mongo/s/balance.cpp +++ b/src/mongo/s/balance.cpp @@ -37,6 +37,7 @@ #include "mongo/base/owned_pointer_map.h" #include "mongo/client/connpool.h" #include "mongo/client/dbclientcursor.h" +#include "mongo/db/client.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" #include "mongo/db/server_options.h" @@ -496,6 +497,7 @@ namespace mongo { void Balancer::run() { + Client::initThread("Balancer"); // this is the body of a BackgroundJob so if we throw here we're basically ending the balancer thread prematurely while ( ! inShutdown() ) { 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 b4bda6824c2..f27041c7167 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; idisable(); + // 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* 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 bd9c633b126..c5d4742095e 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 c409aad00d9..23dac9ad504 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 f76fec271b6..f3de417fc2e 100644 --- a/src/mongo/s/server.cpp +++ b/src/mongo/s/server.cpp @@ -142,13 +142,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(); @@ -165,7 +162,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 ) { @@ -179,7 +176,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 fb1aaa32faa..87eccbe14f9 100644 --- a/src/mongo/s/strategy.cpp +++ b/src/mongo/s/strategy.cpp @@ -654,7 +654,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 requestsOwned; vector& requests = requestsOwned.mutableVector(); @@ -666,7 +666,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; @@ -681,7 +681,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 ); } @@ -691,8 +691,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/s/write_ops/batch_upconvert_test.cpp b/src/mongo/s/write_ops/batch_upconvert_test.cpp index 12c60982da1..c802411c9e5 100644 --- a/src/mongo/s/write_ops/batch_upconvert_test.cpp +++ b/src/mongo/s/write_ops/batch_upconvert_test.cpp @@ -25,6 +25,7 @@ * 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 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()); -- cgit v1.2.1