summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2022-05-25 15:43:58 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-05-25 16:18:08 +0000
commit80e519f931ee0339b34e2546d274e21499e437b6 (patch)
tree4faab13bb94c6d37ff84467cbf81ce5050d7ec0c /src/mongo/db
parent982ba2296ba7e5a9f53e8f36d14310f0f45b7b70 (diff)
downloadmongo-80e519f931ee0339b34e2546d274e21499e437b6.tar.gz
SERVER-66565 Use hint with config.transactions partial index and allow creating it
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/commands/create_indexes.cpp18
-rw-r--r--src/mongo/db/op_observer_impl_test.cpp3
-rw-r--r--src/mongo/db/repl/tenant_oplog_applier_test.cpp7
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_bump_collection_version_and_change_metadata_test.cpp2
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_commit_chunk_migration_test.cpp3
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_merge_chunks_test.cpp3
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_remove_shard_test.cpp3
-rw-r--r--src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp3
-rw-r--r--src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp3
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp3
-rw-r--r--src/mongo/db/s/resharding/resharding_coordinator_test.cpp2
-rw-r--r--src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp2
-rw-r--r--src/mongo/db/s/resharding/resharding_oplog_applier_test.cpp3
-rw-r--r--src/mongo/db/s/session_catalog_migration_source_test.cpp3
-rw-r--r--src/mongo/db/s/sharding_ddl_util_test.cpp3
-rw-r--r--src/mongo/db/session_catalog_mongod.cpp27
-rw-r--r--src/mongo/db/session_catalog_mongod.h8
-rw-r--r--src/mongo/db/transaction_participant.cpp127
18 files changed, 161 insertions, 62 deletions
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index 2b11eb23040..0ce3c6b6067 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -34,6 +34,7 @@
#include <vector>
#include "mongo/base/string_data.h"
+#include "mongo/bson/unordered_fields_bsonobj_comparator.h"
#include "mongo/crypto/encryption_fields_util.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/catalog/clustered_collection_util.h"
@@ -62,6 +63,7 @@
#include "mongo/db/s/database_sharding_state.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/s/sharding_state.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/db/storage/two_phase_index_build_knobs_gen.h"
#include "mongo/db/timeseries/catalog_helper.h"
#include "mongo/db/timeseries/timeseries_commands_conversion_helper.h"
@@ -446,16 +448,28 @@ CreateIndexesReply runCreateIndexesOnNewCollection(
return reply;
}
+bool isCreatingInternalConfigTxnsPartialIndex(const CreateIndexesCommand& cmd) {
+ if (cmd.getIndexes().size() > 1) {
+ return false;
+ }
+ const auto& index = cmd.getIndexes()[0];
+
+ UnorderedFieldsBSONObjComparator comparator;
+ return comparator.compare(index, MongoDSessionCatalog::getConfigTxnPartialIndexSpec()) == 0;
+}
+
CreateIndexesReply runCreateIndexesWithCoordinator(OperationContext* opCtx,
const CreateIndexesCommand& cmd) {
const auto ns = cmd.getNamespace();
uassertStatusOK(userAllowedWriteNS(opCtx, ns));
// Disallow users from creating new indexes on config.transactions since the sessions code
- // was optimized to not update indexes
+ // was optimized to not update indexes. The only exception is the partial index used to support
+ // retryable transactions that the sessions code knows how to handle.
uassert(ErrorCodes::IllegalOperation,
str::stream() << "not allowed to create index on " << ns.ns(),
- ns != NamespaceString::kSessionTransactionsTableNamespace);
+ ns != NamespaceString::kSessionTransactionsTableNamespace ||
+ isCreatingInternalConfigTxnsPartialIndex(cmd));
uassert(ErrorCodes::OperationNotSupportedInTransaction,
str::stream() << "Cannot write to system collection " << ns.toString()
diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp
index 8c2a891f996..0db095e1b6b 100644
--- a/src/mongo/db/op_observer_impl_test.cpp
+++ b/src/mongo/db/op_observer_impl_test.cpp
@@ -178,6 +178,7 @@ public:
// Ensure that we are primary.
auto replCoord = repl::ReplicationCoordinator::get(opCtx.get());
ASSERT_OK(replCoord->setFollowerMode(repl::MemberState::RS_PRIMARY));
+ MongoDSessionCatalog::onStepUp(opCtx.get());
ReadWriteConcernDefaults::create(getServiceContext(), _lookupMock.getFetchDefaultsFn());
}
@@ -725,7 +726,6 @@ public:
OpObserverTest::setUp();
auto opCtx = cc().makeOperationContext();
- MongoDSessionCatalog::onStepUp(opCtx.get());
}
/**
@@ -846,7 +846,6 @@ public:
OpObserverTest::setUp();
_opCtx = cc().makeOperationContext();
_opObserver.emplace();
- MongoDSessionCatalog::onStepUp(opCtx());
_times.emplace(opCtx());
}
diff --git a/src/mongo/db/repl/tenant_oplog_applier_test.cpp b/src/mongo/db/repl/tenant_oplog_applier_test.cpp
index 3cdc4d04e26..4215b04043a 100644
--- a/src/mongo/db/repl/tenant_oplog_applier_test.cpp
+++ b/src/mongo/db/repl/tenant_oplog_applier_test.cpp
@@ -34,6 +34,7 @@
#include <boost/optional/optional_io.hpp>
#include <vector>
+#include "mongo/db/dbdirectclient.h"
#include "mongo/db/logical_session_id_helpers.h"
#include "mongo/db/op_observer_noop.h"
#include "mongo/db/op_observer_registry.h"
@@ -49,6 +50,7 @@
#include "mongo/db/repl/tenant_oplog_batcher.h"
#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/db/service_context_test_fixture.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/db/tenant_id.h"
#include "mongo/executor/thread_pool_task_executor_test_fixture.h"
#include "mongo/logv2/log.h"
@@ -346,6 +348,11 @@ TEST_F(TenantOplogApplierTest, NoOpsForLargeTransaction) {
TEST_F(TenantOplogApplierTest, CommitUnpreparedTransaction_DataPartiallyApplied) {
createCollectionWithUuid(_opCtx.get(), NamespaceString::kSessionTransactionsTableNamespace);
+ {
+ DBDirectClient client(_opCtx.get());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
+ }
NamespaceString nss(_dbName, "bar");
auto uuid = createCollectionWithUuid(_opCtx.get(), nss);
auto lsid = makeLogicalSessionId(_opCtx.get());
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_bump_collection_version_and_change_metadata_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_bump_collection_version_and_change_metadata_test.cpp
index ab5fced5419..a4abd0ff45b 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_bump_collection_version_and_change_metadata_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_bump_collection_version_and_change_metadata_test.cpp
@@ -62,6 +62,8 @@ class ShardingCatalogManagerBumpCollectionVersionAndChangeMetadataTest
auto opCtx = operationContext();
DBDirectClient client(opCtx);
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
client.createCollection(CollectionType::ConfigNS.ns());
LogicalSessionCache::set(getServiceContext(), std::make_unique<LogicalSessionCacheNoop>());
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_commit_chunk_migration_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_commit_chunk_migration_test.cpp
index d3d3960b538..235954c5d5d 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_commit_chunk_migration_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_commit_chunk_migration_test.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/catalog/type_shard.h"
@@ -61,6 +62,8 @@ protected:
ConfigServerTestFixture::setUp();
DBDirectClient client(operationContext());
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
ReadWriteConcernDefaults::create(getServiceContext(), _lookupMock.getFetchDefaultsFn());
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_merge_chunks_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_merge_chunks_test.cpp
index 5026625b52d..3b5951cd82e 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_merge_chunks_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_merge_chunks_test.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/s/catalog/sharding_catalog_client.h"
#include "mongo/s/catalog/type_chunk.h"
@@ -56,6 +57,8 @@ protected:
DBDirectClient client(operationContext());
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
LogicalSessionCache::set(getServiceContext(), std::make_unique<LogicalSessionCacheNoop>());
TransactionCoordinatorService::get(operationContext())
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_remove_shard_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_remove_shard_test.cpp
index 987f15e2b83..5e2c7b656df 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_remove_shard_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_remove_shard_test.cpp
@@ -43,6 +43,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/executor/task_executor.h"
#include "mongo/rpc/metadata/repl_set_metadata.h"
#include "mongo/rpc/metadata/tracking_metadata.h"
@@ -96,6 +97,8 @@ protected:
DBDirectClient client(operationContext());
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
LogicalSessionCache::set(getServiceContext(), std::make_unique<LogicalSessionCacheNoop>());
TransactionCoordinatorService::get(operationContext())
diff --git a/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp b/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
index 97b3b7b55b4..1cc5f1c677d 100644
--- a/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
+++ b/src/mongo/db/s/config/sharding_catalog_manager_split_chunk_test.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/config/sharding_catalog_manager.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/s/catalog/type_chunk.h"
namespace mongo {
@@ -52,6 +53,8 @@ protected:
DBDirectClient client(operationContext());
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
LogicalSessionCache::set(getServiceContext(), std::make_unique<LogicalSessionCacheNoop>());
TransactionCoordinatorService::get(operationContext())
diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
index 623524a545d..91e1b4a21bc 100644
--- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
+++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_test.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/s/migration_chunk_cloner_source_legacy.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/s/shard_server_test_fixture.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/s/catalog/sharding_catalog_client_mock.h"
#include "mongo/s/catalog/type_shard.h"
#include "mongo/s/client/shard_registry.h"
@@ -75,6 +76,8 @@ protected:
auto opCtx = operationContext();
DBDirectClient client(opCtx);
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
// TODO: SERVER-26919 set the flag on the mock repl coordinator just for the window where it
// actually needs to bypass the op observer.
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
index f890ca53ca2..7f57851d8e2 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_service_test.cpp
@@ -48,6 +48,7 @@
#include "mongo/db/s/resharding/resharding_service_test_helpers.h"
#include "mongo/db/s/resharding/resharding_util.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/idl/server_parameter_test_util.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_collection.h"
@@ -147,6 +148,8 @@ public:
auto opCtx = operationContext();
DBDirectClient client(opCtx);
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
client.createCollection(NamespaceString::kConfigReshardingOperationsNamespace.ns());
client.createCollection(CollectionType::ConfigNS.ns());
diff --git a/src/mongo/db/s/resharding/resharding_coordinator_test.cpp b/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
index 6d69dd99f28..1fcb1fe7dd1 100644
--- a/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_coordinator_test.cpp
@@ -75,6 +75,8 @@ protected:
auto opCtx = operationContext();
DBDirectClient client(opCtx);
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
client.createCollection(NamespaceString::kConfigReshardingOperationsNamespace.ns());
client.createCollection(CollectionType::ConfigNS.ns());
client.createIndex(TagsType::ConfigNS.ns(), BSON("ns" << 1 << "min" << 1));
diff --git a/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp b/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
index ed5d6b1cf42..d95f0fdc23e 100644
--- a/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_destined_recipient_test.cpp
@@ -186,6 +186,8 @@ protected:
ReshardingEnv setupReshardingEnv(OperationContext* opCtx, bool refreshTempNss) {
DBDirectClient client(opCtx);
ASSERT(client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns()));
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
OperationShardingState::ScopedAllowImplicitCollectionCreate_UNSAFE unsafeCreateCollection(
opCtx);
diff --git a/src/mongo/db/s/resharding/resharding_oplog_applier_test.cpp b/src/mongo/db/s/resharding/resharding_oplog_applier_test.cpp
index e6e80179440..c6772c93d0b 100644
--- a/src/mongo/db/s/resharding/resharding_oplog_applier_test.cpp
+++ b/src/mongo/db/s/resharding/resharding_oplog_applier_test.cpp
@@ -142,6 +142,9 @@ public:
operationContext(),
NamespaceString::kSessionTransactionsTableNamespace.db().toString(),
BSON("create" << NamespaceString::kSessionTransactionsTableNamespace.coll())));
+ DBDirectClient client(operationContext());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
OperationShardingState::ScopedAllowImplicitCollectionCreate_UNSAFE unsafeCreateCollection(
operationContext());
diff --git a/src/mongo/db/s/session_catalog_migration_source_test.cpp b/src/mongo/db/s/session_catalog_migration_source_test.cpp
index f12f0db6828..d723c069c2a 100644
--- a/src/mongo/db/s/session_catalog_migration_source_test.cpp
+++ b/src/mongo/db/s/session_catalog_migration_source_test.cpp
@@ -45,6 +45,7 @@
#include "mongo/db/s/session_catalog_migration.h"
#include "mongo/db/s/session_catalog_migration_source.h"
#include "mongo/db/session.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/db/session_txn_record_gen.h"
#include "mongo/db/transaction_participant.h"
#include "mongo/executor/remote_command_request.h"
@@ -2553,6 +2554,8 @@ TEST_F(SessionCatalogMigrationSourceTest, UntransferredDataSizeWithCommittedWrit
DBDirectClient client(opCtx());
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
// Enter an oplog entry before creating SessionCatalogMigrationSource to set config.transactions
// average object size to the size of this entry.
auto entry = makeOplogEntry(
diff --git a/src/mongo/db/s/sharding_ddl_util_test.cpp b/src/mongo/db/s/sharding_ddl_util_test.cpp
index 2fc8957a799..fd4e3905980 100644
--- a/src/mongo/db/s/sharding_ddl_util_test.cpp
+++ b/src/mongo/db/s/sharding_ddl_util_test.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/s/config/config_server_test_fixture.h"
#include "mongo/db/s/sharding_ddl_util.h"
#include "mongo/db/s/transaction_coordinator_service.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/logv2/log.h"
#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/catalog/type_collection.h"
@@ -61,6 +62,8 @@ protected:
auto opCtx = operationContext();
DBDirectClient client(opCtx);
client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns());
+ client.createIndexes(NamespaceString::kSessionTransactionsTableNamespace.ns(),
+ {MongoDSessionCatalog::getConfigTxnPartialIndexSpec()});
client.createCollection(NamespaceString::kConfigReshardingOperationsNamespace.ns());
client.createCollection(CollectionType::ConfigNS.ns());
diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp
index 49a4acd2405..bd41df1c1e5 100644
--- a/src/mongo/db/session_catalog_mongod.cpp
+++ b/src/mongo/db/session_catalog_mongod.cpp
@@ -347,19 +347,11 @@ void createTransactionTable(OperationContext* opCtx) {
str::stream() << "Failed to create the "
<< NamespaceString::kSessionTransactionsTableNamespace.ns() << " collection");
- NewIndexSpec index;
- index.setV(int(IndexDescriptor::kLatestIndexVersion));
- index.setKey(BSON(
- SessionTxnRecord::kParentSessionIdFieldName
- << 1
- << (SessionTxnRecord::kSessionIdFieldName + "." + LogicalSessionId::kTxnNumberFieldName)
- << 1 << SessionTxnRecord::kSessionIdFieldName << 1));
- index.setName("parent_lsid");
- index.setPartialFilterExpression(BSON("parentLsid" << BSON("$exists" << true)));
+ auto indexSpec = MongoDSessionCatalog::getConfigTxnPartialIndexSpec();
const auto createIndexStatus =
repl::StorageInterface::get(opCtx)->createIndexesOnEmptyCollection(
- opCtx, NamespaceString::kSessionTransactionsTableNamespace, {index.toBSON()});
+ opCtx, NamespaceString::kSessionTransactionsTableNamespace, {indexSpec});
uassertStatusOKWithContext(
createIndexStatus,
str::stream() << "Failed to create partial index for the "
@@ -412,6 +404,21 @@ void abortInProgressTransactions(OperationContext* opCtx) {
}
} // namespace
+const std::string MongoDSessionCatalog::kConfigTxnsPartialIndexName = "parent_lsid";
+
+BSONObj MongoDSessionCatalog::getConfigTxnPartialIndexSpec() {
+ NewIndexSpec index;
+ index.setV(int(IndexDescriptor::kLatestIndexVersion));
+ index.setKey(BSON(
+ SessionTxnRecord::kParentSessionIdFieldName
+ << 1
+ << (SessionTxnRecord::kSessionIdFieldName + "." + LogicalSessionId::kTxnNumberFieldName)
+ << 1 << SessionTxnRecord::kSessionIdFieldName << 1));
+ index.setName(MongoDSessionCatalog::kConfigTxnsPartialIndexName);
+ index.setPartialFilterExpression(BSON("parentLsid" << BSON("$exists" << true)));
+ return index.toBSON();
+}
+
void MongoDSessionCatalog::onStepUp(OperationContext* opCtx) {
// Invalidate sessions that could have a retryable write on it, so that we can refresh from disk
// in case the in-memory state was out of sync.
diff --git a/src/mongo/db/session_catalog_mongod.h b/src/mongo/db/session_catalog_mongod.h
index a3179683746..eb8402aece4 100644
--- a/src/mongo/db/session_catalog_mongod.h
+++ b/src/mongo/db/session_catalog_mongod.h
@@ -37,6 +37,14 @@ class SessionsCollection;
class MongoDSessionCatalog {
public:
+ static const std::string kConfigTxnsPartialIndexName;
+
+ /**
+ * Returns the specification for the partial index on config.transactions used to support
+ * retryable transactions.
+ */
+ static BSONObj getConfigTxnPartialIndexSpec();
+
/**
* Invoked when the node enters the primary state. Ensures that the transactions collection is
* created. Throws on severe exceptions due to which it is not safe to continue the step-up
diff --git a/src/mongo/db/transaction_participant.cpp b/src/mongo/db/transaction_participant.cpp
index 05b4fd96441..1cff05f29be 100644
--- a/src/mongo/db/transaction_participant.cpp
+++ b/src/mongo/db/transaction_participant.cpp
@@ -65,6 +65,7 @@
#include "mongo/db/s/sharding_write_router.h"
#include "mongo/db/server_recovery.h"
#include "mongo/db/server_transactions_metrics.h"
+#include "mongo/db/session_catalog_mongod.h"
#include "mongo/db/stats/fill_locker_info.h"
#include "mongo/db/storage/flow_control.h"
#include "mongo/db/transaction_history_iterator.h"
@@ -182,6 +183,20 @@ auto performReadWithNoTimestampDBDirectClient(OperationContext* opCtx, Callable&
return callable(&client);
}
+void rethrowPartialIndexQueryBadValueWithContext(const DBException& ex) {
+ if (ex.reason().find("hint provided does not correspond to an existing index")) {
+ uassertStatusOKWithContext(
+ ex.toStatus(),
+ str::stream()
+ << "Failed to find partial index for "
+ << NamespaceString::kSessionTransactionsTableNamespace.ns()
+ << ". Please create an index directly on this replica set with the specification: "
+ << MongoDSessionCatalog::getConfigTxnPartialIndexSpec() << " or drop the "
+ << NamespaceString::kSessionTransactionsTableNamespace.ns()
+ << " collection and step up a new primary.");
+ }
+}
+
struct ActiveTransactionHistory {
boost::optional<SessionTxnRecord> lastTxnRecord;
TransactionParticipant::CommittedStatementTimestampMap committedStatements;
@@ -328,29 +343,35 @@ TxnNumber fetchHighestTxnNumberWithInternalSessions(OperationContext* opCtx,
highestTxnNumber = osession.getHighestTxnNumberWithChildSessions();
});
- performReadWithNoTimestampDBDirectClient(opCtx, [&](DBDirectClient* client) {
- FindCommandRequest findRequest{NamespaceString::kSessionTransactionsTableNamespace};
- findRequest.setFilter(BSON(
- SessionTxnRecord::kParentSessionIdFieldName
- << parentLsid.toBSON()
- << (SessionTxnRecord::kSessionIdFieldName + "." + LogicalSessionId::kTxnNumberFieldName)
- << BSON("$gte" << highestTxnNumber)));
- findRequest.setSort(BSON(
- (SessionTxnRecord::kSessionIdFieldName + "." + LogicalSessionId::kTxnNumberFieldName)
- << -1));
- findRequest.setProjection(BSON(SessionTxnRecord::kSessionIdFieldName << 1));
- findRequest.setLimit(1);
-
- auto cursor = client->find(findRequest);
-
- while (cursor->more()) {
- const auto doc = cursor->next();
- const auto childLsid = LogicalSessionId::parse(
- IDLParserErrorContext("LogicalSessionId"), doc.getObjectField("_id"));
- highestTxnNumber = std::max(highestTxnNumber, *childLsid.getTxnNumber());
- invariant(!cursor->more());
- }
- });
+ try {
+ performReadWithNoTimestampDBDirectClient(opCtx, [&](DBDirectClient* client) {
+ FindCommandRequest findRequest{NamespaceString::kSessionTransactionsTableNamespace};
+ findRequest.setFilter(BSON(SessionTxnRecord::kParentSessionIdFieldName
+ << parentLsid.toBSON()
+ << (SessionTxnRecord::kSessionIdFieldName + "." +
+ LogicalSessionId::kTxnNumberFieldName)
+ << BSON("$gte" << highestTxnNumber)));
+ findRequest.setSort(BSON((SessionTxnRecord::kSessionIdFieldName + "." +
+ LogicalSessionId::kTxnNumberFieldName)
+ << -1));
+ findRequest.setProjection(BSON(SessionTxnRecord::kSessionIdFieldName << 1));
+ findRequest.setLimit(1);
+ findRequest.setHint(BSON("$hint" << MongoDSessionCatalog::kConfigTxnsPartialIndexName));
+
+ auto cursor = client->find(findRequest);
+
+ while (cursor->more()) {
+ const auto doc = cursor->next();
+ const auto childLsid = LogicalSessionId::parse(
+ IDLParserErrorContext("LogicalSessionId"), doc.getObjectField("_id"));
+ highestTxnNumber = std::max(highestTxnNumber, *childLsid.getTxnNumber());
+ invariant(!cursor->more());
+ }
+ });
+ } catch (const ExceptionFor<ErrorCodes::BadValue>& ex) {
+ rethrowPartialIndexQueryBadValueWithContext(ex);
+ throw;
+ }
return highestTxnNumber;
}
@@ -2875,22 +2896,27 @@ void TransactionParticipant::Participant::_refreshActiveTransactionParticipantsF
// Make sure that every child session has a corresponding
// Session/TransactionParticipant.
- performReadWithNoTimestampDBDirectClient(opCtx, [&](DBDirectClient* client) {
- FindCommandRequest findRequest{NamespaceString::kSessionTransactionsTableNamespace};
- findRequest.setFilter(BSON(SessionTxnRecord::kParentSessionIdFieldName
- << parentTxnParticipant._sessionId().toBSON()
- << (SessionTxnRecord::kSessionIdFieldName + "." +
- LogicalSessionId::kTxnNumberFieldName)
- << BSON("$gte" << *activeRetryableWriteTxnNumber)));
- findRequest.setProjection(BSON("_id" << 1));
-
- auto cursor = client->find(findRequest);
-
- while (cursor->more()) {
- const auto doc = cursor->next();
- const auto childLsid = LogicalSessionId::parse(
- IDLParserErrorContext("LogicalSessionId"), doc.getObjectField("_id"));
- uassert(6202001,
+ try {
+ performReadWithNoTimestampDBDirectClient(opCtx, [&](DBDirectClient* client) {
+ FindCommandRequest findRequest{
+ NamespaceString::kSessionTransactionsTableNamespace};
+ findRequest.setFilter(BSON(SessionTxnRecord::kParentSessionIdFieldName
+ << parentTxnParticipant._sessionId().toBSON()
+ << (SessionTxnRecord::kSessionIdFieldName + "." +
+ LogicalSessionId::kTxnNumberFieldName)
+ << BSON("$gte" << *activeRetryableWriteTxnNumber)));
+ findRequest.setProjection(BSON(SessionTxnRecord::kSessionIdFieldName << 1));
+ findRequest.setHint(
+ BSON("$hint" << MongoDSessionCatalog::kConfigTxnsPartialIndexName));
+
+ auto cursor = client->find(findRequest);
+
+ while (cursor->more()) {
+ const auto doc = cursor->next();
+ const auto childLsid = LogicalSessionId::parse(
+ IDLParserErrorContext("LogicalSessionId"), doc.getObjectField("_id"));
+ uassert(
+ 6202001,
str::stream()
<< "Refresh expected the highest transaction number in the session "
<< parentTxnParticipant._sessionId() << " to be "
@@ -2899,15 +2925,20 @@ void TransactionParticipant::Participant::_refreshActiveTransactionParticipantsF
<< " entry for an internal transaction for retryable writes with "
<< "transaction number " << *childLsid.getTxnNumber(),
*childLsid.getTxnNumber() == *activeRetryableWriteTxnNumber);
- auto sessionCatalog = SessionCatalog::get(opCtx);
- sessionCatalog->createSessionIfDoesNotExist(childLsid);
- sessionCatalog->scanSession(childLsid, [&](const ObservableSession& osession) {
- auto childTxnParticipant =
- TransactionParticipant::get(opCtx, osession.get());
- childTxnParticipants.push_back(childTxnParticipant);
- });
- }
- });
+ auto sessionCatalog = SessionCatalog::get(opCtx);
+ sessionCatalog->createSessionIfDoesNotExist(childLsid);
+ sessionCatalog->scanSession(
+ childLsid, [&](const ObservableSession& osession) {
+ auto childTxnParticipant =
+ TransactionParticipant::get(opCtx, osession.get());
+ childTxnParticipants.push_back(childTxnParticipant);
+ });
+ }
+ });
+ } catch (const ExceptionFor<ErrorCodes::BadValue>& ex) {
+ rethrowPartialIndexQueryBadValueWithContext(ex);
+ throw;
+ }
for (auto& childTxnParticipant : childTxnParticipants) {
childTxnParticipant._refreshSelfFromStorageIfNeeded(opCtx, fetchOplogEntries);