summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Suarez <kyle.suarez@mongodb.com>2016-04-27 15:04:17 -0400
committerKyle Suarez <kyle.suarez@mongodb.com>2016-04-27 15:04:17 -0400
commit21fa9ccd4e12d7a94a95d98e1e984ada2ef65548 (patch)
treeec935d3060da16ed7df0720a8e1aa818b993868f
parent99e48007ab663eb0cf1d7c1de2ad6c36374b705c (diff)
downloadmongo-21fa9ccd4e12d7a94a95d98e1e984ada2ef65548.tar.gz
Revert "SERVER-22667 Balancer chunk selection policy interface"
This reverts commit 2cf31060a74ac438b58c5150ba30da4144112744.
-rw-r--r--jstests/sharding/jumbo1.js33
-rw-r--r--src/mongo/s/SConscript2
-rw-r--r--src/mongo/s/balance.cpp190
-rw-r--r--src/mongo/s/balance.h15
-rw-r--r--src/mongo/s/balancer/balancer_chunk_selection_policy.cpp60
-rw-r--r--src/mongo/s/balancer/balancer_chunk_selection_policy.h97
-rw-r--r--src/mongo/s/balancer/balancer_chunk_selection_policy_impl.cpp309
-rw-r--r--src/mongo/s/balancer/balancer_chunk_selection_policy_impl.h69
-rw-r--r--src/mongo/s/balancer_policy.h1
-rw-r--r--src/mongo/s/chunk.cpp10
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;