summaryrefslogtreecommitdiff
path: root/src/mongo/db/db_raii_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/db_raii_test.cpp')
-rw-r--r--src/mongo/db/db_raii_test.cpp82
1 files changed, 78 insertions, 4 deletions
diff --git a/src/mongo/db/db_raii_test.cpp b/src/mongo/db/db_raii_test.cpp
index b101ce91961..eba322c5581 100644
--- a/src/mongo/db/db_raii_test.cpp
+++ b/src/mongo/db/db_raii_test.cpp
@@ -42,6 +42,7 @@
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/storage/snapshot_manager.h"
#include "mongo/logv2/log.h"
+#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/time_support.h"
@@ -219,6 +220,8 @@ TEST_F(DBRAIITestFixture,
Lock::DBLock dbLock1(client1.second.get(), nss.db(), MODE_IX);
ASSERT(client1.second->lockState()->isDbLockedForMode(nss.db(), MODE_IX));
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client2.first->setInDirectClient(true);
AutoGetCollectionForRead coll(client2.second.get(), nss);
}
@@ -239,6 +242,8 @@ TEST_F(DBRAIITestFixture,
Lock::DBLock dbLock1(client1.second.get(), nss.db(), MODE_IX);
ASSERT(client1.second->lockState()->isDbLockedForMode(nss.db(), MODE_IX));
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client2.first->setInDirectClient(true);
AutoGetCollectionForRead coll(client2.second.get(), nss);
}
@@ -266,10 +271,12 @@ TEST_F(DBRAIITestFixture,
Lock::DBLock dbLock1(client1.second.get(), nss.db(), MODE_IX);
ASSERT(client1.second->lockState()->isDbLockedForMode(nss.db(), MODE_IX));
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client2.first->setInDirectClient(true);
AutoGetCollectionForRead coll(client2.second.get(), NamespaceString("local.system.js"));
// Reading from an unreplicated collection does not change the ReadSource to kLastApplied.
ASSERT_EQ(client2.second.get()->recoveryUnit()->getTimestampReadSource(),
- RecoveryUnit::ReadSource::kUnset);
+ RecoveryUnit::ReadSource::kNoTimestamp);
// Reading from a replicated collection will try to switch to kLastApplied. Because we are
// already reading without a timestamp and we can't reacquire the PBWM lock to continue reading
@@ -300,12 +307,15 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadLastAppliedConflict) {
auto snapshotManager =
client1.second.get()->getServiceContext()->getStorageEngine()->getSnapshotManager();
snapshotManager->setLastApplied(opTime.getTimestamp());
+
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client1.first->setInDirectClient(true);
AutoGetCollectionForRead coll(client1.second.get(), nss);
// We can't read from kLastApplied in this scenario because there is a catalog conflict. Resort
// to taking the PBWM lock and reading without a timestamp.
ASSERT_EQ(client1.second.get()->recoveryUnit()->getTimestampReadSource(),
- RecoveryUnit::ReadSource::kUnset);
+ RecoveryUnit::ReadSource::kNoTimestamp);
ASSERT_TRUE(client1.second.get()->lockState()->isLockHeldForMode(
resourceIdParallelBatchWriterMode, MODE_IS));
}
@@ -325,6 +335,9 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadLastAppliedUnavailable) {
auto snapshotManager =
client1.second.get()->getServiceContext()->getStorageEngine()->getSnapshotManager();
ASSERT_FALSE(snapshotManager->getLastApplied());
+
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client1.first->setInDirectClient(true);
AutoGetCollectionForRead coll(client1.second.get(), nss);
ASSERT_EQ(client1.second.get()->recoveryUnit()->getTimestampReadSource(),
@@ -334,6 +347,33 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadLastAppliedUnavailable) {
resourceIdParallelBatchWriterMode, MODE_IS));
}
+TEST_F(DBRAIITestFixture, AutoGetCollectionForReadOplogOnSecondary) {
+ // This test simulates a situation where AutoGetCollectionForRead reads at lastApplied on a
+ // secondary.
+ auto replCoord = repl::ReplicationCoordinator::get(client1.second.get());
+ ASSERT_OK(replCoord->setFollowerMode(repl::MemberState::RS_SECONDARY));
+
+ // Ensure the default ReadSource is used.
+ ASSERT_EQ(client1.second.get()->recoveryUnit()->getTimestampReadSource(),
+ RecoveryUnit::ReadSource::kNoTimestamp);
+
+ // Don't call into the ReplicationCoordinator to update lastApplied because it is only a mock
+ // class and does not update the correct state in the SnapshotManager.
+ repl::OpTime opTime(Timestamp(2, 1), 1);
+ auto snapshotManager =
+ client1.second.get()->getServiceContext()->getStorageEngine()->getSnapshotManager();
+ snapshotManager->setLastApplied(opTime.getTimestamp());
+
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ client1.first->setInDirectClient(true);
+ AutoGetCollectionForRead coll(client1.second.get(), NamespaceString::kRsOplogNamespace);
+
+ ASSERT_EQ(client1.second.get()->recoveryUnit()->getTimestampReadSource(),
+ RecoveryUnit::ReadSource::kLastApplied);
+ ASSERT_FALSE(client1.second.get()->lockState()->isLockHeldForMode(
+ resourceIdParallelBatchWriterMode, MODE_IS));
+}
+
TEST_F(DBRAIITestFixture, AutoGetCollectionForReadUsesLastAppliedOnSecondary) {
auto opCtx = client1.second.get();
@@ -342,11 +382,15 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadUsesLastAppliedOnSecondary) {
CollectionOptions options;
options.capped = true;
ASSERT_OK(storageInterface()->createCollection(opCtx, nss, options));
+
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ opCtx->getClient()->setInDirectClient(true);
AutoGetCollectionForRead autoColl(opCtx, nss);
auto exec = makeTailableQueryPlan(opCtx, autoColl.getCollection());
// The collection scan should use the default ReadSource on a primary.
- ASSERT_EQ(RecoveryUnit::ReadSource::kUnset, opCtx->recoveryUnit()->getTimestampReadSource());
+ ASSERT_EQ(RecoveryUnit::ReadSource::kNoTimestamp,
+ opCtx->recoveryUnit()->getTimestampReadSource());
// When the tailable query recovers from its yield, it should discover that the node is
// secondary and change its read source.
@@ -373,6 +417,9 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadChangedReadSourceAfterStepUp)
ASSERT_OK(storageInterface()->createCollection(opCtx, nss, options));
ASSERT_OK(
repl::ReplicationCoordinator::get(opCtx)->setFollowerMode(repl::MemberState::RS_SECONDARY));
+
+ // Simulate using a DBDirectClient to test this behavior for user reads.
+ opCtx->getClient()->setInDirectClient(true);
AutoGetCollectionForRead autoColl(opCtx, nss);
auto exec = makeTailableQueryPlan(opCtx, autoColl.getCollection());
@@ -390,9 +437,36 @@ TEST_F(DBRAIITestFixture, AutoGetCollectionForReadChangedReadSourceAfterStepUp)
// After restoring, the collection scan should now be reading with kUnset, the default on
// primaries.
- ASSERT_EQ(RecoveryUnit::ReadSource::kUnset, opCtx->recoveryUnit()->getTimestampReadSource());
+ ASSERT_EQ(RecoveryUnit::ReadSource::kNoTimestamp,
+ opCtx->recoveryUnit()->getTimestampReadSource());
ASSERT_EQUALS(PlanExecutor::IS_EOF, exec->getNext(&unused, nullptr));
}
+DEATH_TEST_F(DBRAIITestFixture, AutoGetCollectionForReadUnsafe, "Fatal assertion") {
+ auto opCtx = client1.second.get();
+ ASSERT_OK(storageInterface()->createCollection(opCtx, nss, {}));
+
+ ASSERT_OK(
+ repl::ReplicationCoordinator::get(opCtx)->setFollowerMode(repl::MemberState::RS_SECONDARY));
+
+ // Non-user read on a replicated collection should fail because we are reading on a secondary
+ // without a timestamp.
+ AutoGetCollectionForRead autoColl(opCtx, nss);
+}
+
+TEST_F(DBRAIITestFixture, AutoGetCollectionForReadSafe) {
+ auto opCtx = client1.second.get();
+ ASSERT_OK(storageInterface()->createCollection(opCtx, nss, {}));
+
+ ASSERT_OK(
+ repl::ReplicationCoordinator::get(opCtx)->setFollowerMode(repl::MemberState::RS_SECONDARY));
+
+ // Non-user read on a replicated collection should not fail because of the ShouldNotConflict
+ // block.
+ ShouldNotConflictWithSecondaryBatchApplicationBlock noConflict(opCtx->lockState());
+
+ AutoGetCollectionForRead autoColl(opCtx, nss);
+}
+
} // namespace
} // namespace mongo