diff options
Diffstat (limited to 'src/mongo/db/repl/rs_rollback.cpp')
| -rw-r--r-- | src/mongo/db/repl/rs_rollback.cpp | 157 |
1 files changed, 114 insertions, 43 deletions
diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 68b7fc17529..7f730b8de50 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -13,16 +13,36 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. +* +* As a special exception, the copyright holders give permission to link the +* code of portions of this program with the OpenSSL library under certain +* conditions as described in each individual source file and distribute +* linked combinations including the program with the OpenSSL library. You +* must comply with the GNU Affero General Public License in all respects for +* all of the code used other than as permitted herein. If you modify file(s) +* with this exception, you may extend this exception to your version of the +* file(s), but you are not obligated to do so. If you do not wish to do so, +* delete this exception statement from your version. If you delete this +* exception statement from all source files in the program, then also delete +* it in the license file. */ -#include "pch.h" +#include "mongo/pch.h" +#include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/authorization_manager_global.h" #include "mongo/db/client.h" #include "mongo/db/cloner.h" +#include "mongo/db/dbhelpers.h" +#include "mongo/db/exec/working_set_common.h" #include "mongo/db/ops/update.h" +#include "mongo/db/ops/update_request.h" +#include "mongo/db/ops/update_lifecycle_impl.h" #include "mongo/db/ops/delete.h" +#include "mongo/db/query/internal_plans.h" +#include "mongo/db/query/runner.h" +#include "mongo/db/repl/oplog.h" #include "mongo/db/repl/rs.h" -#include "mongo/db/repl.h" /* Scenarios @@ -144,19 +164,19 @@ namespace mongo { /* Create collection operation { ts: ..., h: ..., op: "c", ns: "foo.$cmd", o: { create: "abc", ... } } */ - string ns = s.db + '.' + o["create"].String(); // -> foo.abc + string ns = s.db().toString() + '.' + o["create"].String(); // -> foo.abc h.toDrop.insert(ns); return; } else if( cmdname == "drop" ) { - string ns = s.db + '.' + first.valuestr(); + string ns = s.db().toString() + '.' + first.valuestr(); h.collectionsToResync.insert(ns); return; } else if( cmdname == "dropIndexes" || cmdname == "deleteIndexes" ) { /* TODO: this is bad. we simply full resync the collection here, which could be very slow. */ log() << "replSet info rollback of dropIndexes is slow in this version of mongod" << rsLog; - string ns = s.db + '.' + first.valuestr(); + string ns = s.db().toString() + '.' + first.valuestr(); h.collectionsToResync.insert(ns); return; } @@ -177,6 +197,16 @@ namespace mongo { log() << "replSet " << o.toString() << rsLog; throw rsfatal(); } + else if( cmdname == "collMod" ) { + if ( o.nFields() == 2 && + o["usePowerOf2Sizes"].type() == Bool ) { + log() << "replSet not rolling back change of usePowerOf2Sizes: " << o; + } + else { + log() << "replSet error cannot rollback a collMod command: " << o; + throw rsfatal(); + } + } else { log() << "replSet error can't rollback this command yet: " << o.toString() << rsLog; log() << "replSet cmdname=" << cmdname << rsLog; @@ -199,11 +229,16 @@ namespace mongo { static void syncRollbackFindCommonPoint(DBClientConnection *them, HowToFixUp& h) { verify( Lock::isLocked() ); Client::Context c(rsoplog); - NamespaceDetails *nsd = nsdetails(rsoplog); - verify(nsd); - ReverseCappedCursor u(nsd); - if( !u.ok() ) + + boost::scoped_ptr<Runner> runner( + InternalPlanner::collectionScan(rsoplog, InternalPlanner::BACKWARD)); + + BSONObj ourObj; + DiskLoc ourLoc; + + if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) { throw rsfatal("our oplog empty or unreadable"); + } const Query q = Query().sort(reverseNaturalObj); const bo fields = BSON( "ts" << 1 << "h" << 1 ); @@ -215,7 +250,6 @@ namespace mongo { if( t.get() == 0 || !t->more() ) throw rsfatal("remote oplog empty or unreadable"); - BSONObj ourObj = u.current(); OpTime ourTime = ourObj["ts"]._opTime(); BSONObj theirObj = t->nextSafe(); OpTime theirTime = theirObj["ts"]._opTime(); @@ -244,7 +278,7 @@ namespace mongo { log() << "replSet rollback found matching events at " << ourTime.toStringPretty() << rsLog; log() << "replSet rollback findcommonpoint scanned : " << scanned << rsLog; h.commonPoint = ourTime; - h.commonPointOurDiskloc = u.currLoc(); + h.commonPointOurDiskloc = ourLoc; return; } @@ -260,15 +294,13 @@ namespace mongo { theirObj = t->nextSafe(); theirTime = theirObj["ts"]._opTime(); - u.advance(); - if( !u.ok() ) { + if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) { log() << "replSet rollback error RS101 reached beginning of local oplog" << rsLog; log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog; log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog; log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog; throw rsfatal("RS101 reached beginning of local oplog [1]"); } - ourObj = u.current(); ourTime = ourObj["ts"]._opTime(); } else if( theirTime > ourTime ) { @@ -285,15 +317,13 @@ namespace mongo { else { // theirTime < ourTime refetch(h, ourObj); - u.advance(); - if( !u.ok() ) { + if (Runner::RUNNER_ADVANCED != runner->getNext(&ourObj, &ourLoc)) { log() << "replSet rollback error RS101 reached beginning of local oplog" << rsLog; log() << "replSet them: " << them->toString() << " scanned: " << scanned << rsLog; log() << "replSet theirTime: " << theirTime.toStringLong() << rsLog; log() << "replSet ourTime: " << ourTime.toStringLong() << rsLog; throw rsfatal("RS101 reached beginning of local oplog [2]"); } - ourObj = u.current(); ourTime = ourObj["ts"]._opTime(); } } @@ -377,10 +407,9 @@ namespace mongo { Client::Context c(ns); { - bob res; - string errmsg; - dropCollection(ns, errmsg, res); + c.db()->dropCollection(ns); { + string errmsg; dbtemprelease r; bool ok = Cloner::copyCollectionFromRemote(them->getServerAddress(), ns, errmsg); uassert(15909, str::stream() << "replSet rollback error resyncing collection " << ns << ' ' << errmsg, ok); @@ -423,15 +452,39 @@ namespace mongo { sethbmsg("rollback 4.3"); } + map<string,shared_ptr<Helpers::RemoveSaver> > removeSavers; + sethbmsg("rollback 4.6"); /** drop collections to drop before doing individual fixups - that might make things faster below actually if there were subsequent inserts to rollback */ for( set<string>::iterator i = h.toDrop.begin(); i != h.toDrop.end(); i++ ) { Client::Context c(*i); try { - bob res; - string errmsg; - LOG(1) << "replSet rollback drop: " << *i << rsLog; - dropCollection(*i, errmsg, res); + log() << "replSet rollback drop: " << *i << rsLog; + shared_ptr<Helpers::RemoveSaver>& removeSaver = removeSavers[*i]; + if (!removeSaver) + removeSaver.reset(new Helpers::RemoveSaver("rollback", "", *i)); + + // perform a collection scan and write all documents in the collection to disk + boost::scoped_ptr<Runner> runner(InternalPlanner::collectionScan(*i)); + BSONObj curObj; + Runner::RunnerState runnerState; + while (Runner::RUNNER_ADVANCED == (runnerState = runner->getNext(&curObj, NULL))) { + removeSaver->goingToDelete(curObj); + } + if (runnerState != Runner::RUNNER_EOF) { + if (runnerState == Runner::RUNNER_ERROR) { + severe() << "rolling back createCollection on " << *i + << " failed with " << WorkingSetCommon::toStatusString(curObj) + << ". A full resync is necessary."; + } + else { + severe() << "rolling back createCollection on " << *i + << " failed. A full resync is necessary."; + } + + throw std::exception(); + } + c.db()->dropCollection(*i); } catch(...) { log() << "replset rollback error dropping collection " << *i << rsLog; @@ -440,10 +493,10 @@ namespace mongo { sethbmsg("rollback 4.7"); Client::Context c(rsoplog); - NamespaceDetails *oplogDetails = nsdetails(rsoplog); - uassert(13423, str::stream() << "replSet error in rollback can't find " << rsoplog, oplogDetails); - - map<string,shared_ptr<RemoveSaver> > removeSavers; + Collection* oplogCollection = c.db()->getCollection( rsoplog ); + uassert(13423, + str::stream() << "replSet error in rollback can't find " << rsoplog, + oplogCollection); unsigned deletes = 0, updates = 0; for( list<pair<DocID,bo> >::iterator i = goodVersions.begin(); i != goodVersions.end(); i++ ) { @@ -459,9 +512,9 @@ namespace mongo { getDur().commitIfNeeded(); /* keep an archive of items rolled back */ - shared_ptr<RemoveSaver>& rs = removeSavers[d.ns]; + shared_ptr<Helpers::RemoveSaver>& rs = removeSavers[d.ns]; if ( ! rs ) - rs.reset( new RemoveSaver( "rollback" , "" , d.ns ) ); + rs.reset( new Helpers::RemoveSaver( "rollback" , "" , d.ns ) ); // todo: lots of overhead in context, this can be faster Client::Context c(d.ns); @@ -480,9 +533,9 @@ namespace mongo { /* TODO1.6 : can't delete from a capped collection. need to handle that here. */ deletes++; - NamespaceDetails *nsd = nsdetails(d.ns); - if( nsd ) { - if( nsd->isCapped() ) { + Collection* collection = c.db()->getCollection(d.ns); + if( collection ) { + if( collection->isCapped() ) { /* can't delete from a capped collection - so we truncate instead. if this item must go, so must all successors!!! */ try { @@ -492,6 +545,7 @@ namespace mongo { DiskLoc loc = Helpers::findOne(d.ns, pattern, false); if( Listener::getElapsedTimeMillis() - start > 200 ) log() << "replSet warning roll back slow no _id index for " << d.ns << " perhaps?" << rsLog; + NamespaceDetails* nsd = collection->details(); //would be faster but requires index: DiskLoc loc = Helpers::findById(nsd, pattern); if( !loc.isNull() ) { try { @@ -515,23 +569,22 @@ namespace mongo { else { try { deletes++; - deleteObjects(d.ns, pattern, /*justone*/true, /*logop*/false, /*god*/true, rs.get() ); + deleteObjects(d.ns, pattern, /*justone*/true, /*logop*/false, /*god*/true); } catch(...) { log() << "replSet error rollback delete failed ns:" << d.ns << rsLog; } } // did we just empty the collection? if so let's check if it even exists on the source. - if( nsd->stats.nrecords == 0 ) { + if( collection->numRecords() == 0 ) { try { - string sys = cc().database()->name + ".system.namespaces"; - bo o = them->findOne(sys, QUERY("name"<<d.ns)); - if( o.isEmpty() ) { + std::list<BSONObj> lst = + them->getCollectionInfos( cc().database()->name(), + BSON( "name" << nsToCollectionSubstring( d.ns ) ) ); + if (lst.empty()) { // we should drop try { - bob res; - string errmsg; - dropCollection(d.ns, errmsg, res); + cc().database()->dropCollection(d.ns); } catch(...) { log() << "replset error rolling back collection " << d.ns << rsLog; @@ -549,7 +602,19 @@ namespace mongo { // todo faster... OpDebug debug; updates++; - _updateObjects(/*god*/true, d.ns, i->second, pattern, /*upsert=*/true, /*multi=*/false , /*logtheop=*/false , debug, rs.get() ); + + const NamespaceString requestNs(d.ns); + UpdateRequest request(requestNs); + + request.setQuery(pattern); + request.setUpdates(i->second); + request.setGod(); + request.setUpsert(); + UpdateLifecycleImpl updateLifecycle(true, requestNs); + request.setLifecycle(&updateLifecycle); + + update(request, &debug); + } } catch(DBException& e) { @@ -567,7 +632,13 @@ namespace mongo { // clean up oplog LOG(2) << "replSet rollback truncate oplog after " << h.commonPoint.toStringPretty() << rsLog; // todo: fatal error if this throws? - oplogDetails->cappedTruncateAfter(rsoplog, h.commonPointOurDiskloc, false); + oplogCollection->details()->cappedTruncateAfter(rsoplog, h.commonPointOurDiskloc, false); + + Status status = getGlobalAuthorizationManager()->initialize(); + if (!status.isOK()) { + warning() << "Failed to reinitialize auth data after rollback: " << status; + warn = true; + } /* reset cached lastoptimewritten and h value */ loadLastOpTimeWritten(); |
