Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-66145

Identify and fix locations that write while holding read tickets

    XMLWordPrintableJSON

Details

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Major - P3 Major - P3
    • 6.3.0-rc0
    • None
    • None
    • None
    • Fully Compatible
    • ALL
    • Execution Team 2022-12-12, Execution Team 2022-11-28, Execution Team 2022-12-26
    • 169

    Description

      Due to our support of recursive locking, it is possible for an operation to hold a global IS, acquiring a read ticket, and then obtain an IX lock at a lower level without taking a write ticket.

      This test passes:

      // d_concurrency_test.cpp
       
      TEST_F(DConcurrencyTestFixture, WrongTicket) {
          auto clientOpctxPairs = makeKClientsWithLockers(1);
          auto opctx1 = clientOpctxPairs[0].second.get();
       
          Lock::GlobalLock read(opctx1, MODE_IS);
          ASSERT_TRUE(opctx1->lockState()->hasReadTicket());
          ASSERT_FALSE(opctx1->lockState()->hasWriteTicket());
          ASSERT_FALSE(opctx1->lockState()->isWriteLocked());
       
          Lock::GlobalLock write(opctx1, MODE_IX);
       
          ASSERT_TRUE(opctx1->lockState()->hasReadTicket());
          ASSERT_FALSE(opctx1->lockState()->hasWriteTicket());
          ASSERT_TRUE(opctx1->lockState()->isWriteLocked());
      }
      

      We can discover violations of this with the following assertion:

      diff --git a/src/mongo/db/concurrency/lock_state.cpp b/src/mongo/db/concurrency/lock_state.cpp
      index a968d2eee6e..2d22ebf6790 100644
      --- a/src/mongo/db/concurrency/lock_state.cpp
      +++ b/src/mongo/db/concurrency/lock_state.cpp
      @@ -409,6 +409,11 @@ void LockerImpl::lockGlobal(OperationContext* opCtx, LockMode mode, Date_t deadl
                           _acquireTicket(opCtx, mode, deadline));
               }
               _modeForTicket = mode;
      +    } else if (!isModeCovered(mode, _modeForTicket)) {
      +        LOGV2_FATAL(99999,
      +                    "Ticket held does not cover requested mode for global lock",
      +                    "held"_attr = _modeForTicket,
      +                    "requested"_attr = mode);
           }
      

      This is mostly an accounting problem since we don't use tickets to block reads or writes. We only use tickets for throttling reads and writes, and most applications do not hit this limit.

      Attachments

        Activity

          People

            louis.williams@mongodb.com Louis Williams
            louis.williams@mongodb.com Louis Williams
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: