TEST_F(TransactionCoordinatorCatalogTest, CreateFollowedByGetReturnsCoordinator) {
    LogicalSessionId lsid = makeLogicalSessionIdForTest();
    TxnNumber txnNumber = 1;
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber);
    auto coordinatorInCatalog = coordinatorCatalog().get(operationContext(), lsid, txnNumber);
    ASSERT(coordinatorInCatalog != nullptr);
}
예제 #2
0
/**
 * Test a manager that has one cursor running inside of a session.
 */
TEST_F(CursorManagerTestCustomOpCtx, OneCursorWithASession) {
    // Add a cursor with a session to the cursor manager.
    auto lsid = makeLogicalSessionIdForTest();
    auto opCtx = _queryServiceContext->makeOperationContext(lsid, boost::none);
    auto pinned = makeCursor(opCtx.get());

    // Retrieve all sessions active in manager - set should contain just lsid.
    LogicalSessionIdSet lsids;
    useCursorManager()->appendActiveSessions(&lsids);
    ASSERT_EQ(lsids.size(), size_t(1));
    ASSERT(lsids.find(lsid) != lsids.end());

    // Retrieve all cursors for this lsid - should be just ours.
    auto cursors = useCursorManager()->getCursorsForSession(lsid);
    ASSERT_EQ(cursors.size(), size_t(1));
    auto cursorId = pinned.getCursor()->cursorid();
    ASSERT(cursors.find(cursorId) != cursors.end());

    // Remove the cursor from the manager.
    pinned.release();
    ASSERT_OK(useCursorManager()->killCursor(opCtx.get(), cursorId, false));

    // There should be no more cursor entries by session id.
    LogicalSessionIdSet sessions;
    useCursorManager()->appendActiveSessions(&sessions);
    ASSERT(sessions.empty());
    ASSERT(useCursorManager()->getCursorsForSession(lsid).empty());
}
예제 #3
0
TEST_F(CursorManagerTestCustomOpCtx, KillCursorRespectsSessionId) {
    // Add a cursor with a session to the cursor manager.
    auto lsid = makeLogicalSessionIdForTest();
    auto opCtx = _queryServiceContext->makeOperationContext(lsid, boost::none);
    auto pinned = makeCursor(opCtx.get());
    auto cursorId = pinned.getCursor()->cursorid();

    // Killing the cursor with incorrect LogicalSessionId fails.
    pinned.release();
    auto wrongLsid = makeLogicalSessionIdForTest();
    auto status =
        useCursorManager()->killCursor(opCtx.get(), cursorId, false, wrongLsid, boost::none);
    ASSERT_NOT_OK(status);
    ASSERT_EQ(status.code(), ErrorCodes::CursorNotFound);

    // Killing the cursor with the correct LogicalSessionId works.
    ASSERT_OK(useCursorManager()->killCursor(opCtx.get(), cursorId, false, lsid, boost::none));
}
TEST_F(TransactionCoordinatorCatalogTest, SecondCreateForSessionDoesNotOverwriteFirstCreate) {
    LogicalSessionId lsid = makeLogicalSessionIdForTest();
    TxnNumber txnNumber1 = 1;
    TxnNumber txnNumber2 = 2;
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber1);
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber2);

    auto coordinator1InCatalog = coordinatorCatalog().get(operationContext(), lsid, txnNumber1);
    ASSERT(coordinator1InCatalog != nullptr);
}
예제 #5
0
/**
 * Test a manager with multiple cursors running inside of different sessions.
 */
