diff options
author | Scott Hernandez <scotthernandez@gmail.com> | 2014-12-30 14:46:29 -0500 |
---|---|---|
committer | Scott Hernandez <scotthernandez@gmail.com> | 2015-01-02 14:21:08 -0500 |
commit | 8b37507dd51cdf058377a24ca0171e7fae6f2c6b (patch) | |
tree | 1bea2528edb8df7cf70fda21f6894e59af820f60 | |
parent | 430bafbd8643bd1d30513ad231850c6927e8553d (diff) | |
download | mongo-8b37507dd51cdf058377a24ca0171e7fae6f2c6b.tar.gz |
SERVER-16502: open database after repair is done
-rw-r--r-- | jstests/core/repair_database.js | 39 | ||||
-rw-r--r-- | src/mongo/db/dbcommands.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/repair_database.cpp | 27 | ||||
-rw-r--r-- | src/mongo/db/repair_database.h | 5 |
4 files changed, 66 insertions, 7 deletions
diff --git a/jstests/core/repair_database.js b/jstests/core/repair_database.js new file mode 100644 index 00000000000..ca4bddd4bb1 --- /dev/null +++ b/jstests/core/repair_database.js @@ -0,0 +1,39 @@ +/** + * This tests checks that repair database works and doesn't leave the database in a bad state + * 1.) Drop "repairDB" database + * 2.) Ensure repair works with single collection with an extra index. and one doc + * 3.) Ensure repair works with no docs, same collection/index as above + * 4.) Ensure repair works with 2 collections, one doc in each + */ + +// 1. Drop db +var mydb = db.getSisterDB( "repairDB" ); +mydb.dropDatabase() + +var myColl = mydb.a; + +// 2 +var doc = {_id:1, a:"hello world"}; +myColl.insert(doc); +myColl.ensureIndex({a:1}) +mydb.repairDatabase(); +var foundDoc = myColl.findOne(); + +assert.neq(null, foundDoc) +assert.eq(1, foundDoc._id) + +assert.docEq(doc, myColl.findOne({a:doc.a})) +assert.docEq(doc, myColl.findOne({_id:1})) + +// 3 +var myColl2 = mydb.b; +myColl.remove({}); +mydb.repairDatabase(); + +// 4 +var myColl2 = mydb.b; +myColl.insert(doc); +myColl2.insert(doc); +mydb.repairDatabase(); +assert.docEq(doc, myColl.findOne({a:doc.a})) +assert.docEq(doc, myColl2.findOne({a:doc.a})) diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index a16a16c22e1..9e9d16f4159 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -290,6 +290,8 @@ namespace mongo { IndexBuilder::restoreIndexes(indexesInProg); + // Open database before returning + dbHolder().openDb(txn, dbname); return appendCommandStatus( result, status ); } } cmdRepairDatabase; diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp index af27db45098..8f49e4df300 100644 --- a/src/mongo/db/repair_database.cpp +++ b/src/mongo/db/repair_database.cpp @@ -55,7 +55,6 @@ namespace { DatabaseCatalogEntry* dbce, const std::string& collectionName) { - Database db(txn, dbce->name(), dbce); CollectionCatalogEntry* cce = dbce->getCollectionCatalogEntry(txn, collectionName); std::vector<string> indexNames; @@ -81,6 +80,7 @@ namespace { // Skip the rest if there are no indexes to rebuild. if (indexSpecs.empty()) return Status::OK(); + boost::scoped_ptr<Database> db; Collection* collection; boost::scoped_ptr<MultiIndexBlock> indexer; { @@ -102,7 +102,8 @@ namespace { // Indexes must be dropped before we open the Collection otherwise we could attempt to // open a bad index and fail. // TODO see if MultiIndexBlock can be made to work without a Collection. - collection = db.getCollection(txn, collectionName); + db.reset(new Database(txn, dbce->name(), dbce)); + collection = db->getCollection(txn, collectionName); invariant(collection); indexer.reset(new MultiIndexBlock(txn, collection)); @@ -166,6 +167,8 @@ namespace { bool preserveClonedFilesOnFailure, bool backupOriginalFiles) { + + // We must hold some form of lock here invariant(txn->lockState()->isLocked()); invariant( dbName.find( '.' ) == string::npos ); @@ -192,12 +195,22 @@ namespace { return Status( ErrorCodes::BadValue, "backupOriginalFiles not supported" ); } - // Close and reopen the db to invalidate all current users and caches. - // WARNING: it is important that the opened Database object isn't used for anything as its - // cache must remain empty until we return. + // Close the db to invalidate all current users and caches. dbHolder().close(txn, dbName); - dbHolder().openDb(txn, dbName); - + // Open the db after everything finishes + class OpenDbInDestructor { + public: + OpenDbInDestructor(OperationContext* txn, const std::string& db) : + _dbName(db) + , _txn(txn) + {} + ~OpenDbInDestructor() { + dbHolder().openDb(_txn, _dbName); + } + private: + const std::string& _dbName; + OperationContext* _txn; + } dbOpener(txn, dbName); DatabaseCatalogEntry* dbce = engine->getDatabaseCatalogEntry(txn, dbName); std::list<std::string> colls; diff --git a/src/mongo/db/repair_database.h b/src/mongo/db/repair_database.h index 85d2729a277..17fb58274aa 100644 --- a/src/mongo/db/repair_database.h +++ b/src/mongo/db/repair_database.h @@ -36,6 +36,11 @@ namespace mongo { class StorageEngine; class StringData; + /** + * Repairs a database using a storage engine-specific, best-effort process. + * Some data may be lost or modified in the process but the output will + * be structurally valid on successful return. + */ Status repairDatabase(OperationContext* txn, StorageEngine* engine, const std::string& dbName, |