virtual bool run(const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj.firstElement().valuestr(); if( coll.empty() || db.empty() ) { errmsg = "no collection name specified"; return false; } if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"; return false; } string ns = db + '.' + coll; if ( ! NamespaceString::normal(ns.c_str()) ) { errmsg = "bad namespace name"; return false; } // parameter validation to avoid triggering assertions in compact() if ( str::contains(ns, ".system.") ) { errmsg = "can't compact a system namespace"; return false; } { writelock lk; Client::Context ctx(ns); NamespaceDetails *d = nsdetails(ns.c_str()); if( ! d ) { errmsg = "namespace does not exist"; return false; } if ( d->capped ) { errmsg = "cannot compact a capped collection"; return false; } } double pf = 1.0; int pb = 0; if( cmdObj.hasElement("paddingFactor") ) { pf = cmdObj["paddingFactor"].Number(); assert( pf >= 1.0 && pf <= 4.0 ); } if( cmdObj.hasElement("paddingBytes") ) { pb = (int) cmdObj["paddingBytes"].Number(); assert( pb >= 0 && pb <= 1024 * 1024 ); } bool validate = !cmdObj.hasElement("validate") || cmdObj["validate"].trueValue(); // default is true at the moment bool ok = compact(ns, errmsg, validate, result, pf, pb); return ok; }
virtual bool run(const string& db, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj.firstElement().valuestr(); if( coll.empty() || db.empty() ) { errmsg = "no collection name specified"; return false; } if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"; return false; } string ns = db + '.' + coll; bool validate = !cmdObj.hasElement("validate") || cmdObj["validate"].trueValue(); // default is true at the moment bool ok = compact(ns, errmsg, validate, result); return ok; }
virtual bool run(const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj.firstElement().valuestr(); if( coll.empty() || db.empty() ) { errmsg = "no collection name specified"; return false; } if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"; return false; } string ns = db + '.' + coll; if ( ! NamespaceString::normal(ns.c_str()) ) { errmsg = "bad namespace name"; return false; } // parameter validation to avoid triggering assertions in compact() if ( str::contains(ns, ".system.") ) { errmsg = "can't compact a system namespace"; return false; } { Lock::DBWrite lk(ns); Client::Context ctx(ns); NamespaceDetails *d = nsdetails(ns); if( ! d ) { errmsg = "namespace does not exist"; return false; } if ( d->isCapped() ) { errmsg = "cannot compact a capped collection"; return false; } } double pf = 1.0; int pb = 0; // preservePadding trumps all other compact methods bool preservePadding = false; // useDefaultPadding is used to track whether or not a padding requirement was passed in // if it wasn't than UsePowerOf2Sizes will be maintained when compacting bool useDefaultPadding = true; if (cmdObj.hasElement("preservePadding")) { preservePadding = cmdObj["preservePadding"].trueValue(); useDefaultPadding = false; } if( cmdObj.hasElement("paddingFactor") ) { if (preservePadding == true) { errmsg = "preservePadding is incompatible with paddingFactor"; return false; } useDefaultPadding = false; pf = cmdObj["paddingFactor"].Number(); verify( pf >= 1.0 && pf <= 4.0 ); } if( cmdObj.hasElement("paddingBytes") ) { if (preservePadding == true) { errmsg = "preservePadding is incompatible with paddingBytes"; return false; } useDefaultPadding = false; pb = (int) cmdObj["paddingBytes"].Number(); verify( pb >= 0 && pb <= 1024 * 1024 ); } bool validate = !cmdObj.hasElement("validate") || cmdObj["validate"].trueValue(); // default is true at the moment massert( 14028, "bad ns", NamespaceString::normal(ns.c_str()) ); massert( 14027, "can't compact a system namespace", !str::contains(ns, ".system.") ); // items in system.indexes cannot be moved there are pointers to those disklocs in NamespaceDetails bool ok; { Lock::DBWrite lk(ns); BackgroundOperation::assertNoBgOpInProgForNs(ns.c_str()); Client::Context ctx(ns); NamespaceDetails *d = nsdetails(ns); massert( 13660, str::stream() << "namespace " << ns << " does not exist", d ); massert( 13661, "cannot compact capped collection", !d->isCapped() ); log() << "compact " << ns << " begin" << endl; std::vector<BSONObj> indexesInProg = stopIndexBuilds(db, cmdObj); if( pf != 0 || pb != 0 ) { log() << "paddingFactor:" << pf << " paddingBytes:" << pb << endl; } try { ok = _compact(ns.c_str(), d, errmsg, validate, result, pf, pb, useDefaultPadding, preservePadding); } catch(...) { log() << "compact " << ns << " end (with error)" << endl; throw; } log() << "compact " << ns << " end" << endl; IndexBuilder::restoreIndexes(indexesInProg); } return ok; }
virtual bool run(const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string coll = cmdObj.firstElement().valuestr(); if( coll.empty() || db.empty() ) { errmsg = "no collection name specified"; return false; } if( isCurrentlyAReplSetPrimary() && !cmdObj["force"].trueValue() ) { errmsg = "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force"; return false; } NamespaceString ns(db,coll); if ( !ns.isNormal() ) { errmsg = "bad namespace name"; return false; } if ( ns.isSystem() ) { // items in system.* cannot be moved as there might be pointers to them // i.e. system.indexes entries are pointed to from NamespaceDetails errmsg = "can't compact a system namespace"; return false; } CompactOptions compactOptions; if ( cmdObj["preservePadding"].trueValue() ) { compactOptions.paddingMode = CompactOptions::PRESERVE; if ( cmdObj.hasElement( "paddingFactor" ) || cmdObj.hasElement( "paddingBytes" ) ) { errmsg = "cannot mix preservePadding and paddingFactor|paddingBytes"; return false; } } else if ( cmdObj.hasElement( "paddingFactor" ) || cmdObj.hasElement( "paddingBytes" ) ) { compactOptions.paddingMode = CompactOptions::MANUAL; if ( cmdObj.hasElement("paddingFactor") ) { compactOptions.paddingFactor = cmdObj["paddingFactor"].Number(); if ( compactOptions.paddingFactor < 1 || compactOptions.paddingFactor > 4 ){ errmsg = "invalid padding factor"; return false; } } if ( cmdObj.hasElement("paddingBytes") ) { compactOptions.paddingBytes = cmdObj["paddingBytes"].numberInt(); if ( compactOptions.paddingBytes < 0 || compactOptions.paddingBytes > ( 1024 * 1024 ) ) { errmsg = "invalid padding bytes"; return false; } } } if ( cmdObj.hasElement("validate") ) compactOptions.validateDocuments = cmdObj["validate"].trueValue(); Lock::DBWrite lk(ns.ns()); BackgroundOperation::assertNoBgOpInProgForNs(ns.ns()); Client::Context ctx(ns); Collection* collection = ctx.db()->getCollection(ns.ns()); if( ! collection ) { errmsg = "namespace does not exist"; return false; } if ( collection->isCapped() ) { errmsg = "cannot compact a capped collection"; return false; } log() << "compact " << ns << " begin, options: " << compactOptions.toString(); std::vector<BSONObj> indexesInProg = stopIndexBuilds(db, cmdObj); StatusWith<CompactStats> status = collection->compact( &compactOptions ); if ( !status.isOK() ) return appendCommandStatus( result, status.getStatus() ); if ( status.getValue().corruptDocuments > 0 ) result.append("invalidObjects", status.getValue().corruptDocuments ); log() << "compact " << ns << " end"; IndexBuilder::restoreIndexes(indexesInProg); return true; }