0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-28 07:59:02 +01:00

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.
This commit is contained in:
Andy Schwerin 2015-04-20 18:51:35 -04:00
parent bdbe140e3c
commit da31be34dc
42 changed files with 231 additions and 323 deletions

View File

@ -15,6 +15,7 @@ function aggregateNoOrder(coll, pipeline) {
return coll.aggregate(pipeline).toArray();
}
jsTestLog("Creating sharded cluster");
var shardedAggTest = new ShardingTest({
shards: 2,
verbose: 2,
@ -23,8 +24,10 @@ var shardedAggTest = new ShardingTest({
}
);
jsTestLog("Setting up sharded cluster");
shardedAggTest.adminCommand( { enablesharding : "aggShard" } );
db = shardedAggTest.getDB( "aggShard" );
assert.commandWorked(db.adminCommand({setParameter: 1, logComponentVerbosity: { network: 0 }}));
/* make sure its cleaned up */
db.ts1.drop();
@ -69,6 +72,7 @@ var strings = [
"twenty"
];
jsTestLog("Bulk inserting data");
var nItems = 200000;
var bulk = db.ts1.initializeUnorderedBulkOp();
for(i = 1; i <= nItems; ++i) {
@ -89,7 +93,7 @@ for ( var i = 0; i < shards.length; i++ ) {
printjson(shardConn.getDB( "admin" ).runCommand({ setParameter : 1, traceExceptions : true }));
}
// a project and group in shards, result combined in mongos
jsTestLog('a project and group in shards, result combined in mongos');
var a1 = aggregateNoOrder(db.ts1, [
{ $project: {
cMod10: {$mod:["$counter", 10]},
@ -111,7 +115,7 @@ for(i = 0 ; i < 10; ++i) {
'agg sharded test numberSet length failed');
}
// an initial group starts the group in the shards, and combines them in mongos
jsTestLog('an initial group starts the group in the shards, and combines them in mongos');
var a2 = aggregateOrdered(db.ts1 , [
{ $group: {
_id: "all",
@ -119,11 +123,11 @@ var a2 = aggregateOrdered(db.ts1 , [
}}
]);
// sum of an arithmetic progression S(n) = (n/2)(a(1) + a(n));
jsTestLog('sum of an arithmetic progression S(n) = (n/2)(a(1) + a(n));');
assert.eq(a2[0].total, (nItems/2)*(1 + nItems),
'agg sharded test counter sum failed');
// an initial group starts the group in the shards, and combines them in mongos
jsTestLog('an initial group starts the group in the shards, and combines them in mongos');
var a3 = aggregateOrdered(db.ts1, [
{ $group: {
_id: "$number",
@ -137,7 +141,7 @@ for(i = 0 ; i < strings.length; ++i) {
'agg sharded test sum numbers failed');
}
// a match takes place in the shards; just returning the results from mongos
jsTestLog('a match takes place in the shards; just returning the results from mongos');
var a4 = aggregateNoOrder(db.ts1, [
{ $match: {$or:[{counter:55}, {counter:1111},
{counter: 2222}, {counter: 33333},
@ -155,6 +159,7 @@ for(i = 0; i < 6; ++i) {
}
function testSkipLimit(ops, expectedCount) {
jsTestLog('testSkipLimit(' + tojson(ops) + ', ' + expectedCount + ')');
if (expectedCount > 10) {
// make shard -> mongos intermediate results less than 16MB
ops.unshift({$project: {_id:1}})
@ -177,6 +182,7 @@ testSkipLimit([{$limit:10}, {$skip:5}, {$skip: 3}], 10 - 3 - 5);
// test sort + limit (using random to pull from both shards)
function testSortLimit(limit, direction) {
jsTestLog('testSortLimit(' + limit + ', ' + direction + ')');
shardedAggTest.stopBalancer(); // TODO: remove after fixing SERVER-9622
var from_cursor = db.ts1.find({},{random:1, _id:0})
.sort({random: direction})
@ -196,7 +202,7 @@ testSortLimit(10, -1);
testSortLimit(100, 1);
testSortLimit(100, -1);
// test $out by copying source collection verbatim to output
jsTestLog('test $out by copying source collection verbatim to output');
var outCollection = db.ts1_out;
var res = aggregateOrdered(db.ts1, [{$out: outCollection.getName()}]);
shardedAggTest.stopBalancer(); // TODO: remove after fixing SERVER-9622
@ -215,7 +221,8 @@ result = aggregateOrdered(db.literal,
assert.eq([{cost:'$.99'}], result);
// Do a basic sharded explain. This just makes sure that it doesn't error and has the right fields.
jsTestLog("Do a basic sharded explain. This just makes sure that it doesn't error and has " +
"the right fields.");
var res = db.ts1.aggregate([{$project: {a: 1}}], {explain:true});
assert.commandWorked(res);
printjson(res);
@ -231,8 +238,10 @@ for (var shardName in res.shards) {
// Call sub-tests designed to work sharded and unsharded.
// They check for this variable to know to shard their collections.
RUNNING_IN_SHARDED_AGG_TEST = true; // global
jsTestLog('running jstests/aggregation/bugs/server9444.js');
load("jstests/aggregation/bugs/server9444.js"); // external sort
jsTestLog('running jstests/aggregation/bugs/server11675.js');
load("jstests/aggregation/bugs/server11675.js"); // text support
// shut everything down
jsTestLog('shut everything down');
shardedAggTest.stop();

View File

@ -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.

View File

@ -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();
}
};

View File

@ -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);

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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.

View File

@ -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 );

View File

@ -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());

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);
}
const Client::Decoration<LastError> LastError::get = Client::declareDecoration<LastError>();
void LastError::reset(bool valid) {
*this = LastError();
_valid = valid;
}
bool LastError::appendSelf( BSONObjBuilder &b , bool blankErr ) {
void LastError::setLastError(int code, std::string msg) {
if (_disabled) {
return;
}
reset(true);
_code = code;
_msg = std::move(msg);
}
if ( !valid ) {
if ( blankErr )
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 {
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();
}
LastErrorHolder::~LastErrorHolder() {
return !_msg.empty();
}
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::disable() {
invariant(!_disabled);
_disabled = true;
_nPrev--; // caller is a command that shouldn't count as an operation
}
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++;
}
}
LastError * LastErrorHolder::startRequest( Message& m , LastError * le ) {
verify( le );
prepareErrForNewRequest( m, le );
return le;
void LastError::startRequest() {
_disabled = false;
++_nPrev;
}
} // namespace mongo

View File

@ -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 );
void reset(bool valid = false);
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();
/**
* Disables error recording for the current operation.
*/
void disable();
/**
* 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);
void recordInsert(long long nObjects);
void recordUpdate(bool updateObjects, long long nObjects, BSONObj upsertedId);
void recordDelete(long long nDeleted);
/**
* Writes the last-error state described by this object to "b".
*
* If "blankErr" is true, the "err" field will be explicitly set to null in the result
* instead of being omitted when the error string is empty.
*
* Returns true if there is a non-empty error message.
*/
bool appendSelf(BSONObjBuilder &b, bool blankErr) const;
bool isValid() const { return _valid; }
int const getNPrev() const { return _nPrev; }
class Disabled {
public:
explicit Disabled(LastError* le) : _le(le), _prev(le->_disabled) {
_le->_disabled = true;
}
~Disabled() {
if ( _le )
_le->disabled = _prev;
_le->_disabled = _prev;
}
LastError * _le;
bool _prev;
private:
LastError * const _le;
const bool _prev;
};
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;
};
extern class LastErrorHolder {
public:
LastErrorHolder(){}
~LastErrorHolder();
LastError * get( bool create = false );
LastError * getSafe();
LastError * _get( bool create = false ); // may return a disabled LastError
void reset( LastError * le );
/** ok to call more than once. */
void initThread();
void release();
/** when db receives a message/request, call this */
LastError * startRequest( Message& m , LastError * connectionOwned );
// 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;
struct Status {
time_t time;
LastError *lerr;
};
} lastError;
void setLastError(int code , const char *msg);
} // namespace mongo

View File

@ -34,6 +34,7 @@
#include "mongo/db/ops/update_result.h"
#include "mongo/db/lasterror.h"
#include "mongo/util/log.h"
namespace mongo {

View File

@ -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);

View File

@ -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())

View File

@ -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";

View File

@ -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;
};

View File

@ -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 {

View File

@ -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 {

View File

@ -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',
],
)

View File

@ -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() ) {

View File

@ -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;

View File

@ -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++ ) {

View File

@ -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);
}

View File

@ -72,7 +72,7 @@ namespace {
BSONObjBuilder& result) {
if (cmdObj["forShell"].trueValue()) {
lastError.disableForCommand();
LastError::get(cc()).disable();
ClusterLastErrorInfo::get(cc()).disableForCommand();
}

View File

@ -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();

View File

@ -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;

View File

@ -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 );

View File

@ -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();

View File

@ -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" );

View File

@ -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()) {

View File

@ -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

View File

@ -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<BatchedCommandRequest> requestsOwned;
vector<BatchedCommandRequest*>& 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 )

View File

@ -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;
}

View File

@ -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"

View File

@ -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();

View File

@ -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 {

View File

@ -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());