bool LockerImpl::isAtLeastReadLocked(const StringData& ns) const { if (threadState() == 'R' || threadState() == 'W') { return true; // global } if (!isLocked()) { return false; } const StringData db = nsToDatabaseSubstring(ns); const newlm::ResourceId resIdDb(newlm::RESOURCE_DATABASE, db); // S on the database means we don't need to check further down the hierarchy if (isLockHeldForMode(resIdDb, newlm::MODE_S)) { return true; } if (!isLockHeldForMode(resIdDb, newlm::MODE_IS)) { return false; } if (nsIsFull(ns)) { const newlm::ResourceId resIdColl(newlm::RESOURCE_DATABASE, ns); return isLockHeldForMode(resIdColl, newlm::MODE_IS); } // We're just asking about a database, so IS on the db is enough. return true; }
bool LockerImpl<IsForMMAPV1>::isCollectionLockedForMode(StringData ns, LockMode mode) const { invariant(nsIsFull(ns)); if (isW()) return true; if (isR() && isSharedLockMode(mode)) return true; const NamespaceString nss(ns); const ResourceId resIdDb(RESOURCE_DATABASE, nss.db()); LockMode dbMode = getLockMode(resIdDb); if (!shouldConflictWithSecondaryBatchApplication()) return true; switch (dbMode) { case MODE_NONE: return false; case MODE_X: return true; case MODE_S: return isSharedLockMode(mode); case MODE_IX: case MODE_IS: { const ResourceId resIdColl(RESOURCE_COLLECTION, ns); return isLockHeldForMode(resIdColl, mode); } break; case LockModesCount: break; } invariant(false); return false; }
void LockerImpl<IsForMMAPV1>::beginWriteUnitOfWork() { // Sanity check that write transactions under MMAP V1 have acquired the flush lock, so we // don't allow partial changes to be written. dassert(!IsForMMAPV1 || isLockHeldForMode(resourceIdMMAPV1Flush, MODE_IX)); _wuowNestingLevel++; }
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())); }; }
bool LockerImpl<IsForMMAPV1>::isWriteLocked(const StringData& ns) const { if (isWriteLocked()) { return true; } const StringData db = nsToDatabaseSubstring(ns); const ResourceId resIdNs(RESOURCE_DATABASE, db); return isLockHeldForMode(resIdNs, MODE_X); }
bool LockerImpl<IsForMMAPV1>::isDbLockedForMode(StringData dbName, LockMode mode) const { invariant(nsIsDbOnly(dbName)); if (isW()) return true; if (isR() && isSharedLockMode(mode)) return true; const ResourceId resIdDb(RESOURCE_DATABASE, dbName); return isLockHeldForMode(resIdDb, mode); }
bool LockerImpl::isAtLeastReadLocked(const StringData& ns) const { if (threadState() == 'R' || threadState() == 'W') return true; // global if (!isLocked()) return false; const StringData db = nsToDatabaseSubstring(ns); const newlm::ResourceId resIdNs(newlm::RESOURCE_DATABASE, db); return isLockHeldForMode(resIdNs, newlm::MODE_S); }
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())); }; }
bool LockerImpl<IsForMMAPV1>::isReadLocked() const { return isLockHeldForMode(resourceIdGlobal, MODE_IS); }
bool LockerImpl::isWriteLocked() const { return isLockHeldForMode(resourceIdGlobal, MODE_IX); }
bool LockerImpl::hasAnyReadLock() const { return isLockHeldForMode(resourceIdGlobal, MODE_IS); }