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

Identify and fix locations that write while holding read tickets

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major - P3
    • Resolution: Fixed
    • None
    • 6.3.0-rc0
    • 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

        Issue Links

          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: