Ejemplo n.º 1
0
 void LockerImpl::_yieldFlushLockForMMAPV1() {
     if (!inAWriteUnitOfWork()) {
         invariant(unlock(resourceIdMMAPV1Flush));
         invariant(LOCK_OK ==
             lock(resourceIdMMAPV1Flush, getLockMode(resourceIdGlobal), UINT_MAX));
     }
 }
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
    LockResult LockerImpl::lock(const ResourceId& resId, LockMode mode, unsigned timeoutMs) {
        _notify.clear();

        _lock.lock();
        LockRequest* request = _find(resId);
        if (request == NULL) {
            request = new LockRequest();
            request->initNew(resId, this, &_notify);

            _requests.insert(LockRequestsPair(resId, request));
        }
        else {
            invariant(request->recursiveCount > 0);
            request->notify = &_notify;
        }
        _lock.unlock();

        // Methods on the Locker class are always called single-threadly, so it is safe to release
        // the spin lock, which protects the Locker here. The only thing which could alter the
        // state of the request is deadlock detection, which however would synchronize on the
        // LockManager calls.

        LockResult result = globalLockManagerPtr->lock(resId, request, mode);
        if (result == LOCK_WAITING) {
            // Under MMAP V1 engine a deadlock can occur if a thread goes to sleep waiting on DB
            // lock, while holding the flush lock, so it has to be released. This is only correct
            // to do if not in a write unit of work.
            bool unlockedFlushLock = false;

            if (!inAWriteUnitOfWork() && 
                (resId != resourceIdGlobal) &&
                (resId != resourceIdMMAPV1Flush) &&
                (resId != resourceIdLocalDB)) {

                invariant(unlock(resourceIdMMAPV1Flush));
                unlockedFlushLock = true;
            }

            // Do the blocking outside of the flush lock (if not in a write unit of work)
            result = _notify.wait(timeoutMs);

            if (unlockedFlushLock) {
                // We cannot obey the timeout here, because it is not correct to return from the
                // lock request with the flush lock released.
                invariant(LOCK_OK ==
                    lock(resourceIdMMAPV1Flush, getLockMode(resourceIdGlobal), UINT_MAX));
            }
        }

        if (result != LOCK_OK) {
            // Can only be LOCK_TIMEOUT, because the lock manager does not return any other errors
            // at this point. Could be LOCK_DEADLOCK, when deadlock detection is implemented.
            invariant(result == LOCK_TIMEOUT);
            invariant(_unlockAndUpdateRequestsList(resId, request));
        }

        return result;
    }
Ejemplo n.º 4
0
void LockerImpl<IsForMMAPV1>::lockMMAPV1Flush() {
    if (!IsForMMAPV1)
        return;

    // The flush lock always has a reference count of 1, because it is dropped at the end of
    // each write unit of work in order to allow the flush thread to run. See the comments in
    // the header for information on how the MMAP V1 journaling system works.
    LockRequest* globalLockRequest = _requests.find(resourceIdGlobal).objAddr();
    if (globalLockRequest->recursiveCount == 1) {
        invariant(LOCK_OK == lock(resourceIdMMAPV1Flush, _getModeForMMAPV1FlushLock()));
    }

    dassert(getLockMode(resourceIdMMAPV1Flush) == _getModeForMMAPV1FlushLock());
}
Ejemplo n.º 5
0
    char LockerImpl::threadState() const {
        switch (getLockMode(resourceIdGlobal)) {
        case MODE_IS:
            return 'r';
        case MODE_IX:
            return 'w';
        case MODE_S:
            return 'R';
        case MODE_X:
            return 'W';
        case MODE_NONE:
            return '\0';
        }

        invariant(false);
    }
Ejemplo n.º 6
0
    LockResult LockerImpl::lockGlobal(LockMode mode, unsigned timeoutMs) {
        LockRequest* request = _find(resourceIdGlobal);
        if (request != NULL) {
            // No upgrades on the GlobalLock are allowed until we can handle deadlocks.
            invariant(request->mode >= mode);
        }
        else {
            // Global lock should be the first lock on the operation
            invariant(_requests.empty());
        }

        Timer timer;

        LockResult globalLockResult = lock(resourceIdGlobal, mode, timeoutMs);
        if (globalLockResult != LOCK_OK) {
            invariant(globalLockResult == LOCK_TIMEOUT);

            return globalLockResult;
        }

        // Obey the requested timeout
        const unsigned elapsedTimeMs = timer.millis();
        const unsigned remainingTimeMs =
            elapsedTimeMs < timeoutMs ? (timeoutMs - elapsedTimeMs) : 0;

        if (request == NULL) {
            // Special-handling for MMAP V1.
            LockResult flushLockResult =
                lock(resourceIdMMAPV1Flush, getLockMode(resourceIdGlobal), remainingTimeMs);

            if (flushLockResult != LOCK_OK) {
                invariant(flushLockResult == LOCK_TIMEOUT);
                invariant(unlock(resourceIdGlobal));

                return flushLockResult;
            }
        }

        return LOCK_OK;
    }
Ejemplo n.º 7
0
bool LockerImpl<IsForMMAPV1>::isLockHeldForMode(ResourceId resId, LockMode mode) const {
    return isModeCovered(mode, getLockMode(resId));
}
Ejemplo n.º 8
0
LockResult LockerImpl<IsForMMAPV1>::lockGlobalComplete(Milliseconds timeout) {
    return lockComplete(resourceIdGlobal, getLockMode(resourceIdGlobal), timeout, false);
}
Ejemplo n.º 9
0
bool LockerImpl<IsForMMAPV1>::isLocked() const {
    return getLockMode(resourceIdGlobal) != MODE_NONE;
}
Ejemplo n.º 10
0
bool LockerImpl<IsForMMAPV1>::isR() const {
    return getLockMode(resourceIdGlobal) == MODE_S;
}
Ejemplo n.º 11
0
LockResult LockerImpl<IsForMMAPV1>::lockGlobalComplete(OperationContext* opCtx, Date_t deadline) {
    return lockComplete(opCtx, resourceIdGlobal, getLockMode(resourceIdGlobal), deadline, false);
}
Ejemplo n.º 12
0
 bool LockerImpl::isR() const {
     return getLockMode(resourceIdGlobal) == MODE_S;
 }
Ejemplo n.º 13
0
 bool LockerImpl::isLockHeldForMode(const ResourceId& resId, LockMode mode) const {
     return getLockMode(resId) >= mode;
 }