diff options
author | Benety Goh <benety@mongodb.com> | 2014-09-25 15:35:28 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2014-09-25 16:23:53 -0400 |
commit | 5886a56330c3775bf5c8bea2a69ec6627822d387 (patch) | |
tree | 90e8cadb5588984883eb81d18bd5114a78375d59 /src/mongo/tools | |
parent | a0f55108e49a4cb3982a5636c2ecdc4ccfe6cf83 (diff) | |
download | mongo-5886a56330c3775bf5c8bea2a69ec6627822d387.tar.gz |
SERVER-15396 added --repair option to mongo shim
Diffstat (limited to 'src/mongo/tools')
-rw-r--r-- | src/mongo/tools/mongoshim_options.cpp | 7 | ||||
-rw-r--r-- | src/mongo/tools/mongoshim_options.h | 4 | ||||
-rw-r--r-- | src/mongo/tools/shim.cpp | 76 |
3 files changed, 87 insertions, 0 deletions
diff --git a/src/mongo/tools/mongoshim_options.cpp b/src/mongo/tools/mongoshim_options.cpp index ff45e8fbc86..e3e14300721 100644 --- a/src/mongo/tools/mongoshim_options.cpp +++ b/src/mongo/tools/mongoshim_options.cpp @@ -94,6 +94,12 @@ namespace mongo { options->addOptionChaining("query", "query,q", moe::String, "query filter, as a JSON string, e.g., '{x:{$gt:1}}'"); + options->addOptionChaining("repair", "repair", moe::Switch, + "try to recover a crashed collection") + .incompatibleWith("applyOps") + .incompatibleWith("load") + .incompatibleWith("remove"); + options->addOptionChaining("slaveOk", "slaveOk,k", moe::Bool, "use secondaries for export if available, default true") .setDefault(moe::Value(true)); @@ -157,6 +163,7 @@ namespace mongo { mongoShimGlobalParams.load = params.count("load") > 0; mongoShimGlobalParams.remove = params.count("remove") > 0; mongoShimGlobalParams.applyOps = params.count("applyOps") > 0; + mongoShimGlobalParams.repair = params.count("repair") > 0; mongoShimGlobalParams.drop = params.count("drop") > 0; mongoShimGlobalParams.upsert = params.count("upsert") > 0; diff --git a/src/mongo/tools/mongoshim_options.h b/src/mongo/tools/mongoshim_options.h index d7b68ed2811..b1cd61d89bc 100644 --- a/src/mongo/tools/mongoshim_options.h +++ b/src/mongo/tools/mongoshim_options.h @@ -50,6 +50,10 @@ namespace mongo { // If true, read oplog entries from stdin to use as input to "applyOps" command. bool applyOps; + // If true, attempts to repair bad data in collection. + // Also writes contents of collection to output. + bool repair; + bool drop; bool upsert; std::vector<std::string> upsertFields; diff --git a/src/mongo/tools/shim.cpp b/src/mongo/tools/shim.cpp index 9aa6ed65a4d..4868818f7d4 100644 --- a/src/mongo/tools/shim.cpp +++ b/src/mongo/tools/shim.cpp @@ -28,12 +28,21 @@ * then also delete it in the license file. */ +#include <boost/scoped_ptr.hpp> + #include "mongo/bson/bsonobjbuilder.h" #include "mongo/client/dbclientcursor.h" +#include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/database.h" +#include "mongo/db/catalog/database_holder.h" +#include "mongo/db/client.h" #include "mongo/db/json.h" +#include "mongo/db/operation_context_impl.h" +#include "mongo/db/storage/record_store.h" #include "mongo/tools/mongoshim_options.h" #include "mongo/tools/tool.h" #include "mongo/tools/tool_logger.h" +#include "mongo/util/assert_util.h" #include "mongo/util/options_parser/option_section.h" using std::string; @@ -124,6 +133,11 @@ public: bool justOne = false; conn().remove(_ns, mongoShimGlobalParams.query, justOne); } + else if (mongoShimGlobalParams.repair) { + // Repairs collection before writing documents to output. + ostream *out = &cout; + _repair(*out); + } else { ostream *out = &cout; @@ -155,6 +169,68 @@ public: } private: + /** + * Writes valid objects in collection to output. + */ + void _repair(std::ostream& out) { + toolInfoLog() << "going to try to recover data from: " << _ns << std::endl; + OperationContextImpl txn; + Client::WriteContext cx(&txn, toolGlobalParams.db); + + Database* db = dbHolder().get(&txn, toolGlobalParams.db); + Collection* collection = db->getCollection(&txn, _ns); + + if (!collection) { + toolError() << "Collection does not exist: " << toolGlobalParams.coll << std::endl; + return; + } + + toolInfoLog() << "nrecords: " << collection->numRecords(&txn) + << " datasize: " << collection->dataSize(&txn); + try { + boost::scoped_ptr<RecordIterator> iter( + collection->getRecordStore()->getIteratorForRepair(&txn)); + for (DiskLoc currLoc = iter->getNext(); !currLoc.isNull(); currLoc = iter->getNext()) { + if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) { + toolInfoLog() << currLoc; + } + + BSONObj obj; + try { + obj = collection->docFor(&txn, currLoc); + + // If this is a corrupted object, just skip it, but do not abort the scan + // + if (!obj.valid()) { + continue; + } + + if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) { + toolInfoLog() << obj; + } + + // Write valid object to output stream. + out.write(obj.objdata(), obj.objsize()); + } + catch (std::exception& ex) { + toolError() << "found invalid document @ " << currLoc << " " << ex.what(); + if ( ! obj.isEmpty() ) { + try { + toolError() << "first element: " << obj.firstElement(); + } + catch ( std::exception& ) { + toolError() << "unable to log invalid document @ " << currLoc; + } + } + } + } + } + catch (DBException& e) { + toolError() << "ERROR recovering: " << _ns << " " << e.toString(); + } + cx.commit(); + } + string _ns; }; |