virtual bool run(OperationContext* txn, const string& db, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result) { const std::string nsToCompact = parseNsCollectionRequired(db, cmdObj); repl::ReplicationCoordinator* replCoord = repl::getGlobalReplicationCoordinator(); if (replCoord->getMemberState().primary() && !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 nss(nsToCompact); if (!nss.isNormal()) { errmsg = "bad namespace name"; return false; } if (nss.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(); ScopedTransaction transaction(txn, MODE_IX); AutoGetDb autoDb(txn, db, MODE_X); Database* const collDB = autoDb.getDb(); Collection* collection = collDB ? collDB->getCollection(nss) : NULL; // If db/collection does not exist, short circuit and return. if (!collDB || !collection) { errmsg = "namespace does not exist"; return false; } OldClientContext ctx(txn, nss.ns()); BackgroundOperation::assertNoBgOpInProgForNs(nss.ns()); log() << "compact " << nss.ns() << " begin, options: " << compactOptions.toString(); StatusWith<CompactStats> status = collection->compact(txn, &compactOptions); if (!status.isOK()) return appendCommandStatus(result, status.getStatus()); if (status.getValue().corruptDocuments > 0) result.append("invalidObjects", status.getValue().corruptDocuments); log() << "compact " << nss.ns() << " end"; return true; }
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; }