summaryrefslogtreecommitdiff
path: root/db/dbcommands.cpp
diff options
context:
space:
mode:
authorAntonin Kral <a.kral@bobek.cz>2010-08-11 12:38:57 +0200
committerAntonin Kral <a.kral@bobek.cz>2010-08-11 12:38:57 +0200
commit7645618fd3914cb8a20561625913c20d49504a49 (patch)
tree8370f846f58f6d71165b7a0e2eda04648584ec76 /db/dbcommands.cpp
parent68c73c3c7608b4c87f07440dc3232801720b1168 (diff)
downloadmongodb-7645618fd3914cb8a20561625913c20d49504a49.tar.gz
Imported Upstream version 1.6.0
Diffstat (limited to 'db/dbcommands.cpp')
-rw-r--r--db/dbcommands.cpp1018
1 files changed, 562 insertions, 456 deletions
diff --git a/db/dbcommands.cpp b/db/dbcommands.cpp
index 85c695d..94edf0a 100644
--- a/db/dbcommands.cpp
+++ b/db/dbcommands.cpp
@@ -15,11 +15,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "stdafx.h"
+#include "pch.h"
#include "query.h"
#include "pdfile.h"
#include "jsobj.h"
-#include "../util/builder.h"
+#include "../bson/util/builder.h"
#include <time.h>
#include "introspect.h"
#include "btree.h"
@@ -28,7 +28,8 @@
#include "../util/processinfo.h"
#include "json.h"
#include "repl.h"
-#include "replset.h"
+#include "repl_block.h"
+#include "replpair.h"
#include "commands.h"
#include "db.h"
#include "instance.h"
@@ -38,38 +39,13 @@
#include "../scripting/engine.h"
#include "stats/counters.h"
#include "background.h"
+#include "../util/version.h"
namespace mongo {
- TicketHolder connTicketHolder( 20000 );
-
extern int otherTraceLevel;
void flushOpLog( stringstream &ss );
- class CmdShutdown : public Command {
- public:
- virtual bool requiresAuth() { return true; }
- virtual bool adminOnly() { return true; }
- virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return true; }
- virtual bool logTheOp() {
- return false;
- }
- virtual bool slaveOk() {
- return true;
- }
- virtual LockType locktype(){ return WRITE; }
- virtual void help( stringstream& help ) const {
- help << "shutdown the database. must be ran against admin db and either (1) ran from localhost or (2) authenticated.\n";
- }
- CmdShutdown() : Command("shutdown") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- cc().shutdown();
- log() << "terminating, shutdown command received" << endl;
- dbexit( EXIT_CLEAN ); // this never returns
- return true;
- }
- } cmdShutdown;
-
/* reset any errors so that getlasterror comes back clean.
useful before performing a long series of operations where we want to
@@ -78,19 +54,19 @@ namespace mongo {
*/
class CmdResetError : public Command {
public:
- virtual LockType locktype(){ return NONE; }
+ virtual LockType locktype() const { return NONE; }
virtual bool requiresAuth() { return false; }
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual void help( stringstream& help ) const {
help << "reset error state (used with getpreverror)";
}
- CmdResetError() : Command("reseterror") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ CmdResetError() : Command("resetError", false, "reseterror") {}
+ bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
LastError *le = lastError.get();
assert( le );
le->reset();
@@ -98,77 +74,70 @@ namespace mongo {
}
} cmdResetError;
- /* for diagnostic / testing purposes. */
- class CmdSleep : public Command {
- public:
- virtual LockType locktype(){ return READ; }
- virtual bool adminOnly() { return true; }
- virtual bool logTheOp() {
- return false;
- }
- virtual bool slaveOk() {
- return true;
- }
- virtual void help( stringstream& help ) const {
- help << "internal / make db block for 100 seconds";
- }
- CmdSleep() : Command("sleep") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- sleepsecs(100);
- return true;
- }
- } cmdSleep;
-
class CmdGetLastError : public Command {
public:
- virtual LockType locktype(){ return NONE; }
+ virtual LockType locktype() const { return NONE; }
virtual bool requiresAuth() { return false; }
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual void help( stringstream& help ) const {
- help << "return error status of the last operation";
+ help << "return error status of the last operation on this connection";
}
- CmdGetLastError() : Command("getlasterror") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ CmdGetLastError() : Command("getLastError", false, "getlasterror") {}
+ bool run(const string& dbnamne, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
LastError *le = lastError.disableForCommand();
if ( le->nPrev != 1 )
LastError::noError.appendSelf( result );
else
le->appendSelf( result );
+ Client& c = cc();
+ c.appendLastOp( result );
+
if ( cmdObj["fsync"].trueValue() ){
log() << "fsync from getlasterror" << endl;
result.append( "fsyncFiles" , MemoryMappedFile::flushAll( true ) );
}
- return true;
- }
- } cmdGetLastError;
+ 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;
+ }
- /* for testing purposes only */
- class CmdForceError : public Command {
- public:
- virtual bool logTheOp() {
- return false;
- }
- virtual bool slaveOk() {
- return true;
- }
- virtual LockType locktype(){ return NONE; }
- CmdForceError() : Command("forceerror") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- uassert( 10038 , "forced error", false);
+ assert( sprintf( buf , "w block pass: %lld" , ++passes ) < 30 );
+ c.curop()->setMessage( buf );
+ sleepmillis(1);
+ killCurrentOp.checkForInterrupt();
+ }
+ result.appendNumber( "wtime" , t.millis() );
+ }
+
return true;
}
- } cmdForceError;
+ } cmdGetLastError;
class CmdGetPrevError : public Command {
public:
- virtual LockType locktype(){ return NONE; }
+ virtual LockType locktype() const { return NONE; }
virtual bool requiresAuth() { return false; }
virtual bool logTheOp() {
return false;
@@ -176,11 +145,11 @@ namespace mongo {
virtual void help( stringstream& help ) const {
help << "check for errors since last reseterror commandcal";
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
- CmdGetPrevError() : Command("getpreverror") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ CmdGetPrevError() : Command("getPrevError", false, "getpreverror") {}
+ bool run(const string& dbnamne, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
LastError *le = lastError.disableForCommand();
le->appendSelf( result );
if ( le->valid )
@@ -200,12 +169,12 @@ namespace mongo {
virtual void help( stringstream& help ) const {
help << "convert to id based errors rather than connection based";
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
- virtual LockType locktype(){ return NONE; }
- CmdSwitchToClientErrors() : Command("switchtoclienterrors") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ virtual LockType locktype() const { return NONE; }
+ CmdSwitchToClientErrors() : Command("switchToClientErrors", false, "switchtoclienterrors") {}
+ bool run(const string& dbnamne , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
if ( lastError.getID() ){
errmsg = "already in client id mode";
return false;
@@ -225,19 +194,19 @@ namespace mongo {
virtual void help( stringstream& help ) const {
help << "drop (delete) this database";
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
CmdDropDatabase() : Command("dropDatabase") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- BSONElement e = cmdObj.getField(name);
- log() << "dropDatabase " << ns << endl;
+ bool run(const string& dbnamne, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ BSONElement e = cmdObj.firstElement();
+ log() << "dropDatabase " << dbnamne << endl;
int p = (int) e.number();
if ( p != 1 )
return false;
- dropDatabase(ns);
- result.append( "dropped" , ns );
+ dropDatabase(dbnamne);
+ result.append( "dropped" , dbnamne );
return true;
}
} cmdDropDatabase;
@@ -247,17 +216,17 @@ namespace mongo {
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual void help( stringstream& help ) const {
help << "repair database. also compacts. note: slow.";
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
CmdRepairDatabase() : Command("repairDatabase") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- BSONElement e = cmdObj.getField(name);
- log() << "repairDatabase " << ns << endl;
+ bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ BSONElement e = cmdObj.firstElement();
+ log() << "repairDatabase " << dbname << endl;
int p = (int) e.number();
if ( p != 1 )
return false;
@@ -265,7 +234,7 @@ namespace mongo {
bool preserveClonedFilesOnFailure = e.isBoolean() && e.boolean();
e = cmdObj.getField( "backupOriginalFiles" );
bool backupOriginalFiles = e.isBoolean() && e.boolean();
- return repairDatabase( ns, errmsg, preserveClonedFilesOnFailure, backupOriginalFiles );
+ return repairDatabase( dbname, errmsg, preserveClonedFilesOnFailure, backupOriginalFiles );
}
} cmdRepairDatabase;
@@ -275,19 +244,25 @@ namespace mongo {
*/
class CmdProfile : public Command {
public:
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual void help( stringstream& help ) const {
- help << "enable or disable performance profiling";
+ 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";
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
CmdProfile() : Command("profile") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- BSONElement e = cmdObj.getField(name);
- result.append("was", (double) cc().database()->profile);
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ BSONElement e = cmdObj.firstElement();
+ result.append("was", cc().database()->profile);
+ result.append("slowms", cmdLine.slowMS );
+
int p = (int) e.number();
bool ok = false;
+
if ( p == -1 )
ok = true;
else if ( p >= 0 && p <= 2 ) {
@@ -304,21 +279,30 @@ namespace mongo {
class CmdServerStatus : public Command {
public:
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
- CmdServerStatus() : Command("serverStatus") {
+ CmdServerStatus() : Command("serverStatus", true) {
started = time(0);
}
- virtual LockType locktype(){ return NONE; }
+ virtual LockType locktype() const { return NONE; }
+
+ virtual void help( stringstream& help ) const {
+ help << "returns lots of administrative server statistics";
+ }
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ long long start = Listener::getElapsedTimeMillis();
+ BSONObjBuilder timeBuilder(128);
+
+
bool authed = cc().getAuthenticationInfo()->isAuthorizedReads("admin");
result.append("version", versionString);
result.append("uptime",(double) (time(0)-started));
+ result.append("uptimeEstimate",(double) (start/1000));
result.appendDate( "localTime" , jsTime() );
{
@@ -333,9 +317,18 @@ namespace mongo {
t.append("lockTime", tl);
t.append("ratio", (tt ? tl/tt : 0));
+ 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();
+
result.append( "globalLock" , t.obj() );
}
-
+ timeBuilder.appendNumber( "after basic" , Listener::getElapsedTimeMillis() - start );
+
if ( authed ){
BSONObjBuilder t( result.subobjStart( "mem" ) );
@@ -358,6 +351,7 @@ namespace mongo {
t.done();
}
+ timeBuilder.appendNumber( "after is authed" , Listener::getElapsedTimeMillis() - start );
{
BSONObjBuilder bb( result.subobjStart( "connections" ) );
@@ -365,6 +359,7 @@ namespace mongo {
bb.append( "available" , connTicketHolder.available() );
bb.done();
}
+ timeBuilder.appendNumber( "after connections" , Listener::getElapsedTimeMillis() - start );
if ( authed ){
BSONObjBuilder bb( result.subobjStart( "extra_info" ) );
@@ -372,26 +367,31 @@ namespace mongo {
ProcessInfo p;
p.getExtraInfo(bb);
bb.done();
+ timeBuilder.appendNumber( "after extra info" , Listener::getElapsedTimeMillis() - start );
+
}
-
{
BSONObjBuilder bb( result.subobjStart( "indexCounters" ) );
globalIndexCounters.append( bb );
bb.done();
}
-
+
{
BSONObjBuilder bb( result.subobjStart( "backgroundFlushing" ) );
globalFlushCounters.append( bb );
bb.done();
}
-
+
+ timeBuilder.appendNumber( "after counters" , Listener::getElapsedTimeMillis() - start );
+
if ( anyReplEnabled() ){
BSONObjBuilder bb( result.subobjStart( "repl" ) );
appendReplicationInfo( bb , authed , cmdObj["repl"].numberInt() );
bb.done();
}
+
+ timeBuilder.appendNumber( "after repl" , Listener::getElapsedTimeMillis() - start );
result.append( "opcounters" , globalOpCounters.getObj() );
@@ -405,44 +405,28 @@ namespace mongo {
asserts.done();
}
+ timeBuilder.appendNumber( "after asserts" , Listener::getElapsedTimeMillis() - start );
+
if ( ! authed )
result.append( "note" , "run against admin for more info" );
+
+ if ( Listener::getElapsedTimeMillis() - start > 1000 )
+ result.append( "timing" , timeBuilder.obj() );
return true;
}
time_t started;
} cmdServerStatus;
- /* just to check if the db has asserted */
- class CmdAssertInfo : public Command {
- public:
- virtual bool slaveOk() {
- return true;
- }
- virtual void help( stringstream& help ) const {
- help << "check if any asserts have occurred on the server";
- }
- virtual LockType locktype(){ return WRITE; }
- CmdAssertInfo() : Command("assertinfo") {}
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
- result.appendBool("dbasserted", lastAssert[0].isSet() || lastAssert[1].isSet() || lastAssert[2].isSet());
- result.appendBool("asserted", lastAssert[0].isSet() || lastAssert[1].isSet() || lastAssert[2].isSet() || lastAssert[3].isSet());
- result.append("assert", lastAssert[AssertRegular].toString());
- result.append("assertw", lastAssert[AssertW].toString());
- result.append("assertmsg", lastAssert[AssertMsg].toString());
- result.append("assertuser", lastAssert[AssertUser].toString());
- return true;
- }
- } cmdAsserts;
-
class CmdGetOpTime : public Command {
public:
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
- virtual LockType locktype(){ return NONE; }
+ virtual void help( stringstream& help ) const { help << "internal"; }
+ virtual LockType locktype() const { return NONE; }
CmdGetOpTime() : Command("getoptime") { }
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
writelock l( "" );
result.appendDate("optime", OpTime::now().asDate());
return true;
@@ -453,7 +437,7 @@ namespace mongo {
class Cmd : public Command {
public:
Cmd() : Command("") { }
- bool adminOnly() { return true; }
+ bool adminOnly() const { return true; }
bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result) {
return true;
}
@@ -462,21 +446,22 @@ namespace mongo {
class CmdDiagLogging : public Command {
public:
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
CmdDiagLogging() : Command("diagLogging") { }
- bool adminOnly() {
+ bool adminOnly() const {
return true;
}
- virtual LockType locktype(){ return WRITE; }
- bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ void help(stringstream& h) const { h << "http://www.mongodb.org/display/DOCS/Monitoring+and+Diagnostics#MonitoringandDiagnostics-DatabaseRecord%2FReplay"; }
+ virtual LockType locktype() const { return WRITE; }
+ bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
int was = _diaglog.setLevel( cmdObj.firstElement().numberInt() );
stringstream ss;
flushOpLog( ss );
out() << ss.str() << endl;
if ( !cmdLine.quiet )
- log() << "CMD: diagLogging set to " << _diaglog.level << " from: " << was << endl;
+ tlog() << "CMD: diagLogging set to " << _diaglog.level << " from: " << was << endl;
result.append( "was" , was );
return true;
}
@@ -584,18 +569,19 @@ namespace mongo {
virtual bool logTheOp() {
return true;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual bool adminOnly() {
+ virtual bool adminOnly() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
- virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
- string nsToDrop = cc().database()->name + '.' + cmdObj.getField(name).valuestr();
+ virtual void help( stringstream& help ) const { help << "drop a collection\n{drop : <collectionName>}"; }
+ virtual LockType locktype() const { return WRITE; }
+ virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ string nsToDrop = dbname + '.' + cmdObj.firstElement().valuestr();
NamespaceDetails *d = nsdetails(nsToDrop.c_str());
if ( !cmdLine.quiet )
- log() << "CMD: drop " << nsToDrop << endl;
+ tlog() << "CMD: drop " << nsToDrop << endl;
if ( d == 0 ) {
errmsg = "ns not found";
return false;
@@ -609,23 +595,24 @@ namespace mongo {
/* select count(*) */
class CmdCount : public Command {
public:
- virtual LockType locktype(){ return READ; }
+ virtual LockType locktype() const { return READ; }
CmdCount() : Command("count") { }
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
// ok on --slave setups, not ok for nonmaster of a repl pair (unless override)
return replSettings.slave == SimpleSlave;
}
virtual bool slaveOverrideOk() {
return true;
}
- virtual bool adminOnly() {
+ virtual bool adminOnly() const {
return false;
}
- virtual bool run(const char *_ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
- string ns = cc().database()->name + '.' + cmdObj.getField(name).valuestr();
+ virtual void help( stringstream& help ) const { help << "count objects in collection"; }
+ virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ string ns = dbname + '.' + cmdObj.firstElement().valuestr();
string err;
long long n = runCount(ns.c_str(), cmdObj, err);
long long nn = n;
@@ -652,18 +639,18 @@ namespace mongo {
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual bool adminOnly() {
+ virtual bool adminOnly() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream& help ) const {
help << "create a collection";
}
- virtual bool run(const char *_ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
- string ns = cc().database()->name + '.' + cmdObj.getField(name).valuestr();
+ virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ string ns = dbname + '.' + cmdObj.firstElement().valuestr();
string err;
bool ok = userCreateNS(ns.c_str(), cmdObj, err, true);
if ( !ok && !err.empty() )
@@ -678,20 +665,20 @@ namespace mongo {
virtual bool logTheOp() {
return true;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream& help ) const {
help << "drop indexes for a collection";
}
- CmdDropIndexes(const char *cmdname = "dropIndexes") : Command(cmdname) { }
- bool run(const char *ns, BSONObj& jsobj, string& errmsg, BSONObjBuilder& anObjBuilder, bool /*fromRepl*/) {
- BSONElement e = jsobj.getField(name.c_str());
- string toDeleteNs = cc().database()->name + '.' + e.valuestr();
+ CmdDropIndexes() : Command("dropIndexes", false, "deleteIndexes") { }
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& anObjBuilder, bool /*fromRepl*/) {
+ BSONElement e = jsobj.firstElement();
+ string toDeleteNs = dbname + '.' + e.valuestr();
NamespaceDetails *d = nsdetails(toDeleteNs.c_str());
if ( !cmdLine.quiet )
- log() << "CMD: dropIndexes " << toDeleteNs << endl;
+ tlog() << "CMD: dropIndexes " << toDeleteNs << endl;
if ( d ) {
BSONElement f = jsobj.getField("index");
if ( f.type() == String ) {
@@ -701,7 +688,7 @@ namespace mongo {
int idxId = d->findIndexByKeyPattern( f.embeddedObject() );
if ( idxId < 0 ){
errmsg = "can't find index with key:";
- errmsg += f.embeddedObject();
+ errmsg += f.embeddedObject().toString();
return false;
}
else {
@@ -721,33 +708,28 @@ namespace mongo {
}
}
} cmdDropIndexes;
- class CmdDeleteIndexes : public CmdDropIndexes {
- public:
- CmdDeleteIndexes() : CmdDropIndexes("deleteIndexes") { }
- } cmdDeleteIndexes;
class CmdReIndex : public Command {
public:
virtual bool logTheOp() {
return true;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream& help ) const {
help << "re-index a collection";
}
CmdReIndex() : Command("reIndex") { }
- bool run(const char *ns, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
- BackgroundOperation::assertNoBgOpInProgForNs(ns);
-
+ bool run(const string& dbname , BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
static DBDirectClient db;
- BSONElement e = jsobj.getField(name.c_str());
- string toDeleteNs = cc().database()->name + '.' + e.valuestr();
+ BSONElement e = jsobj.firstElement();
+ string toDeleteNs = dbname + '.' + e.valuestr();
NamespaceDetails *d = nsdetails(toDeleteNs.c_str());
- log() << "CMD: reIndex " << toDeleteNs << endl;
+ tlog() << "CMD: reIndex " << toDeleteNs << endl;
+ BackgroundOperation::assertNoBgOpInProgForNs(toDeleteNs.c_str());
if ( ! d ){
errmsg = "ns not found";
@@ -772,7 +754,7 @@ namespace mongo {
for ( list<BSONObj>::iterator i=all.begin(); i!=all.end(); i++ ){
BSONObj o = *i;
- db.insert( Namespace( toDeleteNs.c_str() ).getSisterNS( "system.indexes" ).c_str() , o );
+ theDataFileMgr.insertWithObjMod( Namespace( toDeleteNs.c_str() ).getSisterNS( "system.indexes" ).c_str() , o , true );
}
result.append( "ok" , 1 );
@@ -787,18 +769,19 @@ namespace mongo {
virtual bool logTheOp() {
return false;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual bool slaveOverrideOk() {
return true;
}
- virtual bool adminOnly() {
+ virtual bool adminOnly() const {
return true;
}
- virtual LockType locktype(){ return WRITE; }
+ virtual LockType locktype() const { return READ; }
+ virtual void help( stringstream& help ) const { help << "list databases on this server"; }
CmdListDatabases() : Command("listDatabases") {}
- bool run(const char *ns, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
+ bool run(const string& dbname , BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
vector< string > dbNames;
getDatabaseNames( dbNames );
vector< BSONObj > dbInfos;
@@ -846,11 +829,13 @@ namespace mongo {
*/
class CmdCloseAllDatabases : public Command {
public:
- virtual bool adminOnly() { return true; }
- virtual bool slaveOk() { return false; }
- virtual LockType locktype(){ return WRITE; }
+ virtual void help( stringstream& help ) const { help << "Close all database files.\nA new request will cause an immediate reopening; thus, this is mostly for testing purposes."; }
+ virtual bool adminOnly() const { return true; }
+ virtual bool slaveOk() const { return false; }
+ virtual LockType locktype() const { return WRITE; }
+
CmdCloseAllDatabases() : Command( "closeAllDatabases" ) {}
- bool run(const char *ns, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
+ bool run(const string& dbname , BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool /*fromRepl*/) {
return dbHolder.closeAll( dbpath , result, false );
}
} cmdCloseAllDatabases;
@@ -858,17 +843,15 @@ namespace mongo {
class CmdFileMD5 : public Command {
public:
CmdFileMD5() : Command( "filemd5" ){}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
virtual void help( stringstream& help ) const {
- help << " example: { filemd5 : ObjectId(aaaaaaa) , key : { ts : 1 } }";
+ help << " example: { filemd5 : ObjectId(aaaaaaa) , root : \"fs\" }";
}
- virtual LockType locktype(){ return READ; }
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- static DBDirectClient db;
-
- string ns = nsToDatabase( dbname );
+ virtual LockType locktype() const { return READ; }
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ string ns = dbname;
ns += ".";
{
string root = jsobj.getStringField( "root" );
@@ -878,41 +861,71 @@ namespace mongo {
}
ns += ".chunks"; // make this an option in jsobj
- BSONObjBuilder query;
- query.appendAs( jsobj["filemd5"] , "files_id" );
- Query q( query.obj() );
- q.sort( BSON( "files_id" << 1 << "n" << 1 ) );
-
md5digest d;
md5_state_t st;
md5_init(&st);
- dbtemprelease temp;
+ BSONObj query = BSON( "files_id" << jsobj["filemd5"] );
+ BSONObj sort = BSON( "files_id" << 1 << "n" << 1 );
+
+ shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str(), query, sort);
+ scoped_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns.c_str()));
- auto_ptr<DBClientCursor> cursor = db.query( ns.c_str() , q );
int n = 0;
- while ( cursor->more() ){
- BSONObj c = cursor->next();
- int myn = c.getIntField( "n" );
- if ( n != myn ){
- log() << "should have chunk: " << n << " have:" << myn << endl;
- uassert( 10040 , "chunks out of order" , n == myn );
+ while ( cursor->ok() ){
+ if ( ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
+ log() << "**** NOT MATCHING ****" << endl;
+ PRINT(cursor->current());
+ cursor->advance();
+ continue;
}
- int len;
- const char * data = c["data"].binData( len );
- md5_append( &st , (const md5_byte_t*)(data + 4) , len - 4 );
+ BSONObj obj = cursor->current();
+ cursor->advance();
+
+ ClientCursor::YieldLock yield (cc);
+ try {
+
+ BSONElement ne = obj["n"];
+ assert(ne.isNumber());
+ int myn = ne.numberInt();
+ if ( n != myn ){
+ log() << "should have chunk: " << n << " have:" << myn << endl;
+
+ 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 );
+ }
+
+ int len;
+ const char * data = obj["data"].binDataClean( len );
+ md5_append( &st , (const md5_byte_t*)(data) , len );
+
+ n++;
+ } catch (...) {
+ yield.relock(); // needed before yield goes out of scope
+ throw;
+ }
- n++;
+ if ( ! yield.stillOk() ){
+ uasserted(13281, "File deleted during filemd5 command");
+ }
}
+
md5_finish(&st, d);
+ result.append( "numChunks" , n );
result.append( "md5" , digestToString( d ) );
return true;
}
} cmdFileMD5;
- IndexDetails *cmdIndexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern ) {
+ static IndexDetails *cmdIndexDetailsForRange( const char *ns, string &errmsg, BSONObj &min, BSONObj &max, BSONObj &keyPattern ) {
if ( ns[ 0 ] == '\0' || min.isEmpty() || max.isEmpty() ) {
errmsg = "invalid command syntax (note: min and max are required)";
return 0;
@@ -920,103 +933,71 @@ namespace mongo {
return indexDetailsForRange( ns, errmsg, min, max, keyPattern );
}
- class CmdMedianKey : public Command {
- public:
- CmdMedianKey() : Command( "medianKey" ) {}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype(){ return READ; }
- virtual void help( stringstream &help ) const {
- help << " example: { medianKey:\"blog.posts\", keyPattern:{x:1}, min:{x:10}, max:{x:55} }\n"
- "NOTE: This command may take awhile to run";
- }
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- const char *ns = jsobj.getStringField( "medianKey" );
- BSONObj min = jsobj.getObjectField( "min" );
- BSONObj max = jsobj.getObjectField( "max" );
- BSONObj keyPattern = jsobj.getObjectField( "keyPattern" );
-
- Client::Context ctx( ns );
-
- IndexDetails *id = cmdIndexDetailsForRange( ns, errmsg, min, max, keyPattern );
- if ( id == 0 )
- return false;
-
- Timer t;
- int num = 0;
- NamespaceDetails *d = nsdetails(ns);
- int idxNo = d->idxNo(*id);
- for( BtreeCursor c( d, idxNo, *id, min, max, false, 1 ); c.ok(); c.advance(), ++num );
- num /= 2;
- BtreeCursor c( d, idxNo, *id, min, max, false, 1 );
- for( ; num; c.advance(), --num );
- int ms = t.millis();
- if ( ms > cmdLine.slowMS ) {
- out() << "Finding median for index: " << keyPattern << " between " << min << " and " << max << " took " << ms << "ms." << endl;
- }
-
- if ( !c.ok() ) {
- errmsg = "no index entries in the specified range";
- return false;
- }
-
- result.append( "median", c.prettyKey( c.currKey() ) );
- return true;
- }
- } cmdMedianKey;
-
class CmdDatasize : public Command {
public:
- CmdDatasize() : Command( "datasize" ) {}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype(){ return READ; }
+ CmdDatasize() : Command( "dataSize", false, "datasize" ) {}
+ virtual bool slaveOk() const { return true; }
+ virtual LockType locktype() const { return READ; }
virtual void help( stringstream &help ) const {
help <<
- "\ndetermine data size for a set of data in a certain range"
+ "determine data size for a set of data in a certain range"
"\nexample: { datasize:\"blog.posts\", keyPattern:{x:1}, min:{x:10}, max:{x:55} }"
"\nkeyPattern, min, and max parameters are optional."
- "\nnot: This command may take a while to run";
+ "\nnote: This command may take a while to run";
}
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- const char *ns = jsobj.getStringField( "datasize" );
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ string ns = jsobj.firstElement().String();
BSONObj min = jsobj.getObjectField( "min" );
BSONObj max = jsobj.getObjectField( "max" );
BSONObj keyPattern = jsobj.getObjectField( "keyPattern" );
Client::Context ctx( ns );
- auto_ptr< Cursor > c;
+ shared_ptr<Cursor> c;
if ( min.isEmpty() && max.isEmpty() ) {
- c = theDataFileMgr.findAll( ns );
- } else if ( min.isEmpty() || max.isEmpty() ) {
+ c = theDataFileMgr.findAll( ns.c_str() );
+ }
+ else if ( min.isEmpty() || max.isEmpty() ) {
errmsg = "only one of min or max specified";
return false;
- } else {
- IndexDetails *idx = cmdIndexDetailsForRange( ns, errmsg, min, max, keyPattern );
+ }
+ else {
+ IndexDetails *idx = cmdIndexDetailsForRange( ns.c_str(), errmsg, min, max, keyPattern );
if ( idx == 0 )
return false;
- NamespaceDetails *d = nsdetails(ns);
+ NamespaceDetails *d = nsdetails(ns.c_str());
c.reset( new BtreeCursor( d, d->idxNo(*idx), *idx, min, max, false, 1 ) );
}
+
+ long long maxSize = jsobj["maxSize"].numberLong();
+ long long maxObjects = jsobj["maxObjects"].numberLong();
- Timer t;
+ Timer timer;
long long size = 0;
long long numObjects = 0;
while( c->ok() ) {
- size += c->current().objsize();
- c->advance();
+ size += c->currLoc().rec()->netLength();
numObjects++;
- }
- int ms = t.millis();
- if ( ms > cmdLine.slowMS ) {
- if ( min.isEmpty() ) {
- out() << "Finding size for ns: " << ns << " took " << ms << "ms." << endl;
- } else {
- out() << "Finding size for ns: " << ns << " between " << min << " and " << max << " took " << ms << "ms." << endl;
+
+ if ( ( maxSize && size > maxSize ) ||
+ ( maxObjects && numObjects > maxObjects ) ){
+ result.appendBool( "maxReached" , true );
+ break;
}
+
+ c->advance();
}
+ ostringstream os;
+ os << "Finding size for ns: " << ns;
+ if ( ! min.isEmpty() ){
+ os << " between " << min << " and " << max;
+ }
+ logIfSlow( timer , os.str() );
+
result.append( "size", (double)size );
result.append( "numObjects" , (double)numObjects );
+ result.append( "millis" , timer.millis() );
return true;
}
} cmdDatasize;
@@ -1050,19 +1031,16 @@ namespace mongo {
class CollectionStats : public Command {
public:
- CollectionStats() : Command( "collstats" ) {}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype(){ return READ; }
+ CollectionStats() : Command( "collStats", false, "collstats" ) {}
+ virtual bool slaveOk() const { return true; }
+ virtual LockType locktype() const { return READ; }
virtual void help( stringstream &help ) const {
- help << " example: { collstats:\"blog.posts\" } ";
+ help << "{ collStats:\"blog.posts\" , scale : 1 } scale divides sizes e.g. for KB use 1024";
}
- bool run(const char *dbname_c, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- string dbname = dbname_c;
- if ( dbname.find( "." ) != string::npos )
- dbname = dbname.substr( 0 , dbname.find( "." ) );
-
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
string ns = dbname + "." + jsobj.firstElement().valuestr();
-
+ Client::Context cx( ns );
+
NamespaceDetails * nsd = nsdetails( ns.c_str() );
if ( ! nsd ){
errmsg = "ns not found";
@@ -1072,11 +1050,23 @@ namespace mongo {
result.append( "ns" , ns.c_str() );
int scale = 1;
- if ( jsobj["scale"].isNumber() )
+ if ( jsobj["scale"].isNumber() ){
scale = jsobj["scale"].numberInt();
+ if ( scale <= 0 ){
+ errmsg = "scale has to be > 0";
+ return false;
+ }
+
+ }
+ else if ( jsobj["scale"].trueValue() ){
+ errmsg = "scale has to be a number > 0";
+ return false;
+ }
+ long long size = nsd->datasize / scale;
result.appendNumber( "count" , nsd->nrecords );
- result.appendNumber( "size" , nsd->datasize / scale );
+ result.appendNumber( "size" , size );
+ result.append ( "avgObjSize" , double(size) / double(nsd->nrecords) );
int numExtents;
result.appendNumber( "storageSize" , nsd->storageSize( &numExtents ) / scale );
result.append( "numExtents" , numExtents );
@@ -1098,22 +1088,19 @@ namespace mongo {
}
} cmdCollectionStatis;
-
class DBStats : public Command {
public:
- DBStats() : Command( "dbstats" ) {}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype(){ return READ; }
+ DBStats() : Command( "dbStats", false, "dbstats" ) {}
+ virtual bool slaveOk() const { return true; }
+ virtual LockType locktype() const { return READ; }
virtual void help( stringstream &help ) const {
help << " example: { dbstats:1 } ";
}
- bool run(const char *dbname_c, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- string dbname = dbname_c;
- if ( dbname.find( "." ) != string::npos )
- dbname = dbname.substr( 0 , dbname.find( "." ) );
-
- DBDirectClient client;
- const list<string> collections = client.getCollectionNames(dbname);
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ list<string> collections;
+ Database* d = cc().database();
+ if ( d )
+ d->namespaceIndex.getNamespaces( collections );
long long ncollections = 0;
long long objects = 0;
@@ -1128,8 +1115,9 @@ namespace mongo {
NamespaceDetails * nsd = nsdetails( ns.c_str() );
if ( ! nsd ){
- // should this assert here?
- continue;
+ errmsg = "missing ns: ";
+ errmsg += ns;
+ return false;
}
ncollections += 1;
@@ -1146,42 +1134,28 @@ namespace mongo {
result.appendNumber( "collections" , ncollections );
result.appendNumber( "objects" , objects );
+ result.append ( "avgObjSize" , double(size) / double(objects) );
result.appendNumber( "dataSize" , size );
result.appendNumber( "storageSize" , storageSize);
result.appendNumber( "numExtents" , numExtents );
result.appendNumber( "indexes" , indexes );
result.appendNumber( "indexSize" , indexSize );
+ result.appendNumber( "fileSize" , d->fileSize() );
return true;
}
} cmdDBStats;
- class CmdBuildInfo : public Command {
- public:
- CmdBuildInfo() : Command( "buildinfo" ) {}
- virtual bool slaveOk() { return true; }
- virtual bool adminOnly() { return true; }
- virtual LockType locktype(){ return NONE; }
- virtual void help( stringstream &help ) const {
- help << "example: { buildinfo:1 }";
- }
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- result << "version" << versionString << "gitVersion" << gitVersion() << "sysInfo" << sysInfo();
- result << "bits" << ( sizeof( int* ) == 4 ? 32 : 64 );
- return true;
- }
- } cmdBuildInfo;
-
/* convertToCapped seems to use this */
class CmdCloneCollectionAsCapped : public Command {
public:
CmdCloneCollectionAsCapped() : Command( "cloneCollectionAsCapped" ) {}
- virtual bool slaveOk() { return false; }
- virtual LockType locktype(){ return WRITE; }
+ virtual bool slaveOk() const { return false; }
+ virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream &help ) const {
- help << "example: { cloneCollectionAsCapped:<fromName>, toCollection:<toName>, size:<sizeInBytes> }";
+ help << "{ cloneCollectionAsCapped:<fromName>, toCollection:<toName>, size:<sizeInBytes> }";
}
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
string from = jsobj.getStringField( "cloneCollectionAsCapped" );
string to = jsobj.getStringField( "toCollection" );
long long size = (long long)jsobj.getField( "size" ).number();
@@ -1191,11 +1165,8 @@ namespace mongo {
return false;
}
- char realDbName[256];
- nsToDatabase( dbname, realDbName );
-
- string fromNs = string( realDbName ) + "." + from;
- string toNs = string( realDbName ) + "." + to;
+ string fromNs = dbname + "." + from;
+ string toNs = dbname + "." + to;
NamespaceDetails *nsd = nsdetails( fromNs.c_str() );
massert( 10301 , "source collection " + fromNs + " does not exist", nsd );
long long excessSize = nsd->datasize - size * 2; // datasize and extentSize can't be compared exactly, so add some padding to 'size'
@@ -1209,9 +1180,8 @@ namespace mongo {
CursorId id;
{
- auto_ptr< Cursor > c = theDataFileMgr.findAll( fromNs.c_str(), startLoc );
- ClientCursor *cc = new ClientCursor(c, fromNs.c_str(), true);
- cc->matcher.reset( new CoveredIndexMatcher( BSONObj(), fromjson( "{$natural:1}" ) ) );
+ shared_ptr<Cursor> c = theDataFileMgr.findAll( fromNs.c_str(), startLoc );
+ ClientCursor *cc = new ClientCursor(0, c, fromNs.c_str());
id = cc->cursorid;
}
@@ -1241,13 +1211,13 @@ namespace mongo {
class CmdConvertToCapped : public Command {
public:
CmdConvertToCapped() : Command( "convertToCapped" ) {}
- virtual bool slaveOk() { return false; }
- virtual LockType locktype(){ return WRITE; }
+ virtual bool slaveOk() const { return false; }
+ virtual LockType locktype() const { return WRITE; }
virtual void help( stringstream &help ) const {
- help << "example: { convertToCapped:<fromCollectionName>, size:<sizeInBytes> }";
+ help << "{ convertToCapped:<fromCollectionName>, size:<sizeInBytes> }";
}
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- BackgroundOperation::assertNoBgOpInProgForDb(dbname);
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ BackgroundOperation::assertNoBgOpInProgForDb(dbname.c_str());
string from = jsobj.getStringField( "convertToCapped" );
long long size = (long long)jsobj.getField( "size" ).number();
@@ -1257,29 +1227,27 @@ namespace mongo {
return false;
}
- char realDbName[256];
- nsToDatabase( dbname, realDbName );
-
DBDirectClient client;
- client.dropCollection( string( realDbName ) + "." + from + ".$temp_convertToCapped" );
+ client.dropCollection( dbname + "." + from + ".$temp_convertToCapped" );
BSONObj info;
- if ( !client.runCommand( realDbName,
+ if ( !client.runCommand( dbname ,
BSON( "cloneCollectionAsCapped" << from << "toCollection" << ( from + ".$temp_convertToCapped" ) << "size" << double( size ) ),
info ) ) {
- errmsg = "cloneCollectionAsCapped failed: " + string(info);
+ errmsg = "cloneCollectionAsCapped failed: " + info.toString();
return false;
}
- if ( !client.dropCollection( string( realDbName ) + "." + from ) ) {
+ if ( !client.dropCollection( dbname + "." + from ) ) {
errmsg = "failed to drop original collection";
return false;
}
if ( !client.runCommand( "admin",
- BSON( "renameCollection" << ( string( realDbName ) + "." + from + ".$temp_convertToCapped" ) << "to" << ( string( realDbName ) + "." + from ) ),
+ BSON( "renameCollection" << ( dbname + "." + from + ".$temp_convertToCapped" )
+ << "to" << ( dbname + "." + from ) ),
info ) ) {
- errmsg = "renameCollection failed: " + string(info);
+ errmsg = "renameCollection failed: " + info.toString();
return false;
}
@@ -1290,10 +1258,11 @@ namespace mongo {
class GroupCommand : public Command {
public:
GroupCommand() : Command("group"){}
- virtual LockType locktype(){ return READ; }
- virtual bool slaveOk() { return true; }
+ virtual LockType locktype() const { return READ; }
+ virtual bool slaveOk() const { return true; }
+ virtual bool slaveOverrideOk() { return true; }
virtual void help( stringstream &help ) const {
- help << "see http://www.mongodb.org/display/DOCS/Aggregation";
+ help << "http://www.mongodb.org/display/DOCS/Aggregation";
}
BSONObj getKey( const BSONObj& obj , const BSONObj& keyPattern , ScriptingFunction func , double avgSize , Scope * s ){
@@ -1309,7 +1278,7 @@ namespace mongo {
return obj.extractFields( keyPattern , true );
}
- bool group( string realdbname , auto_ptr<DBClientCursor> cursor ,
+ bool group( string realdbname , const string& ns , const BSONObj& query ,
BSONObj keyPattern , string keyFunctionCode , string reduceCode , const char * reduceScope ,
BSONObj initial , string finalize ,
string& errmsg , BSONObjBuilder& result ){
@@ -1349,8 +1318,17 @@ namespace mongo {
map<BSONObj,int,BSONObjCmp> map;
list<BSONObj> blah;
- while ( cursor->more() ){
- BSONObj obj = cursor->next();
+ shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
+
+ while ( cursor->ok() ){
+ if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
+ cursor->advance();
+ continue;
+ }
+
+ BSONObj obj = cursor->current();
+ cursor->advance();
+
BSONObj key = getKey( obj , keyPattern , keyFunction , keysize / keynum , s.get() );
keysize += key.objsize();
keynum++;
@@ -1392,8 +1370,7 @@ namespace mongo {
return true;
}
- bool run(const char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- static DBDirectClient db;
+ bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
/* db.$cmd.findOne( { group : <p> } ) */
const BSONObj& p = jsobj.firstElement().embeddedObjectUserCheck();
@@ -1406,18 +1383,12 @@ namespace mongo {
else
q = getQuery( p );
- string ns = dbname;
- ns = ns.substr( 0 , ns.size() - 4 );
- string realdbname = ns.substr( 0 , ns.size() - 1 );
-
if ( p["ns"].type() != String ){
errmsg = "ns has to be set";
return false;
}
-
- ns += p["ns"].valuestr();
-
- auto_ptr<DBClientCursor> cursor = db.query( ns , q );
+
+ string ns = dbname + "." + p["ns"].String();
BSONObj key;
string keyf;
@@ -1429,7 +1400,7 @@ namespace mongo {
}
}
else if ( p["$keyf"].type() ){
- keyf = p["$keyf"].ascode();
+ keyf = p["$keyf"]._asCode();
}
else {
// no key specified, will use entire object as key
@@ -1450,10 +1421,10 @@ namespace mongo {
string finalize;
if (p["finalize"].type())
- finalize = p["finalize"].ascode();
+ finalize = p["finalize"]._asCode();
- return group( realdbname , cursor ,
- key , keyf , reduce.ascode() , reduce.type() != CodeWScope ? 0 : reduce.codeWScopeScopeData() ,
+ return group( dbname , ns , q ,
+ key , keyf , reduce._asCode() , reduce.type() != CodeWScope ? 0 : reduce.codeWScopeScopeData() ,
initial.embeddedObject() , finalize ,
errmsg , result );
}
@@ -1464,44 +1435,43 @@ namespace mongo {
class DistinctCommand : public Command {
public:
DistinctCommand() : Command("distinct"){}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype(){ return READ; }
+ virtual bool slaveOk() const { return true; }
+ virtual LockType locktype() const { return READ; }
virtual void help( stringstream &help ) const {
- help << "{ distinct : 'collection name' , key : 'a.b' }";
+ help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }";
}
- bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
- static DBDirectClient db;
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
+ string ns = dbname + '.' + cmdObj.firstElement().valuestr();
- string ns = cc().database()->name + '.' + cmdObj.getField(name).valuestr();
string key = cmdObj["key"].valuestrsafe();
-
BSONObj keyPattern = BSON( key << 1 );
- set<BSONObj,BSONObjCmp> map;
-
- long long size = 0;
+ BSONObj query = getQuery( cmdObj );
+
+ BSONElementSet values;
+ shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
- auto_ptr<DBClientCursor> cursor = db.query( ns , getQuery( cmdObj ) , 0 , 0 , &keyPattern );
- while ( cursor->more() ){
- BSONObj o = cursor->next();
- BSONObj value = o.extractFields( keyPattern );
- if ( value.isEmpty() )
+ while ( cursor->ok() ){
+ if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
+ cursor->advance();
continue;
- if ( map.insert( value ).second ){
- size += o.objsize() + 20;
- uassert( 10044 , "distinct too big, 4mb cap" , size < 4 * 1024 * 1024 );
}
+
+ BSONObj o = cursor->current();
+ cursor->advance();
+
+ o.getFieldsDotted( key.c_str(), values );
}
- assert( size <= 0x7fffffff );
- BSONObjBuilder b( (int) size );
- int n=0;
- for ( set<BSONObj,BSONObjCmp>::iterator i = map.begin() ; i != map.end(); i++ ){
- b.appendAs( i->firstElement() , b.numStr( n++ ).c_str() );
+ BSONArrayBuilder b( result.subarrayStart( "values" ) );
+ for ( BSONElementSet::iterator i = values.begin() ; i != values.end(); i++ ){
+ b.append( *i );
}
+ BSONObj arr = b.done();
- result.appendArray( "values" , b.obj() );
+ uassert(10044, "distinct too big, 4mb cap",
+ (arr.objsize() + 1024) < (4 * 1024 * 1024));
return true;
}
@@ -1511,48 +1481,88 @@ namespace mongo {
/* Find and Modify an object returning either the old (default) or new value*/
class CmdFindAndModify : public Command {
public:
- /* {findandmodify: "collection", query: {processed:false}, update: {$set: {processed:true}}, new: true}
- * {findandmodify: "collection", query: {processed:false}, remove: true, sort: {priority:-1}}
- *
- * either update or remove is required, all other fields have default values
- * output is in the "value" field
- */
- CmdFindAndModify() : Command("findandmodify") { }
+ virtual void help( stringstream &help ) const {
+ 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";
+ }
+
+ CmdFindAndModify() : Command("findAndModify", false, "findandmodify") { }
virtual bool logTheOp() {
return false; // the modification will be logged directly
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual LockType locktype(){ return WRITE; }
- virtual bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ virtual LockType locktype() const { return WRITE; }
+ virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
static DBDirectClient db;
- string ns = nsToDatabase(dbname) + '.' + cmdObj.firstElement().valuestr();
+ string ns = dbname + '.' + cmdObj.firstElement().valuestr();
- Query q (cmdObj.getObjectField("query")); // defaults to {}
+ BSONObj origQuery = cmdObj.getObjectField("query"); // defaults to {}
+ Query q (origQuery);
BSONElement sort = cmdObj["sort"];
if (!sort.eoo())
q.sort(sort.embeddedObjectUserCheck());
- BSONObj out = db.findOne(ns, q);
- if (out.firstElement().eoo()){
- errmsg = "No matching object found";
- return false;
- }
+ bool upsert = cmdObj["upsert"].trueValue();
- q = QUERY( "_id" << out["_id"]);
+ BSONObj fieldsHolder (cmdObj.getObjectField("fields"));
+ const BSONObj* fields = (fieldsHolder.isEmpty() ? NULL : &fieldsHolder);
+
+ BSONObj out = db.findOne(ns, q, fields);
+ if (out.isEmpty()){
+ if (!upsert){
+ errmsg = "No matching object found";
+ return false;
+ }
- if (cmdObj["remove"].trueValue()){
- uassert(12515, "can't remove and update", cmdObj["update"].eoo());
- db.remove(ns, q, 1);
- } else {
BSONElement update = cmdObj["update"];
- uassert(12516, "must specify remove or update", !update.eoo());
- db.update(ns, q, update.embeddedObjectUserCheck());
+ 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);
+
+ if (cmdObj["new"].trueValue()){
+ BSONObj gle = db.getLastErrorDetailed();
+
+ BSONElement _id = gle["upserted"];
+ if (_id.eoo())
+ _id = origQuery["_id"];
+
+ out = db.findOne(ns, QUERY("_id" << _id), fields);
+ }
+
+ } else {
- if (cmdObj["new"].trueValue())
- out = db.findOne(ns, q);
+ 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
+
+ // 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);
+ }
}
result.append("value", out);
@@ -1568,17 +1578,17 @@ namespace mongo {
virtual bool logTheOp() {
return false; // the modification will be logged directly
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return true;
}
- virtual LockType locktype(){ return NONE; }
+ virtual LockType locktype() const { return NONE; }
virtual bool requiresAuth() {
return false;
}
virtual void help( stringstream &help ) const {
help << "{whatsmyuri:1}";
}
- virtual bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
BSONObj info = cc().curop()->infoNoauth();
result << "you" << info[ "client" ];
return true;
@@ -1592,35 +1602,36 @@ namespace mongo {
virtual bool logTheOp() {
return true;
}
- virtual bool slaveOk() {
+ virtual bool slaveOk() const {
return false;
}
- virtual LockType locktype() { return WRITE; }
+ virtual LockType locktype() const { return WRITE; }
virtual bool requiresAuth() {
return true;
}
virtual void help( stringstream &help ) const {
- help << "[for testing only]";
+ help << "internal. for testing only.";
}
- virtual bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
+ virtual bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
string coll = cmdObj[ "godinsert" ].valuestrsafe();
uassert( 13049, "godinsert must specify a collection", !coll.empty() );
- string ns = nsToDatabase( dbname ) + "." + coll;
+ string ns = dbname + "." + coll;
BSONObj obj = cmdObj[ "obj" ].embeddedObjectUserCheck();
- DiskLoc loc = theDataFileMgr.insert( ns.c_str(), obj, true );
+ DiskLoc loc = theDataFileMgr.insertWithObjMod( ns.c_str(), obj, true );
return true;
}
} cmdGodInsert;
class DBHashCmd : public Command {
public:
- DBHashCmd() : Command( "dbhash" ){}
- virtual bool slaveOk() { return true; }
- virtual LockType locktype() { return READ; }
- virtual bool run(const char * badns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){
- string dbname = nsToDatabase( badns );
-
- list<string> colls = _db.getCollectionNames( dbname );
+ DBHashCmd() : Command( "dbHash", false, "dbhash" ){}
+ virtual bool slaveOk() const { return true; }
+ virtual LockType locktype() const { return READ; }
+ virtual bool run(const string& dbname , BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool){
+ list<string> colls;
+ Database* db = cc().database();
+ if ( db )
+ db->namespaceIndex.getNamespaces( colls );
colls.sort();
result.appendNumber( "numCollections" , (long long)colls.size() );
@@ -1634,9 +1645,22 @@ namespace mongo {
if ( c.find( ".system.profil" ) != string::npos )
continue;
- auto_ptr<Cursor> cursor;
+ shared_ptr<Cursor> cursor;
NamespaceDetails * nsd = nsdetails( c.c_str() );
+
+ // 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() )
+ log() << " " << idx.info.obj();
+ log() << endl;
+ }
+ }
+
int idNum = nsd->findIdIndex();
if ( idNum >= 0 ){
cursor.reset( new BtreeCursor( nsd , idNum , nsd->idx( idNum ) , BSONObj() , BSONObj() , false , 1 ) );
@@ -1682,8 +1706,91 @@ namespace mongo {
return 1;
}
- DBDirectClient _db;
} dbhashCmd;
+
+ /* for diagnostic / testing purposes. */
+ class CmdSleep : public Command {
+ public:
+ virtual LockType locktype() const { return NONE; }
+ virtual bool adminOnly() const { return true; }
+ virtual bool logTheOp() {
+ return false;
+ }
+ virtual bool slaveOk() const {
+ return true;
+ }
+ 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;
+
+ 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;
+
+ // 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();
+ uassert( 13416, "captrunc must specify a collection", !coll.empty() );
+ string ns = dbname + "." + coll;
+ int n = cmdObj.getIntField( "n" );
+ bool inc = cmdObj.getBoolField( "inc" );
+ NamespaceDetails *nsd = nsdetails( ns.c_str() );
+ ReverseCappedCursor c( nsd );
+ massert( 13417, "captrunc invalid collection", c.ok() );
+ for( int i = 0; i < n; ++i ) {
+ massert( 13418, "captrunc invalid n", c.advance() );
+ }
+ DiskLoc end = c.currLoc();
+ nsd->cappedTruncateAfter( ns.c_str(), end, inc );
+ return true;
+ }
+ } capTruncCmd;
+
+ // 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;
/**
* this handles
@@ -1694,11 +1801,11 @@ namespace mongo {
*/
bool execCommand( Command * c ,
Client& client , int queryOptions ,
- const char *ns, BSONObj& cmdObj ,
+ const char *cmdns, BSONObj& cmdObj ,
BSONObjBuilder& result,
bool fromRepl ){
- string dbname = nsToDatabase( ns );
+ string dbname = nsToDatabase( cmdns );
AuthenticationInfo *ai = client.getAuthenticationInfo();
@@ -1711,7 +1818,7 @@ namespace mongo {
if ( c->adminOnly() && ! fromRepl && dbname != "admin" ) {
- result.append( "errmsg" , "access denied" );
+ result.append( "errmsg" , "access denied- use admin db" );
log() << "command denied: " << cmdObj.toString() << endl;
return false;
}
@@ -1735,11 +1842,14 @@ namespace mongo {
result.append( "errmsg" , "not master" );
return false;
}
+
+ if ( c->adminOnly() )
+ log( 2 ) << "command: " << cmdObj << endl;
if ( c->locktype() == Command::NONE ){
// we also trust that this won't crash
string errmsg;
- int ok = c->run( ns , cmdObj , errmsg , result , fromRepl );
+ int ok = c->run( dbname , cmdObj , errmsg , result , fromRepl );
if ( ! ok )
result.append( "errmsg" , errmsg );
return ok;
@@ -1747,40 +1857,30 @@ namespace mongo {
bool needWriteLock = c->locktype() == Command::WRITE;
- if ( ! c->requiresAuth() &&
- ( ai->isAuthorizedReads( dbname ) &&
- ! ai->isAuthorized( dbname ) ) ){
- // this means that they can read, but not write
- // so only get a read lock
- needWriteLock = false;
- }
-
if ( ! needWriteLock ){
assert( ! c->logTheOp() );
}
mongolock lk( needWriteLock );
- Client::Context ctx( ns , dbpath , &lk , c->requiresAuth() );
-
- if ( c->adminOnly() )
- log( 2 ) << "command: " << cmdObj << endl;
+ Client::Context ctx( dbname , dbpath , &lk , c->requiresAuth() );
try {
string errmsg;
- if ( ! c->run(ns, cmdObj, errmsg, result, fromRepl ) ){
+ if ( ! c->run(dbname, cmdObj, errmsg, result, fromRepl ) ){
result.append( "errmsg" , errmsg );
return false;
}
}
- catch ( AssertionException& e ){
+ catch ( DBException& e ){
stringstream ss;
- ss << "assertion: " << e.what();
+ ss << "exception: " << e.what();
result.append( "errmsg" , ss.str() );
+ result.append( "code" , e.getCode() );
return false;
}
if ( c->logTheOp() && ! fromRepl ){
- logOp("c", ns, cmdObj);
+ logOp("c", cmdns, cmdObj);
}
return true;
@@ -1795,6 +1895,7 @@ namespace mongo {
returns true if ran a cmd
*/
bool _runCommands(const char *ns, BSONObj& _cmdobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions) {
+ cc().curop()->ensureStarted();
string dbname = nsToDatabase( ns );
if( logLevel >= 1 )
@@ -1821,6 +1922,7 @@ namespace mongo {
BSONElement e = jsobj.firstElement();
Command * c = e.type() ? Command::findCommand( e.fieldName() ) : 0;
+
if ( c ){
ok = execCommand( c , client , queryOptions , ns , jsobj , anObjBuilder , fromRepl );
}
@@ -1828,10 +1930,14 @@ namespace mongo {
anObjBuilder.append("errmsg", "no such cmd");
anObjBuilder.append("bad cmd" , _cmdobj );
}
+
+ // switch to bool, but wait a bit longer before switching?
+ // anObjBuilder.append("ok", ok);
anObjBuilder.append("ok", ok?1.0:0.0);
BSONObj x = anObjBuilder.done();
- b.append((void*) x.objdata(), x.objsize());
+ b.appendBuf((void*) x.objdata(), x.objsize());
+
return true;
}
-
+
} // namespace mongo