void IndexBuildInterceptor::_tryYield(OperationContext* opCtx) { // Never yield while holding locks that prevent writes to the collection: only yield while // holding intent locks. This check considers all locks in the hierarchy that would cover this // mode. const NamespaceString nss(_indexCatalogEntry->ns()); if (opCtx->lockState()->isCollectionLockedForMode(nss, MODE_S)) { return; } DEV { invariant(!opCtx->lockState()->isCollectionLockedForMode(nss, MODE_X)); invariant(!opCtx->lockState()->isDbLockedForMode(nss.db(), MODE_X)); } // Releasing locks means a new snapshot should be acquired when restored. opCtx->recoveryUnit()->abandonSnapshot(); auto locker = opCtx->lockState(); Locker::LockSnapshot snapshot; invariant(locker->saveLockStateAndUnlock(&snapshot)); // Track the number of yields in CurOp. CurOp::get(opCtx)->yielded(); MONGO_FAIL_POINT_BLOCK(hangDuringIndexBuildDrainYield, config) { StringData ns{config.getData().getStringField("namespace")}; if (ns == _indexCatalogEntry->ns()) { log() << "Hanging index build during drain yield"; MONGO_FAIL_POINT_PAUSE_WHILE_SET(hangDuringIndexBuildDrainYield); } }
bool LockerImpl::releaseWriteUnitOfWork(LockSnapshot* stateOut) { // Only the global WUOW can be released. invariant(_wuowNestingLevel == 1); --_wuowNestingLevel; invariant(!isGlobalLockedRecursively()); // All locks should be pending to unlock. invariant(_requests.size() == _numResourcesToUnlockAtEndUnitOfWork); for (auto it = _requests.begin(); it; it.next()) { // No converted lock so we don't need to unlock more than once. invariant(it->unlockPending == 1); } _numResourcesToUnlockAtEndUnitOfWork = 0; return saveLockStateAndUnlock(stateOut); }