void LockerImpl<IsForMMAPV1>::getLockerInfo(LockerInfo* lockerInfo) const { invariant(lockerInfo); // Zero-out the contents lockerInfo->locks.clear(); lockerInfo->waitingResource = ResourceId(); lockerInfo->stats.reset(); _lock.lock(); LockRequestsMap::ConstIterator it = _requests.begin(); while (!it.finished()) { OneLock info; info.resourceId = it.key(); info.mode = it->mode; lockerInfo->locks.push_back(info); it.next(); } _lock.unlock(); std::sort(lockerInfo->locks.begin(), lockerInfo->locks.end()); lockerInfo->waitingResource = getWaitingResource(); lockerInfo->stats.append(_stats); }
void LockerImpl::getLockerInfo(LockerInfo* lockerInfo, const boost::optional<SingleThreadedLockStats> lockStatsBase) const { invariant(lockerInfo); // Zero-out the contents lockerInfo->locks.clear(); lockerInfo->waitingResource = ResourceId(); lockerInfo->stats.reset(); _lock.lock(); LockRequestsMap::ConstIterator it = _requests.begin(); while (!it.finished()) { OneLock info; info.resourceId = it.key(); info.mode = it->mode; lockerInfo->locks.push_back(info); it.next(); } _lock.unlock(); std::sort(lockerInfo->locks.begin(), lockerInfo->locks.end()); lockerInfo->waitingResource = getWaitingResource(); lockerInfo->stats.append(_stats); // lockStatsBase is a snapshot of lock stats taken when the sub-operation starts. Only // sub-operations have lockStatsBase. if (lockStatsBase) // Adjust the lock stats by subtracting the lockStatsBase. No mutex is needed because // lockStatsBase is immutable. lockerInfo->stats.subtract(*lockStatsBase); }
LockResult LockerImpl<IsForMMAPV1>::lockBegin(OperationContext* opCtx, ResourceId resId, LockMode mode) { dassert(!getWaitingResource().isValid()); LockRequest* request; bool isNew = true; LockRequestsMap::Iterator it = _requests.find(resId); if (!it) { scoped_spinlock scopedLock(_lock); LockRequestsMap::Iterator itNew = _requests.insert(resId); itNew->initNew(this, &_notify); request = itNew.objAddr(); } else { request = it.objAddr(); isNew = false; } // If unlockPending is nonzero, that means a LockRequest already exists for this resource but // is planned to be released at the end of this WUOW due to two-phase locking. Rather than // unlocking the existing request, we can reuse it if the existing mode matches the new mode. if (request->unlockPending && isModeCovered(mode, request->mode)) { request->unlockPending--; if (!request->unlockPending) { _numResourcesToUnlockAtEndUnitOfWork--; } return LOCK_OK; } // Making this call here will record lock re-acquisitions and conversions as well. globalStats.recordAcquisition(_id, resId, mode); _stats.recordAcquisition(resId, mode); // Give priority to the full modes for global, parallel batch writer mode, // and flush lock so we don't stall global operations such as shutdown or flush. const ResourceType resType = resId.getType(); if (resType == RESOURCE_GLOBAL || (IsForMMAPV1 && resId == resourceIdMMAPV1Flush)) { if (mode == MODE_S || mode == MODE_X) { request->enqueueAtFront = true; request->compatibleFirst = true; } } else if (resType != RESOURCE_MUTEX) { // This is all sanity checks that the global and flush locks are always be acquired // before any other lock has been acquired and they must be in sync with the nesting. DEV { const LockRequestsMap::Iterator itGlobal = _requests.find(resourceIdGlobal); invariant(itGlobal->recursiveCount > 0); invariant(itGlobal->mode != MODE_NONE); // Check the MMAP V1 flush lock is held in the appropriate mode invariant(!IsForMMAPV1 || isLockHeldForMode(resourceIdMMAPV1Flush, _getModeForMMAPV1FlushLock())); }; }
LockResult LockerImpl<IsForMMAPV1>::lockBegin(ResourceId resId, LockMode mode) { dassert(!getWaitingResource().isValid()); LockRequest* request; bool isNew = true; LockRequestsMap::Iterator it = _requests.find(resId); if (!it) { scoped_spinlock scopedLock(_lock); LockRequestsMap::Iterator itNew = _requests.insert(resId); itNew->initNew(this, &_notify); request = itNew.objAddr(); } else { request = it.objAddr(); isNew = false; } // Making this call here will record lock re-acquisitions and conversions as well. globalStats.recordAcquisition(_id, resId, mode); _stats.recordAcquisition(resId, mode); // Give priority to the full modes for global, parallel batch writer mode, // and flush lock so we don't stall global operations such as shutdown or flush. const ResourceType resType = resId.getType(); if (resType == RESOURCE_GLOBAL || (IsForMMAPV1 && resId == resourceIdMMAPV1Flush)) { if (mode == MODE_S || mode == MODE_X) { request->enqueueAtFront = true; request->compatibleFirst = true; } } else if (resType != RESOURCE_MUTEX) { // This is all sanity checks that the global and flush locks are always be acquired // before any other lock has been acquired and they must be in sync with the nesting. DEV { const LockRequestsMap::Iterator itGlobal = _requests.find(resourceIdGlobal); invariant(itGlobal->recursiveCount > 0); invariant(itGlobal->mode != MODE_NONE); // Check the MMAP V1 flush lock is held in the appropriate mode invariant(!IsForMMAPV1 || isLockHeldForMode(resourceIdMMAPV1Flush, _getModeForMMAPV1FlushLock())); }; }