summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-02-14 13:05:52 -0500
committerGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-02-22 23:40:01 -0500
commitcbf90926f4bdc5f3fd6d20291a5e24218e5f77ba (patch)
treef4b7a8e1c4bc9a06f23ec05f1e5fdbc569a7d305
parentb5f25acf119fd8b2c6119474f6b9ef13180ccc59 (diff)
downloadmongo-cbf90926f4bdc5f3fd6d20291a5e24218e5f77ba.tar.gz
SERVER-39527 Implement IndexBuildsCoordinatorMongod::setCommitQuorum
-rw-r--r--jstests/noPassthrough/set_commit_quorum.js80
-rw-r--r--jstests/sharding/database_and_shard_versioning_all_commands.js2
-rw-r--r--src/mongo/db/SConscript2
-rw-r--r--src/mongo/db/commands/set_index_commit_quorum_command.cpp7
-rw-r--r--src/mongo/db/index_builds_coordinator.cpp2
-rw-r--r--src/mongo/db/index_builds_coordinator.h8
-rw-r--r--src/mongo/db/index_builds_coordinator_mongod.cpp65
-rw-r--r--src/mongo/db/index_builds_coordinator_mongod.h3
-rw-r--r--src/mongo/db/index_builds_coordinator_mongod_test.cpp44
-rw-r--r--src/mongo/embedded/index_builds_coordinator_embedded.cpp3
-rw-r--r--src/mongo/embedded/index_builds_coordinator_embedded.h3
11 files changed, 207 insertions, 12 deletions
diff --git a/jstests/noPassthrough/set_commit_quorum.js b/jstests/noPassthrough/set_commit_quorum.js
new file mode 100644
index 00000000000..83cbf07bf1c
--- /dev/null
+++ b/jstests/noPassthrough/set_commit_quorum.js
@@ -0,0 +1,80 @@
+/**
+ * Tests that the commit quorum can be changed during a two-phase index build.
+ *
+ * @tags: [requires_replication]
+ */
+(function() {
+ load("jstests/noPassthrough/libs/index_build.js");
+ load("jstests/libs/check_log.js");
+
+ const replSet = new ReplSetTest({
+ nodes: [
+ {},
+ {
+ // Disallow elections on secondary.
+ rsConfig: {
+ priority: 0,
+ votes: 0,
+ },
+ },
+ ]
+ });
+
+ // Allow the createIndexes command to use the index builds coordinator in single-phase mode.
+ replSet.startSet({setParameter: {enableIndexBuildsCoordinatorForCreateIndexesCommand: true}});
+ replSet.initiate();
+
+ const testDB = replSet.getPrimary().getDB('test');
+ const coll = testDB.twoPhaseIndexBuild;
+
+ const bulk = coll.initializeUnorderedBulkOp();
+ const numDocs = 1000;
+ for (let i = 0; i < numDocs; i++) {
+ bulk.insert({a: i, b: i});
+ }
+ assert.commandWorked(bulk.execute());
+
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangIndexBuildBeforeBuilding", mode: "alwaysOn"}));
+
+ // Starts parallel shell to run the command that will hang.
+ const awaitShell = startParallelShell(function() {
+ // Use the index builds coordinator for a two-phase index build.
+ assert.commandWorked(db.runCommand({
+ twoPhaseCreateIndexes: 'twoPhaseIndexBuild',
+ indexes: [{key: {a: 1}, name: 'a_1'}],
+ commitQuorum: "majority"
+ }));
+ }, testDB.getMongo().port);
+
+ checkLog.contains(replSet.getPrimary(), "Waiting for index build to complete");
+
+ // Test setting various commit quorums on the index build in our two node replica set.
+ assert.commandFailed(testDB.runCommand(
+ {setIndexCommitQuorum: 'twoPhaseIndexBuild', indexNames: ['a_1'], commitQuorum: 3}));
+ assert.commandFailed(testDB.runCommand({
+ setIndexCommitQuorum: 'twoPhaseIndexBuild',
+ indexNames: ['a_1'],
+ commitQuorum: "someTag"
+ }));
+
+ assert.commandWorked(testDB.runCommand(
+ {setIndexCommitQuorum: 'twoPhaseIndexBuild', indexNames: ['a_1'], commitQuorum: 0}));
+ assert.commandWorked(testDB.runCommand(
+ {setIndexCommitQuorum: 'twoPhaseIndexBuild', indexNames: ['a_1'], commitQuorum: 2}));
+ assert.commandWorked(testDB.runCommand({
+ setIndexCommitQuorum: 'twoPhaseIndexBuild',
+ indexNames: ['a_1'],
+ commitQuorum: "majority"
+ }));
+
+ assert.commandWorked(
+ testDB.adminCommand({configureFailPoint: "hangIndexBuildBeforeBuilding", mode: "off"}));
+
+ // Wait for the parallel shell to complete.
+ awaitShell();
+
+ IndexBuildTest.assertIndexes(coll, 2, ["_id_", "a_1"]);
+
+ replSet.stopSet();
+})();
diff --git a/jstests/sharding/database_and_shard_versioning_all_commands.js b/jstests/sharding/database_and_shard_versioning_all_commands.js
index 396c8eb0511..e3e48cd8ef9 100644
--- a/jstests/sharding/database_and_shard_versioning_all_commands.js
+++ b/jstests/sharding/database_and_shard_versioning_all_commands.js
@@ -388,7 +388,7 @@
serverStatus: {skip: "executes locally on mongos (not sent to any remote node)"},
setIndexCommitQuorum: {
skipProfilerCheck: true,
- sendsDbVersion: false,
+ sendsDbVersion: true,
sendsShardVersion: true,
setUp: function(mongosConn) {
// Expects the collection to exist, and doesn't implicitly create it.
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index d549563f498..02de74aa313 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -943,6 +943,8 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'curop',
+ 'db_raii',
+ 'index_build_entry_helpers',
'$BUILD_DIR/mongo/db/catalog/uuid_catalog',
],
)
diff --git a/src/mongo/db/commands/set_index_commit_quorum_command.cpp b/src/mongo/db/commands/set_index_commit_quorum_command.cpp
index bdff7263a7c..2c0555442db 100644
--- a/src/mongo/db/commands/set_index_commit_quorum_command.cpp
+++ b/src/mongo/db/commands/set_index_commit_quorum_command.cpp
@@ -86,8 +86,11 @@ public:
using InvocationBase::InvocationBase;
void typedRun(OperationContext* opCtx) {
- uassertStatusOK(IndexBuildsCoordinator::get(opCtx)->setCommitQuorum(
- request().getNamespace(), request().getIndexNames(), request().getCommitQuorum()));
+ uassertStatusOK(
+ IndexBuildsCoordinator::get(opCtx)->setCommitQuorum(opCtx,
+ request().getNamespace(),
+ request().getIndexNames(),
+ request().getCommitQuorum()));
}
private:
diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp
index 81c5cbe868d..56d73c60ef1 100644
--- a/src/mongo/db/index_builds_coordinator.cpp
+++ b/src/mongo/db/index_builds_coordinator.cpp
@@ -61,6 +61,7 @@ using namespace indexbuildentryhelpers;
MONGO_FAIL_POINT_DEFINE(hangAfterIndexBuildFirstDrain);
MONGO_FAIL_POINT_DEFINE(hangAfterIndexBuildSecondDrain);
MONGO_FAIL_POINT_DEFINE(hangAfterIndexBuildDumpsInsertsFromBulk);
+MONGO_FAIL_POINT_DEFINE(hangIndexBuildBeforeBuilding);
namespace {
@@ -752,6 +753,7 @@ void IndexBuildsCoordinator::_buildIndex(OperationContext* opCtx,
// background.
{
Lock::CollectionLock colLock(opCtx->lockState(), nss.ns(), MODE_IX);
+ MONGO_FAIL_POINT_PAUSE_WHILE_SET(hangIndexBuildBeforeBuilding);
uassertStatusOK(
_indexBuildsManager.startBuildingIndex(opCtx, collection, replState->buildUUID));
}
diff --git a/src/mongo/db/index_builds_coordinator.h b/src/mongo/db/index_builds_coordinator.h
index cb7117376e0..3887e0def46 100644
--- a/src/mongo/db/index_builds_coordinator.h
+++ b/src/mongo/db/index_builds_coordinator.h
@@ -230,10 +230,12 @@ public:
virtual Status voteCommitIndexBuild(const UUID& buildUUID, const HostAndPort& hostAndPort) = 0;
/**
- * TODO: This is not yet implemented. (This will have to take a collection IS lock to look up
- * the collection UUID.)
+ * Sets a new commit quorum on an index build that manages 'indexNames' on collection 'nss'.
+ * If the 'newCommitQuorum' is not satisfiable by the current replica set config, then the
+ * previous commit quorum is kept and the UnsatisfiableCommitQuorum error code is returned.
*/
- virtual Status setCommitQuorum(const NamespaceString& nss,
+ virtual Status setCommitQuorum(OperationContext* opCtx,
+ const NamespaceString& nss,
const std::vector<StringData>& indexNames,
const CommitQuorumOptions& newCommitQuorum) = 0;
diff --git a/src/mongo/db/index_builds_coordinator_mongod.cpp b/src/mongo/db/index_builds_coordinator_mongod.cpp
index de5374e8c98..51d14f6eec4 100644
--- a/src/mongo/db/index_builds_coordinator_mongod.cpp
+++ b/src/mongo/db/index_builds_coordinator_mongod.cpp
@@ -35,6 +35,8 @@
#include "mongo/db/catalog/uuid_catalog.h"
#include "mongo/db/curop.h"
+#include "mongo/db/db_raii.h"
+#include "mongo/db/index_build_entry_helpers.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/service_context.h"
#include "mongo/util/assert_util.h"
@@ -43,6 +45,8 @@
namespace mongo {
+using namespace indexbuildentryhelpers;
+
namespace {
/**
@@ -227,11 +231,66 @@ Status IndexBuildsCoordinatorMongod::voteCommitIndexBuild(const UUID& buildUUID,
return Status::OK();
}
-Status IndexBuildsCoordinatorMongod::setCommitQuorum(const NamespaceString& nss,
+Status IndexBuildsCoordinatorMongod::setCommitQuorum(OperationContext* opCtx,
+ const NamespaceString& nss,
const std::vector<StringData>& indexNames,
const CommitQuorumOptions& newCommitQuorum) {
- // TODO: not yet implemented.
- return Status::OK();
+ if (indexNames.empty()) {
+ return Status(ErrorCodes::IndexNotFound,
+ str::stream()
+ << "Cannot set a new commit quorum on an index build in collection '"
+ << nss
+ << "' without providing any indexes.");
+ }
+
+ AutoGetCollectionForRead autoColl(opCtx, nss);
+ Collection* collection = autoColl.getCollection();
+ if (!collection) {
+ return Status(ErrorCodes::NamespaceNotFound,
+ str::stream() << "Collection '" << nss << "' was not found.");
+ }
+
+ UUID collectionUUID = *collection->uuid();
+
+ stdx::unique_lock<stdx::mutex> lk(_mutex);
+ auto collectionIt = _collectionIndexBuilds.find(collectionUUID);
+ if (collectionIt == _collectionIndexBuilds.end()) {
+ return Status(ErrorCodes::IndexNotFound,
+ str::stream() << "No index builds found on collection '" << nss << "'.");
+ }
+
+ if (!collectionIt->second->hasIndexBuildState(lk, indexNames.front())) {
+ return Status(ErrorCodes::IndexNotFound,
+ str::stream() << "Cannot find an index build on collection '" << nss
+ << "' with the provided index names");
+ }
+
+ // Use the first index to get the ReplIndexBuildState.
+ std::shared_ptr<ReplIndexBuildState> buildState =
+ collectionIt->second->getIndexBuildState(lk, indexNames.front());
+
+ // Ensure the ReplIndexBuildState has the same indexes as 'indexNames'.
+ bool equal = std::equal(
+ buildState->indexNames.begin(), buildState->indexNames.end(), indexNames.begin());
+ if (buildState->indexNames.size() != indexNames.size() || !equal) {
+ return Status(ErrorCodes::IndexNotFound,
+ str::stream() << "Provided indexes are not all being "
+ << "built by the same index builder in collection '"
+ << nss
+ << "'.");
+ }
+
+ // See if the new commit quorum is satisfiable.
+ auto replCoord = repl::ReplicationCoordinator::get(opCtx);
+ Status status = replCoord->checkIfCommitQuorumCanBeSatisfied(newCommitQuorum);
+ if (!status.isOK()) {
+ return status;
+ }
+
+ // Persist the new commit quorum for the index build and write it to the collection.
+ buildState->commitQuorum = newCommitQuorum;
+ const UUID buildUUID = buildState->buildUUID;
+ return indexbuildentryhelpers::setCommitQuorum(opCtx, buildUUID, newCommitQuorum);
}
Status IndexBuildsCoordinatorMongod::_finishScanningPhase() {
diff --git a/src/mongo/db/index_builds_coordinator_mongod.h b/src/mongo/db/index_builds_coordinator_mongod.h
index a9ee94852db..109e53eb028 100644
--- a/src/mongo/db/index_builds_coordinator_mongod.h
+++ b/src/mongo/db/index_builds_coordinator_mongod.h
@@ -90,7 +90,8 @@ public:
Status voteCommitIndexBuild(const UUID& buildUUID, const HostAndPort& hostAndPort) override;
- Status setCommitQuorum(const NamespaceString& nss,
+ Status setCommitQuorum(OperationContext* opCtx,
+ const NamespaceString& nss,
const std::vector<StringData>& indexNames,
const CommitQuorumOptions& newCommitQuorum) override;
diff --git a/src/mongo/db/index_builds_coordinator_mongod_test.cpp b/src/mongo/db/index_builds_coordinator_mongod_test.cpp
index 566219732f7..5dd6938f730 100644
--- a/src/mongo/db/index_builds_coordinator_mongod_test.cpp
+++ b/src/mongo/db/index_builds_coordinator_mongod_test.cpp
@@ -406,6 +406,50 @@ TEST_F(IndexBuildsCoordinatorMongodTest, DisallowNewBuildsOnNamespace) {
}
}
+TEST_F(IndexBuildsCoordinatorMongodTest, SetCommitQuorumWithBadArguments) {
+ _indexBuildsCoord->sleepIndexBuilds_forTestOnly(true);
+
+ CommitQuorumOptions newCommitQuorum("majority");
+
+ // Pass in an empty index list.
+ Status status =
+ _indexBuildsCoord->setCommitQuorum(operationContext(), _testFooNss, {}, newCommitQuorum);
+ ASSERT_EQUALS(ErrorCodes::IndexNotFound, status);
+
+ // Use an invalid collection namespace.
+ NamespaceString nss("bad.collection");
+ status = _indexBuildsCoord->setCommitQuorum(
+ operationContext(), nss, {"a_1", "b_1"}, newCommitQuorum);
+ ASSERT_EQUALS(ErrorCodes::NamespaceNotFound, status);
+
+ // No index builds are happening on the collection.
+ status = _indexBuildsCoord->setCommitQuorum(
+ operationContext(), _testFooNss, {"a_1", "b_1"}, newCommitQuorum);
+ ASSERT_EQUALS(ErrorCodes::IndexNotFound, status);
+
+ // Register an index build on _testFooNss.
+ auto testFoo1Future =
+ assertGet(_indexBuildsCoord->startIndexBuild(operationContext(),
+ _testFooUUID,
+ makeSpecs(_testFooNss, {"a", "b"}),
+ UUID::gen(),
+ IndexBuildProtocol::kTwoPhase,
+ _indexBuildOptions));
+
+ // No index with the name "c" is being built.
+ status =
+ _indexBuildsCoord->setCommitQuorum(operationContext(), _testFooNss, {"c"}, newCommitQuorum);
+ ASSERT_EQUALS(ErrorCodes::IndexNotFound, status);
+
+ // Pass in extra indexes not being built by the same index builder.
+ status = _indexBuildsCoord->setCommitQuorum(
+ operationContext(), _testFooNss, {"a_1", "b_1", "c_1"}, newCommitQuorum);
+ ASSERT_EQUALS(ErrorCodes::IndexNotFound, status);
+
+ _indexBuildsCoord->sleepIndexBuilds_forTestOnly(false);
+ unittest::assertGet(testFoo1Future.getNoThrow());
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/embedded/index_builds_coordinator_embedded.cpp b/src/mongo/embedded/index_builds_coordinator_embedded.cpp
index 206db80a5bd..9609bb7d32b 100644
--- a/src/mongo/embedded/index_builds_coordinator_embedded.cpp
+++ b/src/mongo/embedded/index_builds_coordinator_embedded.cpp
@@ -102,7 +102,8 @@ Status IndexBuildsCoordinatorEmbedded::voteCommitIndexBuild(const UUID& buildUUI
MONGO_UNREACHABLE;
}
-Status IndexBuildsCoordinatorEmbedded::setCommitQuorum(const NamespaceString& nss,
+Status IndexBuildsCoordinatorEmbedded::setCommitQuorum(OperationContext* opCtx,
+ const NamespaceString& nss,
const std::vector<StringData>& indexNames,
const CommitQuorumOptions& newCommitQuorum) {
MONGO_UNREACHABLE;
diff --git a/src/mongo/embedded/index_builds_coordinator_embedded.h b/src/mongo/embedded/index_builds_coordinator_embedded.h
index 718276e8df1..c1085f543aa 100644
--- a/src/mongo/embedded/index_builds_coordinator_embedded.h
+++ b/src/mongo/embedded/index_builds_coordinator_embedded.h
@@ -74,7 +74,8 @@ public:
void signalChangeToSecondaryMode() override;
void signalChangeToInitialSyncMode() override;
Status voteCommitIndexBuild(const UUID& buildUUID, const HostAndPort& hostAndPort) override;
- Status setCommitQuorum(const NamespaceString& nss,
+ Status setCommitQuorum(OperationContext* opCtx,
+ const NamespaceString& nss,
const std::vector<StringData>& indexNames,
const CommitQuorumOptions& newCommitQuorum) override;
};