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"
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 ;
2009-02-04 10:47:36 -05:00
void flushOpLog ( stringstream & ss ) ;
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 :
2010-04-23 15:50:49 -04: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
2010-08-09 16:15:41 -04: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
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-04-23 15:50:49 -04: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-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 < < " return error status of the last operation on this connection " ;
2009-09-01 16:23:56 -04:00
}
2010-04-23 16:41:56 -04:00
CmdGetLastError ( ) : Command ( " getLastError " , false , " getlasterror " ) { }
2010-08-09 16:15:41 -04:00
bool run ( const string & dbnamne , 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
if ( le - > nPrev ! = 1 )
LastError : : noError . appendSelf ( result ) ;
else
le - > appendSelf ( result ) ;
2009-12-17 16:15:36 -05:00
2010-04-02 11:29:45 -04:00
Client & c = cc ( ) ;
c . appendLastOp ( result ) ;
2010-03-30 15:20:22 -04:00
2010-08-09 16:15:41 -04:00
BSONObj cmdObj = _cmdObj ;
{
BSONObj : : iterator i ( _cmdObj ) ;
i . next ( ) ;
if ( ! i . more ( ) ) {
/* empty, use default */
BSONObj * def = getLastErrorDefault ;
if ( def )
cmdObj = * def ;
}
}
2009-12-17 16:15:36 -05:00
if ( cmdObj [ " fsync " ] . trueValue ( ) ) {
log ( ) < < " fsync from getlasterror " < < endl ;
result . append ( " fsyncFiles " , MemoryMappedFile : : flushAll ( true ) ) ;
}
2010-04-02 11:29:45 -04:00
BSONElement e = cmdObj [ " w " ] ;
if ( e . isNumber ( ) ) {
int timeout = cmdObj [ " wtimeout " ] . numberInt ( ) ;
Timer t ;
int w = e . numberInt ( ) ;
long long passes = 0 ;
char buf [ 32 ] ;
while ( 1 ) {
if ( opReplicatedEnough ( c . getLastOp ( ) , w ) )
break ;
if ( timeout > 0 & & t . millis ( ) > = timeout ) {
result . append ( " wtimeout " , true ) ;
errmsg = " timed out waiting for slaves " ;
result . append ( " waited " , t . millis ( ) ) ;
return false ;
}
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 ( ) ) ;
}
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 :
2010-04-23 15:50:49 -04: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-05-03 16:25:34 -04:00
bool run ( const string & dbnamne , 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
}
2010-04-23 15:50:49 -04:00
virtual LockType locktype ( ) const { return WRITE ; }
2009-01-15 10:17:11 -05:00
CmdDropDatabase ( ) : Command ( " dropDatabase " ) { }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbnamne , 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 ( ) < < " dropDatabase " < < dbnamne < < endl ;
2009-01-15 10:17:11 -05:00
int p = ( int ) e . number ( ) ;
if ( p ! = 1 )
return false ;
2010-05-03 16:25:34 -04:00
dropDatabase ( dbnamne ) ;
result . append ( " dropped " , dbnamne ) ;
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. " ;
}
2010-04-23 15:50:49 -04: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 ;
2009-10-07 12:43:24 -04: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 " ;
help < < " http://www.mongodb.org/display/DOCS/Database+Profiler " ;
2009-09-01 16:23:56 -04:00
}
2010-04-23 15:50:49 -04: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 ;
2010-07-24 12:02:43 -04: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 ( ) ;
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 ) ;
}
2010-02-12 13:36:10 -05:00
2010-04-23 15:50:49 -04:00
virtual LockType locktype ( ) const { return NONE ; }
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 ) ;
2010-02-08 17:17:18 -05:00
bool authed = cc ( ) . getAuthenticationInfo ( ) - > isAuthorizedReads ( " admin " ) ;
2008-12-05 16:45:10 -05:00
2010-05-24 11:09:10 -04:00
result . append ( " version " , versionString ) ;
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 ) ) ;
2009-10-07 12:43:24 -04:00
2010-07-12 13:06:16 -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 ( ) ;
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 ) ;
2010-02-08 17:17:18 -05:00
if ( authed ) {
2010-01-10 20:22:17 -05:00
BSONObjBuilder t ( result . subobjStart ( " mem " ) ) ;
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 ;
if ( p . supported ( ) ) {
2010-03-01 17:14:23 -05:00
t . appendNumber ( " resident " , p . getResidentSize ( ) ) ;
t . appendNumber ( " virtual " , p . getVirtualMemorySize ( ) ) ;
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
}
2010-03-01 17:14:23 -05:00
t . appendNumber ( " mapped " , MemoryMappedFile : : totalMappedLength ( ) / ( 1024 * 1024 ) ) ;
2010-01-10 20:22:17 -05:00
t . done ( ) ;
2009-02-20 09:34:25 -05:00
}
2010-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after is authed " , Listener : : getElapsedTimeMillis ( ) - start ) ;
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 ) ;
2010-02-08 17:17:18 -05:00
if ( authed ) {
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 ) ;
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 ( ) ;
}
2010-06-30 12:57:36 -04:00
2010-03-15 16:02:24 -04:00
{
BSONObjBuilder bb ( result . subobjStart ( " backgroundFlushing " ) ) ;
globalFlushCounters . append ( bb ) ;
bb . done ( ) ;
}
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-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after counters " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2010-02-08 17:17:18 -05:00
if ( anyReplEnabled ( ) ) {
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-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after repl " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2010-02-08 17:17:18 -05:00
2010-01-16 00:50:02 -05:00
result . append ( " opcounters " , globalOpCounters . getObj ( ) ) ;
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 ( ) ;
}
2010-06-30 12:57:36 -04:00
timeBuilder . appendNumber ( " after asserts " , Listener : : getElapsedTimeMillis ( ) - start ) ;
2010-02-08 17:17:18 -05:00
if ( ! authed )
result . append ( " note " , " run against admin for more info " ) ;
2010-06-30 12:57:36 -04:00
if ( Listener : : getElapsedTimeMillis ( ) - start > 1000 )
result . append ( " timing " , timeBuilder . obj ( ) ) ;
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 " ; }
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 " ; }
2010-04-23 15:50:49 -04: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 ( ) ) ;
2009-02-04 10:47:36 -05:00
stringstream ss ;
flushOpLog ( ss ) ;
2009-02-19 12:03:15 -05:00
out ( ) < < ss . str ( ) < < endl ;
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
but keep in mind in the future if max indexes were extended to
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 ) ;
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 ) ;
2009-04-20 18:40:38 -04: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 ) ;
2010-01-29 14:58:10 -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 ) ;
2009-04-07 14:24:16 -04: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
if ( n ) {
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>} " ; }
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 :
2010-04-23 15:50:49 -04: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 ;
2009-09-01 17:28:15 -04:00
if ( n = = - 1 ) {
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 ;
}
2010-04-23 15:50:49 -04: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 ;
}
2010-04-23 15:50:49 -04: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
}
2010-01-26 21:04:36 -05:00
else if ( f . type ( ) = = Object ) {
int idxId = d - > findIndexByKeyPattern ( f . embeddedObject ( ) ) ;
if ( idxId < 0 ) {
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
2010-04-23 15:50:49 -04: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
2009-09-29 10:15:06 -04:00
if ( ! d ) {
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 ;
while ( i - > more ( ) ) {
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 ) ;
2009-09-29 10:15:06 -04: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
2009-09-29 10:15:06 -04:00
for ( list < BSONObj > : : iterator i = all . begin ( ) ; i ! = all . end ( ) ; i + + ) {
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 ;
}
2010-07-15 00:31:39 -04: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 " ; }
2009-01-15 10:17:11 -05:00
CmdListDatabases ( ) : Command ( " listDatabases " ) { }
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
}
2010-01-02 01:25:53 -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 ) ;
for ( set < string > : : iterator i = allShortNames . begin ( ) ; i ! = allShortNames . end ( ) ; i + + ) {
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
2010-01-22 15:17:03 -05:00
/* note an access to a database right after this will open it back up - so this is mainly
for diagnostic purposes .
*/
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 ; }
virtual LockType locktype ( ) const { return WRITE ; }
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*/ ) {
2010-01-22 15:17:03 -05:00
return dbHolder . closeAll ( dbpath , result , false ) ;
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 :
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
}
2010-04-23 15:50:49 -04:00
virtual LockType locktype ( ) const { return READ ; }
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
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 ;
2010-05-17 15:14:46 -04:00
while ( cursor - > ok ( ) ) {
2010-05-25 13:37:05 -07:00
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 ( ) ;
if ( n ! = myn ) {
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 + + ;
} catch ( . . . ) {
yield . relock ( ) ; // needed before yield goes out of scope
throw ;
}
if ( ! yield . stillOk ( ) ) {
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 ; }
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 < <
2010-04-23 15:50:49 -04:00
" determine data size for a set of data in a certain range "
2010-08-25 13:50:58 -04:00
" \n example: { dataSize: \" blog.posts \" , keyPattern:{x:1}, min:{x:10}, max:{x:55} } "
2009-09-01 16:03:23 -04:00
" \n keyPattern, min, and max parameters are optional. "
2010-07-22 15:17:34 -04:00
" \n note: This command may take a while to run " ;
2009-04-02 17:29:51 -04:00
}
2010-05-03 16:25:34 -04: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 ( ) ) ;
2010-08-24 01:39:38 -04:00
if ( ! d | | d - > nrecords = = 0 ) {
result . appendNumber ( " size " , 0 ) ;
result . appendNumber ( " numObjects " , 0 ) ;
result . append ( " millis " , timer . millis ( ) ) ;
return true ;
2010-08-24 01:25:45 -04:00
}
2010-01-29 17:22:34 -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 ( ) ) {
2010-08-24 01:25:45 -04:00
if ( estimate ) {
result . appendNumber ( " size " , d - > datasize ) ;
result . appendNumber ( " numObjects " , d - > nrecords ) ;
result . append ( " millis " , timer . millis ( ) ) ;
return 1 ;
}
2010-04-28 12:19:46 -04:00
c = theDataFileMgr . findAll ( ns . c_str ( ) ) ;
}
else if ( min . isEmpty ( ) | | max . isEmpty ( ) ) {
2009-04-02 17:29:51 -04:00
errmsg = " only one of min or max specified " ;
return false ;
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 ;
2010-08-24 01:25:45 -04: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
}
2010-04-28 12:19:46 -04:00
2010-08-24 01:25:45 -04:00
long long avgObjSize = d - > datasize / d - > nrecords ;
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 ( ) ;
2009-04-20 14:45:45 -04:00
numObjects + + ;
2010-04-28 12:19:46 -04:00
if ( ( maxSize & & size > maxSize ) | |
( maxObjects & & numObjects > maxObjects ) ) {
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 ;
if ( ! min . isEmpty ( ) ) {
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 {
2010-02-27 12:11: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 ;
long long totalSize = 0 ;
NamespaceDetails : : IndexIterator ii = nsd - > ii ( ) ;
while ( ii . more ( ) ) {
IndexDetails & d = ii . next ( ) ;
string collNS = d . indexNamespace ( ) ;
NamespaceDetails * mine = nsdetails ( collNS . c_str ( ) ) ;
if ( ! mine ) {
log ( ) < < " error: have index [ " < < collNS < < " ] but no NamespaceDetails " < < endl ;
continue ;
}
totalSize + = mine - > datasize ;
if ( details )
details - > appendNumber ( d . indexName ( ) , mine - > 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 ; }
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
}
2010-05-03 16:25:34 -04: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 ) ;
2009-08-12 13:53:52 -04:00
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
if ( ! nsd ) {
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 ( ) ) ;
2010-02-27 12:11:41 -05:00
int scale = 1 ;
2010-06-22 20:18:30 -04:00
if ( jsobj [ " scale " ] . isNumber ( ) ) {
2010-02-27 12:11:41 -05:00
scale = jsobj [ " scale " ] . numberInt ( ) ;
2010-06-22 20:18:30 -04:00
if ( scale < = 0 ) {
errmsg = " scale has to be > 0 " ;
return false ;
}
}
2010-08-02 11:48:48 -04:00
else if ( jsobj [ " scale " ] . trueValue ( ) ) {
errmsg = " scale has to be a number > 0 " ;
return false ;
}
2009-10-06 14:31:02 -04:00
2010-07-01 17:12:20 -04:00
long long size = nsd - > datasize / scale ;
2010-03-01 17:14:23 -05:00
result . appendNumber ( " count " , nsd - > nrecords ) ;
2010-07-01 17:12:20 -04:00
result . appendNumber ( " size " , size ) ;
result . append ( " avgObjSize " , double ( size ) / double ( nsd - > nrecords ) ) ;
2010-02-07 10:38:23 -05:00
int numExtents ;
2010-03-01 17:14:23 -05:00
result . appendNumber ( " storageSize " , nsd - > storageSize ( & numExtents ) / 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 ( ) ) ;
2010-02-07 10:38:23 -05:00
2009-08-21 17:05:19 -04:00
if ( nsd - > capped ) {
result . append ( " capped " , nsd - > capped ) ;
result . append ( " max " , nsd - > max ) ;
}
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 ; }
virtual LockType locktype ( ) const { return READ ; }
2010-02-22 21:23:20 -05:00
virtual void help ( stringstream & help ) const {
2010-08-25 13:50:58 -04:00
help < < " example: { dbStats:1 } " ;
2010-02-22 21:23:20 -05:00
}
2010-05-03 16:25:34 -04: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 ;
for ( list < string > : : const_iterator it = collections . begin ( ) ; it ! = collections . end ( ) ; + + it ) {
const string ns = * it ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
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 ;
objects + = nsd - > nrecords ;
size + = nsd - > datasize ;
int temp ;
storageSize + = nsd - > storageSize ( & temp ) ;
numExtents + = temp ;
indexes + = nsd - > nIndexes ;
indexSize + = getIndexSizeForCollection ( dbname , ns ) ;
}
2010-03-01 17:14:23 -05:00
result . appendNumber ( " collections " , ncollections ) ;
result . appendNumber ( " objects " , objects ) ;
2010-07-01 17:12:20 -04:00
result . append ( " avgObjSize " , 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 ( ) ) ;
2010-02-22 21:23:20 -05:00
return true ;
}
} 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 ; }
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
}
2010-05-03 16:25:34 -04: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-03-22 13:57:59 -07:00
long long excessSize = nsd - > 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 ( ) ) ;
2009-05-18 13:25:30 -04:00
id = cc - > cursorid ;
}
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
2010-01-21 13:40:18 -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 .
*/
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 ; }
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
}
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
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
2009-05-18 16:25:17 -04:00
DBDirectClient client ;
2010-05-03 16:25:34 -04:00
client . dropCollection ( dbname + " . " + from + " .$temp_convertToCapped " ) ;
2009-05-18 16:25:17 -04:00
BSONObj info ;
2010-05-03 16:25:34 -04:00
if ( ! client . runCommand ( dbname ,
2009-05-18 16:25:17 -04:00
BSON ( " cloneCollectionAsCapped " < < from < < " toCollection " < < ( from + " .$temp_convertToCapped " ) < < " 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-05-03 16:25:34 -04:00
BSON ( " renameCollection " < < ( dbname + " . " + from + " .$temp_convertToCapped " )
< < " to " < < ( dbname + " . " + from ) ) ,
2009-05-18 16:25:17 -04: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
class GroupCommand : public Command {
public :
GroupCommand ( ) : Command ( " group " ) { }
2010-04-23 15:50:49 -04:00
virtual LockType locktype ( ) const { return READ ; }
virtual bool slaveOk ( ) const { return true ; }
2010-05-12 14:49:29 -04:00
virtual bool slaveOverrideOk ( ) { return true ; }
2009-08-19 11:51:16 -04:00
virtual void help ( stringstream & help ) const {
2010-04-23 16:41:56 -04:00
help < < " http://www.mongodb.org/display/DOCS/Aggregation " ;
2009-08-19 11:51:16 -04:00
}
2009-09-15 14:19:54 -04:00
BSONObj getKey ( const BSONObj & obj , const BSONObj & keyPattern , ScriptingFunction func , double avgSize , Scope * s ) {
if ( func ) {
BSONObjBuilder b ( obj . objsize ( ) + 32 ) ;
b . append ( " 0 " , obj ) ;
int res = s - > invoke ( func , b . obj ( ) ) ;
2009-12-28 16:43:43 -05:00
uassert ( 10041 , ( string ) " invoke failed in $keyf: " + s - > getError ( ) , res = = 0 ) ;
2009-09-15 14:19:54 -04:00
int type = s - > type ( " return " ) ;
2009-12-28 16:43:43 -05:00
uassert ( 10042 , " return of $key has to be an object " , type = = Object ) ;
2009-09-15 14:19:54 -04:00
return s - > getObject ( " return " ) ;
}
2009-09-10 15:45:31 -04:00
return obj . extractFields ( keyPattern , true ) ;
2009-08-19 11:51:16 -04:00
}
2009-10-06 14:31:02 -04:00
2010-03-29 13:07:45 -04:00
bool group ( string realdbname , const string & ns , const BSONObj & query ,
2009-09-15 14:19:54 -04:00
BSONObj keyPattern , string keyFunctionCode , string reduceCode , const char * reduceScope ,
2009-09-17 13:09:11 +08:00
BSONObj initial , string finalize ,
2009-09-15 14:02:39 -04:00
string & errmsg , BSONObjBuilder & result ) {
2009-08-19 11:51:16 -04:00
auto_ptr < Scope > s = globalScriptEngine - > getPooledScope ( realdbname ) ;
s - > localConnect ( realdbname . c_str ( ) ) ;
2009-10-06 14:31:02 -04:00
2009-09-15 14:02:39 -04:00
if ( reduceScope )
s - > init ( reduceScope ) ;
2009-08-19 11:51:16 -04:00
s - > setObject ( " $initial " , initial , true ) ;
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
s - > exec ( " $reduce = " + reduceCode , " reduce setup " , false , true , true , 100 ) ;
s - > exec ( " $arr = []; " , " reduce setup 2 " , false , true , true , 100 ) ;
2009-09-17 13:03:30 +08:00
ScriptingFunction f = s - > createFunction (
" function(){ "
" if ( $arr[n] == null ){ "
" next = {}; "
" Object.extend( next , $key ); "
2009-10-15 21:19:24 -04:00
" Object.extend( next , $initial , true ); "
2009-09-17 13:03:30 +08:00
" $arr[n] = next; "
" next = null; "
" } "
" $reduce( obj , $arr[n] ); "
" } " ) ;
2009-09-15 14:19:54 -04:00
ScriptingFunction keyFunction = 0 ;
if ( keyFunctionCode . size ( ) ) {
keyFunction = s - > createFunction ( keyFunctionCode . c_str ( ) ) ;
}
2009-08-19 11:51:16 -04:00
double keysize = keyPattern . objsize ( ) * 3 ;
double keynum = 1 ;
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
map < BSONObj , int , BSONObjCmp > map ;
list < BSONObj > blah ;
2009-10-06 14:31:02 -04:00
2010-05-25 13:37:05 -07:00
shared_ptr < Cursor > cursor = bestGuessCursor ( ns . c_str ( ) , query , BSONObj ( ) ) ;
2010-03-29 13:07:45 -04:00
while ( cursor - > ok ( ) ) {
2010-05-25 13:37:05 -07:00
if ( cursor - > matcher ( ) & & ! cursor - > matcher ( ) - > matchesCurrent ( cursor . get ( ) ) ) {
2010-03-29 13:07:45 -04:00
cursor - > advance ( ) ;
continue ;
}
BSONObj obj = cursor - > current ( ) ;
cursor - > advance ( ) ;
2009-09-15 14:19:54 -04:00
BSONObj key = getKey ( obj , keyPattern , keyFunction , keysize / keynum , s . get ( ) ) ;
2009-08-19 11:51:16 -04:00
keysize + = key . objsize ( ) ;
keynum + + ;
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
int & n = map [ key ] ;
if ( n = = 0 ) {
n = map . size ( ) ;
s - > setObject ( " $key " , key , true ) ;
2009-09-17 22:00:58 -04:00
2009-12-28 16:43:43 -05:00
uassert ( 10043 , " group() can't handle more than 10000 unique keys " , n < = 10000 ) ;
2009-08-19 11:51:16 -04:00
}
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
s - > setObject ( " obj " , obj , true ) ;
s - > setNumber ( " n " , n - 1 ) ;
2009-08-24 11:07:44 -04:00
if ( s - > invoke ( f , BSONObj ( ) , 0 , true ) ) {
2009-12-28 17:06:07 -05:00
throw UserException ( 9010 , ( string ) " reduce invoke failed: " + s - > getError ( ) ) ;
2009-08-24 11:07:44 -04:00
}
2009-08-19 11:51:16 -04:00
}
2009-10-06 14:31:02 -04:00
2009-09-17 13:09:11 +08:00
if ( ! finalize . empty ( ) ) {
s - > exec ( " $finalize = " + finalize , " finalize define " , false , true , true , 100 ) ;
ScriptingFunction g = s - > createFunction (
" function(){ "
" for(var i=0; i < $arr.length; i++){ "
" var ret = $finalize($arr[i]); "
" if (ret !== undefined) "
" $arr[i] = ret; "
" } "
" } " ) ;
s - > invoke ( g , BSONObj ( ) , 0 , true ) ;
}
2009-10-08 12:32:50 -04:00
2009-08-19 11:51:16 -04:00
result . appendArray ( " retval " , s - > getObject ( " $arr " ) ) ;
result . append ( " count " , keynum - 1 ) ;
result . append ( " keys " , ( int ) ( map . size ( ) ) ) ;
2009-10-08 12:32:50 -04:00
s - > exec ( " $arr = []; " , " reduce setup 2 " , false , true , true , 100 ) ;
s - > gc ( ) ;
2009-08-19 11:51:16 -04:00
return true ;
}
2009-10-06 14:31:02 -04:00
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & jsobj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
2009-08-19 11:51:16 -04:00
2009-08-24 11:42:15 -04:00
/* db.$cmd.findOne( { group : <p> } ) */
2009-08-19 11:51:16 -04:00
const BSONObj & p = jsobj . firstElement ( ) . embeddedObjectUserCheck ( ) ;
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
BSONObj q ;
if ( p [ " cond " ] . type ( ) = = Object )
q = p [ " cond " ] . embeddedObject ( ) ;
2009-10-08 20:02:02 -04:00
else if ( p [ " condition " ] . type ( ) = = Object )
q = p [ " condition " ] . embeddedObject ( ) ;
2009-11-24 09:41:33 -05:00
else
q = getQuery ( p ) ;
2009-10-06 14:31:02 -04:00
2009-08-19 12:33:06 -04:00
if ( p [ " ns " ] . type ( ) ! = String ) {
errmsg = " ns has to be set " ;
return false ;
}
2010-05-03 16:25:34 -04:00
string ns = dbname + " . " + p [ " ns " ] . String ( ) ;
2009-08-19 11:51:16 -04:00
BSONObj key ;
string keyf ;
if ( p [ " key " ] . type ( ) = = Object ) {
key = p [ " key " ] . embeddedObjectUserCheck ( ) ;
if ( ! p [ " $keyf " ] . eoo ( ) ) {
errmsg = " can't have key and $keyf " ;
return false ;
}
}
else if ( p [ " $keyf " ] . type ( ) ) {
2010-04-24 17:14:44 -04:00
keyf = p [ " $keyf " ] . _asCode ( ) ;
2009-08-19 11:51:16 -04:00
}
2009-10-06 14:31:02 -04:00
else {
2009-08-24 11:59:00 -04:00
// no key specified, will use entire object as key
2009-08-24 11:42:15 -04:00
}
2009-08-19 11:51:16 -04:00
2009-09-15 14:02:39 -04:00
BSONElement reduce = p [ " $reduce " ] ;
2009-11-18 20:37:00 -05:00
if ( reduce . eoo ( ) ) {
errmsg = " $reduce has to be set " ;
return false ;
}
BSONElement initial = p [ " initial " ] ;
if ( initial . type ( ) ! = Object ) {
errmsg = " initial has to be an object " ;
return false ;
}
2009-09-17 13:09:11 +08:00
string finalize ;
if ( p [ " finalize " ] . type ( ) )
2010-04-24 17:14:44 -04:00
finalize = p [ " finalize " ] . _asCode ( ) ;
2009-10-06 14:31:02 -04:00
2010-05-03 16:25:34 -04:00
return group ( dbname , ns , q ,
2010-04-24 17:14:44 -04:00
key , keyf , reduce . _asCode ( ) , reduce . type ( ) ! = CodeWScope ? 0 : reduce . codeWScopeScopeData ( ) ,
2009-11-18 20:37:00 -05:00
initial . embeddedObject ( ) , finalize ,
2009-09-15 14:02:39 -04:00
errmsg , result ) ;
2009-08-19 11:51:16 -04:00
}
2009-10-06 14:31:02 -04:00
2009-08-19 11:51:16 -04:00
} cmdGroup ;
2009-09-09 17:33:27 -04:00
class DistinctCommand : public Command {
public :
DistinctCommand ( ) : Command ( " distinct " ) { }
2010-04-23 15:50:49 -04:00
virtual bool slaveOk ( ) const { return true ; }
virtual LockType locktype ( ) const { return READ ; }
2009-09-09 17:33:27 -04:00
virtual void help ( stringstream & help ) const {
2010-07-12 12:53:54 -04:00
help < < " { distinct : 'collection name' , key : 'a.b' , query : {} } " ;
2009-09-09 17:33:27 -04:00
}
2009-10-06 14:31:02 -04:00
2010-05-03 16:25:34 -04:00
bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool fromRepl ) {
string ns = dbname + ' . ' + cmdObj . firstElement ( ) . valuestr ( ) ;
2009-10-06 14:31:02 -04:00
2010-03-29 11:24:00 -04:00
string key = cmdObj [ " key " ] . valuestrsafe ( ) ;
2009-09-09 17:33:27 -04:00
BSONObj keyPattern = BSON ( key < < 1 ) ;
2009-10-06 14:31:02 -04:00
2010-03-29 11:24:00 -04:00
BSONObj query = getQuery ( cmdObj ) ;
2010-03-29 17:08:58 -04:00
BSONElementSet values ;
2010-05-25 13:03:47 -07:00
shared_ptr < Cursor > cursor = bestGuessCursor ( ns . c_str ( ) , query , BSONObj ( ) ) ;
2010-08-09 13:57:30 -04:00
scoped_ptr < ClientCursor > cc ( new ClientCursor ( QueryOption_NoCursorTimeout , cursor , ns ) ) ;
2010-03-29 12:55:44 -04:00
while ( cursor - > ok ( ) ) {
2010-08-09 14:42:24 -04:00
if ( ! cursor - > matcher ( ) | | cursor - > matcher ( ) - > matchesCurrent ( cursor . get ( ) ) ) {
BSONObj o = cursor - > current ( ) ;
o . getFieldsDotted ( key , values ) ;
2010-03-29 12:55:44 -04:00
}
cursor - > advance ( ) ;
2010-08-09 13:57:30 -04:00
if ( ! cc - > yieldSometimes ( ) )
break ;
2009-09-09 17:33:27 -04:00
}
2009-09-21 16:37:20 -04:00
2010-03-29 13:49:32 -04:00
BSONArrayBuilder b ( result . subarrayStart ( " values " ) ) ;
2010-03-29 17:08:58 -04:00
for ( BSONElementSet : : iterator i = values . begin ( ) ; i ! = values . end ( ) ; i + + ) {
2010-03-29 13:49:32 -04:00
b . append ( * i ) ;
2009-09-09 17:33:27 -04:00
}
2010-03-29 17:08:58 -04:00
BSONObj arr = b . done ( ) ;
uassert ( 10044 , " distinct too big, 4mb cap " ,
( arr . objsize ( ) + 1024 ) < ( 4 * 1024 * 1024 ) ) ;
2009-09-09 17:33:27 -04:00
return true ;
}
2009-10-06 14:31:02 -04:00
2009-09-09 17:33:27 -04:00
} distinctCmd ;
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 {
help < <
2010-08-25 13:50:58 -04:00
" { findAndModify: \" collection \" , query: {processed:false}, update: {$set: {processed:true}}, new: true} \n "
" { findAndModify: \" collection \" , query: {processed:false}, remove: true, sort: {priority:-1}} \n "
2010-04-23 15:50:49 -04:00
" Either update or remove is required, all other fields have default values. \n "
" Output is in the \" value \" field \n " ;
}
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 ;
}
2010-04-23 15:50:49 -04: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 ) ;
2010-07-01 21:05:04 -04:00
if ( out . isEmpty ( ) ) {
if ( ! upsert ) {
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-07-01 21:05:04 -04:00
if ( cmdObj [ " new " ] . trueValue ( ) ) {
2010-07-02 14:56:45 -04:00
BSONObj gle = db . getLastErrorDetailed ( ) ;
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
2010-07-01 21:05:04 -04:00
} else {
Query idQuery = QUERY ( " _id " < < out [ " _id " ] ) ;
if ( cmdObj [ " remove " ] . trueValue ( ) ) {
uassert ( 12515 , " can't remove and update " , cmdObj [ " update " ] . eoo ( ) ) ;
db . remove ( ns , idQuery , 1 ) ;
} else { // update
2009-12-30 20:08:43 -05:00
2010-07-01 21:05:04 -04:00
// need to include original query for $ positional operator
BSONObjBuilder b ;
b . append ( out [ " _id " ] ) ;
BSONObjIterator it ( origQuery ) ;
while ( it . more ( ) ) {
BSONElement e = it . next ( ) ;
if ( strcmp ( e . fieldName ( ) , " _id " ) )
b . append ( e ) ;
}
q = Query ( b . obj ( ) ) ;
BSONElement update = cmdObj [ " update " ] ;
uassert ( 12516 , " must specify remove or update " , ! update . eoo ( ) ) ;
db . update ( ns , q , update . embeddedObjectUserCheck ( ) ) ;
if ( cmdObj [ " new " ] . trueValue ( ) )
out = db . findOne ( ns , idQuery , fields ) ;
}
2009-12-30 20:08:43 -05:00
}
result . append ( " value " , out ) ;
return true ;
}
} cmdFindAndModify ;
2010-01-20 14:02:14 -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 ;
}
2010-04-23 15:50:49 -04: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} " ;
}
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 ;
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. " ;
2010-03-08 12:54:16 -08: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 :
2010-04-23 16:41:56 -04: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 ; }
2010-05-03 16:25:34 -04: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 ( ) ;
result . appendNumber ( " numCollections " , ( long long ) colls . size ( ) ) ;
md5_state_t globalState ;
md5_init ( & globalState ) ;
BSONObjBuilder bb ( result . subobjStart ( " collections " ) ) ;
for ( list < string > : : iterator i = colls . begin ( ) ; i ! = colls . end ( ) ; i + + ) {
string c = * i ;
if ( c . find ( " .system.profil " ) ! = string : : npos )
continue ;
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 ( ) ) ;
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 ;
}
}
2010-03-11 08:57:00 -05:00
int idNum = nsd - > findIdIndex ( ) ;
if ( idNum > = 0 ) {
cursor . reset ( new BtreeCursor ( nsd , idNum , nsd - > idx ( idNum ) , BSONObj ( ) , BSONObj ( ) , false , 1 ) ) ;
}
else if ( c . find ( " .system. " ) ! = string : : npos ) {
continue ;
}
else if ( nsd - > capped ) {
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 ) ;
long long n = 0 ;
while ( cursor - > ok ( ) ) {
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 ) ;
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. */
class CmdSleep : public Command {
public :
virtual LockType locktype ( ) const { return NONE ; }
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 ) {
if ( cmdObj . getBoolField ( " w " ) ) {
writelock lk ( " " ) ;
sleepsecs ( 100 ) ;
}
else {
readlock lk ( " " ) ;
sleepsecs ( 100 ) ;
}
return true ;
}
} cmdSleep ;
2010-07-14 10:28:38 -07:00
class AvailableQueryOptions : public Command {
public :
AvailableQueryOptions ( ) : Command ( " availablequeryoptions " ) { }
virtual bool slaveOk ( ) const { return true ; }
virtual LockType locktype ( ) const { return NONE ; }
virtual bool requiresAuth ( ) { return false ; }
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
result < < " options " < < QueryOption_AllSupported ;
return true ;
}
} availableQueryOptionsCmd ;
2010-03-08 12:54:16 -08:00
2010-07-26 15:34:16 -07:00
// just for testing
class CapTrunc : public Command {
public :
CapTrunc ( ) : Command ( " captrunc " ) { }
virtual bool slaveOk ( ) const { return false ; }
virtual LockType locktype ( ) const { return WRITE ; }
virtual bool requiresAuth ( ) { return true ; }
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
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 " ) ;
bool inc = cmdObj . getBoolField ( " inc " ) ;
NamespaceDetails * nsd = nsdetails ( ns . c_str ( ) ) ;
ReverseCappedCursor c ( nsd ) ;
2010-07-26 15:45:40 -07:00
massert ( 13417 , " captrunc invalid collection " , 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 ;
}
} capTruncCmd ;
2010-08-02 14:26:14 -07:00
// just for testing
class EmptyCapped : public Command {
public :
EmptyCapped ( ) : Command ( " emptycapped " ) { }
virtual bool slaveOk ( ) const { return false ; }
virtual LockType locktype ( ) const { return WRITE ; }
virtual bool requiresAuth ( ) { return true ; }
virtual bool run ( const string & dbname , BSONObj & cmdObj , string & errmsg , BSONObjBuilder & result , bool ) {
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 ;
}
} emptyCappedCmd ;
2010-02-12 13:21:33 -05:00
/**
* this handles
- auth
- locking
- context
then calls run ( )
*/
bool execCommand ( Command * c ,
Client & client , int queryOptions ,
2010-05-03 16:25:34 -04:00
const char * cmdns , BSONObj & cmdObj ,
2010-02-12 13:21:33 -05:00
BSONObjBuilder & result ,
bool fromRepl ) {
2010-05-03 16:25:34 -04:00
string dbname = nsToDatabase ( cmdns ) ;
2010-02-12 13:21:33 -05:00
AuthenticationInfo * ai = client . getAuthenticationInfo ( ) ;
if ( c - > adminOnly ( ) & & c - > localHostOnlyIfNoAuth ( cmdObj ) & & noauth & & ! ai - > isLocalHost ) {
result . append ( " errmsg " ,
" 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 ;
}
if ( cmdObj [ " help " ] . trueValue ( ) ) {
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 ;
}
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 ;
if ( ! canRunHere ) {
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 ;
2010-02-12 13:21:33 -05:00
2010-02-26 14:38:51 -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 ;
}
2010-02-26 14:38:51 -05:00
bool needWriteLock = c - > locktype ( ) = = Command : : WRITE ;
2010-02-12 13:21:33 -05:00
if ( ! needWriteLock ) {
assert ( ! c - > logTheOp ( ) ) ;
}
mongolock lk ( needWriteLock ) ;
2010-05-03 16:25:34 -04:00
Client : : Context ctx ( dbname , dbpath , & lk , c - > requiresAuth ( ) ) ;
2010-02-12 13:21:33 -05:00
try {
string errmsg ;
2010-05-03 16:25:34 -04:00
if ( ! c - > run ( dbname , cmdObj , errmsg , result , fromRepl ) ) {
2010-02-12 13:21:33 -05:00
result . append ( " errmsg " , errmsg ) ;
return false ;
}
}
2010-05-09 17:29:35 -04: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 ;
}
if ( c - > logTheOp ( ) & & ! fromRepl ) {
2010-05-03 16:25:34 -04:00
logOp ( " c " , cmdns , cmdObj ) ;
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 ) ;
2009-12-03 11:50:09 -05:00
if ( logLevel > = 1 )
2010-07-17 16:07:38 -04:00
log ( ) < < " run command " < < ns < < ' ' < < _cmdobj < < endl ;
2010-02-04 10:49:19 -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 ( ) ;
2010-02-03 11:52:15 -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
2010-01-20 14:02:14 -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 {
2009-01-15 10:17:11 -05:00
anObjBuilder . append ( " errmsg " , " no such cmd " ) ;
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 ;
}
2010-05-26 11:11:10 -04:00
2009-01-14 17:09:51 -05:00
} // namespace mongo