2008-12-28 20:28:49 -05:00
// dbcommands.cpp
2008-10-29 16:48:03 -05:00
2008-10-22 16:56:39 -04:00
/**
2008-12-28 20:28:49 -05:00
*
2008-10-22 16:56:39 -04:00
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License , version 3 ,
* as published by the Free Software Foundation .
2008-12-28 20:28:49 -05:00
*
2008-10-22 16:56:39 -04:00
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
2008-12-28 20:28:49 -05:00
*
2008-10-22 16:56:39 -04:00
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2010-04-27 15:27:52 -04:00
# include "pch.h"
2008-10-22 16:56:39 -04:00
# include "query.h"
# include "pdfile.h"
# include "jsobj.h"
2010-04-24 18:25:58 -04:00
# include "../bson/util/builder.h"
2008-10-22 16:56:39 -04:00
# include <time.h>
# include "introspect.h"
# include "btree.h"
# include "../util/lruishmap.h"
2009-02-11 10:37:27 -05:00
# include "../util/md5.hpp"
2009-02-20 09:34:25 -05:00
# include "../util/processinfo.h"
2008-10-22 16:56:39 -04:00
# include "json.h"
# include "repl.h"
2010-04-13 11:45:01 -04:00
# include "repl_block.h"
2010-04-21 18:46:31 -04:00
# include "replpair.h"
2008-10-22 16:56:39 -04:00
# include "commands.h"
2008-12-05 16:45:10 -05:00
# include "db.h"
2008-12-29 14:07:21 -05:00
# include "instance.h"
2009-01-05 15:30:07 -05:00
# include "lasterror.h"
2009-01-18 20:31:33 -05:00
# include "security.h"
2009-04-30 16:25:36 -04:00
# include "queryoptimizer.h"
2009-08-19 11:51:16 -04:00
# include "../scripting/engine.h"
2010-02-01 10:38:00 -05:00
# include "stats/counters.h"
2010-01-22 15:17:03 -05:00
# include "background.h"
2010-05-28 12:08:36 -04:00
# include "../util/version.h"
2010-09-22 11:58:55 -04:00
# include "../s/d_writeback.h"
2010-12-27 11:29:16 -05:00
# include "dur_stats.h"
2008-10-22 16:56:39 -04:00
2009-01-14 17:09:51 -05:00
namespace mongo {
2009-01-15 10:17:11 -05:00
extern int otherTraceLevel ;
2010-09-21 00:23:33 -04:00
void flushDiagLog ( ) ;
2009-01-15 10:17:11 -05:00
/* reset any errors so that getlasterror comes back clean.
useful before performing a long series of operations where we want to
see if any of the operations triggered an error , but don ' t want to check
after each op as that woudl be a client / server turnaround .
*/
class CmdResetError : public Command {
public :
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2009-01-18 20:31:33 -05:00
virtual bool requiresAuth ( ) { return false ; }
2009-01-15 10:17:11 -05:00
virtual bool logTheOp ( ) {
return false ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-05 15:30:07 -05:00
return true ;
}
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
help < < " reset error state (used with getpreverror) " ;
}
2010-04-23 16:41:56 -04:00
CmdResetError ( ) : Command ( " resetError " , false , " reseterror " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & db , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2009-01-15 10:17:11 -05:00
LastError * le = lastError . get ( ) ;
assert ( le ) ;
2009-03-26 13:45:29 -04:00
le - > reset ( ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdResetError ;
2009-01-05 15:30:07 -05:00
2011-01-04 00:40:41 -05:00
/* set by replica sets if specified in the configuration.
a pointer is used to avoid any possible locking issues with lockless reading ( see below locktype ( ) is NONE
2010-08-09 16:15:41 -04:00
and would like to keep that )
( for now , it simply orphans any old copy as config changes should be extremely rare ) .
note : once non - null , never goes to null again .
*/
BSONObj * getLastErrorDefault = 0 ;
2009-01-15 10:17:11 -05:00
class CmdGetLastError : public Command {
public :
2010-12-13 00:21:08 -05:00
CmdGetLastError ( ) : Command ( " getLastError " , false , " getlasterror " ) { }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2010-12-13 00:21:08 -05:00
virtual bool requiresAuth ( ) { return false ; }
virtual bool logTheOp ( ) { return false ; }
virtual bool slaveOk ( ) const { return true ; }
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
2010-12-13 00:21:08 -05:00
help < < " return error status of the last operation on this connection \n "
2011-01-04 00:40:41 -05:00
< < " options: \n "
2010-12-13 00:21:08 -05:00
< < " fsync - fsync before returning, or wait for journal commit if running with --dur \n "
< < " w - await replication to w servers (including self) before returning \n "
< < " wtimeout - timeout for w in milliseconds " ;
2009-09-01 16:23:56 -04:00
}
2010-12-13 00:21:08 -05:00
bool run ( const string & dbname , BSONObj & _cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-01-12 15:33:29 -08:00
LastError * le = lastError . disableForCommand ( ) ;
2011-01-04 00:40:41 -05:00
2010-11-10 16:03:32 -05:00
bool err = false ;
2009-03-26 13:45:29 -04:00
if ( le - > nPrev ! = 1 )
2010-11-10 16:03:32 -05:00
err = LastError : : noError . appendSelf ( result , false ) ;
2009-03-26 13:45:29 -04:00
else
2010-11-10 16:03:32 -05:00
err = le - > appendSelf ( result , false ) ;
2011-01-04 00:40:41 -05:00
2010-04-02 11:29:45 -04:00
Client & c = cc ( ) ;
c . appendLastOp ( result ) ;
2011-01-04 00:40:41 -05:00
2011-01-03 14:12:04 -05:00
result . appendNumber ( " connectionId " , c . getConnectionId ( ) ) ;
2011-01-03 12:22:00 -05:00
2010-08-09 16:15:41 -04:00
BSONObj cmdObj = _cmdObj ;
2011-01-04 00:40:41 -05:00
{
2010-08-09 16:15:41 -04:00
BSONObj : : iterator i ( _cmdObj ) ;
i . next ( ) ;
2011-01-04 00:40:41 -05:00
if ( ! i . more ( ) ) {
2010-08-09 16:15:41 -04:00
/* empty, use default */
BSONObj * def = getLastErrorDefault ;
if ( def )
cmdObj = * def ;
}
}
2010-12-13 00:21:08 -05:00
if ( cmdObj [ " fsync " ] . trueValue ( ) ) {
Timer t ;
if ( ! getDur ( ) . awaitCommit ( ) ) {
// if get here, not running with --dur
log ( ) < < " fsync from getlasterror " < < endl ;
result . append ( " fsyncFiles " , MemoryMappedFile : : flushAll ( true ) ) ;
}
2011-01-04 00:40:41 -05:00
else {
2011-01-03 14:05:56 -05:00
// this perhaps is temp. how long we wait for the group commit to occur.
2010-12-13 00:21:08 -05:00
result . append ( " waited " , t . millis ( ) ) ;
}
2009-12-17 16:15:36 -05:00
}
2010-11-10 16:03:32 -05:00
2010-12-13 00:21:08 -05:00
if ( err ) {
2010-11-10 16:03:32 -05:00
// doesn't make sense to wait for replication
// if there was an error
return true ;
}
2010-04-02 11:29:45 -04:00
BSONElement e = cmdObj [ " w " ] ;
2011-01-04 00:40:41 -05:00
if ( e . isNumber ( ) ) {
2010-04-02 11:29:45 -04:00
int timeout = cmdObj [ " wtimeout " ] . numberInt ( ) ;
Timer t ;
int w = e . numberInt ( ) ;
2011-01-04 00:40:41 -05:00
2010-04-02 11:29:45 -04:00
long long passes = 0 ;
char buf [ 32 ] ;
2011-01-04 00:40:41 -05:00
while ( 1 ) {
2010-12-24 23:55:59 -05:00
OpTime op ( c . getLastOp ( ) ) ;
2011-01-17 23:31:31 -05:00
2011-01-17 23:44:57 -05:00
if ( op . isNull ( ) ) {
2011-01-31 11:28:14 -05:00
if ( anyReplEnabled ( ) ) {
result . append ( " wnote " , " no write has been done on this connection " ) ;
}
else if ( w < = 1 ) {
// don't do anything
// w=1 and no repl, so this is fine
}
else {
// w=2 and no repl
result . append ( " wnote " , " no replication has been enabled, so w=2+ won't work " ) ;
result . append ( " err " , " norepl " ) ;
return true ;
}
2011-01-17 23:44:57 -05:00
break ;
}
2011-01-17 23:31:31 -05:00
// check this first for w=0 or w=1
2011-01-17 23:30:48 -05:00
if ( opReplicatedEnough ( op , w ) )
break ;
2010-12-24 23:55:59 -05:00
// if replication isn't enabled (e.g., config servers)
2011-01-04 00:40:41 -05:00
if ( ! anyReplEnabled ( ) ) {
2010-12-24 23:55:59 -05:00
result . append ( " err " , " norepl " ) ;
return true ;
}
2011-01-04 00:40:41 -05:00
2010-12-26 00:23:52 -05:00
2011-01-04 00:40:41 -05:00
if ( timeout > 0 & & t . millis ( ) > = timeout ) {
2010-04-02 11:29:45 -04:00
result . append ( " wtimeout " , true ) ;
errmsg = " timed out waiting for slaves " ;
result . append ( " waited " , t . millis ( ) ) ;
2010-11-10 16:03:32 -05:00
result . append ( " err " , " timeout " ) ;
return true ;
2010-04-02 11:29:45 -04:00
}
assert ( sprintf ( buf , " w block pass: %lld " , + + passes ) < 30 ) ;
c . curop ( ) - > setMessage ( buf ) ;
sleepmillis ( 1 ) ;
2010-08-04 10:19:45 -04:00
killCurrentOp . checkForInterrupt ( ) ;
2010-04-02 11:29:45 -04:00
}
result . appendNumber ( " wtime " , t . millis ( ) ) ;
}
2011-01-04 00:40:41 -05:00
2010-11-10 16:03:32 -05:00
result . appendNull ( " err " ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdGetLastError ;
2009-01-05 15:30:07 -05:00
2009-01-15 10:17:11 -05:00
class CmdGetPrevError : public Command {
public :
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2009-01-18 20:31:33 -05:00
virtual bool requiresAuth ( ) { return false ; }
2009-01-15 10:17:11 -05:00
virtual bool logTheOp ( ) {
2008-12-11 10:27:05 -05:00
return false ;
2009-01-15 10:17:11 -05:00
}
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
help < < " check for errors since last reseterror commandcal " ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2010-04-23 16:41:56 -04:00
CmdGetPrevError ( ) : Command ( " getPrevError " , false , " getpreverror " ) { }
2010-12-13 00:21:08 -05:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-01-12 15:33:29 -08:00
LastError * le = lastError . disableForCommand ( ) ;
2009-03-26 13:45:29 -04:00
le - > appendSelf ( result ) ;
if ( le - > valid )
result . append ( " nPrev " , le - > nPrev ) ;
else
result . append ( " nPrev " , - 1 ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdGetPrevError ;
2008-12-11 10:27:05 -05:00
2009-01-15 10:17:11 -05:00
class CmdDropDatabase : public Command {
public :
virtual bool logTheOp ( ) {
return true ;
}
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
help < < " drop (delete) this database " ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2008-12-16 10:20:24 -05:00
return false ;
2009-01-15 10:17:11 -05:00
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-01-15 10:17:11 -05:00
CmdDropDatabase ( ) : Command ( " dropDatabase " ) { }
2010-12-12 19:46:12 -05:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-04-23 17:37:05 -04:00
BSONElement e = cmdObj . firstElement ( ) ;
2010-12-12 19:46:12 -05:00
log ( ) < < " dropDatabase " < < dbname < < endl ;
2009-01-15 10:17:11 -05:00
int p = ( int ) e . number ( ) ;
if ( p ! = 1 )
return false ;
2010-12-12 19:46:12 -05:00
dropDatabase ( dbname ) ;
result . append ( " dropped " , dbname ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdDropDatabase ;
2008-12-16 10:20:24 -05:00
2009-01-15 10:17:11 -05:00
class CmdRepairDatabase : public Command {
public :
virtual bool logTheOp ( ) {
return false ;
2008-12-11 10:27:05 -05:00
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
help < < " repair database. also compacts. note: slow. " ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-01-15 10:17:11 -05:00
CmdRepairDatabase ( ) : Command ( " repairDatabase " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-04-23 17:37:05 -04:00
BSONElement e = cmdObj . firstElement ( ) ;
2010-05-03 16:25:34 -04:00
log ( ) < < " repairDatabase " < < dbname < < endl ;
2009-01-15 10:17:11 -05:00
int p = ( int ) e . number ( ) ;
if ( p ! = 1 )
return false ;
2010-01-28 13:41:51 -05:00
e = cmdObj . getField ( " preserveClonedFilesOnFailure " ) ;
2009-01-15 10:17:11 -05:00
bool preserveClonedFilesOnFailure = e . isBoolean ( ) & & e . boolean ( ) ;
2010-01-28 13:41:51 -05:00
e = cmdObj . getField ( " backupOriginalFiles " ) ;
2009-01-15 10:17:11 -05:00
bool backupOriginalFiles = e . isBoolean ( ) & & e . boolean ( ) ;
2010-05-03 16:25:34 -04:00
return repairDatabase ( dbname , errmsg , preserveClonedFilesOnFailure , backupOriginalFiles ) ;
2009-01-15 10:17:11 -05:00
}
} cmdRepairDatabase ;
2011-01-04 00:40:41 -05:00
2009-01-15 10:17:11 -05:00
/* set db profiling level
todo : how do we handle profiling information put in the db with replication ?
sensibly or not ?
*/
class CmdProfile : public Command {
public :
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
2010-04-23 15:50:49 -04:00
help < < " enable or disable performance profiling \n " ;
help < < " { profile : <n> } \n " ;
help < < " 0=off 1=log slow ops 2=log all \n " ;
2010-09-13 13:19:28 -04:00
help < < " -1 to get current values \n " ;
2010-04-23 15:50:49 -04:00
help < < " http://www.mongodb.org/display/DOCS/Database+Profiler " ;
2009-09-01 16:23:56 -04:00
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-01-15 10:17:11 -05:00
CmdProfile ( ) : Command ( " profile " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-04-23 17:37:05 -04:00
BSONElement e = cmdObj . firstElement ( ) ;
2010-07-24 12:02:43 -04:00
result . append ( " was " , cc ( ) . database ( ) - > profile ) ;
result . append ( " slowms " , cmdLine . slowMS ) ;
2009-01-15 10:17:11 -05:00
int p = ( int ) e . number ( ) ;
bool ok = false ;
2011-01-04 00:40:41 -05:00
2009-01-15 10:17:11 -05:00
if ( p = = - 1 )
ok = true ;
else if ( p > = 0 & & p < = 2 ) {
2009-12-29 12:08:13 -05:00
ok = cc ( ) . database ( ) - > setProfilingLevel ( p , errmsg ) ;
2009-01-15 10:17:11 -05:00
}
2009-12-29 14:48:42 -05:00
BSONElement slow = cmdObj [ " slowms " ] ;
if ( slow . isNumber ( ) )
cmdLine . slowMS = slow . numberInt ( ) ;
2011-01-04 00:40:41 -05:00
2009-01-15 10:17:11 -05:00
return ok ;
}
} cmdProfile ;
2008-12-11 10:27:05 -05:00
2009-10-07 12:43:24 -04:00
class CmdServerStatus : public Command {
2009-01-15 10:17:11 -05:00
public :
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2010-04-19 21:05:46 -04:00
CmdServerStatus ( ) : Command ( " serverStatus " , true ) {
2009-01-26 15:44:48 -05:00
started = time ( 0 ) ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const {
help < < " returns lots of administrative server statistics " ;
}
2010-02-12 13:36:10 -05:00
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-06-30 12:57:36 -04:00
long long start = Listener : : getElapsedTimeMillis ( ) ;
BSONObjBuilder timeBuilder ( 128 ) ;
2011-01-04 00:40:41 -05:00
bool authed = cc ( ) . getAuthenticationInfo ( ) - > isAuthorizedReads ( " admin " ) ;
2008-12-05 16:45:10 -05:00
2010-11-28 02:07:38 -05:00
result . append ( " host " , prettyHostName ( ) ) ;
2010-05-24 11:09:10 -04:00
result . append ( " version " , versionString ) ;
2011-01-16 00:44:18 -05:00
result . append ( " process " , " mongod " ) ;
2009-02-20 09:34:25 -05:00
result . append ( " uptime " , ( double ) ( time ( 0 ) - started ) ) ;
2010-06-30 12:57:36 -04:00
result . append ( " uptimeEstimate " , ( double ) ( start / 1000 ) ) ;
2010-02-11 14:35:55 -05:00
result . appendDate ( " localTime " , jsTime ( ) ) ;
2010-05-24 11:09:10 -04:00
2009-10-07 12:43:24 -04:00
{
BSONObjBuilder t ;
unsigned long long last , start , timeLocked ;
2009-12-03 13:12:51 -05:00
dbMutex . info ( ) . getTimingInfo ( start , timeLocked ) ;
2009-10-07 12:43:24 -04:00
last = curTimeMicros64 ( ) ;
double tt = ( double ) last - start ;
double tl = ( double ) timeLocked ;
t . append ( " totalTime " , tt ) ;
t . append ( " lockTime " , tl ) ;
2010-02-11 13:49:36 -05:00
t . append ( " ratio " , ( tt ? tl / tt : 0 ) ) ;
2011-01-04 00:40:41 -05:00
2010-10-24 20:32:19 -04:00
{
BSONObjBuilder ttt ( t . subobjStart ( " currentQueue " ) ) ;
int w = 0 , r = 0 ;
Client : : recommendedYieldMicros ( & w , & r ) ;
ttt . append ( " total " , w + r ) ;
ttt . append ( " readers " , r ) ;
ttt . append ( " writers " , w ) ;
ttt . done ( ) ;
}
2011-01-04 00:40:41 -05:00
2010-10-24 20:32:19 -04:00
{
BSONObjBuilder ttt ( t . subobjStart ( " activeClients " ) ) ;
int w = 0 , r = 0 ;
Client : : getActiveClientCount ( w , r ) ;
ttt . append ( " total " , w + r ) ;
ttt . append ( " readers " , r ) ;
ttt . append ( " writers " , w ) ;
ttt . done ( ) ;
}
2011-01-04 00:40:41 -05:00
2010-07-12 13:06:16 -04:00
2009-10-07 12:43:24 -04:00
result . append ( " globalLock " , t . obj ( ) ) ;
}
2010-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after basic " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2011-01-27 00:48:22 -05:00
{
2011-01-04 00:40:41 -05:00
2010-01-10 20:22:17 -05:00
BSONObjBuilder t ( result . subobjStart ( " mem " ) ) ;
2011-01-04 00:40:41 -05:00
2010-05-24 11:09:10 -04:00
t . append ( " bits " , ( sizeof ( int * ) = = 4 ? 32 : 64 ) ) ;
2009-10-07 12:43:24 -04:00
ProcessInfo p ;
2011-03-01 01:55:30 -05:00
int v = 0 ;
2011-01-04 00:40:41 -05:00
if ( p . supported ( ) ) {
2010-03-01 17:14:23 -05:00
t . appendNumber ( " resident " , p . getResidentSize ( ) ) ;
2011-03-01 01:55:30 -05:00
v = p . getVirtualMemorySize ( ) ;
t . appendNumber ( " virtual " , v ) ;
2010-01-10 20:22:17 -05:00
t . appendBool ( " supported " , true ) ;
2009-10-07 12:43:24 -04:00
}
else {
2010-01-10 20:22:17 -05:00
result . append ( " note " , " not all mem info support on this platform " ) ;
t . appendBool ( " supported " , false ) ;
2009-10-07 12:43:24 -04:00
}
2011-01-04 00:40:41 -05:00
2011-02-28 18:40:02 -05:00
timeBuilder . appendNumber ( " middle of mem " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2011-03-01 01:55:30 -05:00
int m = ( int ) ( MemoryMappedFile : : totalMappedLength ( ) / ( 1024 * 1024 ) ) ;
t . appendNumber ( " mapped " , m ) ;
if ( v - m > 5000 ) {
t . append ( " note " , " virtual minus mapped is large. could indicate a memory leak " ) ;
log ( ) < < " warning: virtual size ( " < < v < < " MB) - mapped size ( " < < m < < " MB) is large. could indicate a memory leak " < < endl ;
}
2010-01-10 20:22:17 -05:00
t . done ( ) ;
2011-01-04 00:40:41 -05:00
2009-02-20 09:34:25 -05:00
}
2011-01-27 00:48:22 -05:00
timeBuilder . appendNumber ( " after mem " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2011-01-04 00:40:41 -05:00
2009-12-29 14:09:53 -05:00
{
BSONObjBuilder bb ( result . subobjStart ( " connections " ) ) ;
bb . append ( " current " , connTicketHolder . used ( ) ) ;
bb . append ( " available " , connTicketHolder . available ( ) ) ;
bb . done ( ) ;
}
2010-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after connections " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2011-01-04 00:40:41 -05:00
2011-01-27 00:48:22 -05:00
{
2010-01-15 17:53:33 -05:00
BSONObjBuilder bb ( result . subobjStart ( " extra_info " ) ) ;
bb . append ( " note " , " fields vary by platform " ) ;
ProcessInfo p ;
p . getExtraInfo ( bb ) ;
bb . done ( ) ;
2010-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after extra info " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2011-01-04 00:40:41 -05:00
2010-01-15 17:53:33 -05:00
}
2010-01-28 14:14:47 -05:00
{
BSONObjBuilder bb ( result . subobjStart ( " indexCounters " ) ) ;
globalIndexCounters . append ( bb ) ;
bb . done ( ) ;
}
2011-01-04 00:40:41 -05:00
2010-03-15 16:02:24 -04:00
{
BSONObjBuilder bb ( result . subobjStart ( " backgroundFlushing " ) ) ;
globalFlushCounters . append ( bb ) ;
bb . done ( ) ;
}
2011-01-04 00:40:41 -05:00
2010-08-18 09:48:02 -04:00
{
2010-08-19 17:04:49 -04:00
BSONObjBuilder bb ( result . subobjStart ( " cursors " ) ) ;
2010-08-18 09:48:02 -04:00
ClientCursor : : appendStats ( bb ) ;
bb . done ( ) ;
}
2010-11-09 00:14:52 -05:00
{
BSONObjBuilder bb ( result . subobjStart ( " network " ) ) ;
networkCounter . append ( bb ) ;
bb . done ( ) ;
}
2010-06-30 12:57:36 -04:00
2011-01-04 00:40:41 -05:00
timeBuilder . appendNumber ( " after counters " , Listener : : getElapsedTimeMillis ( ) - start ) ;
if ( anyReplEnabled ( ) ) {
2010-02-08 17:17:18 -05:00
BSONObjBuilder bb ( result . subobjStart ( " repl " ) ) ;
2010-02-10 14:18:57 -05:00
appendReplicationInfo ( bb , authed , cmdObj [ " repl " ] . numberInt ( ) ) ;
2010-02-08 17:17:18 -05:00
bb . done ( ) ;
2010-11-09 17:01:58 -05:00
2011-01-04 00:40:41 -05:00
if ( ! _isMaster ( ) ) {
2010-11-09 17:01:58 -05:00
result . append ( " opcountersRepl " , replOpCounters . getObj ( ) ) ;
}
2011-01-04 00:40:41 -05:00
2010-02-08 17:17:18 -05:00
}
2010-06-30 12:57:36 -04:00
2011-01-04 00:40:41 -05:00
timeBuilder . appendNumber ( " after repl " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2010-01-16 00:50:02 -05:00
result . append ( " opcounters " , globalOpCounters . getObj ( ) ) ;
2011-01-04 00:40:41 -05:00
2010-02-23 07:51:36 -05:00
{
BSONObjBuilder asserts ( result . subobjStart ( " asserts " ) ) ;
asserts . append ( " regular " , assertionCount . regular ) ;
asserts . append ( " warning " , assertionCount . warning ) ;
asserts . append ( " msg " , assertionCount . msg ) ;
asserts . append ( " user " , assertionCount . user ) ;
asserts . append ( " rollovers " , assertionCount . rollovers ) ;
asserts . done ( ) ;
}
2011-01-04 00:40:41 -05:00
timeBuilder . appendNumber ( " after asserts " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2010-06-30 12:57:36 -04:00
2010-09-22 11:58:55 -04:00
result . append ( " writeBacksQueued " , ! writeBackManager . queuesEmpty ( ) ) ;
2010-12-27 11:29:16 -05:00
if ( cmdLine . dur ) {
result . append ( " dur " , dur : : stats . asObj ( ) ) ;
}
2010-02-08 17:17:18 -05:00
if ( ! authed )
result . append ( " note " , " run against admin for more info " ) ;
2011-01-04 00:40:41 -05:00
if ( Listener : : getElapsedTimeMillis ( ) - start > 1000 ) {
2010-09-18 23:41:47 -04:00
BSONObj t = timeBuilder . obj ( ) ;
log ( ) < < " serverStatus was very slow: " < < t < < endl ;
result . append ( " timing " , t ) ;
}
2010-02-08 17:17:18 -05:00
2009-02-20 09:34:25 -05:00
return true ;
}
time_t started ;
2009-10-07 12:43:24 -04:00
} cmdServerStatus ;
2009-02-20 09:34:25 -05:00
2009-01-15 10:17:11 -05:00
class CmdGetOpTime : public Command {
public :
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const { help < < " internal " ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2009-01-15 10:17:11 -05:00
CmdGetOpTime ( ) : Command ( " getoptime " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-03-22 11:47:37 -04:00
writelock l ( " " ) ;
2009-01-15 10:17:11 -05:00
result . appendDate ( " optime " , OpTime : : now ( ) . asDate ( ) ) ;
return true ;
}
} cmdgetoptime ;
/*
class Cmd : public Command {
public :
Cmd ( ) : Command ( " " ) { }
2010-04-23 16:41:56 -04:00
bool adminOnly ( ) const { return true ; }
2009-01-15 10:17:11 -05:00
bool run ( const char * ns , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result ) {
return true ;
}
} cmd ;
*/
2008-10-22 16:56:39 -04:00
2009-11-11 13:54:05 -05:00
class CmdDiagLogging : public Command {
2009-01-15 10:17:11 -05:00
public :
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2009-11-11 13:54:05 -05:00
CmdDiagLogging ( ) : Command ( " diagLogging " ) { }
2010-04-23 16:41:56 -04:00
bool adminOnly ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2010-04-23 16:41:56 -04:00
void help ( stringstream & h ) const { h < < " http://www.mongodb.org/display/DOCS/Monitoring+and+Diagnostics#MonitoringandDiagnostics-DatabaseRecord%2FReplay " ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2009-11-11 16:02:47 -05:00
int was = _diaglog . setLevel ( cmdObj . firstElement ( ) . numberInt ( ) ) ;
2010-09-21 00:23:33 -04:00
flushDiagLog ( ) ;
2009-08-25 14:35:22 -04:00
if ( ! cmdLine . quiet )
2010-05-19 12:11:17 -04:00
tlog ( ) < < " CMD: diagLogging set to " < < _diaglog . level < < " from: " < < was < < endl ;
2009-11-11 13:54:05 -05:00
result . append ( " was " , was ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
2009-11-11 13:54:05 -05:00
} cmddiaglogging ;
2008-10-22 16:56:39 -04:00
2009-10-21 18:29:27 -04:00
/* remove bit from a bit array - actually remove its slot, not a clear
note : this function does not work with x = = 63 - - that is ok
2011-01-04 00:40:41 -05:00
but keep in mind in the future if max indexes were extended to
2009-10-21 18:29:27 -04:00
exactly 64 it would be a problem
*/
2009-10-21 16:00:40 -04:00
unsigned long long removeBit ( unsigned long long b , int x ) {
unsigned long long tmp = b ;
2009-10-06 14:31:02 -04:00
return
2009-10-21 16:00:40 -04:00
( tmp & ( ( ( ( unsigned long long ) 1 ) < < x ) - 1 ) ) |
2009-07-07 13:17:53 -04:00
( ( tmp > > ( x + 1 ) ) < < x ) ;
}
struct DBCommandsUnitTest {
DBCommandsUnitTest ( ) {
assert ( removeBit ( 1 , 0 ) = = 0 ) ;
assert ( removeBit ( 2 , 0 ) = = 1 ) ;
assert ( removeBit ( 2 , 1 ) = = 0 ) ;
assert ( removeBit ( 255 , 1 ) = = 127 ) ;
assert ( removeBit ( 21 , 2 ) = = 9 ) ;
2009-10-21 18:29:27 -04:00
assert ( removeBit ( 0x4000000000000001ULL , 62 ) = = 1 ) ;
2009-07-07 13:17:53 -04:00
}
} dbc_unittest ;
2010-01-22 11:03:35 -05:00
void assureSysIndexesEmptied ( const char * ns , IndexDetails * exceptForIdIndex ) ;
int removeFromSysIndexes ( const char * ns , const char * idxName ) ;
2010-01-22 15:58:49 -05:00
bool dropIndexes ( NamespaceDetails * d , const char * ns , const char * name , string & errmsg , BSONObjBuilder & anObjBuilder , bool mayDeleteIdIndex ) {
2009-12-18 17:41:26 -05:00
2010-01-22 15:17:03 -05:00
BackgroundOperation : : assertNoBgOpInProgForNs ( ns ) ;
2010-12-28 17:34:59 -08:00
d = d - > writingWithExtra ( ) ;
2009-04-07 14:24:16 -04:00
d - > aboutToDeleteAnIndex ( ) ;
2009-12-18 17:41:26 -05:00
2009-04-07 14:24:16 -04:00
/* there may be pointers pointing at keys in the btree(s). kill them. */
ClientCursor : : invalidate ( ns ) ;
2009-10-06 14:31:02 -04:00
2009-04-07 14:24:16 -04:00
// delete a specific index or all?
if ( * name = = ' * ' & & name [ 1 ] = = 0 ) {
2009-09-27 14:46:51 -04:00
log ( 4 ) < < " d->nIndexes was " < < d - > nIndexes < < ' \n ' ;
2009-04-07 14:24:16 -04:00
anObjBuilder . append ( " nIndexesWas " , ( double ) d - > nIndexes ) ;
2009-04-20 18:40:38 -04:00
IndexDetails * idIndex = 0 ;
2009-10-06 14:31:02 -04:00
if ( d - > nIndexes ) {
2009-04-20 18:40:38 -04:00
for ( int i = 0 ; i < d - > nIndexes ; i + + ) {
2009-10-21 16:00:40 -04:00
if ( ! mayDeleteIdIndex & & d - > idx ( i ) . isIdIndex ( ) ) {
idIndex = & d - > idx ( i ) ;
2011-01-04 00:40:41 -05:00
}
else {
2009-10-21 16:00:40 -04:00
d - > idx ( i ) . kill_idx ( ) ;
2009-04-20 18:40:38 -04:00
}
}
2009-04-07 14:24:16 -04:00
d - > nIndexes = 0 ;
}
2009-04-20 18:40:38 -04:00
if ( idIndex ) {
2009-10-21 16:00:40 -04:00
d - > addIndex ( ns ) = * idIndex ;
wassert ( d - > nIndexes = = 1 ) ;
2009-04-20 18:40:38 -04:00
}
2009-07-07 13:17:53 -04:00
/* assuming here that id index is not multikey: */
d - > multiKeyIndexBits = 0 ;
2010-01-22 11:03:35 -05:00
assureSysIndexesEmptied ( ns , idIndex ) ;
2011-01-04 00:40:41 -05:00
anObjBuilder . append ( " msg " , mayDeleteIdIndex ?
" indexes dropped for collection " :
" non-_id indexes dropped for collection " ) ;
2009-04-07 14:24:16 -04:00
}
else {
// delete just one index
int x = d - > findIndexByName ( name ) ;
if ( x > = 0 ) {
2009-10-05 10:19:51 -04:00
log ( 4 ) < < " d->nIndexes was " < < d - > nIndexes < < endl ;
2009-04-07 14:24:16 -04:00
anObjBuilder . append ( " nIndexesWas " , ( double ) d - > nIndexes ) ;
2009-10-06 14:31:02 -04:00
2009-04-07 14:24:16 -04:00
/* note it is important we remove the IndexDetails with this
call , otherwise , on recreate , the old one would be reused , and its
IndexDetails : : info ptr would be bad info .
*/
2009-10-21 16:00:40 -04:00
IndexDetails * id = & d - > idx ( x ) ;
2009-04-20 18:40:38 -04:00
if ( ! mayDeleteIdIndex & & id - > isIdIndex ( ) ) {
errmsg = " may not delete _id index " ;
return false ;
}
2009-10-21 16:00:40 -04:00
id - > kill_idx ( ) ;
2009-07-07 13:17:53 -04:00
d - > multiKeyIndexBits = removeBit ( d - > multiKeyIndexBits , x ) ;
2009-04-07 14:24:16 -04:00
d - > nIndexes - - ;
for ( int i = x ; i < d - > nIndexes ; i + + )
2009-10-21 16:00:40 -04:00
d - > idx ( i ) = d - > idx ( i + 1 ) ;
2011-01-04 00:40:41 -05:00
}
else {
2010-01-22 11:03:35 -05:00
int n = removeFromSysIndexes ( ns , name ) ; // just in case an orphaned listing there - i.e. should have been repaired but wasn't
2011-01-04 00:40:41 -05:00
if ( n ) {
2010-01-22 11:03:35 -05:00
log ( ) < < " info: removeFromSysIndexes cleaned up " < < n < < " entries " < < endl ;
}
2010-01-22 15:58:49 -05:00
log ( ) < < " dropIndexes: " < < name < < " not found " < < endl ;
2009-04-07 14:24:16 -04:00
errmsg = " index not found " ;
return false ;
}
}
return true ;
}
2009-10-06 14:31:02 -04:00
2009-01-15 10:17:11 -05:00
/* drop collection */
class CmdDrop : public Command {
public :
CmdDrop ( ) : Command ( " drop " ) { }
virtual bool logTheOp ( ) {
return true ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2008-12-11 18:51:49 -05:00
return false ;
}
2010-04-23 16:41:56 -04:00
virtual bool adminOnly ( ) const {
2008-12-11 18:51:49 -05:00
return false ;
}
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const { help < < " drop a collection \n {drop : <collectionName>} " ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2010-05-03 16:25:34 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
string nsToDrop = dbname + ' . ' + cmdObj . firstElement ( ) . valuestr ( ) ;
2009-01-15 10:17:11 -05:00
NamespaceDetails * d = nsdetails ( nsToDrop . c_str ( ) ) ;
2009-08-25 14:35:22 -04:00
if ( ! cmdLine . quiet )
2010-05-19 12:11:17 -04:00
tlog ( ) < < " CMD: drop " < < nsToDrop < < endl ;
2009-01-15 10:17:11 -05:00
if ( d = = 0 ) {
errmsg = " ns not found " ;
return false ;
}
2009-12-28 16:43:43 -05:00
uassert ( 10039 , " can't drop collection with reserved $ character in name " , strchr ( nsToDrop . c_str ( ) , ' $ ' ) = = 0 ) ;
2009-05-11 10:45:10 -04:00
dropCollection ( nsToDrop , errmsg , result ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdDrop ;
2008-12-11 18:51:49 -05:00
2009-01-15 10:17:11 -05:00
/* select count(*) */
class CmdCount : public Command {
public :
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
2009-01-15 10:17:11 -05:00
CmdCount ( ) : Command ( " count " ) { }
virtual bool logTheOp ( ) {
return false ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-10-06 14:31:02 -04:00
// ok on --slave setups, not ok for nonmaster of a repl pair (unless override)
2010-02-08 21:04:09 -05:00
return replSettings . slave = = SimpleSlave ;
2009-01-15 10:17:11 -05:00
}
2009-02-04 17:24:15 -05:00
virtual bool slaveOverrideOk ( ) {
return true ;
}
2010-04-23 16:41:56 -04:00
virtual bool adminOnly ( ) const {
2009-01-15 10:17:11 -05:00
return false ;
}
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const { help < < " count objects in collection " ; }
2010-05-03 16:25:34 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
string ns = dbname + ' . ' + cmdObj . firstElement ( ) . valuestr ( ) ;
2009-01-15 10:17:11 -05:00
string err ;
2009-03-24 12:12:04 -04:00
long long n = runCount ( ns . c_str ( ) , cmdObj , err ) ;
long long nn = n ;
2009-01-15 10:17:11 -05:00
bool ok = true ;
2011-01-04 00:40:41 -05:00
if ( n = = - 1 ) {
2009-09-01 17:28:15 -04:00
nn = 0 ;
result . appendBool ( " missing " , true ) ;
}
else if ( n < 0 ) {
2009-01-15 10:17:11 -05:00
nn = 0 ;
2009-09-01 17:28:15 -04:00
ok = false ;
2009-01-15 10:17:11 -05:00
if ( ! err . empty ( ) )
errmsg = err ;
}
result . append ( " n " , ( double ) nn ) ;
return ok ;
}
} cmdCount ;
/* create collection */
class CmdCreate : public Command {
public :
CmdCreate ( ) : Command ( " create " ) { }
virtual bool logTheOp ( ) {
2009-05-21 11:07:11 -04:00
return false ;
2009-01-15 10:17:11 -05:00
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return false ;
}
2010-04-23 16:41:56 -04:00
virtual bool adminOnly ( ) const {
2009-01-15 10:17:11 -05:00
return false ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
help < < " create a collection " ;
}
2010-08-31 11:17:58 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-05-03 16:25:34 -04:00
string ns = dbname + ' . ' + cmdObj . firstElement ( ) . valuestr ( ) ;
2009-01-15 10:17:11 -05:00
string err ;
2010-08-31 11:17:58 -04:00
bool ok = userCreateNS ( ns . c_str ( ) , cmdObj , err , ! fromRepl ) ;
2009-01-15 10:17:11 -05:00
if ( ! ok & & ! err . empty ( ) )
2008-12-11 18:51:49 -05:00
errmsg = err ;
2009-01-15 10:17:11 -05:00
return ok ;
2008-12-11 18:51:49 -05:00
}
2009-01-15 10:17:11 -05:00
} cmdCreate ;
2008-12-11 18:51:49 -05:00
2010-01-22 15:58:49 -05:00
/* "dropIndexes" is now the preferred form - "deleteIndexes" deprecated */
class CmdDropIndexes : public Command {
2009-01-15 10:17:11 -05:00
public :
virtual bool logTheOp ( ) {
return true ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return false ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-09-01 16:23:56 -04:00
virtual void help ( stringstream & help ) const {
2010-01-22 15:58:49 -05:00
help < < " drop indexes for a collection " ;
2009-09-01 16:23:56 -04:00
}
2010-04-23 17:35:05 -04:00
CmdDropIndexes ( ) : Command ( " dropIndexes " , false , " deleteIndexes " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & anObjBuilder , bool /*fromRepl*/ ) {
2010-04-23 17:35:05 -04:00
BSONElement e = jsobj . firstElement ( ) ;
2010-05-03 16:25:34 -04:00
string toDeleteNs = dbname + ' . ' + e . valuestr ( ) ;
2009-01-15 10:17:11 -05:00
NamespaceDetails * d = nsdetails ( toDeleteNs . c_str ( ) ) ;
2009-08-25 14:35:22 -04:00
if ( ! cmdLine . quiet )
2010-05-19 12:11:17 -04:00
tlog ( ) < < " CMD: dropIndexes " < < toDeleteNs < < endl ;
2009-01-15 10:17:11 -05:00
if ( d ) {
2010-01-28 13:41:51 -05:00
BSONElement f = jsobj . getField ( " index " ) ;
2009-04-07 14:21:21 -04:00
if ( f . type ( ) = = String ) {
2010-01-22 15:58:49 -05:00
return dropIndexes ( d , toDeleteNs . c_str ( ) , f . valuestr ( ) , errmsg , anObjBuilder , false ) ;
2009-04-07 14:21:21 -04:00
}
2011-01-04 00:40:41 -05:00
else if ( f . type ( ) = = Object ) {
2010-01-26 21:04:36 -05:00
int idxId = d - > findIndexByKeyPattern ( f . embeddedObject ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( idxId < 0 ) {
2010-01-26 21:04:36 -05:00
errmsg = " can't find index with key: " ;
2010-07-18 15:15:31 -04:00
errmsg + = f . embeddedObject ( ) . toString ( ) ;
2010-01-26 21:04:36 -05:00
return false ;
}
else {
IndexDetails & ii = d - > idx ( idxId ) ;
string iName = ii . indexName ( ) ;
return dropIndexes ( d , toDeleteNs . c_str ( ) , iName . c_str ( ) , errmsg , anObjBuilder , false ) ;
}
}
2009-04-07 14:21:21 -04:00
else {
errmsg = " invalid index name spec " ;
return false ;
2008-12-11 10:27:05 -05:00
}
}
2009-01-15 10:17:11 -05:00
else {
errmsg = " ns not found " ;
return false ;
}
2008-12-11 10:27:05 -05:00
}
2010-01-22 15:58:49 -05:00
} cmdDropIndexes ;
2009-10-06 14:31:02 -04:00
2009-09-29 10:15:06 -04:00
class CmdReIndex : public Command {
public :
2010-08-16 15:51:37 -04:00
virtual bool logTheOp ( ) { return false ; } // only reindexes on the one node
virtual bool slaveOk ( ) const { return true ; } // can reindex on a secondary
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-09-29 10:15:06 -04:00
virtual void help ( stringstream & help ) const {
help < < " re-index a collection " ;
}
CmdReIndex ( ) : Command ( " reIndex " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool /*fromRepl*/ ) {
2009-09-29 10:15:06 -04:00
static DBDirectClient db ;
2009-10-06 14:31:02 -04:00
2010-04-23 17:35:05 -04:00
BSONElement e = jsobj . firstElement ( ) ;
2010-05-03 16:25:34 -04:00
string toDeleteNs = dbname + ' . ' + e . valuestr ( ) ;
2009-09-29 10:15:06 -04:00
NamespaceDetails * d = nsdetails ( toDeleteNs . c_str ( ) ) ;
2010-05-23 15:07:32 -04:00
tlog ( ) < < " CMD: reIndex " < < toDeleteNs < < endl ;
2010-05-03 16:25:34 -04:00
BackgroundOperation : : assertNoBgOpInProgForNs ( toDeleteNs . c_str ( ) ) ;
2009-10-06 14:31:02 -04:00
2011-01-04 00:40:41 -05:00
if ( ! d ) {
2009-09-29 10:15:06 -04:00
errmsg = " ns not found " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2009-09-29 10:15:06 -04:00
list < BSONObj > all ;
auto_ptr < DBClientCursor > i = db . getIndexes ( toDeleteNs ) ;
BSONObjBuilder b ;
2011-01-04 00:40:41 -05:00
while ( i - > more ( ) ) {
2009-09-29 10:15:06 -04:00
BSONObj o = i - > next ( ) . getOwned ( ) ;
b . append ( BSONObjBuilder : : numStr ( all . size ( ) ) , o ) ;
all . push_back ( o ) ;
}
2009-10-06 14:31:02 -04:00
2010-01-22 15:58:49 -05:00
bool ok = dropIndexes ( d , toDeleteNs . c_str ( ) , " * " , errmsg , result , true ) ;
2011-01-04 00:40:41 -05:00
if ( ! ok ) {
2010-01-22 15:58:49 -05:00
errmsg = " dropIndexes failed " ;
2009-09-29 10:15:06 -04:00
return false ;
}
2009-10-06 14:31:02 -04:00
2011-01-04 00:40:41 -05:00
for ( list < BSONObj > : : iterator i = all . begin ( ) ; i ! = all . end ( ) ; i + + ) {
2009-09-29 10:15:06 -04:00
BSONObj o = * i ;
2010-05-11 10:48:41 -04:00
theDataFileMgr . insertWithObjMod ( Namespace ( toDeleteNs . c_str ( ) ) . getSisterNS ( " system.indexes " ) . c_str ( ) , o , true ) ;
2009-09-29 10:15:06 -04:00
}
2009-10-06 14:31:02 -04:00
2009-09-29 10:15:06 -04:00
result . append ( " ok " , 1 ) ;
result . append ( " nIndexes " , ( int ) all . size ( ) ) ;
result . appendArray ( " indexes " , b . obj ( ) ) ;
return true ;
}
} cmdReIndex ;
2009-10-06 14:31:02 -04:00
2009-01-15 10:17:11 -05:00
class CmdListDatabases : public Command {
public :
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2009-02-09 17:22:26 -05:00
virtual bool slaveOverrideOk ( ) {
return true ;
}
2010-04-23 16:41:56 -04:00
virtual bool adminOnly ( ) const {
2009-01-15 10:17:11 -05:00
return true ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const { help < < " list databases on this server " ; }
2010-10-08 16:58:34 -04:00
CmdListDatabases ( ) : Command ( " listDatabases " , true ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool /*fromRepl*/ ) {
2009-01-15 10:17:11 -05:00
vector < string > dbNames ;
getDatabaseNames ( dbNames ) ;
vector < BSONObj > dbInfos ;
2009-10-06 14:31:02 -04:00
2009-01-29 22:42:12 -05:00
set < string > seen ;
2009-04-17 13:33:44 -04:00
boost : : intmax_t totalSize = 0 ;
2009-01-15 10:17:11 -05:00
for ( vector < string > : : iterator i = dbNames . begin ( ) ; i ! = dbNames . end ( ) ; + + i ) {
BSONObjBuilder b ;
b . append ( " name " , i - > c_str ( ) ) ;
2009-04-17 13:33:44 -04:00
boost : : intmax_t size = dbSize ( i - > c_str ( ) ) ;
b . append ( " sizeOnDisk " , ( double ) size ) ;
2010-01-29 17:22:34 -05:00
Client : : Context ctx ( * i ) ;
b . appendBool ( " empty " , ctx . db ( ) - > isEmpty ( ) ) ;
2009-04-17 13:33:44 -04:00
totalSize + = size ;
2009-02-09 13:04:32 -05:00
dbInfos . push_back ( b . obj ( ) ) ;
2009-01-29 22:42:12 -05:00
seen . insert ( i - > c_str ( ) ) ;
2009-01-15 10:17:11 -05:00
}
2011-01-04 00:40:41 -05:00
2010-01-02 01:28:08 -05:00
// TODO: erh 1/1/2010 I think this is broken where path != dbpath ??
2010-01-02 01:25:53 -05:00
set < string > allShortNames ;
dbHolder . getAllShortNames ( allShortNames ) ;
2011-01-04 00:40:41 -05:00
for ( set < string > : : iterator i = allShortNames . begin ( ) ; i ! = allShortNames . end ( ) ; i + + ) {
2010-01-02 01:25:53 -05:00
string name = * i ;
2009-01-29 22:42:12 -05:00
if ( seen . count ( name ) )
continue ;
2009-10-06 14:31:02 -04:00
2009-05-01 12:18:17 -04:00
BSONObjBuilder b ;
b < < " name " < < name < < " sizeOnDisk " < < double ( 1 ) ;
2010-01-29 17:22:34 -05:00
Client : : Context ctx ( name ) ;
b . appendBool ( " empty " , ctx . db ( ) - > isEmpty ( ) ) ;
2009-10-06 14:31:02 -04:00
2009-05-01 12:18:17 -04:00
dbInfos . push_back ( b . obj ( ) ) ;
2009-01-29 22:42:12 -05:00
}
2009-01-15 10:17:11 -05:00
result . append ( " databases " , dbInfos ) ;
2009-04-17 13:33:44 -04:00
result . append ( " totalSize " , double ( totalSize ) ) ;
2009-01-15 10:17:11 -05:00
return true ;
}
} cmdListDatabases ;
2008-12-29 13:24:24 -05:00
2011-01-04 00:40:41 -05:00
/* note an access to a database right after this will open it back up - so this is mainly
for diagnostic purposes .
2010-01-22 15:17:03 -05:00
*/
2009-02-17 11:11:13 -05:00
class CmdCloseAllDatabases : public Command {
public :
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const { help < < " Close all database files. \n A new request will cause an immediate reopening; thus, this is mostly for testing purposes. " ; }
2010-04-23 16:41:56 -04:00
virtual bool adminOnly ( ) const { return true ; }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return false ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2010-04-23 15:50:49 -04:00
2009-02-17 11:11:13 -05:00
CmdCloseAllDatabases ( ) : Command ( " closeAllDatabases " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool /*fromRepl*/ ) {
2011-01-19 17:31:52 -05:00
bool ok ;
try {
ok = dbHolder . closeAll ( dbpath , result , false ) ;
}
catch ( DBException & ) {
throw ;
}
catch ( . . . ) {
log ( ) < < " ERROR uncaught exception in command closeAllDatabases " < < endl ;
errmsg = " unexpected uncaught exception " ;
return false ;
}
return ok ;
2009-02-17 11:11:13 -05:00
}
} cmdCloseAllDatabases ;
2009-02-17 11:16:13 -05:00
2009-02-11 10:37:27 -05:00
class CmdFileMD5 : public Command {
public :
2011-01-04 00:40:41 -05:00
CmdFileMD5 ( ) : Command ( " filemd5 " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-02-11 10:37:27 -05:00
return true ;
}
2009-02-18 11:29:04 -05:00
virtual void help ( stringstream & help ) const {
2010-04-13 20:53:48 -04:00
help < < " example: { filemd5 : ObjectId(aaaaaaa) , root : \" fs \" } " ;
2009-02-18 11:29:04 -05:00
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-05-03 16:25:34 -04:00
string ns = dbname ;
2009-02-18 13:11:22 -05:00
ns + = " . " ;
{
string root = jsobj . getStringField ( " root " ) ;
if ( root . size ( ) = = 0 )
root = " fs " ;
ns + = root ;
}
ns + = " .chunks " ; // make this an option in jsobj
2009-10-06 14:31:02 -04:00
2009-02-11 10:37:27 -05:00
md5digest d ;
md5_state_t st ;
md5_init ( & st ) ;
2010-05-17 15:14:46 -04:00
BSONObj query = BSON ( " files_id " < < jsobj [ " filemd5 " ] ) ;
BSONObj sort = BSON ( " files_id " < < 1 < < " n " < < 1 ) ;
2010-05-25 13:37:05 -07:00
shared_ptr < Cursor > cursor = bestGuessCursor ( ns . c_str ( ) , query , sort ) ;
2010-05-18 19:45:23 -04:00
scoped_ptr < ClientCursor > cc ( new ClientCursor ( QueryOption_NoCursorTimeout , cursor , ns . c_str ( ) ) ) ;
2009-10-06 14:31:02 -04:00
2009-02-11 10:37:27 -05:00
int n = 0 ;
2011-01-04 00:40:41 -05:00
while ( cursor - > ok ( ) ) {
if ( ! cursor - > matcher ( ) - > matchesCurrent ( cursor . get ( ) ) ) {
2010-05-18 19:45:23 -04:00
log ( ) < < " **** NOT MATCHING **** " < < endl ;
PRINT ( cursor - > current ( ) ) ;
2010-05-17 15:14:46 -04:00
cursor - > advance ( ) ;
continue ;
}
BSONObj obj = cursor - > current ( ) ;
cursor - > advance ( ) ;
2010-05-19 19:27:04 -04:00
ClientCursor : : YieldLock yield ( cc ) ;
2010-05-18 19:45:23 -04:00
try {
BSONElement ne = obj [ " n " ] ;
assert ( ne . isNumber ( ) ) ;
int myn = ne . numberInt ( ) ;
2011-01-04 00:40:41 -05:00
if ( n ! = myn ) {
2010-05-18 19:45:23 -04:00
log ( ) < < " should have chunk: " < < n < < " have: " < < myn < < endl ;
2009-10-06 14:31:02 -04:00
2010-05-18 19:45:23 -04:00
DBDirectClient client ;
Query q ( query ) ;
q . sort ( sort ) ;
auto_ptr < DBClientCursor > c = client . query ( ns , q ) ;
while ( c - > more ( ) )
PRINT ( c - > nextSafe ( ) ) ;
uassert ( 10040 , " chunks out of order " , n = = myn ) ;
}
2009-02-11 10:37:27 -05:00
2010-05-18 19:45:23 -04:00
int len ;
2010-06-14 06:30:19 -04:00
const char * data = obj [ " data " ] . binDataClean ( len ) ;
md5_append ( & st , ( const md5_byte_t * ) ( data ) , len ) ;
2010-05-17 15:14:46 -04:00
2010-05-18 19:45:23 -04:00
n + + ;
2011-01-04 00:40:41 -05:00
}
catch ( . . . ) {
2010-05-18 19:45:23 -04:00
yield . relock ( ) ; // needed before yield goes out of scope
throw ;
}
2011-01-04 00:40:41 -05:00
if ( ! yield . stillOk ( ) ) {
2010-05-18 19:45:23 -04:00
uasserted ( 13281 , " File deleted during filemd5 command " ) ;
}
2009-02-11 10:37:27 -05:00
}
2010-05-17 15:14:46 -04:00
2009-02-11 10:37:27 -05:00
md5_finish ( & st , d ) ;
2009-10-06 14:31:02 -04:00
2010-07-14 14:18:08 -04:00
result . append ( " numChunks " , n ) ;
2009-10-06 14:31:02 -04:00
result . append ( " md5 " , digestToString ( d ) ) ;
2009-02-11 10:37:27 -05:00
return true ;
}
} cmdFileMD5 ;
2009-10-06 14:31:02 -04:00
2010-07-02 14:05:49 -04:00
static IndexDetails * cmdIndexDetailsForRange ( const char * ns , string & errmsg , BSONObj & min , BSONObj & max , BSONObj & keyPattern ) {
2009-04-30 17:36:25 -04:00
if ( ns [ 0 ] = = ' \0 ' | | min . isEmpty ( ) | | max . isEmpty ( ) ) {
errmsg = " invalid command syntax (note: min and max are required) " ;
return 0 ;
}
return indexDetailsForRange ( ns , errmsg , min , max , keyPattern ) ;
}
2009-10-06 14:31:02 -04:00
2009-04-02 17:29:51 -04:00
class CmdDatasize : public Command {
public :
2010-04-23 15:50:49 -04:00
CmdDatasize ( ) : Command ( " dataSize " , false , " datasize " ) { }
virtual bool slaveOk ( ) const { return true ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
2009-04-02 17:29:51 -04:00
virtual void help ( stringstream & help ) const {
2009-10-06 14:31:02 -04:00
help < <
2011-01-04 00:40:41 -05:00
" determine data size for a set of data in a certain range "
" \n example: { dataSize: \" blog.posts \" , keyPattern:{x:1}, min:{x:10}, max:{x:55} } "
" \n keyPattern, min, and max parameters are optional. "
" \n note: This command may take a while to run " ;
2009-04-02 17:29:51 -04:00
}
2011-01-04 00:40:41 -05:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-08-24 01:25:45 -04:00
Timer timer ;
2010-04-28 12:19:46 -04:00
string ns = jsobj . firstElement ( ) . String ( ) ;
2009-04-02 17:29:51 -04:00
BSONObj min = jsobj . getObjectField ( " min " ) ;
BSONObj max = jsobj . getObjectField ( " max " ) ;
BSONObj keyPattern = jsobj . getObjectField ( " keyPattern " ) ;
2010-08-24 01:25:45 -04:00
bool estimate = jsobj [ " estimate " ] . trueValue ( ) ;
2009-04-02 17:29:51 -04:00
2010-01-29 17:22:34 -05:00
Client : : Context ctx ( ns ) ;
2010-08-24 01:25:45 -04:00
NamespaceDetails * d = nsdetails ( ns . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( ! d | | d - > stats . nrecords = = 0 ) {
2010-08-24 01:39:38 -04:00
result . appendNumber ( " size " , 0 ) ;
result . appendNumber ( " numObjects " , 0 ) ;
result . append ( " millis " , timer . millis ( ) ) ;
return true ;
2010-08-24 01:25:45 -04:00
}
2011-01-04 00:40:41 -05:00
2010-08-24 01:25:45 -04:00
result . appendBool ( " estimate " , estimate ) ;
2010-05-07 17:25:57 -04:00
shared_ptr < Cursor > c ;
2009-04-02 17:29:51 -04:00
if ( min . isEmpty ( ) & & max . isEmpty ( ) ) {
2011-01-04 00:40:41 -05:00
if ( estimate ) {
2010-09-27 12:35:22 -04:00
result . appendNumber ( " size " , d - > stats . datasize ) ;
result . appendNumber ( " numObjects " , d - > stats . nrecords ) ;
2010-08-24 01:25:45 -04:00
result . append ( " millis " , timer . millis ( ) ) ;
return 1 ;
}
2010-04-28 12:19:46 -04:00
c = theDataFileMgr . findAll ( ns . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
}
2010-04-28 12:19:46 -04:00
else if ( min . isEmpty ( ) | | max . isEmpty ( ) ) {
2009-04-02 17:29:51 -04:00
errmsg = " only one of min or max specified " ;
return false ;
2011-01-04 00:40:41 -05:00
}
2010-04-28 12:19:46 -04:00
else {
IndexDetails * idx = cmdIndexDetailsForRange ( ns . c_str ( ) , errmsg , min , max , keyPattern ) ;
2009-07-07 13:17:53 -04:00
if ( idx = = 0 )
2009-04-02 17:29:51 -04:00
return false ;
2011-01-04 00:40:41 -05:00
2010-07-16 01:49:15 -07:00
c . reset ( new BtreeCursor ( d , d - > idxNo ( * idx ) , * idx , min , max , false , 1 ) ) ;
2009-04-02 17:29:51 -04:00
}
2011-01-04 00:40:41 -05:00
2010-09-27 12:35:22 -04:00
long long avgObjSize = d - > stats . datasize / d - > stats . nrecords ;
2010-08-24 01:25:45 -04:00
2010-04-28 12:19:46 -04:00
long long maxSize = jsobj [ " maxSize " ] . numberLong ( ) ;
long long maxObjects = jsobj [ " maxObjects " ] . numberLong ( ) ;
2009-10-06 14:31:02 -04:00
2009-04-02 17:29:51 -04:00
long long size = 0 ;
2009-04-20 14:45:45 -04:00
long long numObjects = 0 ;
2009-04-02 17:29:51 -04:00
while ( c - > ok ( ) ) {
2010-08-24 01:25:45 -04:00
if ( estimate )
size + = avgObjSize ;
else
size + = c - > currLoc ( ) . rec ( ) - > netLength ( ) ;
2011-01-04 00:40:41 -05:00
2009-04-20 14:45:45 -04:00
numObjects + + ;
2011-01-04 00:40:41 -05:00
if ( ( maxSize & & size > maxSize ) | |
( maxObjects & & numObjects > maxObjects ) ) {
2010-04-28 12:19:46 -04:00
result . appendBool ( " maxReached " , true ) ;
break ;
}
c - > advance ( ) ;
2009-04-02 17:29:51 -04:00
}
2010-07-02 11:43:26 -04:00
ostringstream os ;
os < < " Finding size for ns: " < < ns ;
2011-01-04 00:40:41 -05:00
if ( ! min . isEmpty ( ) ) {
2010-07-02 11:43:26 -04:00
os < < " between " < < min < < " and " < < max ;
2009-04-02 17:29:51 -04:00
}
2010-07-03 14:20:18 -04:00
logIfSlow ( timer , os . str ( ) ) ;
2009-10-06 14:31:02 -04:00
2010-08-24 01:25:45 -04:00
result . appendNumber ( " size " , size ) ;
result . appendNumber ( " numObjects " , numObjects ) ;
2010-07-03 14:20:18 -04:00
result . append ( " millis " , timer . millis ( ) ) ;
2009-04-02 17:29:51 -04:00
return true ;
}
} cmdDatasize ;
2010-02-22 21:23:20 -05:00
namespace {
2011-01-04 00:40:41 -05:00
long long getIndexSizeForCollection ( string db , string ns , BSONObjBuilder * details = NULL , int scale = 1 ) {
2010-04-01 10:19:38 -04:00
dbMutex . assertAtLeastReadLocked ( ) ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
if ( ! nsd )
return 0 ;
2011-01-04 00:40:41 -05:00
long long totalSize = 0 ;
2010-04-01 10:19:38 -04:00
NamespaceDetails : : IndexIterator ii = nsd - > ii ( ) ;
2011-01-04 00:40:41 -05:00
while ( ii . more ( ) ) {
2010-04-01 10:19:38 -04:00
IndexDetails & d = ii . next ( ) ;
string collNS = d . indexNamespace ( ) ;
NamespaceDetails * mine = nsdetails ( collNS . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( ! mine ) {
2010-04-01 10:19:38 -04:00
log ( ) < < " error: have index [ " < < collNS < < " ] but no NamespaceDetails " < < endl ;
continue ;
}
2010-09-27 12:35:22 -04:00
totalSize + = mine - > stats . datasize ;
2010-04-01 10:19:38 -04:00
if ( details )
2010-09-27 12:35:22 -04:00
details - > appendNumber ( d . indexName ( ) , mine - > stats . datasize / scale ) ;
2010-02-22 21:23:20 -05:00
}
return totalSize ;
}
}
2009-08-12 13:53:52 -04:00
class CollectionStats : public Command {
public :
2010-04-23 16:41:56 -04:00
CollectionStats ( ) : Command ( " collStats " , false , " collstats " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return true ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
2009-08-12 13:53:52 -04:00
virtual void help ( stringstream & help ) const {
2010-08-02 11:48:48 -04:00
help < < " { collStats: \" blog.posts \" , scale : 1 } scale divides sizes e.g. for KB use 1024 " ;
2009-08-12 13:53:52 -04:00
}
2011-01-04 00:40:41 -05:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-02-22 22:16:13 -05:00
string ns = dbname + " . " + jsobj . firstElement ( ) . valuestr ( ) ;
2010-07-23 10:51:48 -04:00
Client : : Context cx ( ns ) ;
2011-01-04 00:40:41 -05:00
2009-08-12 13:53:52 -04:00
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( ! nsd ) {
2009-08-12 13:53:52 -04:00
errmsg = " ns not found " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2009-08-12 13:53:52 -04:00
result . append ( " ns " , ns . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
2010-02-27 12:11:41 -05:00
int scale = 1 ;
2011-01-04 00:40:41 -05:00
if ( jsobj [ " scale " ] . isNumber ( ) ) {
2010-02-27 12:11:41 -05:00
scale = jsobj [ " scale " ] . numberInt ( ) ;
2011-01-04 00:40:41 -05:00
if ( scale < = 0 ) {
2010-06-22 20:18:30 -04:00
errmsg = " scale has to be > 0 " ;
return false ;
}
2011-01-04 00:40:41 -05:00
2010-06-22 20:18:30 -04:00
}
2011-01-04 00:40:41 -05:00
else if ( jsobj [ " scale " ] . trueValue ( ) ) {
2010-08-02 11:48:48 -04:00
errmsg = " scale has to be a number > 0 " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2010-12-27 14:20:49 -05:00
bool verbose = jsobj [ " verbose " ] . trueValue ( ) ;
2010-09-27 12:35:22 -04:00
long long size = nsd - > stats . datasize / scale ;
result . appendNumber ( " count " , nsd - > stats . nrecords ) ;
2010-07-01 17:12:20 -04:00
result . appendNumber ( " size " , size ) ;
2010-10-17 19:22:46 -04:00
if ( nsd - > stats . nrecords )
result . append ( " avgObjSize " , double ( size ) / double ( nsd - > stats . nrecords ) ) ;
2010-12-27 14:20:49 -05:00
2010-02-07 10:38:23 -05:00
int numExtents ;
2010-12-27 14:20:49 -05:00
BSONArrayBuilder extents ;
2011-01-04 00:40:41 -05:00
2010-12-27 14:20:49 -05:00
result . appendNumber ( " storageSize " , nsd - > storageSize ( & numExtents , verbose ? & extents : 0 ) / scale ) ;
2010-02-07 10:38:23 -05:00
result . append ( " numExtents " , numExtents ) ;
2009-08-12 13:53:52 -04:00
result . append ( " nindexes " , nsd - > nIndexes ) ;
2010-02-27 12:11:41 -05:00
result . append ( " lastExtentSize " , nsd - > lastExtentSize / scale ) ;
2010-02-07 10:38:23 -05:00
result . append ( " paddingFactor " , nsd - > paddingFactor ) ;
result . append ( " flags " , nsd - > flags ) ;
2010-02-22 22:16:13 -05:00
BSONObjBuilder indexSizes ;
2010-03-01 17:14:23 -05:00
result . appendNumber ( " totalIndexSize " , getIndexSizeForCollection ( dbname , ns , & indexSizes , scale ) / scale ) ;
2010-02-22 22:16:13 -05:00
result . append ( " indexSizes " , indexSizes . obj ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( nsd - > capped ) {
2009-08-21 17:05:19 -04:00
result . append ( " capped " , nsd - > capped ) ;
result . append ( " max " , nsd - > max ) ;
}
2011-01-04 00:40:41 -05:00
2010-12-27 14:20:49 -05:00
if ( verbose )
result . appendArray ( " extents " , extents . arr ( ) ) ;
2009-08-21 17:05:19 -04:00
2009-08-12 13:53:52 -04:00
return true ;
}
} cmdCollectionStatis ;
2010-02-22 21:23:20 -05:00
class DBStats : public Command {
public :
2010-04-23 16:41:56 -04:00
DBStats ( ) : Command ( " dbStats " , false , " dbstats " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return true ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return READ ; }
2010-02-22 21:23:20 -05:00
virtual void help ( stringstream & help ) const {
2011-03-01 15:46:27 -05:00
help < <
" Get stats on a database. Not instantaneous. Slower for databases with large .ns files. \n " < <
" Example: { dbStats:1 } " ;
2010-02-22 21:23:20 -05:00
}
2011-01-04 00:40:41 -05:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-04-25 23:15:42 -04:00
list < string > collections ;
Database * d = cc ( ) . database ( ) ;
if ( d )
d - > namespaceIndex . getNamespaces ( collections ) ;
2010-02-22 21:23:20 -05:00
long long ncollections = 0 ;
long long objects = 0 ;
long long size = 0 ;
long long storageSize = 0 ;
long long numExtents = 0 ;
long long indexes = 0 ;
long long indexSize = 0 ;
2011-01-04 00:40:41 -05:00
for ( list < string > : : const_iterator it = collections . begin ( ) ; it ! = collections . end ( ) ; + + it ) {
2010-02-22 21:23:20 -05:00
const string ns = * it ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
if ( ! nsd ) {
2010-04-25 23:15:42 -04:00
errmsg = " missing ns: " ;
errmsg + = ns ;
return false ;
2010-02-22 21:23:20 -05:00
}
ncollections + = 1 ;
2010-09-27 12:35:22 -04:00
objects + = nsd - > stats . nrecords ;
size + = nsd - > stats . datasize ;
2010-02-22 21:23:20 -05:00
int temp ;
storageSize + = nsd - > storageSize ( & temp ) ;
numExtents + = temp ;
indexes + = nsd - > nIndexes ;
indexSize + = getIndexSizeForCollection ( dbname , ns ) ;
}
2011-01-27 17:00:51 -05:00
result . append ( " db " , dbname ) ;
2010-03-01 17:14:23 -05:00
result . appendNumber ( " collections " , ncollections ) ;
result . appendNumber ( " objects " , objects ) ;
2011-01-31 01:42:59 -05:00
result . append ( " avgObjSize " , objects = = 0 ? 0 : double ( size ) / double ( objects ) ) ;
2010-03-01 17:14:23 -05:00
result . appendNumber ( " dataSize " , size ) ;
result . appendNumber ( " storageSize " , storageSize ) ;
result . appendNumber ( " numExtents " , numExtents ) ;
result . appendNumber ( " indexes " , indexes ) ;
result . appendNumber ( " indexSize " , indexSize ) ;
2010-06-03 19:46:53 -04:00
result . appendNumber ( " fileSize " , d - > fileSize ( ) ) ;
2011-03-01 15:46:27 -05:00
if ( d )
2011-03-01 16:56:58 -05:00
result . appendNumber ( " nsSizeMB " , ( int ) d - > namespaceIndex . fileLength ( ) / 1024 / 1024 ) ;
2010-02-22 21:23:20 -05:00
2010-10-13 16:11:32 -04:00
return true ;
2010-02-22 21:23:20 -05:00
}
} cmdDBStats ;
2010-01-21 12:23:44 -05:00
/* convertToCapped seems to use this */
2009-05-18 13:25:30 -04:00
class CmdCloneCollectionAsCapped : public Command {
public :
CmdCloneCollectionAsCapped ( ) : Command ( " cloneCollectionAsCapped " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return false ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-05-18 13:25:30 -04:00
virtual void help ( stringstream & help ) const {
2010-04-23 15:50:49 -04:00
help < < " { cloneCollectionAsCapped:<fromName>, toCollection:<toName>, size:<sizeInBytes> } " ;
2009-05-18 13:25:30 -04:00
}
2011-01-04 00:40:41 -05:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2009-05-18 13:25:30 -04:00
string from = jsobj . getStringField ( " cloneCollectionAsCapped " ) ;
string to = jsobj . getStringField ( " toCollection " ) ;
long long size = ( long long ) jsobj . getField ( " size " ) . number ( ) ;
2009-10-06 14:31:02 -04:00
2009-05-18 13:25:30 -04:00
if ( from . empty ( ) | | to . empty ( ) | | size = = 0 ) {
errmsg = " invalid command spec " ;
return false ;
}
2010-05-03 16:25:34 -04:00
string fromNs = dbname + " . " + from ;
string toNs = dbname + " . " + to ;
2009-05-18 13:25:30 -04:00
NamespaceDetails * nsd = nsdetails ( fromNs . c_str ( ) ) ;
2009-12-28 16:43:43 -05:00
massert ( 10301 , " source collection " + fromNs + " does not exist " , nsd ) ;
2010-09-27 12:35:22 -04:00
long long excessSize = nsd - > stats . datasize - size * 2 ; // datasize and extentSize can't be compared exactly, so add some padding to 'size'
2009-05-18 13:25:30 -04:00
DiskLoc extent = nsd - > firstExtent ;
2010-03-22 13:57:59 -07:00
for ( ; excessSize > extent . ext ( ) - > length & & extent ! = nsd - > lastExtent ; extent = extent . ext ( ) - > xnext ) {
2009-05-18 13:25:30 -04:00
excessSize - = extent . ext ( ) - > length ;
2010-03-22 13:57:59 -07:00
log ( 2 ) < < " cloneCollectionAsCapped skipping extent of size " < < extent . ext ( ) - > length < < endl ;
2009-05-18 13:25:30 -04:00
log ( 6 ) < < " excessSize: " < < excessSize < < endl ;
}
DiskLoc startLoc = extent . ext ( ) - > firstRecord ;
2009-10-06 14:31:02 -04:00
2009-05-18 13:25:30 -04:00
CursorId id ;
{
2010-05-07 17:25:57 -04:00
shared_ptr < Cursor > c = theDataFileMgr . findAll ( fromNs . c_str ( ) , startLoc ) ;
2010-03-25 16:16:59 -04:00
ClientCursor * cc = new ClientCursor ( 0 , c , fromNs . c_str ( ) ) ;
2010-10-29 11:00:38 -04:00
id = cc - > cursorid ( ) ;
2009-05-18 13:25:30 -04:00
}
2009-10-06 14:31:02 -04:00
2009-05-18 13:25:30 -04:00
DBDirectClient client ;
2010-01-29 17:22:34 -05:00
Client : : Context ctx ( toNs ) ;
2009-05-18 13:25:30 -04:00
BSONObjBuilder spec ;
spec . appendBool ( " capped " , true ) ;
spec . append ( " size " , double ( size ) ) ;
if ( ! userCreateNS ( toNs . c_str ( ) , spec . done ( ) , errmsg , true ) )
return false ;
2009-10-06 14:31:02 -04:00
2009-05-18 13:25:30 -04:00
auto_ptr < DBClientCursor > c = client . getMore ( fromNs , id ) ;
while ( c - > more ( ) ) {
BSONObj obj = c - > next ( ) ;
2009-08-13 13:26:03 -04:00
theDataFileMgr . insertAndLog ( toNs . c_str ( ) , obj , true ) ;
2009-05-18 13:25:30 -04:00
}
2009-10-06 14:31:02 -04:00
2009-05-18 13:25:30 -04:00
return true ;
2009-10-06 14:31:02 -04:00
}
2009-05-18 13:25:30 -04:00
} cmdCloneCollectionAsCapped ;
2009-10-06 14:31:02 -04:00
2011-01-04 00:40:41 -05:00
/* jan2010:
Converts the given collection to a capped collection w / the specified size .
This command is not highly used , and is not currently supported with sharded
environments .
2010-01-21 13:40:18 -05:00
*/
2009-05-18 16:25:17 -04:00
class CmdConvertToCapped : public Command {
public :
CmdConvertToCapped ( ) : Command ( " convertToCapped " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return false ; }
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-05-18 16:25:17 -04:00
virtual void help ( stringstream & help ) const {
2010-04-23 15:50:49 -04:00
help < < " { convertToCapped:<fromCollectionName>, size:<sizeInBytes> } " ;
2009-05-18 16:25:17 -04:00
}
2011-01-04 00:40:41 -05:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2010-05-03 16:25:34 -04:00
BackgroundOperation : : assertNoBgOpInProgForDb ( dbname . c_str ( ) ) ;
2010-01-22 15:17:03 -05:00
2009-05-18 16:25:17 -04:00
string from = jsobj . getStringField ( " convertToCapped " ) ;
long long size = ( long long ) jsobj . getField ( " size " ) . number ( ) ;
2009-10-06 14:31:02 -04:00
2009-05-18 16:25:17 -04:00
if ( from . empty ( ) | | size = = 0 ) {
errmsg = " invalid command spec " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2010-10-17 22:59:27 -04:00
string shortTmpName = str : : stream ( ) < < " .tmp.convertToCapped. " < < from ;
string longTmpName = str : : stream ( ) < < dbname < < " . " < < shortTmpName ;
2009-05-18 16:25:17 -04:00
DBDirectClient client ;
2010-10-17 22:59:27 -04:00
client . dropCollection ( longTmpName ) ;
2009-05-18 16:25:17 -04:00
BSONObj info ;
2010-05-03 16:25:34 -04:00
if ( ! client . runCommand ( dbname ,
2011-01-04 00:40:41 -05:00
BSON ( " cloneCollectionAsCapped " < < from < < " toCollection " < < shortTmpName < < " size " < < double ( size ) ) ,
info ) ) {
2010-07-18 15:15:31 -04:00
errmsg = " cloneCollectionAsCapped failed: " + info . toString ( ) ;
2009-05-18 16:25:17 -04:00
return false ;
}
2009-10-06 14:31:02 -04:00
2010-05-03 16:25:34 -04:00
if ( ! client . dropCollection ( dbname + " . " + from ) ) {
2009-05-18 16:25:17 -04:00
errmsg = " failed to drop original collection " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2009-05-18 16:25:17 -04:00
if ( ! client . runCommand ( " admin " ,
2010-10-17 22:59:27 -04:00
BSON ( " renameCollection " < < longTmpName < <
" to " < < ( dbname + " . " + from ) ) ,
2011-01-04 00:40:41 -05:00
info ) ) {
2010-07-18 15:15:31 -04:00
errmsg = " renameCollection failed: " + info . toString ( ) ;
2009-05-18 16:25:17 -04:00
return false ;
}
return true ;
}
} cmdConvertToCapped ;
2009-08-19 11:51:16 -04:00
2009-12-30 20:08:43 -05:00
/* Find and Modify an object returning either the old (default) or new value*/
class CmdFindAndModify : public Command {
public :
2010-04-23 15:50:49 -04:00
virtual void help ( stringstream & help ) const {
2011-01-04 00:40:41 -05:00
help < <
" { findAndModify: \" collection \" , query: {processed:false}, update: {$set: {processed:true}}, new: true} \n "
" { findAndModify: \" collection \" , query: {processed:false}, remove: true, sort: {priority:-1}} \n "
" Either update or remove is required, all other fields have default values. \n "
" Output is in the \" value \" field \n " ;
2010-04-23 15:50:49 -04:00
}
2010-04-23 16:41:56 -04:00
CmdFindAndModify ( ) : Command ( " findAndModify " , false , " findandmodify " ) { }
2009-12-30 20:08:43 -05:00
virtual bool logTheOp ( ) {
return false ; // the modification will be logged directly
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2009-12-30 20:08:43 -05:00
return false ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return WRITE ; }
2010-05-03 16:25:34 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2009-12-30 20:08:43 -05:00
static DBDirectClient db ;
2010-05-03 16:25:34 -04:00
string ns = dbname + ' . ' + cmdObj . firstElement ( ) . valuestr ( ) ;
2009-12-30 20:08:43 -05:00
2010-05-11 12:43:33 -04:00
BSONObj origQuery = cmdObj . getObjectField ( " query " ) ; // defaults to {}
Query q ( origQuery ) ;
2009-12-30 20:08:43 -05:00
BSONElement sort = cmdObj [ " sort " ] ;
if ( ! sort . eoo ( ) )
q . sort ( sort . embeddedObjectUserCheck ( ) ) ;
2010-07-01 21:05:04 -04:00
bool upsert = cmdObj [ " upsert " ] . trueValue ( ) ;
2010-03-29 20:41:57 -04:00
BSONObj fieldsHolder ( cmdObj . getObjectField ( " fields " ) ) ;
const BSONObj * fields = ( fieldsHolder . isEmpty ( ) ? NULL : & fieldsHolder ) ;
BSONObj out = db . findOne ( ns , q , fields ) ;
2011-01-04 00:40:41 -05:00
if ( out . isEmpty ( ) ) {
if ( ! upsert ) {
2010-07-01 21:05:04 -04:00
errmsg = " No matching object found " ;
return false ;
}
2009-12-30 20:08:43 -05:00
2010-07-01 21:05:04 -04:00
BSONElement update = cmdObj [ " update " ] ;
uassert ( 13329 , " upsert mode requires update field " , ! update . eoo ( ) ) ;
uassert ( 13330 , " upsert mode requires query field " , ! origQuery . isEmpty ( ) ) ;
db . update ( ns , origQuery , update . embeddedObjectUserCheck ( ) , true ) ;
2010-05-11 12:43:33 -04:00
2010-09-23 19:36:51 -04:00
BSONObj gle = db . getLastErrorDetailed ( ) ;
2011-01-04 00:40:41 -05:00
if ( gle [ " err " ] . type ( ) = = String ) {
2010-09-23 19:36:51 -04:00
errmsg = gle [ " err " ] . String ( ) ;
return false ;
}
2010-07-02 14:56:45 -04:00
2011-01-04 00:40:41 -05:00
if ( cmdObj [ " new " ] . trueValue ( ) ) {
2010-07-02 14:56:45 -04:00
BSONElement _id = gle [ " upserted " ] ;
2010-07-01 21:05:04 -04:00
if ( _id . eoo ( ) )
2010-07-02 14:56:45 -04:00
_id = origQuery [ " _id " ] ;
2010-07-01 21:05:04 -04:00
out = db . findOne ( ns , QUERY ( " _id " < < _id ) , fields ) ;
2010-05-11 15:10:07 -04:00
}
2010-05-11 12:43:33 -04:00
2011-01-04 00:40:41 -05:00
}
else {
2010-07-01 21:05:04 -04:00
2011-01-04 00:40:41 -05:00
if ( cmdObj [ " remove " ] . trueValue ( ) ) {
2010-07-01 21:05:04 -04:00
uassert ( 12515 , " can't remove and update " , cmdObj [ " update " ] . eoo ( ) ) ;
2010-10-28 15:39:09 -04:00
db . remove ( ns , QUERY ( " _id " < < out [ " _id " ] ) , 1 ) ;
2010-07-01 21:05:04 -04:00
2011-01-04 00:40:41 -05:00
}
else { // update
2009-12-30 20:08:43 -05:00
2010-10-28 16:16:38 -04:00
BSONElement queryId = origQuery [ " _id " ] ;
2011-01-04 00:40:41 -05:00
if ( queryId . eoo ( ) | | getGtLtOp ( queryId ) ! = BSONObj : : Equality ) {
2010-10-28 15:39:09 -04:00
// need to include original query for $ positional operator
BSONObjBuilder b ;
b . append ( out [ " _id " ] ) ;
BSONObjIterator it ( origQuery ) ;
2011-01-04 00:40:41 -05:00
while ( it . more ( ) ) {
2010-10-28 15:39:09 -04:00
BSONElement e = it . next ( ) ;
if ( strcmp ( e . fieldName ( ) , " _id " ) )
b . append ( e ) ;
}
q = Query ( b . obj ( ) ) ;
2010-07-01 21:05:04 -04:00
}
2011-02-10 15:46:34 -05:00
if ( q . isComplex ( ) ) // update doesn't work with complex queries
q = Query ( q . getFilter ( ) . getOwned ( ) ) ;
2010-07-01 21:05:04 -04:00
BSONElement update = cmdObj [ " update " ] ;
uassert ( 12516 , " must specify remove or update " , ! update . eoo ( ) ) ;
db . update ( ns , q , update . embeddedObjectUserCheck ( ) ) ;
2010-09-23 19:36:51 -04:00
BSONObj gle = db . getLastErrorDetailed ( ) ;
2011-01-04 00:40:41 -05:00
if ( gle [ " err " ] . type ( ) = = String ) {
2010-09-23 19:36:51 -04:00
errmsg = gle [ " err " ] . String ( ) ;
return false ;
}
2010-07-01 21:05:04 -04:00
if ( cmdObj [ " new " ] . trueValue ( ) )
2010-10-28 15:39:09 -04:00
out = db . findOne ( ns , QUERY ( " _id " < < out [ " _id " ] ) , fields ) ;
2010-07-01 21:05:04 -04:00
}
2009-12-30 20:08:43 -05:00
}
result . append ( " value " , out ) ;
return true ;
}
} cmdFindAndModify ;
2011-01-04 00:40:41 -05:00
2010-02-17 17:06:54 -08:00
/* Returns client's uri */
class CmdWhatsMyUri : public Command {
public :
CmdWhatsMyUri ( ) : Command ( " whatsmyuri " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2010-02-17 17:06:54 -08:00
return true ;
}
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2010-02-17 17:06:54 -08:00
virtual bool requiresAuth ( ) {
return false ;
}
2010-03-08 12:54:16 -08:00
virtual void help ( stringstream & help ) const {
help < < " {whatsmyuri:1} " ;
2011-01-04 00:40:41 -05:00
}
2010-05-03 16:25:34 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2010-02-17 17:06:54 -08:00
BSONObj info = cc ( ) . curop ( ) - > infoNoauth ( ) ;
result < < " you " < < info [ " client " ] ;
return true ;
}
} cmdWhatsMyUri ;
2011-01-04 00:40:41 -05:00
2010-03-08 12:54:16 -08:00
/* For testing only, not for general use */
class GodInsert : public Command {
public :
GodInsert ( ) : Command ( " godinsert " ) { }
virtual bool logTheOp ( ) {
return true ;
}
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const {
2010-03-08 12:54:16 -08:00
return false ;
}
2010-04-23 15:50:49 -04:00
virtual LockType locktype ( ) const { return WRITE ; }
2010-03-08 12:54:16 -08:00
virtual bool requiresAuth ( ) {
return true ;
}
virtual void help ( stringstream & help ) const {
2010-04-23 15:50:49 -04:00
help < < " internal. for testing only. " ;
2011-01-04 00:40:41 -05:00
}
2010-05-03 16:25:34 -04:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2010-03-08 12:54:16 -08:00
string coll = cmdObj [ " godinsert " ] . valuestrsafe ( ) ;
uassert ( 13049 , " godinsert must specify a collection " , ! coll . empty ( ) ) ;
2010-05-03 16:25:34 -04:00
string ns = dbname + " . " + coll ;
2010-03-08 12:54:16 -08:00
BSONObj obj = cmdObj [ " obj " ] . embeddedObjectUserCheck ( ) ;
2010-04-28 08:25:56 -04:00
DiskLoc loc = theDataFileMgr . insertWithObjMod ( ns . c_str ( ) , obj , true ) ;
2010-03-08 12:54:16 -08:00
return true ;
}
} cmdGodInsert ;
2010-03-11 08:57:00 -05:00
class DBHashCmd : public Command {
public :
2011-01-04 00:40:41 -05:00
DBHashCmd ( ) : Command ( " dbHash " , false , " dbhash " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return true ; }
virtual LockType locktype ( ) const { return READ ; }
2011-01-04 00:40:41 -05:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2010-04-25 23:15:42 -04:00
list < string > colls ;
Database * db = cc ( ) . database ( ) ;
if ( db )
db - > namespaceIndex . getNamespaces ( colls ) ;
2010-03-11 08:57:00 -05:00
colls . sort ( ) ;
2011-01-04 00:40:41 -05:00
2010-03-11 08:57:00 -05:00
result . appendNumber ( " numCollections " , ( long long ) colls . size ( ) ) ;
2010-11-28 02:07:38 -05:00
result . append ( " host " , prettyHostName ( ) ) ;
2011-01-04 00:40:41 -05:00
2010-03-11 08:57:00 -05:00
md5_state_t globalState ;
md5_init ( & globalState ) ;
BSONObjBuilder bb ( result . subobjStart ( " collections " ) ) ;
2011-01-04 00:40:41 -05:00
for ( list < string > : : iterator i = colls . begin ( ) ; i ! = colls . end ( ) ; i + + ) {
2010-03-11 08:57:00 -05:00
string c = * i ;
if ( c . find ( " .system.profil " ) ! = string : : npos )
continue ;
2011-01-04 00:40:41 -05:00
2010-05-07 17:25:57 -04:00
shared_ptr < Cursor > cursor ;
2010-03-11 08:57:00 -05:00
NamespaceDetails * nsd = nsdetails ( c . c_str ( ) ) ;
2011-01-04 00:40:41 -05:00
2010-03-30 11:58:21 -07:00
// debug SERVER-761
NamespaceDetails : : IndexIterator ii = nsd - > ii ( ) ;
while ( ii . more ( ) ) {
const IndexDetails & idx = ii . next ( ) ;
if ( ! idx . head . isValid ( ) | | ! idx . info . isValid ( ) ) {
log ( ) < < " invalid index for ns: " < < c < < " " < < idx . head < < " " < < idx . info ;
if ( idx . info . isValid ( ) )
2010-07-17 16:07:38 -04:00
log ( ) < < " " < < idx . info . obj ( ) ;
2010-03-30 11:58:21 -07:00
log ( ) < < endl ;
}
}
2011-01-04 00:40:41 -05:00
2010-03-11 08:57:00 -05:00
int idNum = nsd - > findIdIndex ( ) ;
2011-01-04 00:40:41 -05:00
if ( idNum > = 0 ) {
2010-03-11 08:57:00 -05:00
cursor . reset ( new BtreeCursor ( nsd , idNum , nsd - > idx ( idNum ) , BSONObj ( ) , BSONObj ( ) , false , 1 ) ) ;
}
2011-01-04 00:40:41 -05:00
else if ( c . find ( " .system. " ) ! = string : : npos ) {
2010-03-11 08:57:00 -05:00
continue ;
}
2011-01-04 00:40:41 -05:00
else if ( nsd - > capped ) {
2010-03-11 08:57:00 -05:00
cursor = findTableScan ( c . c_str ( ) , BSONObj ( ) ) ;
}
else {
bb . done ( ) ;
errmsg = ( string ) " can't find _id index for: " + c ;
return 0 ;
}
md5_state_t st ;
md5_init ( & st ) ;
2011-01-04 00:40:41 -05:00
2010-03-11 08:57:00 -05:00
long long n = 0 ;
2011-01-04 00:40:41 -05:00
while ( cursor - > ok ( ) ) {
2010-03-11 08:57:00 -05:00
BSONObj c = cursor - > current ( ) ;
md5_append ( & st , ( const md5_byte_t * ) c . objdata ( ) , c . objsize ( ) ) ;
n + + ;
cursor - > advance ( ) ;
}
md5digest d ;
md5_finish ( & st , d ) ;
string hash = digestToString ( d ) ;
2011-01-04 00:40:41 -05:00
2010-03-11 08:57:00 -05:00
bb . append ( c . c_str ( ) + ( dbname . size ( ) + 1 ) , hash ) ;
md5_append ( & globalState , ( const md5_byte_t * ) hash . c_str ( ) , hash . size ( ) ) ;
}
bb . done ( ) ;
md5digest d ;
md5_finish ( & globalState , d ) ;
string hash = digestToString ( d ) ;
result . append ( " md5 " , hash ) ;
return 1 ;
}
} dbhashCmd ;
2010-07-14 10:28:38 -07:00
2010-08-02 15:00:47 -04:00
/* for diagnostic / testing purposes. */
2011-01-04 00:40:41 -05:00
class CmdSleep : public Command {
2010-08-02 15:00:47 -04:00
public :
2011-01-04 00:40:41 -05:00
virtual LockType locktype ( ) const { return NONE ; }
2010-08-02 15:00:47 -04:00
virtual bool adminOnly ( ) const { return true ; }
2010-08-16 09:00:58 -04:00
virtual bool logTheOp ( ) { return false ; }
virtual bool slaveOk ( ) const { return true ; }
2010-08-02 15:00:47 -04:00
virtual void help ( stringstream & help ) const {
help < < " internal testing command. Makes db block (in a read lock) for 100 seconds \n " ;
help < < " w:true write lock " ;
}
CmdSleep ( ) : Command ( " sleep " ) { }
bool run ( const string & ns , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2011-01-04 00:40:41 -05:00
2010-10-13 10:42:18 -04:00
int secs = 100 ;
if ( cmdObj [ " secs " ] . isNumber ( ) )
secs = cmdObj [ " secs " ] . numberInt ( ) ;
2011-01-04 00:40:41 -05:00
if ( cmdObj . getBoolField ( " w " ) ) {
2010-08-02 15:00:47 -04:00
writelock lk ( " " ) ;
2010-10-13 10:42:18 -04:00
sleepsecs ( secs ) ;
2010-08-02 15:00:47 -04:00
}
else {
readlock lk ( " " ) ;
2010-10-13 10:42:18 -04:00
sleepsecs ( secs ) ;
2010-08-02 15:00:47 -04:00
}
2010-10-13 10:42:18 -04:00
2010-08-02 15:00:47 -04:00
return true ;
}
} cmdSleep ;
2010-07-26 15:34:16 -07:00
// just for testing
class CapTrunc : public Command {
public :
2011-01-04 00:40:41 -05:00
CapTrunc ( ) : Command ( " captrunc " ) { }
2010-07-26 15:34:16 -07:00
virtual bool slaveOk ( ) const { return false ; }
virtual LockType locktype ( ) const { return WRITE ; }
virtual bool requiresAuth ( ) { return true ; }
2011-01-04 00:40:41 -05:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2010-07-26 15:34:16 -07:00
string coll = cmdObj [ " captrunc " ] . valuestrsafe ( ) ;
2010-07-26 15:45:40 -07:00
uassert ( 13416 , " captrunc must specify a collection " , ! coll . empty ( ) ) ;
2010-07-26 15:34:16 -07:00
string ns = dbname + " . " + coll ;
int n = cmdObj . getIntField ( " n " ) ;
2010-12-22 12:29:30 -05:00
// inclusive range?
2010-07-26 15:34:16 -07:00
bool inc = cmdObj . getBoolField ( " inc " ) ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
ReverseCappedCursor c ( nsd ) ;
2010-12-22 12:29:30 -05:00
massert ( 13417 , " captrunc collection not found or empty " , c . ok ( ) ) ;
2010-07-26 15:34:16 -07:00
for ( int i = 0 ; i < n ; + + i ) {
2010-07-26 15:45:40 -07:00
massert ( 13418 , " captrunc invalid n " , c . advance ( ) ) ;
2010-07-26 15:34:16 -07:00
}
DiskLoc end = c . currLoc ( ) ;
nsd - > cappedTruncateAfter ( ns . c_str ( ) , end , inc ) ;
return true ;
}
2011-01-04 00:40:41 -05:00
} capTruncCmd ;
2010-08-02 14:26:14 -07:00
// just for testing
class EmptyCapped : public Command {
public :
2011-01-04 00:40:41 -05:00
EmptyCapped ( ) : Command ( " emptycapped " ) { }
2010-08-02 14:26:14 -07:00
virtual bool slaveOk ( ) const { return false ; }
virtual LockType locktype ( ) const { return WRITE ; }
virtual bool requiresAuth ( ) { return true ; }
2011-01-04 00:40:41 -05:00
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
2010-08-02 14:26:14 -07:00
string coll = cmdObj [ " emptycapped " ] . valuestrsafe ( ) ;
uassert ( 13428 , " emptycapped must specify a collection " , ! coll . empty ( ) ) ;
string ns = dbname + " . " + coll ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
massert ( 13429 , " emptycapped no such collection " , nsd ) ;
nsd - > emptyCappedCollection ( ns . c_str ( ) ) ;
return true ;
}
2011-01-04 00:40:41 -05:00
} emptyCappedCmd ;
/**
2010-02-12 13:21:33 -05:00
* this handles
- auth
- locking
- context
then calls run ( )
*/
bool execCommand ( Command * c ,
2011-01-04 00:40:41 -05:00
Client & client , int queryOptions ,
const char * cmdns , BSONObj & cmdObj ,
BSONObjBuilder & result ,
bool fromRepl ) {
2010-05-03 16:25:34 -04:00
string dbname = nsToDatabase ( cmdns ) ;
2010-02-12 13:21:33 -05:00
2011-01-04 00:40:41 -05:00
AuthenticationInfo * ai = client . getAuthenticationInfo ( ) ;
if ( c - > adminOnly ( ) & & c - > localHostOnlyIfNoAuth ( cmdObj ) & & noauth & & ! ai - > isLocalHost ) {
result . append ( " errmsg " ,
2010-02-12 13:21:33 -05:00
" unauthorized: this command must run from localhost when running db without auth " ) ;
log ( ) < < " command denied: " < < cmdObj . toString ( ) < < endl ;
return false ;
}
if ( c - > adminOnly ( ) & & ! fromRepl & & dbname ! = " admin " ) {
2010-08-18 11:50:52 -04:00
result . append ( " errmsg " , " access denied; use admin db " ) ;
2010-02-12 13:21:33 -05:00
log ( ) < < " command denied: " < < cmdObj . toString ( ) < < endl ;
return false ;
2011-01-04 00:40:41 -05:00
}
2010-02-12 13:21:33 -05:00
2011-01-04 00:40:41 -05:00
if ( cmdObj [ " help " ] . trueValue ( ) ) {
2010-02-12 13:21:33 -05:00
stringstream ss ;
ss < < " help for: " < < c - > name < < " " ;
c - > help ( ss ) ;
result . append ( " help " , ss . str ( ) ) ;
2010-03-11 11:20:10 -05:00
result . append ( " lockType " , c - > locktype ( ) ) ;
2010-02-12 13:21:33 -05:00
return true ;
2011-01-04 00:40:41 -05:00
}
2010-02-12 13:21:33 -05:00
2011-01-04 00:40:41 -05:00
bool canRunHere =
2010-02-12 13:36:10 -05:00
isMaster ( dbname . c_str ( ) ) | |
2010-02-12 13:21:33 -05:00
c - > slaveOk ( ) | |
( c - > slaveOverrideOk ( ) & & ( queryOptions & QueryOption_SlaveOk ) ) | |
fromRepl ;
2011-01-04 00:40:41 -05:00
if ( ! canRunHere ) {
2010-02-12 13:21:33 -05:00
result . append ( " errmsg " , " not master " ) ;
return false ;
}
2010-05-11 10:05:34 -04:00
if ( c - > adminOnly ( ) )
2010-07-17 16:07:38 -04:00
log ( 2 ) < < " command: " < < cmdObj < < endl ;
2011-01-04 00:40:41 -05:00
if ( c - > locktype ( ) = = Command : : NONE ) {
2010-02-12 13:21:33 -05:00
// we also trust that this won't crash
string errmsg ;
2010-05-03 16:25:34 -04:00
int ok = c - > run ( dbname , cmdObj , errmsg , result , fromRepl ) ;
2010-02-12 13:21:33 -05:00
if ( ! ok )
result . append ( " errmsg " , errmsg ) ;
return ok ;
}
2011-01-04 00:40:41 -05:00
2010-02-26 14:38:51 -05:00
bool needWriteLock = c - > locktype ( ) = = Command : : WRITE ;
2011-01-04 00:40:41 -05:00
if ( ! needWriteLock ) {
2010-02-12 13:21:33 -05:00
assert ( ! c - > logTheOp ( ) ) ;
}
mongolock lk ( needWriteLock ) ;
2010-05-03 16:25:34 -04:00
Client : : Context ctx ( dbname , dbpath , & lk , c - > requiresAuth ( ) ) ;
2011-01-04 00:40:41 -05:00
2010-02-12 13:21:33 -05:00
try {
string errmsg ;
2011-01-04 00:40:41 -05:00
if ( ! c - > run ( dbname , cmdObj , errmsg , result , fromRepl ) ) {
2010-02-12 13:21:33 -05:00
result . append ( " errmsg " , errmsg ) ;
return false ;
}
}
2011-01-04 00:40:41 -05:00
catch ( DBException & e ) {
2010-02-12 13:21:33 -05:00
stringstream ss ;
2010-05-09 17:29:35 -04:00
ss < < " exception: " < < e . what ( ) ;
2010-02-12 13:21:33 -05:00
result . append ( " errmsg " , ss . str ( ) ) ;
2010-04-16 01:14:45 -04:00
result . append ( " code " , e . getCode ( ) ) ;
2010-02-12 13:21:33 -05:00
return false ;
}
2011-01-04 00:40:41 -05:00
if ( c - > logTheOp ( ) & & ! fromRepl ) {
2010-05-03 16:25:34 -04:00
logOp ( " c " , cmdns , cmdObj ) ;
2010-02-12 13:21:33 -05:00
}
2011-01-04 00:40:41 -05:00
2010-02-12 13:21:33 -05:00
return true ;
}
2009-01-15 10:17:11 -05:00
/* TODO make these all command objects -- legacy stuff here
2008-12-05 10:09:16 -05:00
2009-01-15 10:17:11 -05:00
usage :
abc . $ cmd . findOne ( { ismaster : 1 } ) ;
2008-12-05 10:09:16 -05:00
2009-01-15 10:17:11 -05:00
returns true if ran a cmd
*/
2009-12-29 23:30:29 -05:00
bool _runCommands ( const char * ns , BSONObj & _cmdobj , BufBuilder & b , BSONObjBuilder & anObjBuilder , bool fromRepl , int queryOptions ) {
2010-05-26 11:11:10 -04:00
cc ( ) . curop ( ) - > ensureStarted ( ) ;
2010-02-04 10:49:19 -05:00
string dbname = nsToDatabase ( ns ) ;
2011-01-04 00:40:41 -05:00
if ( logLevel > = 1 )
2010-07-17 16:07:38 -04:00
log ( ) < < " run command " < < ns < < ' ' < < _cmdobj < < endl ;
2011-01-04 00:40:41 -05:00
2009-01-15 10:17:11 -05:00
const char * p = strchr ( ns , ' . ' ) ;
if ( ! p ) return false ;
if ( strcmp ( p , " .$cmd " ) ! = 0 ) return false ;
2008-10-22 16:56:39 -04:00
2009-01-15 10:17:11 -05:00
BSONObj jsobj ;
{
BSONElement e = _cmdobj . firstElement ( ) ;
if ( e . type ( ) = = Object & & string ( " query " ) = = e . fieldName ( ) ) {
jsobj = e . embeddedObject ( ) ;
}
else {
jsobj = _cmdobj ;
}
2008-12-15 09:45:51 -05:00
}
2010-02-04 10:49:19 -05:00
Client & client = cc ( ) ;
2009-01-15 10:17:11 -05:00
bool ok = false ;
2009-11-11 13:30:11 -05:00
BSONElement e = jsobj . firstElement ( ) ;
2011-01-04 00:40:41 -05:00
2010-01-20 14:02:14 -05:00
Command * c = e . type ( ) ? Command : : findCommand ( e . fieldName ( ) ) : 0 ;
2010-05-26 11:11:10 -04:00
2011-01-04 00:40:41 -05:00
if ( c ) {
2010-02-12 13:21:33 -05:00
ok = execCommand ( c , client , queryOptions , ns , jsobj , anObjBuilder , fromRepl ) ;
2008-12-28 20:28:49 -05:00
}
2009-11-11 13:30:11 -05:00
else {
2011-01-21 12:44:13 -05:00
anObjBuilder . append ( " errmsg " , str : : stream ( ) < < " no such cmd: " < < e . fieldName ( ) ) ;
2009-09-01 12:17:41 -04:00
anObjBuilder . append ( " bad cmd " , _cmdobj ) ;
}
2010-05-26 11:11:10 -04:00
2010-07-06 16:17:10 -04:00
// switch to bool, but wait a bit longer before switching?
// anObjBuilder.append("ok", ok);
2010-07-16 01:49:15 -07:00
anObjBuilder . append ( " ok " , ok ? 1.0 : 0.0 ) ;
2009-01-15 10:17:11 -05:00
BSONObj x = anObjBuilder . done ( ) ;
2010-07-19 09:56:24 -04:00
b . appendBuf ( ( void * ) x . objdata ( ) , x . objsize ( ) ) ;
2010-05-26 11:11:10 -04:00
2009-01-15 10:17:11 -05:00
return true ;
}
2011-01-04 00:40:41 -05:00
2009-01-14 17:09:51 -05:00
} // namespace mongo