diff options
Diffstat (limited to 'src/mongo/db/session_catalog_mongod.cpp')
-rw-r--r-- | src/mongo/db/session_catalog_mongod.cpp | 141 |
1 files changed, 80 insertions, 61 deletions
diff --git a/src/mongo/db/session_catalog_mongod.cpp b/src/mongo/db/session_catalog_mongod.cpp index eeb1ffb175a..fcefa1ed69b 100644 --- a/src/mongo/db/session_catalog_mongod.cpp +++ b/src/mongo/db/session_catalog_mongod.cpp @@ -208,12 +208,70 @@ const auto kIdProjection = BSON(SessionTxnRecord::kSessionIdFieldName << 1); const auto kSortById = BSON(SessionTxnRecord::kSessionIdFieldName << 1); const auto kLastWriteDateFieldName = SessionTxnRecord::kLastWriteDateFieldName; +template <typename SessionContainer> +int removeSessionsTransactionRecordsFromDisk(OperationContext* opCtx, + const SessionContainer& transactionSessionIdsToReap) { + if (transactionSessionIdsToReap.empty()) { + return 0; + } + + // Remove the config.image_collection entries for the expired transaction session ids. We first + // delete any images belonging to sessions about to be reaped, followed by the sessions. This + // way if there's a failure, we'll only be left with sessions that have a dangling reference + // to an image. Session reaping will rediscover the sessions to delete and try again. + // + // We opt for this rather than performing the two sets of deletes in a single transaction simply + // to reduce code complexity. + DBDirectClient client(opCtx); + write_ops::checkWriteErrors(client.remove([&] { + write_ops::DeleteCommandRequest imageDeleteOp(NamespaceString::kConfigImagesNamespace); + imageDeleteOp.setWriteCommandRequestBase([] { + write_ops::WriteCommandRequestBase base; + base.setOrdered(false); + return base; + }()); + imageDeleteOp.setDeletes([&] { + std::vector<write_ops::DeleteOpEntry> entries; + for (const auto& transactionSessionId : transactionSessionIdsToReap) { + entries.emplace_back( + BSON(LogicalSessionRecord::kIdFieldName << transactionSessionId.toBSON()), + false /* multi = false */); + } + return entries; + }()); + return imageDeleteOp; + }())); + + // Remove the config.transaction entries for the expired transaction session ids. + auto sessionDeleteReply = write_ops::checkWriteErrors(client.remove([&] { + write_ops::DeleteCommandRequest sessionDeleteOp( + NamespaceString::kSessionTransactionsTableNamespace); + sessionDeleteOp.setWriteCommandRequestBase([] { + write_ops::WriteCommandRequestBase base; + base.setOrdered(false); + return base; + }()); + sessionDeleteOp.setDeletes([&] { + std::vector<write_ops::DeleteOpEntry> entries; + for (const auto& transactionSessionId : transactionSessionIdsToReap) { + entries.emplace_back( + BSON(LogicalSessionRecord::kIdFieldName << transactionSessionId.toBSON()), + false /* multi = false */); + } + return entries; + }()); + return sessionDeleteOp; + }())); + + return sessionDeleteReply.getN(); +} + /** * Removes the the config.transactions and the config.image_collection entries for the transaction * sessions in 'expiredTransactionSessionIdsNotInUse' that are safe to reap. Returns the number * of transaction sessions whose entries were removed. */ -int removeSessionsTransactionRecords( +int removeSessionsTransactionRecordsIfExpired( OperationContext* opCtx, SessionsCollection& sessionsCollection, const LogicalSessionIdSet& expiredTransactionSessionIdsNotInUse) { @@ -267,59 +325,7 @@ int removeSessionsTransactionRecords( } } - if (transactionSessionIdsToReap.empty()) { - return 0; - } - - // Remove the config.image_collection entries for the expired transaction session ids. We first - // delete any images belonging to sessions about to be reaped, followed by the sessions. This - // way if there's a failure, we'll only be left with sessions that have a dangling reference - // to an image. Session reaping will rediscover the sessions to delete and try again. - // - // We opt for this rather than performing the two sets of deletes in a single transaction simply - // to reduce code complexity. - DBDirectClient client(opCtx); - write_ops::checkWriteErrors(client.remove([&] { - write_ops::DeleteCommandRequest imageDeleteOp(NamespaceString::kConfigImagesNamespace); - imageDeleteOp.setWriteCommandRequestBase([] { - write_ops::WriteCommandRequestBase base; - base.setOrdered(false); - return base; - }()); - imageDeleteOp.setDeletes([&] { - std::vector<write_ops::DeleteOpEntry> entries; - for (const auto& transactionSessionId : transactionSessionIdsToReap) { - entries.emplace_back( - BSON(LogicalSessionRecord::kIdFieldName << transactionSessionId.toBSON()), - false /* multi = false */); - } - return entries; - }()); - return imageDeleteOp; - }())); - - // Remove the config.transaction entries for the expired transaction session ids. - auto sessionDeleteReply = write_ops::checkWriteErrors(client.remove([&] { - write_ops::DeleteCommandRequest sessionDeleteOp( - NamespaceString::kSessionTransactionsTableNamespace); - sessionDeleteOp.setWriteCommandRequestBase([] { - write_ops::WriteCommandRequestBase base; - base.setOrdered(false); - return base; - }()); - sessionDeleteOp.setDeletes([&] { - std::vector<write_ops::DeleteOpEntry> entries; - for (const auto& transactionSessionId : transactionSessionIdsToReap) { - entries.emplace_back( - BSON(LogicalSessionRecord::kIdFieldName << transactionSessionId.toBSON()), - false /* multi = false */); - } - return entries; - }()); - return sessionDeleteOp; - }())); - - return sessionDeleteReply.getN(); + return removeSessionsTransactionRecordsFromDisk(opCtx, transactionSessionIdsToReap); } /** @@ -340,10 +346,6 @@ int removeExpiredTransactionSessionsFromDisk( findRequest.setProjection(kIdProjection); auto cursor = client.find(std::move(findRequest)); - // The max batch size is chosen so that a single batch won't exceed the 16MB BSON object size - // limit. - const int kMaxBatchSize = 10'000; - LogicalSessionIdSet expiredTransactionSessionIdsNotInUse; int numReaped = 0; while (cursor->more()) { @@ -357,13 +359,14 @@ int removeExpiredTransactionSessionsFromDisk( } expiredTransactionSessionIdsNotInUse.insert(transactionSessionId); - if (expiredTransactionSessionIdsNotInUse.size() > kMaxBatchSize) { - numReaped += removeSessionsTransactionRecords( + if (expiredTransactionSessionIdsNotInUse.size() > + MongoDSessionCatalog::kMaxSessionDeletionBatchSize) { + numReaped += removeSessionsTransactionRecordsIfExpired( opCtx, sessionsCollection, expiredTransactionSessionIdsNotInUse); expiredTransactionSessionIdsNotInUse.clear(); } } - numReaped += removeSessionsTransactionRecords( + numReaped += removeSessionsTransactionRecordsIfExpired( opCtx, sessionsCollection, expiredTransactionSessionIdsNotInUse); return numReaped; @@ -621,6 +624,22 @@ int MongoDSessionCatalog::reapSessionsOlderThan(OperationContext* opCtx, opCtx, sessionsCollection, possiblyExpired, expiredTransactionSessionIdsStillInUse); } +int MongoDSessionCatalog::removeSessionsTransactionRecords( + OperationContext* opCtx, const std::vector<LogicalSessionId>& transactionSessionIdsToRemove) { + std::vector<LogicalSessionId> nextLsidBatch; + int numReaped = 0; + for (const auto& transactionSessionIdToRemove : transactionSessionIdsToRemove) { + nextLsidBatch.push_back(transactionSessionIdToRemove); + if (nextLsidBatch.size() > MongoDSessionCatalog::kMaxSessionDeletionBatchSize) { + numReaped += removeSessionsTransactionRecordsFromDisk(opCtx, nextLsidBatch); + nextLsidBatch.clear(); + } + } + numReaped += removeSessionsTransactionRecordsFromDisk(opCtx, nextLsidBatch); + + return numReaped; +} + MongoDOperationContextSession::MongoDOperationContextSession(OperationContext* opCtx) : _operationContextSession(opCtx) { invariant(!opCtx->getClient()->isInDirectClient()); |