diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2014-04-18 15:28:50 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2014-04-21 11:17:37 -0400 |
commit | 001b2c1ee301f814c4b9128b2f0ef1ee1354a4f1 (patch) | |
tree | aae749fbf8554a03c2cc334c05b7815dfb7f48bc /src/mongo/db/background.cpp | |
parent | 9be380c23afdad4ab7c4b09762f2f3d95caf674f (diff) | |
download | mongo-001b2c1ee301f814c4b9128b2f0ef1ee1354a4f1.tar.gz |
SERVER-13620 Refactor background.h/cpp; add awaitNoBgOp methods.
(cherry picked from commit 9ad97ac9fd08cf56d4e6c4bdb5c1b10085b9040c)
Diffstat (limited to 'src/mongo/db/background.cpp')
-rw-r--r-- | src/mongo/db/background.cpp | 143 |
1 files changed, 116 insertions, 27 deletions
diff --git a/src/mongo/db/background.cpp b/src/mongo/db/background.cpp index ecfd756542d..98965289f6a 100644 --- a/src/mongo/db/background.cpp +++ b/src/mongo/db/background.cpp @@ -28,63 +28,152 @@ * it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/db/background.h" +#include <boost/shared_ptr.hpp> +#include <boost/thread.hpp> +#include <iostream> +#include <string> + +#include "mongo/base/disallow_copying.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/map_util.h" +#include "mongo/util/mongoutils/str.h" +#include "mongo/util/string_map.h" + namespace mongo { - SimpleMutex BackgroundOperation::m("bg"); - std::map<std::string, unsigned> BackgroundOperation::dbsInProg; - std::set<std::string> BackgroundOperation::nsInProg; +namespace { + + class BgInfo { + MONGO_DISALLOW_COPYING(BgInfo); + public: + BgInfo() : _opsInProgCount(0) {} + + void recordBegin(); + int recordEnd(); + void awaitNoBgOps(boost::unique_lock<boost::mutex>& lk); + + int getOpsInProgCount() const { return _opsInProgCount; } + + private: + int _opsInProgCount; + boost::condition_variable _noOpsInProg; + }; + + typedef StringMap<boost::shared_ptr<BgInfo> > BgInfoMap; + typedef BgInfoMap::const_iterator BgInfoMapIterator; + + boost::mutex m; + BgInfoMap dbsInProg; + BgInfoMap nsInProg; + + void BgInfo::recordBegin() { + ++_opsInProgCount; + } + + int BgInfo::recordEnd() { + dassert(_opsInProgCount > 0); + --_opsInProgCount; + if (0 == _opsInProgCount) { + _noOpsInProg.notify_all(); + } + return _opsInProgCount; + } + + void BgInfo::awaitNoBgOps(boost::unique_lock<boost::mutex>& lk) { + while (_opsInProgCount > 0) + _noOpsInProg.wait(lk); + } + void recordBeginAndInsert(BgInfoMap* bgiMap, const StringData& key) { + boost::shared_ptr<BgInfo>& bgInfo = bgiMap->get(key); + if (!bgInfo) + bgInfo.reset(new BgInfo); + bgInfo->recordBegin(); + } + + void recordEndAndRemove(BgInfoMap* bgiMap, const StringData& key) { + BgInfoMapIterator iter = bgiMap->find(key); + fassert(0, iter != bgiMap->end()); + if (0 == iter->second->recordEnd()) { + bgiMap->erase(iter); + } + } + + void awaitNoBgOps( + boost::unique_lock<boost::mutex>& lk, + BgInfoMap* bgiMap, + const StringData& key) { + + boost::shared_ptr<BgInfo> bgInfo = mapFindWithDefault( + *bgiMap, key, boost::shared_ptr<BgInfo>()); + if (!bgInfo) + return; + bgInfo->awaitNoBgOps(lk); + } + +} // namespace bool BackgroundOperation::inProgForDb(const StringData& db) { - SimpleMutex::scoped_lock lk(m); - return dbsInProg[db.toString()] > 0; + boost::mutex::scoped_lock lk(m); + return dbsInProg.find(db) != dbsInProg.end(); } bool BackgroundOperation::inProgForNs(const StringData& ns) { - SimpleMutex::scoped_lock lk(m); - return nsInProg.count(ns.toString()) > 0; + boost::mutex::scoped_lock lk(m); + return nsInProg.find(ns) != nsInProg.end(); } void BackgroundOperation::assertNoBgOpInProgForDb(const StringData& db) { - uassert(12586, - "cannot perform operation: a background operation is currently running for this database", + uassert(ErrorCodes::BackgroundOperationInProgressForDatabase, mongoutils::str::stream() << + "cannot perform operation: a background operation is currently running for " + "database " << db, !inProgForDb(db)); } void BackgroundOperation::assertNoBgOpInProgForNs(const StringData& ns) { - uassert(12587, - "cannot perform operation: a background operation is currently running for this collection", + uassert(ErrorCodes::BackgroundOperationInProgressForNamespace, mongoutils::str::stream() << + "cannot perform operation: a background operation is currently running for " + "collection" << ns, !inProgForNs(ns)); } + void BackgroundOperation::awaitNoBgOpInProgForDb(const StringData& db) { + boost::unique_lock<boost::mutex> lk(m); + awaitNoBgOps(lk, &dbsInProg, db); + } + + void BackgroundOperation::awaitNoBgOpInProgForNs(const StringData& ns) { + boost::unique_lock<boost::mutex> lk(m); + awaitNoBgOps(lk, &nsInProg, ns); + } + BackgroundOperation::BackgroundOperation(const StringData& ns) : _ns(ns) { - SimpleMutex::scoped_lock lk(m); - dbsInProg[_ns.db().toString()]++; - nsInProg.insert(_ns.ns()); + boost::mutex::scoped_lock lk(m); + recordBeginAndInsert(&dbsInProg, _ns.db()); + recordBeginAndInsert(&nsInProg, _ns.ns()); } BackgroundOperation::~BackgroundOperation() { - SimpleMutex::scoped_lock lk(m); - dbsInProg[_ns.db().toString()]--; - nsInProg.erase(_ns.ns()); + boost::mutex::scoped_lock lk(m); + recordEndAndRemove(&dbsInProg, _ns.db()); + recordEndAndRemove(&nsInProg, _ns.ns()); } - void BackgroundOperation::dump(std::stringstream& ss) { - SimpleMutex::scoped_lock lk(m); + void BackgroundOperation::dump(std::ostream& ss) { + boost::mutex::scoped_lock lk(m); if( nsInProg.size() ) { ss << "\n<b>Background Jobs in Progress</b>\n"; - for( std::set<std::string>::iterator i = nsInProg.begin(); i != nsInProg.end(); i++ ) - ss << " " << *i << '\n'; + for( BgInfoMapIterator i = nsInProg.begin(); i != nsInProg.end(); ++i ) + ss << " " << i->first << '\n'; } - for( std::map<std::string,unsigned>::iterator i = dbsInProg.begin(); i != dbsInProg.end(); i++ ) { - if( i->second ) - ss << "database " << i->first << ": " << i->second << '\n'; + for( BgInfoMapIterator i = dbsInProg.begin(); i != dbsInProg.end(); ++i ) { + if( i->second->getOpsInProgCount() ) + ss << "database " << i->first << ": " << i->second->getOpsInProgCount() << '\n'; } } - - - } // namespace mongo |