diff options
Diffstat (limited to 'src/mongo/s/config.cpp')
-rw-r--r-- | src/mongo/s/config.cpp | 1155 |
1 files changed, 558 insertions, 597 deletions
diff --git a/src/mongo/s/config.cpp b/src/mongo/s/config.cpp index 0a1904c9552..7481f949a2a 100644 --- a/src/mongo/s/config.cpp +++ b/src/mongo/s/config.cpp @@ -56,751 +56,712 @@ namespace mongo { - using std::endl; - using std::set; - using std::string; - using std::unique_ptr; - using std::vector; - - CollectionInfo::CollectionInfo(const CollectionType& coll) { - _dropped = coll.getDropped(); - - shard(new ChunkManager(coll)); - _dirty = false; +using std::endl; +using std::set; +using std::string; +using std::unique_ptr; +using std::vector; + +CollectionInfo::CollectionInfo(const CollectionType& coll) { + _dropped = coll.getDropped(); + + shard(new ChunkManager(coll)); + _dirty = false; +} + +CollectionInfo::~CollectionInfo() {} + +void CollectionInfo::resetCM(ChunkManager* cm) { + invariant(cm); + invariant(_cm); + + _cm.reset(cm); +} + +void CollectionInfo::shard(ChunkManager* manager) { + // Do this *first* so we're invisible to everyone else + manager->loadExistingRanges(nullptr); + + // + // Collections with no chunks are unsharded, no matter what the collections entry says + // This helps prevent errors when dropping in a different process + // + + if (manager->numChunks() != 0) { + useChunkManager(ChunkManagerPtr(manager)); + } else { + warning() << "no chunks found for collection " << manager->getns() + << ", assuming unsharded"; + unshard(); } - - CollectionInfo::~CollectionInfo() { - +} + +void CollectionInfo::unshard() { + _cm.reset(); + _dropped = true; + _dirty = true; + _key = BSONObj(); +} + +void CollectionInfo::useChunkManager(ChunkManagerPtr manager) { + _cm = manager; + _key = manager->getShardKeyPattern().toBSON().getOwned(); + _unique = manager->isUnique(); + _dirty = true; + _dropped = false; +} + +void CollectionInfo::save(const string& ns) { + CollectionType coll; + coll.setNs(NamespaceString{ns}); + + if (_cm) { + invariant(!_dropped); + coll.setEpoch(_cm->getVersion().epoch()); + // TODO(schwerin): The following isn't really a date, but is stored as one in-memory and + // in config.collections, as a historical oddity. + coll.setUpdatedAt(Date_t::fromMillisSinceEpoch(_cm->getVersion().toLong())); + coll.setKeyPattern(_cm->getShardKeyPattern().toBSON()); + coll.setUnique(_cm->isUnique()); + } else { + invariant(_dropped); + coll.setDropped(true); + coll.setEpoch(ChunkVersion::DROPPED().epoch()); + coll.setUpdatedAt(Date_t::now()); } - void CollectionInfo::resetCM(ChunkManager* cm) { - invariant(cm); - invariant(_cm); - - _cm.reset(cm); + uassertStatusOK(grid.catalogManager()->updateCollection(ns, coll)); + _dirty = false; +} + +DBConfig::DBConfig(std::string name, const DatabaseType& dbt) : _name(name) { + invariant(_name == dbt.getName()); + _primaryId = dbt.getPrimary(); + _shardingEnabled = dbt.getSharded(); +} + +bool DBConfig::isSharded(const string& ns) { + if (!_shardingEnabled) + return false; + stdx::lock_guard<stdx::mutex> lk(_lock); + return _isSharded(ns); +} + +bool DBConfig::_isSharded(const string& ns) { + if (!_shardingEnabled) { + return false; } - - void CollectionInfo::shard(ChunkManager* manager) { - // Do this *first* so we're invisible to everyone else - manager->loadExistingRanges(nullptr); - - // - // Collections with no chunks are unsharded, no matter what the collections entry says - // This helps prevent errors when dropping in a different process - // - if (manager->numChunks() != 0) { - useChunkManager(ChunkManagerPtr(manager)); - } - else{ - warning() << "no chunks found for collection " << manager->getns() - << ", assuming unsharded"; - unshard(); - } + CollectionInfoMap::iterator i = _collections.find(ns); + if (i == _collections.end()) { + return false; } - void CollectionInfo::unshard() { - _cm.reset(); - _dropped = true; - _dirty = true; - _key = BSONObj(); - } + return i->second.isSharded(); +} - void CollectionInfo::useChunkManager(ChunkManagerPtr manager) { - _cm = manager; - _key = manager->getShardKeyPattern().toBSON().getOwned(); - _unique = manager->isUnique(); - _dirty = true; - _dropped = false; - } +const ShardId& DBConfig::getShardId(const string& ns) { + uassert(28679, "ns can't be sharded", !isSharded(ns)); - void CollectionInfo::save(const string& ns) { - CollectionType coll; - coll.setNs(NamespaceString{ns}); + uassert(10178, "no primary!", grid.shardRegistry()->getShard(_primaryId)); + return _primaryId; +} - if (_cm) { - invariant(!_dropped); - coll.setEpoch(_cm->getVersion().epoch()); - // TODO(schwerin): The following isn't really a date, but is stored as one in-memory and - // in config.collections, as a historical oddity. - coll.setUpdatedAt(Date_t::fromMillisSinceEpoch(_cm->getVersion().toLong())); - coll.setKeyPattern(_cm->getShardKeyPattern().toBSON()); - coll.setUnique(_cm->isUnique()); - } - else { - invariant(_dropped); - coll.setDropped(true); - coll.setEpoch(ChunkVersion::DROPPED().epoch()); - coll.setUpdatedAt(Date_t::now()); - } +void DBConfig::enableSharding(bool save) { + if (_shardingEnabled) + return; - uassertStatusOK(grid.catalogManager()->updateCollection(ns, coll)); - _dirty = false; - } + verify(_name != "config"); - DBConfig::DBConfig(std::string name, const DatabaseType& dbt) - : _name(name) { + stdx::lock_guard<stdx::mutex> lk(_lock); + _shardingEnabled = true; + if (save) + _save(); +} - invariant(_name == dbt.getName()); - _primaryId = dbt.getPrimary(); - _shardingEnabled = dbt.getSharded(); +bool DBConfig::removeSharding(const string& ns) { + if (!_shardingEnabled) { + warning() << "could not remove sharding for collection " << ns + << ", sharding not enabled for db" << endl; + return false; } - bool DBConfig::isSharded( const string& ns ) { - if ( ! _shardingEnabled ) - return false; - stdx::lock_guard<stdx::mutex> lk( _lock ); - return _isSharded( ns ); - } + stdx::lock_guard<stdx::mutex> lk(_lock); - bool DBConfig::_isSharded( const string& ns ) { - if (!_shardingEnabled) { - return false; - } + CollectionInfoMap::iterator i = _collections.find(ns); - CollectionInfoMap::iterator i = _collections.find( ns ); - if (i == _collections.end()) { - return false; - } + if (i == _collections.end()) + return false; - return i->second.isSharded(); + CollectionInfo& ci = _collections[ns]; + if (!ci.isSharded()) { + warning() << "could not remove sharding for collection " << ns + << ", no sharding information found" << endl; + return false; } - const ShardId& DBConfig::getShardId(const string& ns) { - uassert(28679, "ns can't be sharded", !isSharded(ns)); + ci.unshard(); + _save(false, true); + return true; +} - uassert(10178, - "no primary!", - grid.shardRegistry()->getShard(_primaryId)); - return _primaryId; - } +// Handles weird logic related to getting *either* a chunk manager *or* the collection primary shard +void DBConfig::getChunkManagerOrPrimary(const string& ns, + std::shared_ptr<ChunkManager>& manager, + std::shared_ptr<Shard>& primary) { + // The logic here is basically that at any time, our collection can become sharded or unsharded + // via a command. If we're not sharded, we want to send data to the primary, if sharded, we want + // to send data to the correct chunks, and we can't check both w/o the lock. - void DBConfig::enableSharding( bool save ) { - if ( _shardingEnabled ) - return; - - verify( _name != "config" ); + manager.reset(); + primary.reset(); - stdx::lock_guard<stdx::mutex> lk( _lock ); - _shardingEnabled = true; - if( save ) _save(); - } + { + stdx::lock_guard<stdx::mutex> lk(_lock); - bool DBConfig::removeSharding( const string& ns ) { - if ( ! _shardingEnabled ) { + CollectionInfoMap::iterator i = _collections.find(ns); - warning() << "could not remove sharding for collection " << ns - << ", sharding not enabled for db" << endl; - return false; + // No namespace + if (i == _collections.end()) { + // If we don't know about this namespace, it's unsharded by default + primary = grid.shardRegistry()->getShard(_primaryId); + } else { + CollectionInfo& cInfo = i->second; + + // TODO: we need to be careful about handling shardingEnabled, b/c in some places we seem to use and + // some we don't. If we use this function in combination with just getChunkManager() on a slightly + // borked config db, we'll get lots of staleconfig retries + if (_shardingEnabled && cInfo.isSharded()) { + manager = cInfo.getCM(); + } else { + primary = grid.shardRegistry()->getShard(_primaryId); + } } + } - stdx::lock_guard<stdx::mutex> lk( _lock ); + verify(manager || primary); + verify(!manager || !primary); +} - CollectionInfoMap::iterator i = _collections.find( ns ); - if ( i == _collections.end() ) - return false; +ChunkManagerPtr DBConfig::getChunkManagerIfExists(const string& ns, + bool shouldReload, + bool forceReload) { + // Don't report exceptions here as errors in GetLastError + LastError::Disabled ignoreForGLE(&LastError::get(cc())); - CollectionInfo& ci = _collections[ns]; - if ( ! ci.isSharded() ){ - - warning() << "could not remove sharding for collection " << ns - << ", no sharding information found" << endl; - return false; - } - - ci.unshard(); - _save( false, true ); - return true; + try { + return getChunkManager(ns, shouldReload, forceReload); + } catch (AssertionException& e) { + warning() << "chunk manager not found for " << ns << causedBy(e); + return ChunkManagerPtr(); } +} - // Handles weird logic related to getting *either* a chunk manager *or* the collection primary shard - void DBConfig::getChunkManagerOrPrimary(const string& ns, - std::shared_ptr<ChunkManager>& manager, - std::shared_ptr<Shard>& primary) { - - // The logic here is basically that at any time, our collection can become sharded or unsharded - // via a command. If we're not sharded, we want to send data to the primary, if sharded, we want - // to send data to the correct chunks, and we can't check both w/o the lock. +std::shared_ptr<ChunkManager> DBConfig::getChunkManager(const string& ns, + bool shouldReload, + bool forceReload) { + BSONObj key; + ChunkVersion oldVersion; + ChunkManagerPtr oldManager; - manager.reset(); - primary.reset(); - - { - stdx::lock_guard<stdx::mutex> lk( _lock ); - - CollectionInfoMap::iterator i = _collections.find( ns ); + { + stdx::lock_guard<stdx::mutex> lk(_lock); - // No namespace - if( i == _collections.end() ){ - // If we don't know about this namespace, it's unsharded by default - primary = grid.shardRegistry()->getShard(_primaryId); - } - else { - CollectionInfo& cInfo = i->second; - - // TODO: we need to be careful about handling shardingEnabled, b/c in some places we seem to use and - // some we don't. If we use this function in combination with just getChunkManager() on a slightly - // borked config db, we'll get lots of staleconfig retries - if( _shardingEnabled && cInfo.isSharded() ){ - manager = cInfo.getCM(); - } - else{ - primary = grid.shardRegistry()->getShard(_primaryId); - } - } + bool earlyReload = !_collections[ns].isSharded() && (shouldReload || forceReload); + if (earlyReload) { + // This is to catch cases where there this is a new sharded collection + _reload(); } - verify( manager || primary ); - verify( ! manager || ! primary ); + CollectionInfo& ci = _collections[ns]; + uassert(10181, str::stream() << "not sharded:" << ns, ci.isSharded()); - } + invariant(!ci.key().isEmpty()); + if (!(shouldReload || forceReload) || earlyReload) { + return ci.getCM(); + } - ChunkManagerPtr DBConfig::getChunkManagerIfExists(const string& ns, - bool shouldReload, - bool forceReload) { + key = ci.key().copy(); - // Don't report exceptions here as errors in GetLastError - LastError::Disabled ignoreForGLE(&LastError::get(cc())); - - try{ - return getChunkManager(ns, shouldReload, forceReload); - } - catch (AssertionException& e) { - warning() << "chunk manager not found for " << ns << causedBy(e); - return ChunkManagerPtr(); + if (ci.getCM()) { + oldManager = ci.getCM(); + oldVersion = ci.getCM()->getVersion(); } } - std::shared_ptr<ChunkManager> DBConfig::getChunkManager(const string& ns, - bool shouldReload, - bool forceReload) { - BSONObj key; - ChunkVersion oldVersion; - ChunkManagerPtr oldManager; - - { - stdx::lock_guard<stdx::mutex> lk(_lock); - - bool earlyReload = !_collections[ns].isSharded() && (shouldReload || forceReload); - if (earlyReload) { - // This is to catch cases where there this is a new sharded collection - _reload(); - } - - CollectionInfo& ci = _collections[ns]; - uassert(10181, str::stream() << "not sharded:" << ns, ci.isSharded()); - - invariant(!ci.key().isEmpty()); - - if (!(shouldReload || forceReload) || earlyReload) { + invariant(!key.isEmpty()); + + // TODO: We need to keep this first one-chunk check in until we have a more efficient way of + // creating/reusing a chunk manager, as doing so requires copying the full set of chunks currently + vector<ChunkType> newestChunk; + if (oldVersion.isSet() && !forceReload) { + uassertStatusOK(grid.catalogManager()->getChunks( + Query(BSON(ChunkType::ns(ns))).sort(ChunkType::DEPRECATED_lastmod(), -1), + 1, + &newestChunk)); + + if (!newestChunk.empty()) { + invariant(newestChunk.size() == 1); + ChunkVersion v = newestChunk[0].getVersion(); + if (v.equals(oldVersion)) { + stdx::lock_guard<stdx::mutex> lk(_lock); + const CollectionInfo& ci = _collections[ns]; + uassert(15885, + str::stream() << "not sharded after reloading from chunks : " << ns, + ci.isSharded()); return ci.getCM(); } - - key = ci.key().copy(); - - if (ci.getCM()){ - oldManager = ci.getCM(); - oldVersion = ci.getCM()->getVersion(); - } } - - invariant(!key.isEmpty()); - - // TODO: We need to keep this first one-chunk check in until we have a more efficient way of - // creating/reusing a chunk manager, as doing so requires copying the full set of chunks currently - vector<ChunkType> newestChunk; - if ( oldVersion.isSet() && ! forceReload ) { - uassertStatusOK(grid.catalogManager()->getChunks( - Query(BSON(ChunkType::ns(ns))) - .sort(ChunkType::DEPRECATED_lastmod(), -1), - 1, - &newestChunk)); - - if (!newestChunk.empty()) { - invariant(newestChunk.size() == 1); - ChunkVersion v = newestChunk[0].getVersion(); - if (v.equals(oldVersion)) { - stdx::lock_guard<stdx::mutex> lk( _lock ); - const CollectionInfo& ci = _collections[ns]; - uassert(15885, - str::stream() << "not sharded after reloading from chunks : " - << ns, ci.isSharded()); - return ci.getCM(); - } - } - } - else if (!oldVersion.isSet()) { - warning() << "version 0 found when " << (forceReload ? "reloading" : "checking") - << " chunk manager; collection '" << ns << "' initially detected as sharded"; - } + } else if (!oldVersion.isSet()) { + warning() << "version 0 found when " << (forceReload ? "reloading" : "checking") + << " chunk manager; collection '" << ns << "' initially detected as sharded"; + } - // we are not locked now, and want to load a new ChunkManager - - unique_ptr<ChunkManager> tempChunkManager; + // we are not locked now, and want to load a new ChunkManager - { - stdx::lock_guard<stdx::mutex> lll ( _hitConfigServerLock ); + unique_ptr<ChunkManager> tempChunkManager; - if (!newestChunk.empty() && !forceReload) { - // If we have a target we're going for see if we've hit already - stdx::lock_guard<stdx::mutex> lk( _lock ); + { + stdx::lock_guard<stdx::mutex> lll(_hitConfigServerLock); - CollectionInfo& ci = _collections[ns]; + if (!newestChunk.empty() && !forceReload) { + // If we have a target we're going for see if we've hit already + stdx::lock_guard<stdx::mutex> lk(_lock); - if ( ci.isSharded() && ci.getCM() ) { - ChunkVersion currentVersion = newestChunk[0].getVersion(); + CollectionInfo& ci = _collections[ns]; - // Only reload if the version we found is newer than our own in the same epoch - if (currentVersion <= ci.getCM()->getVersion() && - ci.getCM()->getVersion().hasEqualEpoch(currentVersion)) { + if (ci.isSharded() && ci.getCM()) { + ChunkVersion currentVersion = newestChunk[0].getVersion(); - return ci.getCM(); - } + // Only reload if the version we found is newer than our own in the same epoch + if (currentVersion <= ci.getCM()->getVersion() && + ci.getCM()->getVersion().hasEqualEpoch(currentVersion)) { + return ci.getCM(); } } - - tempChunkManager.reset(new ChunkManager(oldManager->getns(), - oldManager->getShardKeyPattern(), - oldManager->isUnique())); - tempChunkManager->loadExistingRanges(oldManager.get()); - - if (tempChunkManager->numChunks() == 0) { - // Maybe we're not sharded any more, so do a full reload - reload(); - - return getChunkManager(ns, false); - } } - stdx::lock_guard<stdx::mutex> lk( _lock ); + tempChunkManager.reset(new ChunkManager( + oldManager->getns(), oldManager->getShardKeyPattern(), oldManager->isUnique())); + tempChunkManager->loadExistingRanges(oldManager.get()); - CollectionInfo& ci = _collections[ns]; - uassert(14822, (string)"state changed in the middle: " + ns, ci.isSharded()); - - // Reset if our versions aren't the same - bool shouldReset = !tempChunkManager->getVersion().equals(ci.getCM()->getVersion()); - - // Also reset if we're forced to do so - if (!shouldReset && forceReload) { - shouldReset = true; - warning() << "chunk manager reload forced for collection '" << ns - << "', config version is " << tempChunkManager->getVersion(); - } + if (tempChunkManager->numChunks() == 0) { + // Maybe we're not sharded any more, so do a full reload + reload(); - // - // LEGACY BEHAVIOR - // - // It's possible to get into a state when dropping collections when our new version is - // less than our prev version. Behave identically to legacy mongos, for now, and warn to - // draw attention to the problem. - // - // TODO: Assert in next version, to allow smooth upgrades - // - - if (shouldReset && tempChunkManager->getVersion() < ci.getCM()->getVersion()) { - shouldReset = false; - - warning() << "not resetting chunk manager for collection '" << ns - << "', config version is " << tempChunkManager->getVersion() << " and " - << "old version is " << ci.getCM()->getVersion(); + return getChunkManager(ns, false); } + } - // end legacy behavior + stdx::lock_guard<stdx::mutex> lk(_lock); - if (shouldReset) { - ci.resetCM(tempChunkManager.release()); - } + CollectionInfo& ci = _collections[ns]; + uassert(14822, (string) "state changed in the middle: " + ns, ci.isSharded()); - uassert(15883, str::stream() << "not sharded after chunk manager reset : " - << ns, ci.isSharded()); + // Reset if our versions aren't the same + bool shouldReset = !tempChunkManager->getVersion().equals(ci.getCM()->getVersion()); - return ci.getCM(); + // Also reset if we're forced to do so + if (!shouldReset && forceReload) { + shouldReset = true; + warning() << "chunk manager reload forced for collection '" << ns << "', config version is " + << tempChunkManager->getVersion(); } - void DBConfig::setPrimary(const std::string& s) { - const auto shard = grid.shardRegistry()->getShard(s); - - stdx::lock_guard<stdx::mutex> lk( _lock ); - _primaryId = shard->getId(); - _save(); + // + // LEGACY BEHAVIOR + // + // It's possible to get into a state when dropping collections when our new version is + // less than our prev version. Behave identically to legacy mongos, for now, and warn to + // draw attention to the problem. + // + // TODO: Assert in next version, to allow smooth upgrades + // + + if (shouldReset && tempChunkManager->getVersion() < ci.getCM()->getVersion()) { + shouldReset = false; + + warning() << "not resetting chunk manager for collection '" << ns << "', config version is " + << tempChunkManager->getVersion() << " and " + << "old version is " << ci.getCM()->getVersion(); } - bool DBConfig::load() { - stdx::lock_guard<stdx::mutex> lk( _lock ); - return _load(); + // end legacy behavior + + if (shouldReset) { + ci.resetCM(tempChunkManager.release()); } - bool DBConfig::_load() { - StatusWith<DatabaseType> status = grid.catalogManager()->getDatabase(_name); - if (status == ErrorCodes::DatabaseNotFound) { - return false; - } + uassert( + 15883, str::stream() << "not sharded after chunk manager reset : " << ns, ci.isSharded()); - // All other errors are connectivity, etc so throw an exception. - uassertStatusOK(status.getStatus()); + return ci.getCM(); +} - DatabaseType dbt = status.getValue(); - invariant(_name == dbt.getName()); - _primaryId = dbt.getPrimary(); - _shardingEnabled = dbt.getSharded(); +void DBConfig::setPrimary(const std::string& s) { + const auto shard = grid.shardRegistry()->getShard(s); - // Load all collections - vector<CollectionType> collections; - uassertStatusOK(grid.catalogManager()->getCollections(&_name, &collections)); + stdx::lock_guard<stdx::mutex> lk(_lock); + _primaryId = shard->getId(); + _save(); +} - int numCollsErased = 0; - int numCollsSharded = 0; +bool DBConfig::load() { + stdx::lock_guard<stdx::mutex> lk(_lock); + return _load(); +} - for (const auto& coll : collections) { - if (coll.getDropped()) { - _collections.erase(coll.getNs()); - numCollsErased++; - } - else { - _collections[coll.getNs()] = CollectionInfo(coll); - numCollsSharded++; - } - } - - LOG(2) << "found " << numCollsSharded << " collections left and " - << numCollsErased << " collections dropped for database " << _name; - - return true; +bool DBConfig::_load() { + StatusWith<DatabaseType> status = grid.catalogManager()->getDatabase(_name); + if (status == ErrorCodes::DatabaseNotFound) { + return false; } - void DBConfig::_save(bool db, bool coll) { - if (db) { - DatabaseType dbt; - dbt.setName(_name); - dbt.setPrimary(_primaryId); - dbt.setSharded(_shardingEnabled); + // All other errors are connectivity, etc so throw an exception. + uassertStatusOK(status.getStatus()); - uassertStatusOK(grid.catalogManager()->updateDatabase(_name, dbt)); - } + DatabaseType dbt = status.getValue(); + invariant(_name == dbt.getName()); + _primaryId = dbt.getPrimary(); + _shardingEnabled = dbt.getSharded(); - if (coll) { - for (CollectionInfoMap::iterator i = _collections.begin(); - i != _collections.end(); - ++i) { + // Load all collections + vector<CollectionType> collections; + uassertStatusOK(grid.catalogManager()->getCollections(&_name, &collections)); - if (!i->second.isDirty()) { - continue; - } + int numCollsErased = 0; + int numCollsSharded = 0; - i->second.save(i->first); - } + for (const auto& coll : collections) { + if (coll.getDropped()) { + _collections.erase(coll.getNs()); + numCollsErased++; + } else { + _collections[coll.getNs()] = CollectionInfo(coll); + numCollsSharded++; } } - bool DBConfig::reload() { - bool successful = false; + LOG(2) << "found " << numCollsSharded << " collections left and " << numCollsErased + << " collections dropped for database " << _name; - { - stdx::lock_guard<stdx::mutex> lk( _lock ); - successful = _reload(); - } + return true; +} - // If we aren't successful loading the database entry, we don't want to keep the stale - // object around which has invalid data. - if (!successful) { - grid.catalogCache()->invalidate(_name); - } +void DBConfig::_save(bool db, bool coll) { + if (db) { + DatabaseType dbt; + dbt.setName(_name); + dbt.setPrimary(_primaryId); + dbt.setSharded(_shardingEnabled); - return successful; + uassertStatusOK(grid.catalogManager()->updateDatabase(_name, dbt)); } - bool DBConfig::_reload() { - // TODO: i don't think is 100% correct - return _load(); + if (coll) { + for (CollectionInfoMap::iterator i = _collections.begin(); i != _collections.end(); ++i) { + if (!i->second.isDirty()) { + continue; + } + + i->second.save(i->first); + } } +} - bool DBConfig::dropDatabase(string& errmsg) { - /** - * 1) update config server - * 2) drop and reset sharded collections - * 3) drop and reset primary - * 4) drop everywhere to clean up loose ends - */ +bool DBConfig::reload() { + bool successful = false; - log() << "DBConfig::dropDatabase: " << _name << endl; - grid.catalogManager()->logChange(NULL, "dropDatabase.start", _name, BSONObj()); + { + stdx::lock_guard<stdx::mutex> lk(_lock); + successful = _reload(); + } - // 1 + // If we aren't successful loading the database entry, we don't want to keep the stale + // object around which has invalid data. + if (!successful) { grid.catalogCache()->invalidate(_name); + } - Status result = grid.catalogManager()->remove(DatabaseType::ConfigNS, - BSON(DatabaseType::name(_name)), - 0, - NULL); - if (!result.isOK()) { - errmsg = result.reason(); - log() << "could not drop '" << _name << "': " << errmsg << endl; - return false; - } + return successful; +} + +bool DBConfig::_reload() { + // TODO: i don't think is 100% correct + return _load(); +} + +bool DBConfig::dropDatabase(string& errmsg) { + /** + * 1) update config server + * 2) drop and reset sharded collections + * 3) drop and reset primary + * 4) drop everywhere to clean up loose ends + */ + + log() << "DBConfig::dropDatabase: " << _name << endl; + grid.catalogManager()->logChange(NULL, "dropDatabase.start", _name, BSONObj()); + + // 1 + grid.catalogCache()->invalidate(_name); + + Status result = grid.catalogManager()->remove( + DatabaseType::ConfigNS, BSON(DatabaseType::name(_name)), 0, NULL); + if (!result.isOK()) { + errmsg = result.reason(); + log() << "could not drop '" << _name << "': " << errmsg << endl; + return false; + } - LOG(1) << "\t removed entry from config server for: " << _name << endl; + LOG(1) << "\t removed entry from config server for: " << _name << endl; - set<ShardId> shardIds; + set<ShardId> shardIds; - // 2 - while ( true ) { - int num = 0; - if (!_dropShardedCollections(num, shardIds, errmsg)) { - return 0; - } + // 2 + while (true) { + int num = 0; + if (!_dropShardedCollections(num, shardIds, errmsg)) { + return 0; + } - log() << " DBConfig::dropDatabase: " << _name - << " dropped sharded collections: " << num; + log() << " DBConfig::dropDatabase: " << _name << " dropped sharded collections: " << num; - if (num == 0) { - break; - } + if (num == 0) { + break; } + } - // 3 - { - const auto shard = grid.shardRegistry()->getShard(_primaryId); - ScopedDbConnection conn(shard->getConnString(), 30.0); - BSONObj res; - if ( ! conn->dropDatabase( _name , &res ) ) { - errmsg = res.toString(); - return 0; - } - conn.done(); + // 3 + { + const auto shard = grid.shardRegistry()->getShard(_primaryId); + ScopedDbConnection conn(shard->getConnString(), 30.0); + BSONObj res; + if (!conn->dropDatabase(_name, &res)) { + errmsg = res.toString(); + return 0; } + conn.done(); + } - // 4 - for (const ShardId& shardId : shardIds) { - const auto shard = grid.shardRegistry()->getShard(shardId); - if (!shard) { - continue; - } - - ScopedDbConnection conn(shard->getConnString(), 30.0); - BSONObj res; - if ( ! conn->dropDatabase( _name , &res ) ) { - errmsg = res.toString(); - return 0; - } - conn.done(); + // 4 + for (const ShardId& shardId : shardIds) { + const auto shard = grid.shardRegistry()->getShard(shardId); + if (!shard) { + continue; } - LOG(1) << "\t dropped primary db for: " << _name << endl; - - grid.catalogManager()->logChange(NULL, "dropDatabase", _name, BSONObj()); - - return true; + ScopedDbConnection conn(shard->getConnString(), 30.0); + BSONObj res; + if (!conn->dropDatabase(_name, &res)) { + errmsg = res.toString(); + return 0; + } + conn.done(); } - bool DBConfig::_dropShardedCollections(int& num, set<ShardId>& shardIds, string& errmsg) { - num = 0; - set<string> seen; - while ( true ) { - CollectionInfoMap::iterator i = _collections.begin(); - for ( ; i != _collections.end(); ++i ) { - // log() << "coll : " << i->first << " and " << i->second.isSharded() << endl; - if ( i->second.isSharded() ) - break; - } - - if ( i == _collections.end() ) - break; - - if ( seen.count( i->first ) ) { - errmsg = "seen a collection twice!"; - return false; - } + LOG(1) << "\t dropped primary db for: " << _name << endl; - seen.insert( i->first ); - LOG(1) << "\t dropping sharded collection: " << i->first << endl; + grid.catalogManager()->logChange(NULL, "dropDatabase", _name, BSONObj()); - i->second.getCM()->getAllShardIds(&shardIds); + return true; +} - uassertStatusOK(grid.catalogManager()->dropCollection(i->first)); +bool DBConfig::_dropShardedCollections(int& num, set<ShardId>& shardIds, string& errmsg) { + num = 0; + set<string> seen; + while (true) { + CollectionInfoMap::iterator i = _collections.begin(); + for (; i != _collections.end(); ++i) { + // log() << "coll : " << i->first << " and " << i->second.isSharded() << endl; + if (i->second.isSharded()) + break; + } - // We should warn, but it's not a fatal error if someone else reloaded the db/coll as - // unsharded in the meantime - if( ! removeSharding( i->first ) ){ - warning() << "collection " << i->first - << " was reloaded as unsharded before drop completed" - << " during drop of all collections" << endl; - } + if (i == _collections.end()) + break; - num++; - uassert( 10184 , "_dropShardedCollections too many collections - bailing" , num < 100000 ); - LOG(2) << "\t\t dropped " << num << " so far" << endl; + if (seen.count(i->first)) { + errmsg = "seen a collection twice!"; + return false; } - return true; - } + seen.insert(i->first); + LOG(1) << "\t dropping sharded collection: " << i->first << endl; - void DBConfig::getAllShardIds(set<ShardId>* shardIds) { - dassert(shardIds); + i->second.getCM()->getAllShardIds(&shardIds); - stdx::lock_guard<stdx::mutex> lk(_lock); - shardIds->insert(getPrimaryId()); - for (CollectionInfoMap::const_iterator it(_collections.begin()), end(_collections.end()); - it != end; - ++it) { - if (it->second.isSharded()) { - it->second.getCM()->getAllShardIds(shardIds); - } // TODO: handle collections on non-primary shard - } - } + uassertStatusOK(grid.catalogManager()->dropCollection(i->first)); - void DBConfig::getAllShardedCollections( set<string>& namespaces ) { - stdx::lock_guard<stdx::mutex> lk(_lock); - - for( CollectionInfoMap::const_iterator i = _collections.begin(); i != _collections.end(); i++ ) { - log() << "Coll : " << i->first << " sharded? " << i->second.isSharded() << endl; - if( i->second.isSharded() ) namespaces.insert( i->first ); + // We should warn, but it's not a fatal error if someone else reloaded the db/coll as + // unsharded in the meantime + if (!removeSharding(i->first)) { + warning() << "collection " << i->first + << " was reloaded as unsharded before drop completed" + << " during drop of all collections" << endl; } + num++; + uassert(10184, "_dropShardedCollections too many collections - bailing", num < 100000); + LOG(2) << "\t\t dropped " << num << " so far" << endl; } - /* --- ConfigServer ---- */ + return true; +} - void ConfigServer::reloadSettings() { - auto chunkSizeResult = grid.catalogManager()->getGlobalSettings(SettingsType::ChunkSizeDocKey); - if (chunkSizeResult.isOK()) { - const int csize = chunkSizeResult.getValue().getChunkSizeMB(); - LOG(1) << "Found MaxChunkSize: " << csize; +void DBConfig::getAllShardIds(set<ShardId>* shardIds) { + dassert(shardIds); - if (!Chunk::setMaxChunkSizeSizeMB(csize)) { - warning() << "invalid chunksize: " << csize; - } - } - else if (chunkSizeResult.getStatus() == ErrorCodes::NoMatchingDocument) { - const int chunkSize = Chunk::MaxChunkSize / (1024 * 1024); - Status result = - grid.catalogManager()->insert(SettingsType::ConfigNS, - BSON(SettingsType::key(SettingsType::ChunkSizeDocKey) - << SettingsType::chunkSizeMB(chunkSize)), - NULL); - if (!result.isOK()) { - warning() << "couldn't set chunkSize on config db" << causedBy(result); - } - } - else { - warning() << "couldn't load settings on config db: " << chunkSizeResult.getStatus(); - } + stdx::lock_guard<stdx::mutex> lk(_lock); + shardIds->insert(getPrimaryId()); + for (CollectionInfoMap::const_iterator it(_collections.begin()), end(_collections.end()); + it != end; + ++it) { + if (it->second.isSharded()) { + it->second.getCM()->getAllShardIds(shardIds); + } // TODO: handle collections on non-primary shard + } +} - // indexes - Status result = clusterCreateIndex( ChunkType::ConfigNS, - BSON( ChunkType::ns() << 1 << ChunkType::min() << 1 ), - true, // unique - NULL ); +void DBConfig::getAllShardedCollections(set<string>& namespaces) { + stdx::lock_guard<stdx::mutex> lk(_lock); + for (CollectionInfoMap::const_iterator i = _collections.begin(); i != _collections.end(); i++) { + log() << "Coll : " << i->first << " sharded? " << i->second.isSharded() << endl; + if (i->second.isSharded()) + namespaces.insert(i->first); + } +} + +/* --- ConfigServer ---- */ + +void ConfigServer::reloadSettings() { + auto chunkSizeResult = grid.catalogManager()->getGlobalSettings(SettingsType::ChunkSizeDocKey); + if (chunkSizeResult.isOK()) { + const int csize = chunkSizeResult.getValue().getChunkSizeMB(); + LOG(1) << "Found MaxChunkSize: " << csize; + + if (!Chunk::setMaxChunkSizeSizeMB(csize)) { + warning() << "invalid chunksize: " << csize; + } + } else if (chunkSizeResult.getStatus() == ErrorCodes::NoMatchingDocument) { + const int chunkSize = Chunk::MaxChunkSize / (1024 * 1024); + Status result = + grid.catalogManager()->insert(SettingsType::ConfigNS, + BSON(SettingsType::key(SettingsType::ChunkSizeDocKey) + << SettingsType::chunkSizeMB(chunkSize)), + NULL); if (!result.isOK()) { - warning() << "couldn't create ns_1_min_1 index on config db" << causedBy(result); + warning() << "couldn't set chunkSize on config db" << causedBy(result); } + } else { + warning() << "couldn't load settings on config db: " << chunkSizeResult.getStatus(); + } - result = clusterCreateIndex( ChunkType::ConfigNS, - BSON( ChunkType::ns() << 1 << - ChunkType::shard() << 1 << - ChunkType::min() << 1 ), - true, // unique - NULL ); + // indexes + Status result = clusterCreateIndex(ChunkType::ConfigNS, + BSON(ChunkType::ns() << 1 << ChunkType::min() << 1), + true, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create ns_1_shard_1_min_1 index on config db" - << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create ns_1_min_1 index on config db" << causedBy(result); + } - result = clusterCreateIndex( ChunkType::ConfigNS, - BSON( ChunkType::ns() << 1 << - ChunkType::DEPRECATED_lastmod() << 1 ), - true, // unique - NULL ); + result = clusterCreateIndex( + ChunkType::ConfigNS, + BSON(ChunkType::ns() << 1 << ChunkType::shard() << 1 << ChunkType::min() << 1), + true, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create ns_1_lastmod_1 index on config db" << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create ns_1_shard_1_min_1 index on config db" << causedBy(result); + } - result = clusterCreateIndex( ShardType::ConfigNS, - BSON( ShardType::host() << 1 ), - true, // unique - NULL ); + result = clusterCreateIndex(ChunkType::ConfigNS, + BSON(ChunkType::ns() << 1 << ChunkType::DEPRECATED_lastmod() << 1), + true, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create host_1 index on config db" << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create ns_1_lastmod_1 index on config db" << causedBy(result); + } - result = clusterCreateIndex(LocksType::ConfigNS, - BSON(LocksType::lockID() << 1), - false, // unique - NULL); + result = clusterCreateIndex(ShardType::ConfigNS, + BSON(ShardType::host() << 1), + true, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create lock id index on config db" << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create host_1 index on config db" << causedBy(result); + } - result = clusterCreateIndex( LocksType::ConfigNS, - BSON( LocksType::state() << 1 << - LocksType::process() << 1 ), - false, // unique - NULL ); + result = clusterCreateIndex(LocksType::ConfigNS, + BSON(LocksType::lockID() << 1), + false, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create state and process id index on config db" - << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create lock id index on config db" << causedBy(result); + } - result = clusterCreateIndex( LockpingsType::ConfigNS, - BSON( LockpingsType::ping() << 1 ), - false, // unique - NULL ); + result = clusterCreateIndex(LocksType::ConfigNS, + BSON(LocksType::state() << 1 << LocksType::process() << 1), + false, // unique + NULL); - if (!result.isOK()) { - warning() << "couldn't create lockping ping time index on config db" - << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create state and process id index on config db" << causedBy(result); + } - result = clusterCreateIndex(TagsType::ConfigNS, - BSON(TagsType::ns() << 1 << TagsType::min() << 1), - true, // unique - NULL); + result = clusterCreateIndex(LockpingsType::ConfigNS, + BSON(LockpingsType::ping() << 1), + false, // unique + NULL); - if (!result.isOK()) { - warning() << "could not create index ns_1_min_1: " << causedBy(result); - } + if (!result.isOK()) { + warning() << "couldn't create lockping ping time index on config db" << causedBy(result); } - void ConfigServer::replicaSetChange(const string& setName, const string& newConnectionString) { - // This is run in it's own thread. Exceptions escaping would result in a call to terminate. - Client::initThread("replSetChange"); + result = clusterCreateIndex(TagsType::ConfigNS, + BSON(TagsType::ns() << 1 << TagsType::min() << 1), + true, // unique + NULL); - try { - ShardPtr s = Shard::lookupRSName(setName); - if (!s) { - LOG(1) << "shard not found for set: " << newConnectionString; - return; - } + if (!result.isOK()) { + warning() << "could not create index ns_1_min_1: " << causedBy(result); + } +} - Status result = grid.catalogManager()->update( - ShardType::ConfigNS, - BSON(ShardType::name(s->getId())), - BSON("$set" << BSON(ShardType::host( - newConnectionString))), - false, // upsert - false, // multi - NULL); - if (!result.isOK()) { - error() << "RSChangeWatcher: could not update config db for set: " - << setName - << " to: " << newConnectionString - << ": " << result.reason(); - } - } - catch (const std::exception& e) { - log() << "caught exception while updating config servers: " << e.what(); +void ConfigServer::replicaSetChange(const string& setName, const string& newConnectionString) { + // This is run in it's own thread. Exceptions escaping would result in a call to terminate. + Client::initThread("replSetChange"); + + try { + ShardPtr s = Shard::lookupRSName(setName); + if (!s) { + LOG(1) << "shard not found for set: " << newConnectionString; + return; } - catch (...) { - log() << "caught unknown exception while updating config servers"; + + Status result = grid.catalogManager()->update( + ShardType::ConfigNS, + BSON(ShardType::name(s->getId())), + BSON("$set" << BSON(ShardType::host(newConnectionString))), + false, // upsert + false, // multi + NULL); + if (!result.isOK()) { + error() << "RSChangeWatcher: could not update config db for set: " << setName + << " to: " << newConnectionString << ": " << result.reason(); } + } catch (const std::exception& e) { + log() << "caught exception while updating config servers: " << e.what(); + } catch (...) { + log() << "caught unknown exception while updating config servers"; } +} -} // namespace mongo +} // namespace mongo |