2009-03-26 13:45:29 -04:00
|
|
|
// lasterror.cpp
|
|
|
|
|
|
2009-10-27 15:58:27 -04:00
|
|
|
/* Copyright 2009 10gen Inc.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-04-27 15:27:52 -04:00
|
|
|
#include "pch.h"
|
2009-03-26 13:45:29 -04:00
|
|
|
|
2009-09-11 11:56:57 -04:00
|
|
|
#include "../util/unittest.h"
|
2009-09-11 12:52:17 -04:00
|
|
|
#include "../util/message.h"
|
|
|
|
|
|
2009-03-26 13:45:29 -04:00
|
|
|
|
2009-09-11 11:56:57 -04:00
|
|
|
#include "lasterror.h"
|
2009-03-26 13:45:29 -04:00
|
|
|
#include "jsobj.h"
|
|
|
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
|
|
|
|
|
LastError LastError::noError;
|
2009-09-11 11:56:57 -04:00
|
|
|
LastErrorHolder lastError;
|
2010-05-26 00:46:49 -04:00
|
|
|
mongo::mutex LastErrorHolder::_idsmutex("LastErrorHolder");
|
2009-10-12 15:12:16 -04:00
|
|
|
|
2010-06-11 08:48:18 -04:00
|
|
|
bool isShell = false;
|
|
|
|
|
void raiseError(int code , const char *msg) {
|
|
|
|
|
LastError *le = lastError.get();
|
|
|
|
|
if ( le == 0 ) {
|
|
|
|
|
/* might be intentional (non-user thread) */
|
2010-07-28 20:24:21 -04:00
|
|
|
OCCASIONALLY DEV if( !isShell ) log() << "warning dev: lastError==0 won't report:" << msg << endl;
|
2010-06-11 08:48:18 -04:00
|
|
|
} else if ( le->disabled ) {
|
2010-08-02 15:17:24 -04:00
|
|
|
log() << "lastError disabled, can't report: " << code << ":" << msg << endl;
|
2010-06-11 08:48:18 -04:00
|
|
|
} else {
|
|
|
|
|
le->raiseError(code, msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-03-26 13:45:29 -04:00
|
|
|
void LastError::appendSelf( BSONObjBuilder &b ) {
|
|
|
|
|
if ( !valid ) {
|
|
|
|
|
b.appendNull( "err" );
|
|
|
|
|
b.append( "n", 0 );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ( msg.empty() )
|
|
|
|
|
b.appendNull( "err" );
|
|
|
|
|
else
|
|
|
|
|
b.append( "err", msg );
|
2009-12-28 17:12:49 -05:00
|
|
|
if ( code )
|
|
|
|
|
b.append( "code" , code );
|
2009-03-26 13:45:29 -04:00
|
|
|
if ( updatedExisting != NotUpdate )
|
|
|
|
|
b.appendBool( "updatedExisting", updatedExisting == True );
|
2010-06-24 11:24:54 -04:00
|
|
|
if ( upsertedId.isSet() )
|
|
|
|
|
b.append( "upserted" , upsertedId );
|
2010-07-22 13:52:42 -04:00
|
|
|
if ( writebackId.isSet() )
|
|
|
|
|
b.append( "writeback" , writebackId );
|
2010-04-27 15:58:45 -04:00
|
|
|
b.appendNumber( "n", nObjects );
|
2009-03-26 13:45:29 -04:00
|
|
|
}
|
2009-09-11 11:56:57 -04:00
|
|
|
|
|
|
|
|
void LastErrorHolder::setID( int id ){
|
2009-10-13 12:55:23 -04:00
|
|
|
_id.set( id );
|
2009-09-11 11:56:57 -04:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 12:52:17 -04:00
|
|
|
int LastErrorHolder::getID(){
|
|
|
|
|
return _id.get();
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-12 15:33:29 -08:00
|
|
|
LastError * LastErrorHolder::disableForCommand() {
|
2010-01-12 16:56:29 -08:00
|
|
|
LastError *le = _get();
|
2010-01-12 15:33:29 -08:00
|
|
|
assert( le );
|
2010-01-12 16:56:29 -08:00
|
|
|
le->disabled = true;
|
2010-01-12 15:33:29 -08:00
|
|
|
le->nPrev--; // caller is a command that shouldn't count as an operation
|
|
|
|
|
return le;
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-12 16:56:29 -08:00
|
|
|
LastError * LastErrorHolder::get( bool create ) {
|
|
|
|
|
LastError *ret = _get( create );
|
|
|
|
|
if ( ret && !ret->disabled )
|
|
|
|
|
return ret;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LastError * LastErrorHolder::_get( bool create ){
|
2009-09-11 11:56:57 -04:00
|
|
|
int id = _id.get();
|
2010-03-28 17:15:27 -04:00
|
|
|
if ( id == 0 ){
|
|
|
|
|
LastError * le = _tl.get();
|
|
|
|
|
if ( ! le && create ){
|
|
|
|
|
le = new LastError();
|
|
|
|
|
_tl.reset( le );
|
|
|
|
|
}
|
|
|
|
|
return le;
|
|
|
|
|
}
|
2010-01-15 15:57:57 -05:00
|
|
|
|
2010-03-15 09:42:01 -07:00
|
|
|
scoped_lock lock(_idsmutex);
|
2009-10-12 15:12:16 -04:00
|
|
|
map<int,Status>::iterator i = _ids.find( id );
|
2009-09-11 12:52:17 -04:00
|
|
|
if ( i == _ids.end() ){
|
|
|
|
|
if ( ! create )
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
LastError * le = new LastError();
|
2009-10-12 15:12:16 -04:00
|
|
|
Status s;
|
|
|
|
|
s.time = time(0);
|
|
|
|
|
s.lerr = le;
|
|
|
|
|
_ids[id] = s;
|
2009-09-11 12:52:17 -04:00
|
|
|
return le;
|
|
|
|
|
}
|
2009-09-11 11:56:57 -04:00
|
|
|
|
2009-10-12 15:12:16 -04:00
|
|
|
Status &status = i->second;
|
|
|
|
|
status.time = time(0);
|
|
|
|
|
return status.lerr;
|
2009-09-11 11:56:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LastErrorHolder::remove( int id ){
|
2010-03-15 09:42:01 -07:00
|
|
|
scoped_lock lock(_idsmutex);
|
2009-10-12 15:12:16 -04:00
|
|
|
map<int,Status>::iterator i = _ids.find( id );
|
2009-09-11 11:56:57 -04:00
|
|
|
if ( i == _ids.end() )
|
|
|
|
|
return;
|
|
|
|
|
|
2009-10-12 15:12:16 -04:00
|
|
|
delete i->second.lerr;
|
2009-09-11 11:56:57 -04:00
|
|
|
_ids.erase( i );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LastErrorHolder::release(){
|
|
|
|
|
int id = _id.get();
|
|
|
|
|
if ( id == 0 ){
|
|
|
|
|
_tl.release();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remove( id );
|
|
|
|
|
}
|
2010-05-18 14:47:11 -04:00
|
|
|
|
|
|
|
|
/** ok to call more than once. */
|
|
|
|
|
void LastErrorHolder::initThread() {
|
|
|
|
|
if( _tl.get() ) return;
|
|
|
|
|
assert( _id.get() == 0 );
|
|
|
|
|
_tl.reset( new LastError() );
|
|
|
|
|
}
|
2009-03-26 13:45:29 -04:00
|
|
|
|
2009-09-11 11:56:57 -04:00
|
|
|
void LastErrorHolder::reset( LastError * le ){
|
|
|
|
|
int id = _id.get();
|
|
|
|
|
if ( id == 0 ){
|
|
|
|
|
_tl.reset( le );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-01-15 15:57:57 -05:00
|
|
|
|
2010-03-15 09:42:01 -07:00
|
|
|
scoped_lock lock(_idsmutex);
|
2009-10-12 15:12:16 -04:00
|
|
|
Status & status = _ids[id];
|
|
|
|
|
status.time = time(0);
|
|
|
|
|
status.lerr = le;
|
2009-09-11 11:56:57 -04:00
|
|
|
}
|
2010-04-28 15:39:52 -04:00
|
|
|
|
2010-01-12 16:56:29 -08:00
|
|
|
void prepareErrForNewRequest( Message &m, LastError * err ) {
|
|
|
|
|
// a killCursors message shouldn't affect last error
|
2010-05-12 15:26:00 -07:00
|
|
|
if ( m.operation() == dbKillCursors ) {
|
2010-01-12 16:56:29 -08:00
|
|
|
err->disabled = true;
|
|
|
|
|
} else {
|
|
|
|
|
err->disabled = false;
|
|
|
|
|
err->nPrev++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-11 12:52:17 -04:00
|
|
|
|
2010-04-28 15:39:52 -04:00
|
|
|
LastError * LastErrorHolder::startRequest( Message& m , int clientId ) {
|
2010-08-17 17:01:33 -04:00
|
|
|
assert( clientId );
|
2010-04-28 15:39:52 -04:00
|
|
|
setID( clientId );
|
|
|
|
|
|
2010-01-12 16:56:29 -08:00
|
|
|
LastError * le = _get( true );
|
|
|
|
|
prepareErrForNewRequest( m, le );
|
2010-04-28 15:39:52 -04:00
|
|
|
return le;
|
2009-09-11 12:52:17 -04:00
|
|
|
}
|
|
|
|
|
|
2009-10-12 15:12:16 -04:00
|
|
|
void LastErrorHolder::startRequest( Message& m , LastError * connectionOwned ) {
|
2010-08-17 17:01:33 -04:00
|
|
|
prepareErrForNewRequest( m, connectionOwned );
|
2009-10-12 15:12:16 -04:00
|
|
|
}
|
2009-09-11 11:56:57 -04:00
|
|
|
|
2010-05-28 17:07:18 -04:00
|
|
|
void LastErrorHolder::disconnect( int clientId ){
|
2010-07-26 22:55:56 -04:00
|
|
|
if ( clientId )
|
|
|
|
|
remove(clientId);
|
2010-05-28 17:07:18 -04:00
|
|
|
}
|
|
|
|
|
|
2009-09-11 11:56:57 -04:00
|
|
|
struct LastErrorHolderTest : public UnitTest {
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
void test( int i ){
|
2009-10-13 12:55:23 -04:00
|
|
|
_tl.set( i );
|
2009-09-11 11:56:57 -04:00
|
|
|
assert( _tl.get() == i );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tlmaptest(){
|
|
|
|
|
test( 1 );
|
|
|
|
|
test( 12123123 );
|
|
|
|
|
test( -123123 );
|
|
|
|
|
test( numeric_limits<int>::min() );
|
|
|
|
|
test( numeric_limits<int>::max() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void run(){
|
|
|
|
|
tlmaptest();
|
|
|
|
|
|
|
|
|
|
LastError * a = new LastError();
|
|
|
|
|
LastError * b = new LastError();
|
|
|
|
|
|
|
|
|
|
LastErrorHolder holder;
|
|
|
|
|
holder.reset( a );
|
|
|
|
|
assert( a == holder.get() );
|
|
|
|
|
holder.setID( 1 );
|
|
|
|
|
assert( 0 == holder.get() );
|
|
|
|
|
holder.reset( b );
|
|
|
|
|
assert( b == holder.get() );
|
|
|
|
|
holder.setID( 0 );
|
|
|
|
|
assert( a == holder.get() );
|
|
|
|
|
|
|
|
|
|
holder.remove( 1 );
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-13 12:55:23 -04:00
|
|
|
ThreadLocalValue<int> _tl;
|
2009-09-11 11:56:57 -04:00
|
|
|
} lastErrorHolderTest;
|
|
|
|
|
|
2009-03-26 13:45:29 -04:00
|
|
|
} // namespace mongo
|