TEST_F(CursorManagerTestCustomOpCtx, MultipleCursorsMultipleSessions) {
    auto lsid1 = makeLogicalSessionIdForTest();
    auto lsid2 = makeLogicalSessionIdForTest();

    CursorId cursor1;
    CursorId cursor2;

    // Cursor with session 1.
    {
        auto opCtx1 = _queryServiceContext->makeOperationContext(lsid1, boost::none);
        cursor1 = makeCursor(opCtx1.get()).getCursor()->cursorid();
    }

    // Cursor with session 2.
    {
        auto opCtx2 = _queryServiceContext->makeOperationContext(lsid2, boost::none);
        cursor2 = makeCursor(opCtx2.get()).getCursor()->cursorid();
    }

    // Cursor with no session.
    {
        auto opCtx3 = _queryServiceContext->makeOperationContext();
        makeCursor(opCtx3.get()).getCursor();
    }

    // Retrieve all sessions - should be both lsids.
    LogicalSessionIdSet lsids;
    useCursorManager()->appendActiveSessions(&lsids);
    ASSERT_EQ(lsids.size(), size_t(2));
    ASSERT(lsids.find(lsid1) != lsids.end());
    ASSERT(lsids.find(lsid2) != lsids.end());

    // Retrieve cursors for each session - should be just one.
    auto cursors1 = useCursorManager()->getCursorsForSession(lsid1);
    ASSERT_EQ(cursors1.size(), size_t(1));
    ASSERT(cursors1.find(cursor1) != cursors1.end());

    auto cursors2 = useCursorManager()->getCursorsForSession(lsid2);
    ASSERT_EQ(cursors2.size(), size_t(1));
    ASSERT(cursors2.find(cursor2) != cursors2.end());
}
예제 #6
0
TEST(OperationContextTest, SessionIdAndTransactionNumber) {
    auto serviceCtx = ServiceContext::make();
    auto client = serviceCtx->makeClient("OperationContextTest");
    auto opCtx = client->makeOperationContext();

    const auto lsid = makeLogicalSessionIdForTest();
    opCtx->setLogicalSessionId(lsid);
    opCtx->setTxnNumber(5);

    ASSERT(opCtx->getTxnNumber());
    ASSERT_EQUALS(5, *opCtx->getTxnNumber());
}
예제 #7
0
TEST_F(CursorManagerTestCustomOpCtx,
       KillCursorWithSessionDoesNotKillCursorCreatedOutsideOfSession) {
    // Add a cursor with a session to the cursor manager.
    auto opCtx = _queryServiceContext->makeOperationContext();
    auto pinned = makeCursor(opCtx.get());
    auto cursorId = pinned.getCursor()->cursorid();

    // Killing the cursor with the correct cursorId but with an unrelated LogicalSessionId fails.
    auto lsid = makeLogicalSessionIdForTest();
    auto status = useCursorManager()->killCursor(opCtx.get(), cursorId, false, lsid, boost::none);
    ASSERT_NOT_OK(status);
    ASSERT_EQ(status.code(), ErrorCodes::CursorNotFound);
}
BSONObj ClusterCommandTestFixture::_makeCmd(BSONObj cmdObj, bool includeAfterClusterTime) {
    BSONObjBuilder bob(cmdObj);
    // Each command runs in a new session.
    bob.append("lsid", makeLogicalSessionIdForTest().toBSON());
    bob.append("txnNumber", TxnNumber(1));
    bob.append("autocommit", false);
    bob.append("startTransaction", true);

    BSONObjBuilder readConcernBob = bob.subobjStart(repl::ReadConcernArgs::kReadConcernFieldName);
    readConcernBob.append("level", "snapshot");
    if (includeAfterClusterTime) {
        readConcernBob.append("afterClusterTime", kAfterClusterTime);
    }

    readConcernBob.doneFast();
    return bob.obj();
}
예제 #9
0
/**
 * Test that cursors inherit the logical session id from their operation context
 */
