summaryrefslogtreecommitdiff
path: root/src/mongo/db/s/split_chunk.cpp
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@10gen.com>2017-11-15 17:58:58 -0500
committerDianna Hohensee <dianna.hohensee@10gen.com>2017-11-28 13:32:07 -0500
commitc9a30dfc4dcf383131ae059b154968a302fbe17c (patch)
tree01a1d6dd7e480e5fb51d4a2ef8d3998f2ba6cbcf /src/mongo/db/s/split_chunk.cpp
parent85d6d1457bcf5cc2aaf650b5ba5d856a50461b52 (diff)
downloadmongo-c9a30dfc4dcf383131ae059b154968a302fbe17c.tar.gz
SERVER-27724 Minimize split chunk command routing table refreshes
Diffstat (limited to 'src/mongo/db/s/split_chunk.cpp')
-rw-r--r--src/mongo/db/s/split_chunk.cpp148
1 files changed, 39 insertions, 109 deletions
diff --git a/src/mongo/db/s/split_chunk.cpp b/src/mongo/db/s/split_chunk.cpp
index 28cdab7fd83..3dea2009f94 100644
--- a/src/mongo/db/s/split_chunk.cpp
+++ b/src/mongo/db/s/split_chunk.cpp
@@ -134,105 +134,40 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
ShardingState* shardingState = ShardingState::get(opCtx);
std::string errmsg;
- const BSONObj min = chunkRange.getMin();
- const BSONObj max = chunkRange.getMax();
-
//
// Lock the collection's metadata and get highest version for the current shard
// TODO(SERVER-25086): Remove distLock acquisition from split chunk
//
const std::string whyMessage(
- str::stream() << "splitting chunk [" << min << ", " << max << ") in " << nss.toString());
+ str::stream() << "splitting chunk " << chunkRange.toString() << " in " << nss.toString());
auto scopedDistLock = Grid::get(opCtx)->catalogClient()->getDistLockManager()->lock(
opCtx, nss.ns(), whyMessage, DistLockManager::kSingleLockAttemptTimeout);
if (!scopedDistLock.isOK()) {
errmsg = str::stream() << "could not acquire collection lock for " << nss.toString()
- << " to split chunk [" << redact(min) << "," << redact(max) << ") "
- << causedBy(redact(scopedDistLock.getStatus()));
- warning() << errmsg;
- return scopedDistLock.getStatus();
- }
-
- // Always check our version remotely
- ChunkVersion shardVersion;
- Status refreshStatus = shardingState->refreshMetadataNow(opCtx, nss, &shardVersion);
-
- if (!refreshStatus.isOK()) {
- errmsg = str::stream() << "splitChunk cannot split chunk "
- << "[" << redact(min) << "," << redact(max) << ") "
- << causedBy(redact(refreshStatus));
-
- warning() << errmsg;
- return refreshStatus;
- }
-
- if (shardVersion.majorVersion() == 0) {
- // It makes no sense to split if our version is zero and we have no chunks
- errmsg = str::stream() << "splitChunk cannot split chunk "
- << "[" << redact(min) << "," << redact(max) << ") "
- << " with zero shard version";
-
- warning() << errmsg;
- return {ErrorCodes::CannotSplit, errmsg};
- }
-
- // Even though the splitChunk command transmits a value in the operation's shardVersion
- // field, this value does not actually contain the shard version, but the global collection
- // version.
- if (expectedCollectionEpoch != shardVersion.epoch()) {
- std::string msg = str::stream() << "splitChunk cannot split chunk "
- << "[" << redact(min) << "," << redact(max) << "), "
- << "collection '" << nss.ns() << "' may have been dropped. "
- << "current epoch: " << shardVersion.epoch()
- << ", cmd epoch: " << expectedCollectionEpoch;
- warning() << msg;
- return {ErrorCodes::StaleEpoch, msg};
+ << " to split chunk " << chunkRange.toString() << " "
+ << causedBy(scopedDistLock.getStatus());
+ return {scopedDistLock.getStatus().code(), errmsg};
}
- ScopedCollectionMetadata collMetadata;
- {
- AutoGetCollection autoColl(opCtx, nss, MODE_IS);
-
- // Get collection metadata
- collMetadata = CollectionShardingState::get(opCtx, nss.ns())->getMetadata();
- }
-
- // With nonzero shard version, we must have metadata
- invariant(collMetadata);
-
- KeyPattern shardKeyPattern(collMetadata->getKeyPattern());
-
- // If the shard uses a hashed key, then we must make sure that the split point is of
- // type NumberLong.
- if (KeyPattern::isHashedKeyPattern(shardKeyPattern.toBSON())) {
+ // If the shard key is hashed, then we must make sure that the split points are of type
+ // NumberLong.
+ if (KeyPattern::isHashedKeyPattern(keyPatternObj)) {
for (BSONObj splitKey : splitKeys) {
BSONObjIterator it(splitKey);
while (it.more()) {
BSONElement splitKeyElement = it.next();
if (splitKeyElement.type() != NumberLong) {
- errmsg = str::stream() << "splitChunk cannot split chunk [" << redact(min)
- << "," << redact(max) << "), split point "
+ errmsg = str::stream() << "splitChunk cannot split chunk "
+ << chunkRange.toString() << ", split point "
<< splitKeyElement.toString()
<< " must be of type "
"NumberLong for hashed shard key patterns";
- warning() << errmsg;
return {ErrorCodes::CannotSplit, errmsg};
}
}
}
}
- ChunkVersion collVersion = collMetadata->getCollVersion();
- // With nonzero shard version, we must have a coll version >= our shard version
- invariant(collVersion >= shardVersion);
-
- {
- ChunkType chunkToMove;
- chunkToMove.setMin(min);
- chunkToMove.setMax(max);
- uassertStatusOK(collMetadata->checkChunkIsValid(chunkToMove));
- }
-
// Commit the split to the config server.
auto request =
SplitChunkRequest(nss, shardName, expectedCollectionEpoch, chunkRange, splitKeys);
@@ -248,22 +183,6 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
configCmdObj,
Shard::RetryPolicy::kIdempotent);
- //
- // Refresh chunk metadata regardless of whether or not the split succeeded
- //
- {
- ChunkVersion unusedShardVersion;
- refreshStatus = shardingState->refreshMetadataNow(opCtx, nss, &unusedShardVersion);
-
- if (!refreshStatus.isOK()) {
- errmsg = str::stream() << "failed to refresh metadata for split chunk [" << redact(min)
- << "," << redact(max) << ") " << causedBy(redact(refreshStatus));
-
- warning() << errmsg;
- return refreshStatus;
- }
- }
-
// If we failed to get any response from the config server at all, despite retries, then we
// should just go ahead and fail the whole operation.
if (!cmdResponseStatus.isOK()) {
@@ -276,31 +195,41 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
// Send stale epoch if epoch of request did not match epoch of collection
if (commandStatus == ErrorCodes::StaleEpoch) {
- std::string msg = str::stream() << "splitChunk cannot split chunk "
- << "[" << redact(min) << "," << redact(max) << "), "
- << "collection '" << nss.ns() << "' may have been dropped. "
- << "current epoch: " << collVersion.epoch()
- << ", cmd epoch: " << expectedCollectionEpoch;
- warning() << msg;
-
- return {commandStatus.code(), str::stream() << msg << redact(causedBy(commandStatus))};
+ return commandStatus;
}
//
- // If _configsvrCommitChunkSplit returned an error, look at this shard's metadata to
+ // If _configsvrCommitChunkSplit returned an error, refresh and look at the metadata to
// determine if the split actually did happen. This can happen if there's a network error
// getting the response from the first call to _configsvrCommitChunkSplit, but it actually
// succeeds, thus the automatic retry fails with a precondition violation, for example.
//
- if ((!commandStatus.isOK() || !writeConcernStatus.isOK()) &&
- checkMetadataForSuccessfulSplitChunk(opCtx, nss, chunkRange, splitKeys)) {
+ if (!commandStatus.isOK() || !writeConcernStatus.isOK()) {
+ {
+ ChunkVersion unusedShardVersion;
+ Status refreshStatus =
+ shardingState->refreshMetadataNow(opCtx, nss, &unusedShardVersion);
+
+ if (!refreshStatus.isOK()) {
+ Status errorStatus = commandStatus.isOK() ? writeConcernStatus : commandStatus;
+ errmsg = str::stream()
+ << "splitChunk failed for chunk " << chunkRange.toString() << ", collection '"
+ << nss.ns() << "' due to " << errorStatus.toString()
+ << ". Attempt to verify if the commit succeeded anyway failed due to: "
+ << refreshStatus.toString();
+
+ warning() << redact(errmsg);
+ return {errorStatus.code(), errmsg};
+ }
+ }
- LOG(1) << "splitChunk [" << redact(min) << "," << redact(max)
- << ") has already been committed.";
- } else if (!commandStatus.isOK()) {
- return commandStatus;
- } else if (!writeConcernStatus.isOK()) {
- return writeConcernStatus;
+ if (checkMetadataForSuccessfulSplitChunk(opCtx, nss, chunkRange, splitKeys)) {
+ // Split was committed.
+ } else if (!commandStatus.isOK()) {
+ return commandStatus;
+ } else if (!writeConcernStatus.isOK()) {
+ return writeConcernStatus;
+ }
}
AutoGetCollection autoColl(opCtx, nss, MODE_IS);
@@ -322,12 +251,13 @@ StatusWith<boost::optional<ChunkRange>> splitChunk(OperationContext* opCtx,
auto backChunk = ChunkType();
backChunk.setMin(splitKeys.back());
- backChunk.setMax(max);
+ backChunk.setMax(chunkRange.getMax());
auto frontChunk = ChunkType();
- frontChunk.setMin(min);
+ frontChunk.setMin(chunkRange.getMin());
frontChunk.setMax(splitKeys.front());
+ KeyPattern shardKeyPattern(keyPatternObj);
if (shardKeyPattern.globalMax().woCompare(backChunk.getMax()) == 0 &&
checkIfSingleDoc(opCtx, collection, idx, &backChunk)) {
return boost::optional<ChunkRange>(ChunkRange(backChunk.getMin(), backChunk.getMax()));