diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2014-04-18 15:28:50 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2014-04-18 17:33:29 -0400 |
commit | 9ad97ac9fd08cf56d4e6c4bdb5c1b10085b9040c (patch) | |
tree | a0cce7eee8486969a2a7ea4372c0d0e0543b1ff3 | |
parent | d4b1e9e2e5097ff777b69543183088fa1fbb0129 (diff) | |
download | mongo-9ad97ac9fd08cf56d4e6c4bdb5c1b10085b9040c.tar.gz |
SERVER-13620 Refactor background.h/cpp; add awaitNoBgOp methods.
-rw-r--r-- | src/mongo/db/background.cpp | 143 | ||||
-rw-r--r-- | src/mongo/db/background.h | 15 |
2 files changed, 123 insertions, 35 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 diff --git a/src/mongo/db/background.h b/src/mongo/db/background.h index 7cde9ffa8de..3db4767f95a 100644 --- a/src/mongo/db/background.h +++ b/src/mongo/db/background.h @@ -35,12 +35,11 @@ #include <map> #include <set> -#include <string> -#include <sstream> +#include <iosfwd> +#include "mongo/base/disallow_copying.h" #include "mongo/base/string_data.h" #include "mongo/db/namespace_string.h" -#include "mongo/util/concurrency/mutex.h" namespace mongo { @@ -54,13 +53,16 @@ namespace mongo { It's assumed this is not for super-high RPS things, so we don't do anything special in the implementation here to be fast. */ - class BackgroundOperation : public boost::noncopyable { + class BackgroundOperation { + MONGO_DISALLOW_COPYING(BackgroundOperation); public: static bool inProgForDb(const StringData& db); static bool inProgForNs(const StringData& ns); static void assertNoBgOpInProgForDb(const StringData& db); static void assertNoBgOpInProgForNs(const StringData& ns); - static void dump(std::stringstream&); + static void awaitNoBgOpInProgForDb(const StringData& db); + static void awaitNoBgOpInProgForNs(const StringData& ns); + static void dump(std::ostream&); /* check for in progress before instantiating */ BackgroundOperation(const StringData& ns); @@ -69,9 +71,6 @@ namespace mongo { private: NamespaceString _ns; - static std::map<std::string, unsigned> dbsInProg; - static std::set<std::string> nsInProg; - static SimpleMutex m; }; } // namespace mongo |