summaryrefslogtreecommitdiff
path: root/src/mongo/tools
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2014-09-25 15:35:28 -0400
committerBenety Goh <benety@mongodb.com>2014-09-25 16:23:53 -0400
commit5886a56330c3775bf5c8bea2a69ec6627822d387 (patch)
tree90e8cadb5588984883eb81d18bd5114a78375d59 /src/mongo/tools
parenta0f55108e49a4cb3982a5636c2ecdc4ccfe6cf83 (diff)
downloadmongo-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.cpp7
-rw-r--r--src/mongo/tools/mongoshim_options.h4
-rw-r--r--src/mongo/tools/shim.cpp76
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;
};