diff options
author | Kyle Suarez <kyle.suarez@mongodb.com> | 2016-04-27 15:04:17 -0400 |
---|---|---|
committer | Kyle Suarez <kyle.suarez@mongodb.com> | 2016-04-27 15:04:17 -0400 |
commit | 21fa9ccd4e12d7a94a95d98e1e984ada2ef65548 (patch) | |
tree | ec935d3060da16ed7df0720a8e1aa818b993868f | |
parent | 99e48007ab663eb0cf1d7c1de2ad6c36374b705c (diff) | |
download | mongo-21fa9ccd4e12d7a94a95d98e1e984ada2ef65548.tar.gz |
Revert "SERVER-22667 Balancer chunk selection policy interface"
This reverts commit 2cf31060a74ac438b58c5150ba30da4144112744.
-rw-r--r-- | jstests/sharding/jumbo1.js | 33 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/s/balance.cpp | 190 | ||||
-rw-r--r-- | src/mongo/s/balance.h | 15 | ||||
-rw-r--r-- | src/mongo/s/balancer/balancer_chunk_selection_policy.cpp | 60 | ||||
-rw-r--r-- | src/mongo/s/balancer/balancer_chunk_selection_policy.h | 97 | ||||
-rw-r--r-- | src/mongo/s/balancer/balancer_chunk_selection_policy_impl.cpp | 309 | ||||
-rw-r--r-- | src/mongo/s/balancer/balancer_chunk_selection_policy_impl.h | 69 | ||||
-rw-r--r-- | src/mongo/s/balancer_policy.h | 1 | ||||
-rw-r--r-- | src/mongo/s/chunk.cpp | 10 |
10 files changed, 168 insertions, 618 deletions
diff --git a/jstests/sharding/jumbo1.js b/jstests/sharding/jumbo1.js index 594c8165ab2..1e8a3a9fdb2 100644 --- a/jstests/sharding/jumbo1.js +++ b/jstests/sharding/jumbo1.js @@ -1,40 +1,39 @@ (function() { - 'use strict'; - var s = new ShardingTest({shards: 2, mongos: 1, other: {chunkSize: 1}}); + var s = new ShardingTest({name: "jumbo1", shards: 2, mongos: 1, other: {chunkSize: 1}}); - assert.commandWorked(s.s0.adminCommand({enablesharding: "test"})); + s.adminCommand({enablesharding: "test"}); s.ensurePrimaryShard('test', 'shard0001'); - assert.commandWorked(s.s0.adminCommand({shardcollection: "test.foo", key: {x: 1}})); + s.adminCommand({shardcollection: "test.foo", key: {x: 1}}); - var db = s.getDB("test"); + db = s.getDB("test"); - var big = ""; - while (big.length < 10000) { + big = ""; + while (big.length < 10000) big += "."; - } - var x = 0; + x = 0; var bulk = db.foo.initializeUnorderedBulkOp(); - for (; x < 500; x++) { + for (; x < 500; x++) bulk.insert({x: x, big: big}); - } - for (var i = 0; i < 500; i++) { + for (i = 0; i < 500; i++) bulk.insert({x: x, big: big}); - } - for (; x < 2000; x++) { + for (; x < 2000; x++) bulk.insert({x: x, big: big}); - } assert.writeOK(bulk.execute()); s.printShardingStatus(true); - assert.commandWorked(s.s0.adminCommand({moveChunk: 'test.foo', find: {x: 0}, to: 'shard0000'})); + + res = sh.moveChunk("test.foo", {x: 0}, "shard0001"); + if (!res.ok) + res = sh.moveChunk("test.foo", {x: 0}, "shard0000"); + s.printShardingStatus(true); - s.startBalancer(); + sh.setBalancerState(true); function diff1() { var x = s.chunkCounts("foo"); diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index cc2c15cbbcd..9c5b15b7daf 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -162,8 +162,6 @@ env.Library( # This is only here temporarily for auto-split logic in chunk.cpp. 'balance.cpp', 'balancer_policy.cpp', - 'balancer/balancer_chunk_selection_policy.cpp', - 'balancer/balancer_chunk_selection_policy_impl.cpp', 'balancer/balancer_configuration.cpp', 'balancer/cluster_statistics.cpp', 'balancer/cluster_statistics_impl.cpp', diff --git a/src/mongo/s/balance.cpp b/src/mongo/s/balance.cpp index 0d5ff1a5ff7..d363fa2bb42 100644 --- a/src/mongo/s/balance.cpp +++ b/src/mongo/s/balance.cpp @@ -32,8 +32,6 @@ #include "mongo/s/balance.h" -#include <set> - #include "mongo/base/status_with.h" #include "mongo/client/read_preference.h" #include "mongo/client/remote_command_targeter.h" @@ -42,7 +40,6 @@ #include "mongo/db/operation_context.h" #include "mongo/db/server_options.h" #include "mongo/rpc/get_status_from_command_result.h" -#include "mongo/s/balancer/balancer_chunk_selection_policy_impl.h" #include "mongo/s/balancer/balancer_configuration.h" #include "mongo/s/balancer/cluster_statistics_impl.h" #include "mongo/s/catalog/catalog_cache.h" @@ -157,10 +154,7 @@ MONGO_FP_DECLARE(balancerRoundIntervalSetting); } // namespace Balancer::Balancer() - : _balancedLastTime(0), - _chunkSelectionPolicy(stdx::make_unique<BalancerChunkSelectionPolicyImpl>( - stdx::make_unique<ClusterStatisticsImpl>())), - _clusterStats(stdx::make_unique<ClusterStatisticsImpl>()) {} + : _balancedLastTime(0), _clusterStats(stdx::make_unique<ClusterStatisticsImpl>()) {} Balancer::~Balancer() = default; @@ -246,18 +240,7 @@ void Balancer::run() { << ", secondaryThrottle: " << balancerConfig->getSecondaryThrottle().toBSON(); - OCCASIONALLY warnOnMultiVersion( - uassertStatusOK(_clusterStats->getStats(txn.get()))); - - Status status = _enforceTagRanges(txn.get()); - if (!status.isOK()) { - warning() << "Failed to enforce tag ranges" << causedBy(status); - } else { - LOG(1) << "Done enforcing tag range boundaries."; - } - - const auto candidateChunks = uassertStatusOK( - _chunkSelectionPolicy->selectChunksToMove(txn.get(), _balancedLastTime)); + const auto candidateChunks = uassertStatusOK(_getCandidateChunks(txn.get())); if (candidateChunks.empty()) { LOG(1) << "no need to move any chunk"; @@ -398,52 +381,157 @@ bool Balancer::_checkOIDs(OperationContext* txn) { return true; } -Status Balancer::_enforceTagRanges(OperationContext* txn) { - auto chunksToSplitStatus = _chunkSelectionPolicy->selectChunksToSplit(txn); - if (!chunksToSplitStatus.isOK()) { - return chunksToSplitStatus.getStatus(); +StatusWith<MigrateInfoVector> Balancer::_getCandidateChunks(OperationContext* txn) { + vector<CollectionType> collections; + + Status collsStatus = + grid.catalogManager(txn)->getCollections(txn, nullptr, &collections, nullptr); + if (!collsStatus.isOK()) { + return collsStatus; } - for (const auto& splitInfo : chunksToSplitStatus.getValue()) { - // Ensure the database exists - auto dbStatus = - Grid::get(txn)->catalogCache()->getDatabase(txn, splitInfo.nss.db().toString()); - if (!dbStatus.isOK()) { - return {dbStatus.getStatus().code(), - str::stream() << "Database " << splitInfo.nss.ns() << " was not found due to " - << dbStatus.getStatus().toString()}; + if (collections.empty()) { + return MigrateInfoVector(); + } + + const auto clusterStats = uassertStatusOK(_clusterStats->getStats(txn)); + if (clusterStats.size() < 2) { + return MigrateInfoVector(); + } + + OCCASIONALLY warnOnMultiVersion(clusterStats); + + MigrateInfoVector candidateChunks; + + // For each collection, check if the balancing policy recommends moving anything around. + for (const auto& coll : collections) { + // Skip collections for which balancing is disabled + const NamespaceString& nss = coll.getNs(); + + if (!coll.getAllowBalance()) { + LOG(1) << "Not balancing collection " << nss << "; explicitly disabled."; + continue; + } + + std::vector<ChunkType> allNsChunks; + Status status = grid.catalogManager(txn)->getChunks(txn, + BSON(ChunkType::ns(nss.ns())), + BSON(ChunkType::min() << 1), + boost::none, // all chunks + &allNsChunks, + nullptr); + if (!status.isOK()) { + warning() << "failed to load chunks for ns " << nss.ns() << causedBy(status); + continue; + } + + set<BSONObj> allChunkMinimums; + map<string, vector<ChunkType>> shardToChunksMap; + + for (const ChunkType& chunk : allNsChunks) { + allChunkMinimums.insert(chunk.getMin().getOwned()); + shardToChunksMap[chunk.getShard()].push_back(chunk); + } + + if (shardToChunksMap.empty()) { + LOG(1) << "skipping empty collection (" << nss.ns() << ")"; + continue; } - shared_ptr<DBConfig> db = dbStatus.getValue(); - invariant(db); + for (const auto& stat : clusterStats) { + // This loop just makes sure there is an entry in shardToChunksMap for every shard + shardToChunksMap[stat.shardId]; + } - // Ensure that the collection is sharded - shared_ptr<ChunkManager> cm = db->getChunkManagerIfExists(txn, splitInfo.nss.ns(), true); + DistributionStatus distStatus(clusterStats, shardToChunksMap); + + // TODO: TagRange contains all the information from TagsType except for the namespace, + // so maybe the two can be merged at some point in order to avoid the + // transformation below. + vector<TagRange> ranges; + + { + vector<TagsType> collectionTags; + uassertStatusOK( + grid.catalogManager(txn)->getTagsForCollection(txn, nss.ns(), &collectionTags)); + for (const auto& tt : collectionTags) { + ranges.push_back( + TagRange(tt.getMinKey().getOwned(), tt.getMaxKey().getOwned(), tt.getTag())); + uassert(16356, + str::stream() << "tag ranges not valid for: " << nss.ns(), + distStatus.addTagRange(ranges.back())); + } + } + + auto statusGetDb = grid.catalogCache()->getDatabase(txn, nss.db().toString()); + if (!statusGetDb.isOK()) { + warning() << "could not load db config to balance collection [" << nss.ns() + << "]: " << statusGetDb.getStatus(); + continue; + } + + shared_ptr<DBConfig> cfg = statusGetDb.getValue(); + + // This line reloads the chunk manager once if this process doesn't know the collection + // is sharded yet. + shared_ptr<ChunkManager> cm = cfg->getChunkManagerIfExists(txn, nss.ns(), true); if (!cm) { - return {ErrorCodes::NamespaceNotSharded, - str::stream() << "Collection " << splitInfo.nss.ns() - << " does not exist or is not sharded."}; + warning() << "could not load chunks to balance " << nss.ns() << " collection"; + continue; + } + + // Loop through tags to make sure no chunk spans tags. Split on tag min for all chunks. + bool didAnySplits = false; + + for (const TagRange& range : ranges) { + BSONObj min = + cm->getShardKeyPattern().getKeyPattern().extendRangeBound(range.min, false); + + if (allChunkMinimums.count(min) > 0) { + continue; + } + + didAnySplits = true; + + log() << "nss: " << nss.ns() << " need to split on " << min + << " because there is a range there"; + + shared_ptr<Chunk> c = cm->findIntersectingChunk(txn, min); + + auto splitStatus = shardutil::splitChunkAtMultiplePoints(txn, + c->getShardId(), + nss, + cm->getShardKeyPattern(), + cm->getVersion(), + c->getMin(), + c->getMax(), + {min}); + if (!status.isOK()) { + error() << "split failed: " << status; + } else { + LOG(1) << "split worked"; + } + + break; + } + + if (didAnySplits) { + // State change, just wait till next round + continue; } - auto splitStatus = shardutil::splitChunkAtMultiplePoints(txn, - splitInfo.shardId, - splitInfo.nss, - cm->getShardKeyPattern(), - splitInfo.collectionVersion, - splitInfo.minKey, - splitInfo.maxKey, - {splitInfo.splitKey}); - if (!splitStatus.isOK()) { - warning() << "Failed to enforce tag range for chunk " << splitInfo - << causedBy(splitStatus.getStatus()); + shared_ptr<MigrateInfo> migrateInfo( + BalancerPolicy::balance(nss.ns(), distStatus, _balancedLastTime)); + if (migrateInfo) { + candidateChunks.emplace_back(*migrateInfo); } } - return Status::OK(); + return candidateChunks; } int Balancer::_moveChunks(OperationContext* txn, - const BalancerChunkSelectionPolicy::MigrateInfoVector& candidateChunks, + const MigrateInfoVector& candidateChunks, const MigrationSecondaryThrottleOptions& secondaryThrottle, bool waitForDelete) { int movedCount = 0; diff --git a/src/mongo/s/balance.h b/src/mongo/s/balance.h index 41c0349716a..7cdf867c6ab 100644 --- a/src/mongo/s/balance.h +++ b/src/mongo/s/balance.h @@ -31,7 +31,7 @@ #include <string> #include <vector> -#include "mongo/s/balancer/balancer_chunk_selection_policy.h" +#include "mongo/s/balancer_policy.h" #include "mongo/util/background.h" #include "mongo/util/timer.h" @@ -97,10 +97,12 @@ private: bool _checkOIDs(OperationContext* txn); /** - * Iterates through all chunks in all collections and ensures that no chunks straddle tag - * boundary. If any do, they will be split. + * Gathers all the necessary information about shards and chunks, and decides whether there are + * candidate chunks to be moved. + * + * Returns candidate chunks, one per collection, that could possibly be moved */ - Status _enforceTagRanges(OperationContext* txn); + StatusWith<MigrateInfoVector> _getCandidateChunks(OperationContext* txn); /** * Issues chunk migration request, one at a time. @@ -111,7 +113,7 @@ private: * @return number of chunks effectively moved */ int _moveChunks(OperationContext* txn, - const BalancerChunkSelectionPolicy::MigrateInfoVector& candidateChunks, + const MigrateInfoVector& candidateChunks, const MigrationSecondaryThrottleOptions& secondaryThrottle, bool waitForDelete); @@ -124,9 +126,6 @@ private: // number of moved chunks in last round int _balancedLastTime; - // Balancer policy - std::unique_ptr<BalancerChunkSelectionPolicy> _chunkSelectionPolicy; - // Source for cluster statistics std::unique_ptr<ClusterStatistics> _clusterStats; }; diff --git a/src/mongo/s/balancer/balancer_chunk_selection_policy.cpp b/src/mongo/s/balancer/balancer_chunk_selection_policy.cpp deleted file mode 100644 index 7113ae60258..00000000000 --- a/src/mongo/s/balancer/balancer_chunk_selection_policy.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (C) 2016 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * 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 "mongo/platform/basic.h" - -#include "mongo/s/balancer/balancer_chunk_selection_policy.h" - -#include "mongo/util/mongoutils/str.h" - -namespace mongo { - -BalancerChunkSelectionPolicy::BalancerChunkSelectionPolicy() = default; - -BalancerChunkSelectionPolicy::~BalancerChunkSelectionPolicy() = default; - -BalancerChunkSelectionPolicy::SplitInfo::SplitInfo(ShardId inShardId, - NamespaceString inNss, - ChunkVersion inCollectionVersion, - const BSONObj& inMinKey, - const BSONObj& inMaxKey, - const BSONObj& inSplitKey) - : shardId(std::move(inShardId)), - nss(std::move(inNss)), - collectionVersion(inCollectionVersion), - minKey(inMinKey), - maxKey(inMaxKey), - splitKey(inSplitKey) {} - -std::string BalancerChunkSelectionPolicy::SplitInfo::toString() const { - return str::stream() << "Splitting chunk in " << nss.ns() << " [ " << minKey << ", " << maxKey - << "), residing on " << shardId << " at " << splitKey << " with version " - << collectionVersion.toString(); -} - -} // namespace mongo diff --git a/src/mongo/s/balancer/balancer_chunk_selection_policy.h b/src/mongo/s/balancer/balancer_chunk_selection_policy.h deleted file mode 100644 index de0761009c6..00000000000 --- a/src/mongo/s/balancer/balancer_chunk_selection_policy.h +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (C) 2016 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * 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. - */ - -#pragma once - -#include "mongo/base/disallow_copying.h" -#include "mongo/s/balancer_policy.h" -#include "mongo/s/chunk_version.h" - -namespace mongo { - -class NamespaceString; -class OperationContext; -template <typename T> -class StatusWith; - -/** - * Interface used by the balancer for selecting chunks, which need to be moved around in order for - * the sharded cluster to be balanced. It is up to the implementation to decide what exactly - * 'balanced' means. - */ -class BalancerChunkSelectionPolicy { - MONGO_DISALLOW_COPYING(BalancerChunkSelectionPolicy); - -public: - /** - * Describes a chunk which needs to be split, because it violates the balancer policy. - */ - struct SplitInfo { - SplitInfo(ShardId shardId, - NamespaceString nss, - ChunkVersion collectionVersion, - const BSONObj& minKey, - const BSONObj& maxKey, - const BSONObj& splitKey); - - std::string toString() const; - - ShardId shardId; - NamespaceString nss; - ChunkVersion collectionVersion; - BSONObj minKey; - BSONObj maxKey; - BSONObj splitKey; - }; - - typedef std::vector<SplitInfo> SplitInfoVector; - - typedef std::vector<MigrateInfo> MigrateInfoVector; - - virtual ~BalancerChunkSelectionPolicy(); - - /** - * Potentially blocking method, which gives out a set of chunks, which need to be split because - * they violate the policy for some reason. The reason is decided by the policy and may include - * chunk is too big or chunk straddles a tag range. - */ - virtual StatusWith<SplitInfoVector> selectChunksToSplit(OperationContext* txn) = 0; - - /** - * Potentially blocking method, which gives out a set of chunks to be moved. The - * aggressiveBalanceHint indicates to the balancing logic that it should lower the threshold for - * difference in number of chunks across shards and thus potentially cause more chunks to move. - */ - virtual StatusWith<MigrateInfoVector> selectChunksToMove(OperationContext* txn, - bool aggressiveBalanceHint) = 0; - -protected: - BalancerChunkSelectionPolicy(); -}; - -} // namespace mongo diff --git a/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.cpp b/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.cpp deleted file mode 100644 index 7dc068a4803..00000000000 --- a/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/** - * Copyright (C) 2016 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * 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. - */ - -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding - -#include "mongo/platform/basic.h" - -#include "mongo/s/balancer/balancer_chunk_selection_policy_impl.h" - -#include <set> -#include <vector> - -#include "mongo/base/status_with.h" -#include "mongo/s/catalog/catalog_cache.h" -#include "mongo/s/catalog/catalog_manager.h" -#include "mongo/s/catalog/type_chunk.h" -#include "mongo/s/catalog/type_collection.h" -#include "mongo/s/catalog/type_tags.h" -#include "mongo/s/chunk_manager.h" -#include "mongo/s/config.h" -#include "mongo/s/grid.h" -#include "mongo/stdx/memory.h" -#include "mongo/util/log.h" -#include "mongo/util/mongoutils/str.h" - -namespace mongo { - -using MigrateInfoVector = BalancerChunkSelectionPolicy::MigrateInfoVector; -using SplitInfoVector = BalancerChunkSelectionPolicy::SplitInfoVector; -using std::shared_ptr; -using std::unique_ptr; -using std::vector; - -BalancerChunkSelectionPolicyImpl::BalancerChunkSelectionPolicyImpl( - std::unique_ptr<ClusterStatistics> clusterStats) - : _clusterStats(std::move(clusterStats)) {} - -BalancerChunkSelectionPolicyImpl::~BalancerChunkSelectionPolicyImpl() = default; - -StatusWith<SplitInfoVector> BalancerChunkSelectionPolicyImpl::selectChunksToSplit( - OperationContext* txn) { - vector<CollectionType> collections; - - Status collsStatus = - grid.catalogManager(txn)->getCollections(txn, nullptr, &collections, nullptr); - if (!collsStatus.isOK()) { - return collsStatus; - } - - if (collections.empty()) { - return SplitInfoVector{}; - } - - SplitInfoVector splitCandidates; - - for (const auto& coll : collections) { - const NamespaceString nss(coll.getNs()); - - auto candidatesStatus = _getSplitCandidatesForCollection(txn, nss); - if (!candidatesStatus.isOK()) { - warning() << "Unable to enforce tag range policy for collection " << nss.ns() - << causedBy(candidatesStatus.getStatus()); - continue; - } - - splitCandidates.insert(splitCandidates.end(), - std::make_move_iterator(candidatesStatus.getValue().begin()), - std::make_move_iterator(candidatesStatus.getValue().end())); - } - - return splitCandidates; -} - -StatusWith<MigrateInfoVector> BalancerChunkSelectionPolicyImpl::selectChunksToMove( - OperationContext* txn, bool aggressiveBalanceHint) { - auto shardStatsStatus = _clusterStats->getStats(txn); - if (!shardStatsStatus.isOK()) { - return shardStatsStatus.getStatus(); - } - - const auto shardStats = std::move(shardStatsStatus.getValue()); - if (shardStats.size() < 2) { - return MigrateInfoVector{}; - } - - vector<CollectionType> collections; - - Status collsStatus = - grid.catalogManager(txn)->getCollections(txn, nullptr, &collections, nullptr); - if (!collsStatus.isOK()) { - return collsStatus; - } - - if (collections.empty()) { - return MigrateInfoVector{}; - } - - MigrateInfoVector candidateChunks; - - for (const auto& coll : collections) { - const NamespaceString nss(coll.getNs()); - - if (!coll.getAllowBalance()) { - LOG(1) << "Not balancing collection " << nss << "; explicitly disabled."; - continue; - } - - auto candidatesStatus = - _getMigrateCandidatesForCollection(txn, nss, shardStats, aggressiveBalanceHint); - if (!candidatesStatus.isOK()) { - warning() << "Unable to balance collection " << nss.ns() - << causedBy(candidatesStatus.getStatus()); - continue; - } - - candidateChunks.insert(candidateChunks.end(), - std::make_move_iterator(candidatesStatus.getValue().begin()), - std::make_move_iterator(candidatesStatus.getValue().end())); - } - - return candidateChunks; -} - -StatusWith<SplitInfoVector> BalancerChunkSelectionPolicyImpl::_getSplitCandidatesForCollection( - OperationContext* txn, const NamespaceString& nss) { - // Ensure the database exists - auto dbStatus = Grid::get(txn)->catalogCache()->getDatabase(txn, nss.db().toString()); - if (!dbStatus.isOK()) { - return {dbStatus.getStatus().code(), - str::stream() << "Database " << nss.ns() << " was not found due to " - << dbStatus.getStatus().toString()}; - } - - shared_ptr<DBConfig> db = dbStatus.getValue(); - invariant(db); - - // Ensure that the collection is sharded - shared_ptr<ChunkManager> cm = db->getChunkManagerIfExists(txn, nss.ns(), true); - if (!cm) { - return {ErrorCodes::NamespaceNotSharded, - str::stream() << "Collection " << nss.ns() << " does not exist or is not sharded."}; - } - - if (cm->getChunkMap().empty()) { - return {ErrorCodes::NamespaceNotSharded, - str::stream() << "Collection " << nss.ns() << " does not have any chunks."}; - } - - vector<TagsType> collectionTags; - Status tagsStatus = - grid.catalogManager(txn)->getTagsForCollection(txn, nss.ns(), &collectionTags); - if (!tagsStatus.isOK()) { - return {tagsStatus.code(), - str::stream() << "Unable to load tags for collection " << nss.ns() << " due to " - << tagsStatus.toString()}; - } - - std::set<BSONObj> allChunkMinimums; - - for (const auto& entry : cm->getChunkMap()) { - const auto& chunkEntry = entry.second; - allChunkMinimums.insert(chunkEntry->getMin()); - } - - SplitInfoVector splitCandidates; - - for (const auto& tagInfo : collectionTags) { - BSONObj min = - cm->getShardKeyPattern().getKeyPattern().extendRangeBound(tagInfo.getMinKey(), false); - - if (allChunkMinimums.count(min)) { - continue; - } - - shared_ptr<Chunk> chunk = cm->findIntersectingChunk(txn, min); - invariant(chunk); - - splitCandidates.emplace_back( - chunk->getShardId(), nss, cm->getVersion(), chunk->getMin(), chunk->getMax(), min); - } - - return splitCandidates; -} - -StatusWith<MigrateInfoVector> BalancerChunkSelectionPolicyImpl::_getMigrateCandidatesForCollection( - OperationContext* txn, - const NamespaceString& nss, - const ShardStatisticsVector& shardStats, - bool aggressiveBalanceHint) { - // Ensure the database exists - auto dbStatus = Grid::get(txn)->catalogCache()->getDatabase(txn, nss.db().toString()); - if (!dbStatus.isOK()) { - return {dbStatus.getStatus().code(), - str::stream() << "Database " << nss.ns() << " was not found due to " - << dbStatus.getStatus().toString()}; - } - - shared_ptr<DBConfig> db = dbStatus.getValue(); - invariant(db); - - // Ensure that the collection is sharded - shared_ptr<ChunkManager> cm = db->getChunkManagerIfExists(txn, nss.ns(), true); - if (!cm) { - return {ErrorCodes::NamespaceNotSharded, - str::stream() << "Collection " << nss.ns() << " does not exist or is not sharded."}; - } - - if (cm->getChunkMap().empty()) { - return {ErrorCodes::NamespaceNotSharded, - str::stream() << "Collection " << nss.ns() << " does not have any chunks."}; - } - - ShardToChunksMap shardToChunksMap; - std::set<BSONObj> allChunkMinimums; - - for (const auto& entry : cm->getChunkMap()) { - const auto& chunkEntry = entry.second; - - ChunkType chunk; - chunk.setMin(chunkEntry->getMin()); - chunk.setMax(chunkEntry->getMax()); - chunk.setJumbo(chunkEntry->isJumbo()); - - shardToChunksMap[chunkEntry->getShardId()].push_back(chunk); - allChunkMinimums.insert(chunkEntry->getMin()); - } - - for (const auto& stat : shardStats) { - // This loop just makes sure there is an entry in shardToChunksMap for every shard, which we - // plan to consider. - shardToChunksMap[stat.shardId]; - } - - DistributionStatus distStatus(shardStats, shardToChunksMap); - { - vector<TagsType> collectionTags; - Status status = - grid.catalogManager(txn)->getTagsForCollection(txn, nss.ns(), &collectionTags); - if (!status.isOK()) { - return status; - } - - for (const auto& tagInfo : collectionTags) { - BSONObj min = cm->getShardKeyPattern().getKeyPattern().extendRangeBound( - tagInfo.getMinKey(), false); - - if (!allChunkMinimums.count(min)) { - // This tag falls somewhere at the middle of a chunk. Therefore we must skip - // balancing this collection until it is split at the next iteration. - // - // TODO: We should be able to just skip chunks, which straddle tags and still make - // some progress balancing. - return {ErrorCodes::IllegalOperation, - str::stream() - << "Tag boundaries " << tagInfo.toString() - << " fall in the middle of an existing chunk. Balancing for collection " - << nss.ns() - << " will be postponed until the chunk is split appropriately."}; - } - - // TODO: TagRange contains all the information from TagsType except for the namespace, - // so maybe the two can be merged at some point in order to avoid the transformation - // below. - if (!distStatus.addTagRange(TagRange(tagInfo.getMinKey().getOwned(), - tagInfo.getMaxKey().getOwned(), - tagInfo.getTag()))) { - return {ErrorCodes::BadValue, - str::stream() << "Tag ranges are not valid for collection " << nss.ns() - << ". Balancing for this collection will be skipped until " - "the ranges are fixed."}; - } - } - } - - unique_ptr<MigrateInfo> migrateInfo( - BalancerPolicy::balance(nss.ns(), distStatus, aggressiveBalanceHint)); - if (migrateInfo) { - return MigrateInfoVector{*migrateInfo}; - } - - return MigrateInfoVector{}; -} - -} // namespace mongo diff --git a/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.h b/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.h deleted file mode 100644 index e26c333975d..00000000000 --- a/src/mongo/s/balancer/balancer_chunk_selection_policy_impl.h +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (C) 2016 MongoDB Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * 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. - */ - -#pragma once - -#include "mongo/s/balancer/balancer_chunk_selection_policy.h" - -namespace mongo { - -class ClusterStatistics; - -class BalancerChunkSelectionPolicyImpl final : public BalancerChunkSelectionPolicy { -public: - BalancerChunkSelectionPolicyImpl(std::unique_ptr<ClusterStatistics> clusterStats); - ~BalancerChunkSelectionPolicyImpl(); - - StatusWith<SplitInfoVector> selectChunksToSplit(OperationContext* txn) override; - - StatusWith<MigrateInfoVector> selectChunksToMove(OperationContext* txn, - bool aggressiveBalanceHint) override; - -private: - /** - * Synchronous method, which iterates the collection's chunks and uses the tags information to - * figure out whether some of them validate the tag range boundaries and need to be split. - */ - StatusWith<SplitInfoVector> _getSplitCandidatesForCollection(OperationContext* txn, - const NamespaceString& nss); - - /** - * Synchronous method, which iterates the collection's chunks and uses the cluster statistics to - * figure out where to place them. - */ - StatusWith<MigrateInfoVector> _getMigrateCandidatesForCollection( - OperationContext* txn, - const NamespaceString& nss, - const ShardStatisticsVector& shardStats, - bool aggressiveBalanceHint); - - // Source for obtaining cluster statistics - std::unique_ptr<ClusterStatistics> _clusterStats; -}; - -} // namespace mongo diff --git a/src/mongo/s/balancer_policy.h b/src/mongo/s/balancer_policy.h index 47775e864cf..14f2a21d037 100644 --- a/src/mongo/s/balancer_policy.h +++ b/src/mongo/s/balancer_policy.h @@ -68,6 +68,7 @@ struct MigrateInfo { BSONObj maxKey; }; +typedef std::vector<MigrateInfo> MigrateInfoVector; typedef std::vector<ClusterStatistics::ShardStatistics> ShardStatisticsVector; typedef std::map<ShardId, std::vector<ChunkType>> ShardToChunksMap; diff --git a/src/mongo/s/chunk.cpp b/src/mongo/s/chunk.cpp index df1abc1c96f..a8a603ace35 100644 --- a/src/mongo/s/chunk.cpp +++ b/src/mongo/s/chunk.cpp @@ -78,7 +78,7 @@ const uint64_t kTooManySplitPoints = 4; * Returns true if the chunk was actually moved. */ bool tryMoveToOtherShard(OperationContext* txn, - const ChunkManager* manager, + const ChunkManager& manager, const ChunkType& chunk) { auto clusterStatsStatus(Balancer::get(txn)->getClusterStatistics()->getStats(txn)); if (!clusterStatsStatus.isOK()) { @@ -97,13 +97,13 @@ bool tryMoveToOtherShard(OperationContext* txn, // Reload sharding metadata before starting migration. Only reload the differences though, // because the entire chunk manager was reloaded during the call to split, which immediately // precedes this move logic - shared_ptr<ChunkManager> chunkMgr = manager->reload(txn, false); + shared_ptr<ChunkManager> chunkMgr = manager.reload(txn, false); map<string, vector<ChunkType>> shardToChunkMap; DistributionStatus::populateShardToChunksMap(clusterStats, *chunkMgr, &shardToChunkMap); StatusWith<string> tagStatus = - grid.catalogManager(txn)->getTagForChunk(txn, manager->getns(), chunk); + grid.catalogManager(txn)->getTagForChunk(txn, manager.getns(), chunk); if (!tagStatus.isOK()) { warning() << "Not auto-moving chunk because of an error encountered while " << "checking tag for chunk: " << tagStatus.getStatus(); @@ -154,7 +154,7 @@ bool tryMoveToOtherShard(OperationContext* txn, } // update our config - manager->reload(txn); + manager.reload(txn); return true; } @@ -521,7 +521,7 @@ bool Chunk::splitIfShould(OperationContext* txn, long dataWritten) { chunkToMove.setMin(suggestedMigrateChunk->first); chunkToMove.setMax(suggestedMigrateChunk->second); - tryMoveToOtherShard(txn, _manager, chunkToMove); + tryMoveToOtherShard(txn, *_manager, chunkToMove); } return true; |