diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2022-05-25 15:43:58 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-05-25 16:18:08 +0000 |
commit | 80e519f931ee0339b34e2546d274e21499e437b6 (patch) | |
tree | 4faab13bb94c6d37ff84467cbf81ce5050d7ec0c /src/mongo/db | |
parent | 982ba2296ba7e5a9f53e8f36d14310f0f45b7b70 (diff) | |
download | mongo-80e519f931ee0339b34e2546d274e21499e437b6.tar.gz |
SERVER-66565 Use hint with config.transactions partial index and allow creating it
Diffstat (limited to 'src/mongo/db')
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); |