summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/base/error_codes.yml2
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/index_builds_coordinator_mongod.cpp12
-rw-r--r--src/mongo/db/s/SConscript3
-rw-r--r--src/mongo/db/s/global_user_write_block_state.cpp4
-rw-r--r--src/mongo/db/user_write_block_mode_op_observer.cpp107
-rw-r--r--src/mongo/db/user_write_block_mode_op_observer.h110
-rw-r--r--src/mongo/db/user_write_block_mode_op_observer_test.cpp119
8 files changed, 283 insertions, 75 deletions
diff --git a/src/mongo/base/error_codes.yml b/src/mongo/base/error_codes.yml
index 809a76b89b9..23fbd301d72 100644
--- a/src/mongo/base/error_codes.yml
+++ b/src/mongo/base/error_codes.yml
@@ -482,6 +482,8 @@ error_codes:
- {code: 369, name: FLETransactionAbort}
- {code: 370, name: CannotDropShardKeyIndex}
+ - {code: 371, name: UserWritesBlocked}
+
# Error codes 4000-8999 are reserved.
# Non-sequential error codes for compatibility only)
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index 53d0a9067e9..043d2a0d512 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -1182,6 +1182,7 @@ env.Library(
'$BUILD_DIR/mongo/db/catalog/collection_catalog',
'$BUILD_DIR/mongo/db/catalog/index_build_entry_idl',
'$BUILD_DIR/mongo/db/repl/tenant_migration_access_blocker',
+ '$BUILD_DIR/mongo/db/s/forwardable_operation_metadata',
'$BUILD_DIR/mongo/db/storage/two_phase_index_build_knobs_idl',
'$BUILD_DIR/mongo/executor/task_executor_interface',
'curop',
diff --git a/src/mongo/db/index_builds_coordinator_mongod.cpp b/src/mongo/db/index_builds_coordinator_mongod.cpp
index 233e9df2fa1..1b98e9c5f67 100644
--- a/src/mongo/db/index_builds_coordinator_mongod.cpp
+++ b/src/mongo/db/index_builds_coordinator_mongod.cpp
@@ -45,6 +45,7 @@
#include "mongo/db/index_build_entry_helpers.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/tenant_migration_access_blocker_util.h"
+#include "mongo/db/s/forwardable_operation_metadata.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/service_context.h"
#include "mongo/db/stats/resource_consumption_metrics.h"
@@ -64,6 +65,7 @@ namespace {
MONGO_FAIL_POINT_DEFINE(hangAfterAcquiringIndexBuildSlot);
MONGO_FAIL_POINT_DEFINE(hangBeforeInitializingIndexBuild);
MONGO_FAIL_POINT_DEFINE(hangIndexBuildAfterSignalPrimaryForCommitReadiness);
+MONGO_FAIL_POINT_DEFINE(hangBeforeRunningIndexBuild);
const StringData kMaxNumActiveUserIndexBuildsServerParameterName = "maxNumActiveUserIndexBuilds"_sd;
@@ -306,6 +308,7 @@ IndexBuildsCoordinatorMongod::_startIndexBuild(OperationContext* opCtx,
// Since index builds occur in a separate thread, client attributes that are audited must be
// extracted from the client object and passed into the thread separately.
audit::ImpersonatedClientAttrs impersonatedClientAttrs(opCtx->getClient());
+ ForwardableOperationMetadata forwardableOpMetadata(opCtx);
// The thread pool task will be responsible for signalling the condition variable when the index
// build thread is done running.
@@ -324,7 +327,8 @@ IndexBuildsCoordinatorMongod::_startIndexBuild(OperationContext* opCtx,
shardVersion = oss.getShardVersion(nss),
dbVersion = oss.getDbVersion(dbName),
resumeInfo,
- impersonatedClientAttrs = std::move(impersonatedClientAttrs)
+ impersonatedClientAttrs = std::move(impersonatedClientAttrs),
+ forwardableOpMetadata = std::move(forwardableOpMetadata)
](auto status) mutable noexcept {
ScopeGuard onScopeExitGuard([&] {
stdx::unique_lock<Latch> lk(_throttlingMutex);
@@ -341,6 +345,10 @@ IndexBuildsCoordinatorMongod::_startIndexBuild(OperationContext* opCtx,
auto opCtx = Client::getCurrent()->makeOperationContext();
+ // Forward the forwardable operation metadata from the external client to this thread's
+ // client.
+ forwardableOpMetadata.setOn(opCtx.get());
+
// Load the external client's attributes into this thread's client for auditing.
auto authSession = AuthorizationSession::get(opCtx->getClient());
if (authSession) {
@@ -385,6 +393,8 @@ IndexBuildsCoordinatorMongod::_startIndexBuild(OperationContext* opCtx,
// Signal that the index build started successfully.
startPromise.setWith([] {});
+ hangBeforeRunningIndexBuild.pauseWhileSet(opCtx.get());
+
// Runs the remainder of the index build. Sets the promise result and cleans up the index
// build.
_runIndexBuild(opCtx.get(), buildUUID, indexBuildOptions, resumeInfo);
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index d16459c2c44..bf63a589862 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -231,6 +231,9 @@ env.Library(
LIBDEPS=[
'$BUILD_DIR/mongo/base',
'$BUILD_DIR/mongo/s/grid',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/write_block_bypass',
]
)
diff --git a/src/mongo/db/s/global_user_write_block_state.cpp b/src/mongo/db/s/global_user_write_block_state.cpp
index 5bdd8e944c8..0b579d1fcf3 100644
--- a/src/mongo/db/s/global_user_write_block_state.cpp
+++ b/src/mongo/db/s/global_user_write_block_state.cpp
@@ -59,7 +59,7 @@ void GlobalUserWriteBlockState::disableUserWriteBlocking(OperationContext* opCtx
void GlobalUserWriteBlockState::checkUserWritesAllowed(OperationContext* opCtx,
const NamespaceString& nss) const {
invariant(opCtx->lockState()->isLocked());
- uassert(ErrorCodes::OperationFailed,
+ uassert(ErrorCodes::UserWritesBlocked,
"User writes blocked",
!_globalUserWritesBlocked || WriteBlockBypass::get(opCtx).isWriteBlockBypassEnabled() ||
nss.isOnInternalDb() || nss.isTemporaryReshardingCollection());
@@ -81,7 +81,7 @@ void GlobalUserWriteBlockState::disableUserShardedDDLBlocking(OperationContext*
void GlobalUserWriteBlockState::checkShardedDDLAllowedToStart(OperationContext* opCtx,
const NamespaceString& nss) const {
invariant(serverGlobalParams.clusterRole == ClusterRole::ShardServer);
- uassert(ErrorCodes::OperationFailed,
+ uassert(ErrorCodes::UserWritesBlocked,
"User writes blocked",
!_userShardedDDLBlocked.load() ||
WriteBlockBypass::get(opCtx).isWriteBlockBypassEnabled() || nss.isOnInternalDb());
diff --git a/src/mongo/db/user_write_block_mode_op_observer.cpp b/src/mongo/db/user_write_block_mode_op_observer.cpp
index 93a7fb2749c..2ef15e1ef20 100644
--- a/src/mongo/db/user_write_block_mode_op_observer.cpp
+++ b/src/mongo/db/user_write_block_mode_op_observer.cpp
@@ -175,6 +175,113 @@ void UserWriteBlockModeOpObserver::_onReplicationRollback(OperationContext* opCt
}
}
+void UserWriteBlockModeOpObserver::onCreateIndex(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& uuid,
+ BSONObj indexDoc,
+ bool fromMigrate) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+void UserWriteBlockModeOpObserver::onStartIndexBuild(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& collUUID,
+ const UUID& indexBuildUUID,
+ const std::vector<BSONObj>& indexes,
+ bool fromMigrate) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+void UserWriteBlockModeOpObserver::onCommitIndexBuild(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& collUUID,
+ const UUID& indexBuildUUID,
+ const std::vector<BSONObj>& indexes,
+ bool fromMigrate) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+void UserWriteBlockModeOpObserver::onStartIndexBuildSinglePhase(OperationContext* opCtx,
+ const NamespaceString& nss) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+void UserWriteBlockModeOpObserver::onCreateCollection(OperationContext* opCtx,
+ const CollectionPtr& coll,
+ const NamespaceString& collectionName,
+ const CollectionOptions& options,
+ const BSONObj& idIndex,
+ const OplogSlot& createOpTime,
+ bool fromMigrate) {
+ _checkWriteAllowed(opCtx, collectionName);
+}
+
+void UserWriteBlockModeOpObserver::onCollMod(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& uuid,
+ const BSONObj& collModCmd,
+ const CollectionOptions& oldCollOptions,
+ boost::optional<IndexCollModInfo> indexInfo) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+void UserWriteBlockModeOpObserver::onDropDatabase(OperationContext* opCtx,
+ const std::string& dbName) {
+ _checkWriteAllowed(opCtx, NamespaceString(dbName));
+}
+
+repl::OpTime UserWriteBlockModeOpObserver::onDropCollection(OperationContext* opCtx,
+ const NamespaceString& collectionName,
+ const UUID& uuid,
+ std::uint64_t numRecords,
+ CollectionDropType dropType) {
+ _checkWriteAllowed(opCtx, collectionName);
+ return repl::OpTime();
+}
+
+void UserWriteBlockModeOpObserver::onDropIndex(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& uuid,
+ const std::string& indexName,
+ const BSONObj& indexInfo) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
+repl::OpTime UserWriteBlockModeOpObserver::preRenameCollection(
+ OperationContext* opCtx,
+ const NamespaceString& fromCollection,
+ const NamespaceString& toCollection,
+ const UUID& uuid,
+ const boost::optional<UUID>& dropTargetUUID,
+ std::uint64_t numRecords,
+ bool stayTemp) {
+ _checkWriteAllowed(opCtx, fromCollection);
+ _checkWriteAllowed(opCtx, toCollection);
+ return repl::OpTime();
+}
+
+void UserWriteBlockModeOpObserver::onRenameCollection(OperationContext* opCtx,
+ const NamespaceString& fromCollection,
+ const NamespaceString& toCollection,
+ const UUID& uuid,
+ const boost::optional<UUID>& dropTargetUUID,
+ std::uint64_t numRecords,
+ bool stayTemp) {
+ _checkWriteAllowed(opCtx, fromCollection);
+ _checkWriteAllowed(opCtx, toCollection);
+}
+
+void UserWriteBlockModeOpObserver::onImportCollection(OperationContext* opCtx,
+ const UUID& importUUID,
+ const NamespaceString& nss,
+ long long numRecords,
+ long long dataSize,
+ const BSONObj& catalogEntry,
+ const BSONObj& storageMetadata,
+ bool isDryRun) {
+ _checkWriteAllowed(opCtx, nss);
+}
+
void UserWriteBlockModeOpObserver::_checkWriteAllowed(OperationContext* opCtx,
const NamespaceString& nss) {
// Evaluate write blocking only on replica set primaries.
diff --git a/src/mongo/db/user_write_block_mode_op_observer.h b/src/mongo/db/user_write_block_mode_op_observer.h
index 38f61233176..5c3e21f12b9 100644
--- a/src/mongo/db/user_write_block_mode_op_observer.h
+++ b/src/mongo/db/user_write_block_mode_op_observer.h
@@ -47,6 +47,7 @@ public:
// Operations to check for allowed writes.
+ // CUD operations
void onInserts(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& uuid,
@@ -62,55 +63,30 @@ public:
StmtId stmtId,
const OplogDeleteEntryArgs& args) final;
- // Noop operations.
-
+ // DDL operations
void onCreateIndex(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& uuid,
BSONObj indexDoc,
- bool fromMigrate) final {}
+ bool fromMigrate) final;
+ // We need to check the startIndexBuild ops because onCreateIndex is only called for empty
+ // collections.
void onStartIndexBuild(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& collUUID,
const UUID& indexBuildUUID,
const std::vector<BSONObj>& indexes,
- bool fromMigrate) final {}
-
- void onStartIndexBuildSinglePhase(OperationContext* opCtx, const NamespaceString& nss) final {}
-
- void onAbortIndexBuildSinglePhase(OperationContext* opCtx, const NamespaceString& nss) final {}
+ bool fromMigrate) final;
void onCommitIndexBuild(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& collUUID,
const UUID& indexBuildUUID,
const std::vector<BSONObj>& indexes,
- bool fromMigrate) final {}
-
- void onAbortIndexBuild(OperationContext* opCtx,
- const NamespaceString& nss,
- const UUID& collUUID,
- const UUID& indexBuildUUID,
- const std::vector<BSONObj>& indexes,
- const Status& cause,
- bool fromMigrate) final {}
-
+ bool fromMigrate) final;
- void aboutToDelete(OperationContext* opCtx,
- const NamespaceString& nss,
- const UUID& uuid,
- const BSONObj& doc) final;
-
- void onInternalOpMessage(OperationContext* opCtx,
- const NamespaceString& nss,
- const boost::optional<UUID>& uuid,
- const BSONObj& msgObj,
- const boost::optional<BSONObj> o2MsgObj,
- const boost::optional<repl::OpTime> preImageOpTime,
- const boost::optional<repl::OpTime> postImageOpTime,
- const boost::optional<repl::OpTime> prevWriteOpTimeInTransaction,
- const boost::optional<OplogSlot> slot) final {}
+ void onStartIndexBuildSinglePhase(OperationContext* opCtx, const NamespaceString& nss) final;
void onCreateCollection(OperationContext* opCtx,
const CollectionPtr& coll,
@@ -118,31 +94,40 @@ public:
const CollectionOptions& options,
const BSONObj& idIndex,
const OplogSlot& createOpTime,
- bool fromMigrate) final {}
+ bool fromMigrate) final;
void onCollMod(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<IndexCollModInfo> indexInfo) final {}
+ boost::optional<IndexCollModInfo> indexInfo) final;
- void onDropDatabase(OperationContext* opCtx, const std::string& dbName) final {}
+ void onDropDatabase(OperationContext* opCtx, const std::string& dbName) final;
using OpObserver::onDropCollection;
repl::OpTime onDropCollection(OperationContext* opCtx,
const NamespaceString& collectionName,
const UUID& uuid,
std::uint64_t numRecords,
- CollectionDropType dropType) final {
- return repl::OpTime();
- }
+ CollectionDropType dropType) final;
void onDropIndex(OperationContext* opCtx,
const NamespaceString& nss,
const UUID& uuid,
const std::string& indexName,
- const BSONObj& indexInfo) final {}
+ const BSONObj& indexInfo) final;
+
+ // onRenameCollection is only for renaming to a nonexistent target NS, so we need
+ // preRenameCollection too.
+ using OpObserver::preRenameCollection;
+ repl::OpTime preRenameCollection(OperationContext* opCtx,
+ const NamespaceString& fromCollection,
+ const NamespaceString& toCollection,
+ const UUID& uuid,
+ const boost::optional<UUID>& dropTargetUUID,
+ std::uint64_t numRecords,
+ bool stayTemp) final;
using OpObserver::onRenameCollection;
void onRenameCollection(OperationContext* opCtx,
@@ -151,7 +136,7 @@ public:
const UUID& uuid,
const boost::optional<UUID>& dropTargetUUID,
std::uint64_t numRecords,
- bool stayTemp) final {}
+ bool stayTemp) final;
void onImportCollection(OperationContext* opCtx,
const UUID& importUUID,
@@ -160,19 +145,40 @@ public:
long long dataSize,
const BSONObj& catalogEntry,
const BSONObj& storageMetadata,
- bool isDryRun) final {}
+ bool isDryRun) final;
- using OpObserver::preRenameCollection;
- repl::OpTime preRenameCollection(OperationContext* opCtx,
- const NamespaceString& fromCollection,
- const NamespaceString& toCollection,
- const UUID& uuid,
- const boost::optional<UUID>& dropTargetUUID,
- std::uint64_t numRecords,
- bool stayTemp) final {
- return repl::OpTime();
- }
+ // Note aboutToDelete is unchecked, but defined.
+ void aboutToDelete(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& uuid,
+ const BSONObj& doc) final;
+
+ // Noop operations (don't perform any check).
+
+ // At the moment we are leaving the onAbortIndexBuilds as unchecked. This is because they can be
+ // called from both user and internal codepaths, and we don't want to risk throwing an assert
+ // for the internal paths.
+ void onAbortIndexBuildSinglePhase(OperationContext* opCtx, const NamespaceString& nss) final {}
+
+ void onAbortIndexBuild(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const UUID& collUUID,
+ const UUID& indexBuildUUID,
+ const std::vector<BSONObj>& indexes,
+ const Status& cause,
+ bool fromMigrate) final {}
+
+ void onInternalOpMessage(OperationContext* opCtx,
+ const NamespaceString& nss,
+ const boost::optional<UUID>& uuid,
+ const BSONObj& msgObj,
+ const boost::optional<BSONObj> o2MsgObj,
+ const boost::optional<repl::OpTime> preImageOpTime,
+ const boost::optional<repl::OpTime> postImageOpTime,
+ const boost::optional<repl::OpTime> prevWriteOpTimeInTransaction,
+ const boost::optional<OplogSlot> slot) final {}
+ // We don't need to check this and preRenameCollection (they are in the same WUOW).
void postRenameCollection(OperationContext* opCtx,
const NamespaceString& fromCollection,
const NamespaceString& toCollection,
@@ -180,6 +186,8 @@ public:
const boost::optional<UUID>& dropTargetUUID,
bool stayTemp) final {}
+ // The transaction commit related hooks don't need to be checked, because all of the operations
+ // inside the transaction are checked and they all execute in one WUOW.
void onApplyOps(OperationContext* opCtx,
const std::string& dbName,
const BSONObj& applyOpCmd) final {}
diff --git a/src/mongo/db/user_write_block_mode_op_observer_test.cpp b/src/mongo/db/user_write_block_mode_op_observer_test.cpp
index 1f1f1b9a9b5..512f42b7003 100644
--- a/src/mongo/db/user_write_block_mode_op_observer_test.cpp
+++ b/src/mongo/db/user_write_block_mode_op_observer_test.cpp
@@ -62,12 +62,12 @@ public:
}
protected:
- // Ensure that inserts, updates, and deletes with the given opCtx on the given namespace will
- // succeed or fail depending on the value of shouldSucceed.
+ // Ensure that CUD ops with the given opCtx on the given namespace will succeed or fail
+ // depending on the value of shouldSucceed.
void runCUD(OperationContext* opCtx,
const NamespaceString& nss,
bool shouldSucceed,
- bool fromMigrate = false) {
+ bool fromMigrate) {
UserWriteBlockModeOpObserver opObserver;
std::vector<InsertStatement> inserts;
CollectionUpdateArgs collectionUpdateArgs;
@@ -78,7 +78,6 @@ protected:
updateArgs.nss = nss;
OplogDeleteEntryArgs deleteArgs;
deleteArgs.fromMigrate = fromMigrate;
-
if (shouldSucceed) {
try {
opObserver.onInserts(opCtx, nss, uuid, inserts.begin(), inserts.end(), fromMigrate);
@@ -98,6 +97,83 @@ protected:
}
}
+ // Ensure that all checked ops with the given opCtx on the given namespace will
+ // succeed or fail depending on the value of shouldSucceed.
+ void runCheckedOps(OperationContext* opCtx,
+ const NamespaceString& nss,
+ bool shouldSucceed,
+ bool fromMigrate = false) {
+ runCUD(opCtx, nss, shouldSucceed, fromMigrate);
+ UserWriteBlockModeOpObserver opObserver;
+ auto uuid = UUID::gen();
+ NamespaceString adminNss = NamespaceString("admin");
+
+ if (shouldSucceed) {
+ try {
+ opObserver.onCreateIndex(opCtx, nss, uuid, BSONObj(), false);
+ opObserver.onStartIndexBuild(opCtx, nss, uuid, uuid, {}, false);
+ opObserver.onStartIndexBuildSinglePhase(opCtx, nss);
+ opObserver.onCreateCollection(
+ opCtx, nullptr, nss, {}, BSONObj(), OplogSlot(), false);
+ opObserver.onCollMod(opCtx, nss, uuid, BSONObj(), {}, boost::none);
+ opObserver.onDropDatabase(opCtx, std::string(nss.db()));
+ opObserver.onDropCollection(
+ opCtx,
+ nss,
+ uuid,
+ 0,
+ UserWriteBlockModeOpObserver::CollectionDropType::kOnePhase);
+ opObserver.onDropIndex(opCtx, nss, uuid, "", BSONObj());
+ // For renames, make sure we check both from and to for the given namespace
+ opObserver.preRenameCollection(opCtx, nss, adminNss, uuid, boost::none, 0, false);
+ opObserver.preRenameCollection(opCtx, adminNss, nss, uuid, boost::none, 0, false);
+ opObserver.onRenameCollection(opCtx, nss, adminNss, uuid, boost::none, 0, false);
+ opObserver.onRenameCollection(opCtx, adminNss, nss, uuid, boost::none, 0, false);
+ opObserver.onImportCollection(opCtx, uuid, nss, 0, 0, BSONObj(), BSONObj(), false);
+ } catch (...) {
+ // Make it easier to see that this is where we failed.
+ ASSERT_OK(exceptionToStatus());
+ }
+ } else {
+ ASSERT_THROWS(opObserver.onCreateIndex(opCtx, nss, uuid, BSONObj(), false),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onStartIndexBuild(opCtx, nss, uuid, uuid, {}, false),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onStartIndexBuildSinglePhase(opCtx, nss), AssertionException);
+ ASSERT_THROWS(opObserver.onCreateCollection(
+ opCtx, nullptr, nss, {}, BSONObj(), OplogSlot(), false),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onCollMod(opCtx, nss, uuid, BSONObj(), {}, boost::none),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onDropDatabase(opCtx, std::string(nss.db())),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onDropCollection(
+ opCtx,
+ nss,
+ uuid,
+ 0,
+ UserWriteBlockModeOpObserver::CollectionDropType::kOnePhase),
+ AssertionException);
+ ASSERT_THROWS(opObserver.onDropIndex(opCtx, nss, uuid, "", BSONObj()),
+ AssertionException);
+ ASSERT_THROWS(
+ opObserver.preRenameCollection(opCtx, nss, adminNss, uuid, boost::none, 0, false),
+ AssertionException);
+ ASSERT_THROWS(
+ opObserver.preRenameCollection(opCtx, adminNss, nss, uuid, boost::none, 0, false),
+ AssertionException);
+ ASSERT_THROWS(
+ opObserver.onRenameCollection(opCtx, nss, adminNss, uuid, boost::none, 0, false),
+ AssertionException);
+ ASSERT_THROWS(
+ opObserver.onRenameCollection(opCtx, adminNss, nss, uuid, boost::none, 0, false),
+ AssertionException);
+ ASSERT_THROWS(
+ opObserver.onImportCollection(opCtx, uuid, nss, 0, 0, BSONObj(), BSONObj(), false),
+ AssertionException);
+ }
+ }
+
private:
// Creates a reasonable set of ReplSettings for most tests.
repl::ReplSettings createReplSettings() {
@@ -117,10 +193,10 @@ TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingDisabledNoBypass) {
ASSERT(!WriteBlockBypass::get(opCtx.get()).isWriteBlockBypassEnabled());
// Ensure writes succeed
- runCUD(opCtx.get(), NamespaceString("a.b"), true);
- runCUD(opCtx.get(), NamespaceString("admin"), true);
- runCUD(opCtx.get(), NamespaceString("local"), true);
- runCUD(opCtx.get(), NamespaceString("config"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("a.b"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("admin"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("local"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("config"), true);
}
TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingDisabledWithBypass) {
@@ -137,10 +213,10 @@ TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingDisabledWithBypass) {
ASSERT(WriteBlockBypass::get(opCtx.get()).isWriteBlockBypassEnabled());
// Ensure writes succeed
- runCUD(opCtx.get(), NamespaceString("a.b"), true);
- runCUD(opCtx.get(), NamespaceString("admin"), true);
- runCUD(opCtx.get(), NamespaceString("local"), true);
- runCUD(opCtx.get(), NamespaceString("config"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("a.b"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("admin"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("local"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("config"), true);
}
TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingEnabledNoBypass) {
@@ -152,12 +228,12 @@ TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingEnabledNoBypass) {
ASSERT(!WriteBlockBypass::get(opCtx.get()).isWriteBlockBypassEnabled());
// Ensure user writes now fail, while non-user writes still succeed
- runCUD(opCtx.get(), NamespaceString("a.b"), false);
- runCUD(opCtx.get(), NamespaceString("admin"), true);
- runCUD(opCtx.get(), NamespaceString("local"), true);
- runCUD(opCtx.get(), NamespaceString("config"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("a.b"), false);
+ runCheckedOps(opCtx.get(), NamespaceString("admin"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("local"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("config"), true);
- // Ensure that writes from migrations succeed
+ // Ensure that CUD ops from migrations succeed
runCUD(opCtx.get(), NamespaceString("a.b"), true, true /* fromMigrate */);
}
@@ -175,10 +251,11 @@ TEST_F(UserWriteBlockModeOpObserverTest, WriteBlockingEnabledWithBypass) {
ASSERT(WriteBlockBypass::get(opCtx.get()).isWriteBlockBypassEnabled());
// Ensure user writes succeed
- runCUD(opCtx.get(), NamespaceString("a.b"), true);
- runCUD(opCtx.get(), NamespaceString("admin"), true);
- runCUD(opCtx.get(), NamespaceString("local"), true);
- runCUD(opCtx.get(), NamespaceString("config"), true);
+
+ runCheckedOps(opCtx.get(), NamespaceString("a.b"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("admin"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("local"), true);
+ runCheckedOps(opCtx.get(), NamespaceString("config"), true);
}
} // namespace