TEST_F(CursorManagerTestCustomOpCtx, LogicalSessionIdOnOperationCtxTest) {
    // Cursors created on an op ctx without a session id have no session id.
    {
        auto opCtx = _queryServiceContext->makeOperationContext();
        auto pinned = makeCursor(opCtx.get());

        ASSERT_EQUALS(pinned.getCursor()->getSessionId(), boost::none);
    }

    // Cursors created on an op ctx with a session id have a session id.
    {
        auto lsid = makeLogicalSessionIdForTest();
        auto opCtx2 = _queryServiceContext->makeOperationContext(lsid, boost::none);
        auto pinned2 = makeCursor(opCtx2.get());

        ASSERT_EQUALS(pinned2.getCursor()->getSessionId(), lsid);
    }
}
예제 #10
0
/**
 * Test a manager with multiple cursors running inside of the same session.
 */
TEST_F(CursorManagerTestCustomOpCtx, MultipleCursorsWithSameSession) {
    // Add two cursors on the same session to the cursor manager.
    auto lsid = makeLogicalSessionIdForTest();
    auto opCtx = _queryServiceContext->makeOperationContext(lsid, boost::none);
    auto pinned = makeCursor(opCtx.get());
    auto pinned2 = makeCursor(opCtx.get());

    auto cursorId1 = pinned.getCursor()->cursorid();
    auto cursorId2 = pinned2.getCursor()->cursorid();

    // Retrieve all sessions - set should contain just lsid.
    stdx::unordered_set<LogicalSessionId, LogicalSessionIdHash> lsids;
    useCursorManager()->appendActiveSessions(&lsids);
    ASSERT_EQ(lsids.size(), size_t(1));
    ASSERT(lsids.find(lsid) != lsids.end());

    // Retrieve all cursors for session - should be both cursors.
    auto cursors = useCursorManager()->getCursorsForSession(lsid);
    ASSERT_EQ(cursors.size(), size_t(2));
    ASSERT(cursors.find(cursorId1) != cursors.end());
    ASSERT(cursors.find(cursorId2) != cursors.end());

    // Remove one cursor from the manager.
    pinned.release();
    ASSERT_OK(useCursorManager()->killCursor(opCtx.get(), cursorId1, false));

    // Should still be able to retrieve the session.
    lsids.clear();
    useCursorManager()->appendActiveSessions(&lsids);
    ASSERT_EQ(lsids.size(), size_t(1));
    ASSERT(lsids.find(lsid) != lsids.end());

    // Should still be able to retrieve remaining cursor by session.
    cursors = useCursorManager()->getCursorsForSession(lsid);
    ASSERT_EQ(cursors.size(), size_t(1));
    ASSERT(cursors.find(cursorId2) != cursors.end());
}
예제 #11
0
TEST_F(CursorManagerTestCustomOpCtx,
       KillAllCursorsForTransactionRemovesCorrectEntryFromTransactionMap) {
    CursorManager* cursorManager = CursorManager::getGlobalCursorManager();

    // Create 3 sets of cursors, each with a unique LogicalSessionId/TxnNumber pair, but each
    // sharing either LogicalSessionId or TxnNumber with another set.
    auto lsid1 = makeLogicalSessionIdForTest();
    TxnNumber txnNumber1 = 0;
    {
        auto opCtx = _queryServiceContext->makeOperationContext(lsid1, txnNumber1);
        auto pinned = cursorManager->registerCursor(opCtx.get(),
                                                    {makeFakePlanExecutor(),
                                                     NamespaceString{"test.collection"},
                                                     {},
                                                     repl::ReadConcernLevel::kLocalReadConcern,
                                                     BSONObj()});
        pinned.release();
    }

    auto lsid2 = lsid1;
    TxnNumber txnNumber2 = 1;
    {
        auto opCtx = _queryServiceContext->makeOperationContext(lsid2, txnNumber2);
        auto pinned = cursorManager->registerCursor(opCtx.get(),
                                                    {makeFakePlanExecutor(),
                                                     NamespaceString{"test.collection"},
                                                     {},
                                                     repl::ReadConcernLevel::kLocalReadConcern,
                                                     BSONObj()});
        pinned.release();
    }

    auto lsid3 = makeLogicalSessionIdForTest();
    TxnNumber txnNumber3 = txnNumber1;
    {
        auto opCtx = _queryServiceContext->makeOperationContext(lsid3, txnNumber3);
        // Create 2 cursors for the third set to confirm multiple cursor deregistration.
        auto pinned = cursorManager->registerCursor(opCtx.get(),
                                                    {makeFakePlanExecutor(),
                                                     NamespaceString{"test.collection"},
                                                     {},
                                                     repl::ReadConcernLevel::kLocalReadConcern,
                                                     BSONObj()});
        pinned.release();
        pinned = cursorManager->registerCursor(opCtx.get(),
                                               {makeFakePlanExecutor(),
                                                NamespaceString{"test.collection"},
                                                {},
                                                repl::ReadConcernLevel::kLocalReadConcern,
                                                BSONObj()});
        pinned.release();
    }

    auto opCtx = _queryServiceContext->makeOperationContext();

    // Transaction reference exists for all 3 sets.
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid1, txnNumber1));
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid2, txnNumber2));
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid3, txnNumber3));

    // Transaction reference does not exist for LogicalSessionId/TxnNumber that has no cursors.
    ASSERT_FALSE(cursorManager->hasTransactionCursorReference(makeLogicalSessionIdForTest(), 99));

    // Kill cursors for set 1.
    ASSERT_EQ(1ul, cursorManager->killAllCursorsForTransaction(opCtx.get(), lsid1, txnNumber1));
    ASSERT_FALSE(cursorManager->hasTransactionCursorReference(lsid1, txnNumber1));
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid2, txnNumber2));
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid3, txnNumber3));

    // Kill cursors for set 2.
    ASSERT_EQ(1ul, cursorManager->killAllCursorsForTransaction(opCtx.get(), lsid2, txnNumber2));
    ASSERT_FALSE(cursorManager->hasTransactionCursorReference(lsid2, txnNumber2));
    ASSERT_TRUE(cursorManager->hasTransactionCursorReference(lsid3, txnNumber3));

    // Kill cursors for set 3.
    ASSERT_EQ(2ul, cursorManager->killAllCursorsForTransaction(opCtx.get(), lsid3, txnNumber3));
    ASSERT_FALSE(cursorManager->hasTransactionCursorReference(lsid3, txnNumber3));
}
TEST_F(TransactionCoordinatorCatalogTest, SecondCreateForSessionDoesNotOverwriteFirstCreate) {
    LogicalSessionId lsid = makeLogicalSessionIdForTest();
    TxnNumber txnNumber1 = 1;
    TxnNumber txnNumber2 = 2;
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber1);
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber2);

    auto coordinator1InCatalog = coordinatorCatalog().get(operationContext(), lsid, txnNumber1);
    ASSERT(coordinator1InCatalog != nullptr);
}

DEATH_TEST_F(TransactionCoordinatorCatalogTest,
             CreatingACoordinatorWithASessionIdAndTxnNumberThatAlreadyExistFails,
             "Invariant failure") {
    LogicalSessionId lsid = makeLogicalSessionIdForTest();
    TxnNumber txnNumber = 1;
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber);
    // Re-creating w/ same session id and txn number should cause invariant failure
    createCoordinatorInCatalog(operationContext(), lsid, txnNumber);
}

TEST_F(TransactionCoordinatorCatalogTest, GetLatestOnSessionWithNoCoordinatorsReturnsNone) {
    LogicalSessionId lsid = makeLogicalSessionIdForTest();
    auto latestTxnNumAndCoordinator =
        coordinatorCatalog().getLatestOnSession(operationContext(), lsid);
    ASSERT_FALSE(latestTxnNumAndCoordinator);
}

TEST_F(TransactionCoordinatorCatalogTest,
       CreateFollowedByGetLatestOnSessionReturnsOnlyCoordinator) {